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 §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 }