001    /* Copyright (c) 2011, Jesper Öqvist <jesper.oqvist@cs.lth.se>
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    
032    aspect SafeVarargs {
033    
034      /**
035       * @return true if the modifier list includes the SafeVarargs annotation
036       */
037      syn boolean TypeDecl.hasAnnotationSafeVarargs() = getModifiers().hasAnnotationSafeVarargs();
038    
039      /**
040       * @return true if the modifier list includes the SafeVarargs annotation
041       */
042      syn boolean BodyDecl.hasAnnotationSafeVarargs() = false;
043    
044      /**
045       * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
046       */
047      eq MemberTypeDecl.hasAnnotationSafeVarargs() = typeDecl().hasAnnotationSafeVarargs();
048    
049      /**
050       * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
051       */
052      eq MethodDecl.hasAnnotationSafeVarargs() = getModifiers().hasAnnotationSafeVarargs();
053    
054      /**
055       * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
056       */
057      eq ConstructorDecl.hasAnnotationSafeVarargs() = getModifiers().hasAnnotationSafeVarargs();
058    
059      /**
060       * @see AST.Modifiers#hasAnnotationSafeVarargs() Modifiers.hasAnnotationSafeVarargs()
061       */
062      eq FieldDeclaration.hasAnnotationSafeVarargs() = getModifiers().hasAnnotationSafeVarargs();
063    
064      /**
065       * @return true if the modifier list includes the SafeVarargs annotation
066       */
067      syn boolean Modifiers.hasAnnotationSafeVarargs() = hasAnnotation("java.lang", "SafeVarargs");
068    
069      /**
070       * It is an error if the SafeVarargs annotation is used on something
071       * that is not a variable arity method or constructor.
072       */
073      syn boolean BodyDecl.hasIllegalAnnotationSafeVarargs() = hasAnnotationSafeVarargs();
074    
075      /**
076       * The SafeVarargs annotation is allowed on a constructor if it
077       * has variable arity.
078       */
079      eq ConstructorDecl.hasIllegalAnnotationSafeVarargs() = hasAnnotationSafeVarargs() && !isVariableArity();
080    
081      /**
082       * The SafeVarargs annotation is allowed on a method if it
083       * has variable arity and is either static or final.
084       */
085      eq MethodDecl.hasIllegalAnnotationSafeVarargs() =
086          hasAnnotationSafeVarargs() && (!isVariableArity() || (!isFinal() && !isStatic()));
087    
088      public void MethodAccess.checkWarnings() {
089    
090        MethodDecl decl = decl();
091        if (decl.getNumParameter() == 0 || decl.getNumParameter() > getNumArg()) {
092          return;
093        }
094    
095        ParameterDeclaration param = decl.getParameter(decl.getNumParameter()-1);
096        if (!withinSuppressWarnings("unchecked")
097            && !decl.hasAnnotationSafeVarargs()
098            && param.isVariableArity()
099            && !param.type().isReifiable()) {
100          warning("unchecked array creation for variable " + "arity parameter of " + decl().name());
101        }
102      }
103    
104      /**
105       * We must report illegal uses of the SafeVarargs annotation.
106       * It is only allowed on variable arity method and constructor declarations.
107       */
108      public void BodyDecl.checkWarnings() {
109        if (hasIllegalAnnotationSafeVarargs()) {
110          error("@SafeVarargs is only allowed for variable arity method and constructor declarations");
111        }
112      }
113    
114      /**
115       * Check if the method is missing a SafeVarargs annotation.
116       */
117      public void MethodDecl.checkWarnings() {
118        // Check for illegal use of @SafeVarargs.
119        super.checkWarnings();
120    
121        if (!suppressWarnings("unchecked")
122            && !hasAnnotationSafeVarargs()
123            && isVariableArity()
124            && !getParameter(getNumParameter()-1).type().isReifiable()) {
125          warning("possible heap pollution for "
126              + "variable arity parameter");
127        }
128      }
129    
130    }