001    /*
002     * JastAddJ is covered by the modified BSD License. You should have received
003     * a copy of the modified BSD license with this compiler.
004     * 
005     * Copyright (c) 2011, Jesper Öqvist <jesper.oqvist@cs.lth.se>
006     * All rights reserved.
007     */
008    
009    aspect SafeVarargs {
010    
011        /**
012         * @return true if the modifier list includes the SafeVarargs annotation
013         */
014        syn boolean TypeDecl.hasAnnotationSafeVarargs() =
015                getModifiers().hasAnnotationSafeVarargs();
016    
017        /**
018         * @return true if the modifier list includes the SafeVarargs annotation
019         */
020        syn boolean BodyDecl.hasAnnotationSafeVarargs() = false;
021        
022        /**
023         * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
024         */
025        eq MemberTypeDecl.hasAnnotationSafeVarargs() =
026                typeDecl().hasAnnotationSafeVarargs();
027        
028        /**
029         * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
030         */
031        eq MethodDecl.hasAnnotationSafeVarargs() =
032                getModifiers().hasAnnotationSafeVarargs();
033        
034        /**
035         * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
036         */
037        eq ConstructorDecl.hasAnnotationSafeVarargs() =
038                getModifiers().hasAnnotationSafeVarargs();
039    
040        /**
041         * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
042         */
043        eq FieldDeclaration.hasAnnotationSafeVarargs() =
044                getModifiers().hasAnnotationSafeVarargs();
045    
046        /**
047         * @return true if the modifier list includes the SafeVarargs annotation
048         */
049        syn boolean Modifiers.hasAnnotationSafeVarargs() =
050                annotation(lookupType("java.lang", "SafeVarargs")) != null;
051    
052        /**
053         * It is an error if the SafeVarargs annotation is used on something
054         * that is not a variable arity method or constructor.
055         */
056        syn boolean BodyDecl.hasIllegalAnnotationSafeVarargs() =
057                hasAnnotationSafeVarargs();
058    
059        /**
060         * The SafeVarargs annotation is allowed on a constructor if it
061         * has variable arity.
062         */
063        eq ConstructorDecl.hasIllegalAnnotationSafeVarargs() =
064                hasAnnotationSafeVarargs() && !isVariableArity();
065    
066        /**
067         * The SafeVarargs annotation is allowed on a method if it
068         * has variable arity and is either static or final.
069         */
070        eq MethodDecl.hasIllegalAnnotationSafeVarargs() =
071                hasAnnotationSafeVarargs() && (!isVariableArity() || (!isFinal() && !isStatic()));
072    
073        public void MethodAccess.checkWarnings() {
074    
075                MethodDecl decl = decl();
076                if (decl.getNumParameter() == 0) return;
077                if (decl.getNumParameter() > getNumArg()) return;
078    
079                ParameterDeclaration param = decl.getParameter(
080                                decl.getNumParameter()-1);
081                if (!withinSuppressWarnings("unchecked") &&
082                                !decl.hasAnnotationSafeVarargs() &&
083                                param.isVariableArity() &&
084                                !param.type().isReifiable())
085                        warning("unchecked array creation for variable " +
086                                "arity parameter of " + decl().name());
087        }
088    
089        /**
090         * We must report illegal uses of the SafeVarargs annotation.
091         * It is only allowed on variable arity method and constructor declarations.
092         */
093        public void BodyDecl.checkWarnings() {
094                if (hasIllegalAnnotationSafeVarargs())
095                        error("@SafeVarargs is only allowed for variable " +
096                                "arity method and constructor declarations");
097        }
098    
099        /**
100        * A type is reifiable if it either refers to a non-parameterized type,
101        * is a raw type, is a parameterized type with only unbound wildcard
102        * parameters or is an array type with a reifiable type parameter.
103        *
104        * @see "JLSv3 &sect;4.7"
105        */
106       syn boolean TypeDecl.isReifiable() = true;
107    
108       /**
109        * A type variable is never reifiable.
110        * @return false
111        */
112       eq TypeVariable.isReifiable() = false;
113    
114       /**
115        * A parameterized type is reifiable only if it's
116        * type parameters are all unbound wildcard types.
117        */
118       eq ParInterfaceDecl.isReifiable() {
119               if (isRawType())
120                       return true;
121               for (int i = 0; i < getNumArgument(); ++i) {
122                       if (!getArgument(i).type().isWildcard())
123                               return false;
124               }
125               return true;
126       }
127    
128       /**
129        * A parameterized type is reifiable only if it's
130        * type parameters are all unbound wildcard types.
131        */
132       eq ParClassDecl.isReifiable() {
133               if (isRawType())
134                       return true;
135               for (int i = 0; i < getNumArgument(); ++i) {
136                       if (!getArgument(i).type().isWildcard())
137                               return false;
138               }
139               return true;
140       }
141    
142       /**
143        * An array type is reifiable only if the elements of the
144        * array are reifiable.
145        */
146       eq ArrayDecl.isReifiable() = elementType().isReifiable();
147    
148       /**
149        * Check if the method is missing a SafeVarargs annotation.
150        */
151       public void MethodDecl.checkWarnings() {
152               // check for illegal use of @SafeVarargs
153               super.checkWarnings();
154    
155               if (!suppressWarnings("unchecked") &&
156                               !hasAnnotationSafeVarargs() &&
157                               isVariableArity() &&
158                               !getParameter(getNumParameter()-1).type().isReifiable())
159                       warning("possible heap pollution for " +
160                               "variable arity parameter");
161       }
162    
163    }