001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect NameCheck { 011 public void ASTNode.nameCheck() { 012 } 013 014 public TypeDecl ASTNode.extractSingleType(SimpleSet c) { 015 if(c.size() != 1) 016 return null; 017 return (TypeDecl)c.iterator().next(); 018 } 019 020 public void SingleTypeImportDecl.nameCheck() { 021 if(!getAccess().type().typeName().equals(typeName()) && !getAccess().type().isUnknown()) 022 error("Single-type import " + typeName() + " is not the canonical name of type " + getAccess().type().typeName()); 023 else if(allImportedTypes(getAccess().type().name()).size() > 1) 024 error(getAccess().type().name() + " is imported multiple times"); 025 } 026 inh SimpleSet SingleTypeImportDecl.allImportedTypes(String name); 027 eq CompilationUnit.getImportDecl().allImportedTypes(String name) = 028 importedTypes(name); 029 030 public void TypeImportOnDemandDecl.nameCheck() { 031 if(getAccess().lastAccess().isTypeAccess() && !getAccess().type().typeName().equals(typeName())) 032 error("On demand type import " + typeName() + ".* is not the canonical name of type " + getAccess().type().typeName()); 033 } 034 035 public void CompilationUnit.nameCheck() { 036 for(int i = 0; i < getNumImportDecl(); i++) { 037 ImportDecl decl = getImportDecl(i); 038 if(decl instanceof SingleTypeImportDecl) { 039 TypeDecl importedType = decl.getAccess().type(); 040 Iterator iter = localLookupType(importedType.name()).iterator(); 041 while (iter.hasNext()) { 042 TypeDecl local = (TypeDecl) iter.next(); 043 if (local != importedType) 044 error("imported type " + decl + " is conflicting with visible type"); 045 } 046 } 047 } 048 } 049 050 public void PackageAccess.nameCheck() { 051 if(!hasPackage(packageName())) { 052 error(packageName() + " not found"); 053 } 054 } 055 056 public void AmbiguousAccess.nameCheck() { 057 error("ambiguous name " + name()); 058 } 059 060 public void PackageOrTypeAccess.nameCheck() { 061 error("packageortype name " + name()); 062 } 063 064 065 syn boolean MethodAccess.validArgs() { 066 for(int i = 0; i < getNumArg(); i++) 067 if(getArg(i).type().isUnknown()) 068 return false; 069 return true; 070 } 071 072 073 public void ConstructorDecl.nameCheck() { 074 super.nameCheck(); 075 // 8.8 076 if(!hostType().name().equals(name())) 077 error("constructor " + name() +" does not have the same name as the simple name of the host class " + hostType().name()); 078 079 // 8.8.2 080 if(hostType().lookupConstructor(this) != this) 081 error("constructor with signature " + signature() + " is multiply declared in type " + hostType().typeName()); 082 083 if(circularThisInvocation(this)) 084 error("The constructor " + signature() + " may not directly or indirectly invoke itself"); 085 } 086 087 // 8.8.5 088 syn lazy boolean ConstructorDecl.circularThisInvocation(ConstructorDecl decl) circular [true] { 089 if(hasConstructorInvocation()) { 090 Expr e = ((ExprStmt)getConstructorInvocation()).getExpr(); 091 if(e instanceof ConstructorAccess) { 092 ConstructorDecl constructorDecl = ((ConstructorAccess)e).decl(); 093 if(constructorDecl == decl) 094 return true; 095 return constructorDecl.circularThisInvocation(decl); 096 } 097 } 098 return false; 099 } 100 101 public void MethodDecl.nameCheck() { 102 // 8.4 103 // 8.4.2 104 if(!hostType().methodsSignature(signature()).contains(this)) 105 error("method with signature " + signature() + " is multiply declared in type " + hostType().typeName()); 106 // 8.4.3.4 107 if(isNative() && hasBlock()) 108 error("native methods must have an empty semicolon body"); 109 // 8.4.5 110 if(isAbstract() && hasBlock()) 111 error("abstract methods must have an empty semicolon body"); 112 // 8.4.5 113 if(!hasBlock() && !(isNative() || isAbstract())) 114 error("only abstract and native methods may have an empty semicolon body"); 115 } 116 117 public void ConstructorAccess.nameCheck() { 118 super.nameCheck(); 119 if(decls().isEmpty()) 120 error("no constructor named " + this); 121 if(decls().size() > 1 && validArgs()) { 122 error("several most specific constructors for " + this); 123 for(Iterator iter = decls().iterator(); iter.hasNext(); ) { 124 error(" " + ((ConstructorDecl)iter.next()).signature()); 125 } 126 } 127 } 128 129 syn boolean ConstructorAccess.validArgs() { 130 for(int i = 0; i < getNumArg(); i++) 131 if(getArg(i).type().isUnknown()) 132 return false; 133 return true; 134 } 135 syn boolean ClassInstanceExpr.validArgs() { 136 for(int i = 0; i < getNumArg(); i++) 137 if(getArg(i).type().isUnknown()) 138 return false; 139 return true; 140 } 141 142 public void ClassInstanceExpr.nameCheck() { 143 super.nameCheck(); 144 if(decls().isEmpty()) 145 error("can not instantiate " + type().typeName() + " no matching constructor found in " + type().typeName()); 146 else if(decls().size() > 1 && validArgs()) { 147 error("several most specific constructors found"); 148 for(Iterator iter = decls().iterator(); iter.hasNext(); ) { 149 error(" " + ((ConstructorDecl)iter.next()).signature()); 150 } 151 } 152 } 153 154 155 public void ArrayTypeAccess.nameCheck() { 156 if(decl().elementType().isUnknown()) 157 error("no type named " + decl().elementType().typeName()); 158 } 159 160 public void TypeAccess.nameCheck() { 161 if(isQualified() && !qualifier().isTypeAccess() && !qualifier().isPackageAccess()) 162 error("can not access the type named " + decl().typeName() + " in this context"); 163 if(decls().isEmpty()) 164 error("no visible type named " + typeName()); 165 if(decls().size() > 1) { 166 StringBuffer s = new StringBuffer(); 167 s.append("several types named " + name() + ":"); 168 for(Iterator iter = decls().iterator(); iter.hasNext(); ) { 169 TypeDecl t = (TypeDecl)iter.next(); 170 s.append(" " + t.typeName()); 171 } 172 error(s.toString()); 173 } 174 } 175 176 177 public void ClassAccess.nameCheck() { 178 if(isQualified() && !qualifier().isTypeAccess()) 179 error("class literal may only contain type names"); 180 } 181 182 public void VarAccess.nameCheck() { 183 if(decls().isEmpty() && (!isQualified() || !qualifier().type().isUnknown() || qualifier().isPackageAccess())) 184 error("no field named " + name() + " is accessible"); 185 if(decls().size() > 1) { 186 StringBuffer s = new StringBuffer(); 187 s.append("several fields named " + name()); 188 for(Iterator iter = decls().iterator(); iter.hasNext(); ) { 189 Variable v = (Variable)iter.next(); 190 s.append("\n " + v.type().typeName() + "." + v.name() + " declared in " + v.hostType().typeName()); 191 } 192 error(s.toString()); 193 } 194 195 // 8.8.5.1 196 if(inExplicitConstructorInvocation() && !isQualified() && decl().isInstanceVariable() && hostType() == decl().hostType()) 197 error("instance variable " + name() + " may not be accessed in an explicit constructor invocation"); 198 199 Variable v = decl(); 200 if(!v.isFinal() && !v.isClassVariable() && !v.isInstanceVariable() && v.hostType() != hostType()) 201 error("A parameter/variable used but not declared in an inner class must be declared final"); 202 203 // 8.3.2.3 204 if((decl().isInstanceVariable() || decl().isClassVariable()) && !isQualified()) { 205 if(hostType() != null && !hostType().declaredBeforeUse(decl(), this)) { 206 if(inSameInitializer() && !simpleAssignment() && inDeclaringClass()) { 207 BodyDecl b = closestBodyDecl(hostType()); 208 error("variable " + decl().name() + " is used in " + b + " before it is declared"); 209 } 210 } 211 } 212 213 } 214 215 // find the bodydecl declared in t in which this construct is nested 216 public BodyDecl VarAccess.closestBodyDecl(TypeDecl t) { 217 ASTNode node = this; 218 while(!(node.getParent().getParent() instanceof Program) && node.getParent().getParent() != t) { 219 node = node.getParent(); 220 } 221 if(node instanceof BodyDecl) 222 return (BodyDecl)node; 223 return null; 224 } 225 226 syn boolean VarAccess.inSameInitializer() { 227 BodyDecl b = closestBodyDecl(decl().hostType()); 228 if(b == null) return false; 229 if(b instanceof FieldDeclaration && ((FieldDeclaration)b).isStatic() == decl().isStatic()) 230 return true; 231 if(b instanceof InstanceInitializer && !decl().isStatic()) 232 return true; 233 if(b instanceof StaticInitializer && decl().isStatic()) 234 return true; 235 return false; 236 } 237 238 syn boolean VarAccess.simpleAssignment() = isDest() && getParent() instanceof AssignSimpleExpr; 239 240 syn boolean VarAccess.inDeclaringClass() = hostType() == decl().hostType(); 241 242 inh boolean TypeDecl.hasPackage(String packageName); 243 inh boolean PackageAccess.hasPackage(String packageName); 244 245 inh ASTNode TypeDecl.enclosingBlock(); 246 eq MethodDecl.getBlock().enclosingBlock() = this; 247 eq ConstructorDecl.getBlock().enclosingBlock() = this; 248 eq InstanceInitializer.getBlock().enclosingBlock() = this; 249 eq Program.getChild().enclosingBlock() = null; 250 251 public void TypeDecl.nameCheck() { 252 if(isTopLevelType() && lookupType(packageName(), name()) != this) 253 error("duplicate type " + name() + " in package " + packageName()); 254 255 if(!isTopLevelType() && !isAnonymous() && !isLocalClass() && extractSingleType(enclosingType().memberTypes(name())) != this) 256 error("duplicate member type " + name() + " in type " + enclosingType().typeName()); 257 258 // 14.3 259 if(isLocalClass()) { 260 TypeDecl typeDecl = extractSingleType(lookupType(name())); 261 if(typeDecl != null && typeDecl != this && typeDecl.isLocalClass() && enclosingBlock() == typeDecl.enclosingBlock()) 262 error("local class named " + name() + " may not be redeclared as a local class in the same block"); 263 } 264 265 if(!packageName().equals("") && hasPackage(fullName())) 266 error("type name conflicts with a package using the same name: " + name()); 267 268 // 8.1 & 9.1 269 if(hasEnclosingTypeDecl(name())) { 270 error("type may not have the same simple name as an enclosing type declaration"); 271 } 272 } 273 274 syn boolean TypeDecl.hasEnclosingTypeDecl(String name) { 275 TypeDecl enclosingType = enclosingType(); 276 if(enclosingType != null) { 277 return enclosingType.name().equals(name) || enclosingType.hasEnclosingTypeDecl(name); 278 } 279 return false; 280 } 281 282 public void FieldDeclaration.nameCheck() { 283 super.nameCheck(); 284 // 8.3 285 for(Iterator iter = hostType().memberFields(name()).iterator(); iter.hasNext(); ) { 286 Variable v = (Variable)iter.next(); 287 if(v != this && v.hostType() == hostType()) 288 error("field named " + name() + " is multiply declared in type " + hostType().typeName()); 289 } 290 291 } 292 293 inh VariableScope ParameterDeclaration.outerScope(); 294 inh VariableScope VariableDeclaration.outerScope(); 295 eq BasicCatch.getParameter().outerScope() = this; 296 eq Block.getStmt().outerScope() = this; 297 eq TypeDecl.getBodyDecl().outerScope() = this; 298 eq ForStmt.getInitStmt().outerScope() = this; 299 eq ForStmt.getStmt().outerScope() = this; 300 eq Program.getChild().outerScope() { 301 throw new UnsupportedOperationException("outerScope() not defined"); 302 } 303 304 public void VariableDeclaration.nameCheck() { 305 SimpleSet decls = outerScope().lookupVariable(name()); 306 for(Iterator iter = decls.iterator(); iter.hasNext(); ) { 307 Variable var = (Variable)iter.next(); 308 if(var instanceof VariableDeclaration) { 309 VariableDeclaration decl = (VariableDeclaration)var; 310 if(decl != this && decl.enclosingBodyDecl() == enclosingBodyDecl()) 311 error("duplicate declaration of local variable " + name() + " in enclosing scope"); 312 } 313 // 8.4.1 314 else if(var instanceof ParameterDeclaration) { 315 ParameterDeclaration decl = (ParameterDeclaration)var; 316 if(decl.enclosingBodyDecl() == enclosingBodyDecl()) 317 error("duplicate declaration of local variable and parameter " + name()); 318 } 319 } 320 if(getParent().getParent() instanceof Block) { 321 Block block = (Block)getParent().getParent(); 322 for(int i = 0; i < block.getNumStmt(); i++) { 323 if(block.getStmt(i) instanceof Variable) { 324 Variable v = (Variable)block.getStmt(i); 325 if(v.name().equals(name()) && v != this) { 326 error("duplicate declaration of local variable " + name()); 327 } 328 } 329 } 330 } 331 } 332 333 public void ParameterDeclaration.nameCheck() { 334 SimpleSet decls = outerScope().lookupVariable(name()); 335 for(Iterator iter = decls.iterator(); iter.hasNext(); ) { 336 Variable var = (Variable)iter.next(); 337 if(var instanceof VariableDeclaration) { 338 VariableDeclaration decl = (VariableDeclaration)var; 339 if(decl.enclosingBodyDecl() == enclosingBodyDecl()) 340 error("duplicate declaration of local variable " + name()); 341 } 342 else if(var instanceof ParameterDeclaration) { 343 ParameterDeclaration decl = (ParameterDeclaration)var; 344 if(decl.enclosingBodyDecl() == enclosingBodyDecl()) 345 error("duplicate declaration of local variable " + name()); 346 } 347 } 348 349 // 8.4.1 350 if(!lookupVariable(name()).contains(this)) { 351 error("duplicate declaration of parameter " + name()); 352 } 353 } 354 inh BodyDecl ParameterDeclaration.enclosingBodyDecl(); 355 356 public void LabeledStmt.nameCheck() { 357 LabeledStmt stmt = lookupLabel(getLabel()); 358 if(stmt != null) { 359 if(stmt.enclosingBodyDecl() == enclosingBodyDecl()) { 360 error("Labels can not shadow labels in the same member"); 361 } 362 } 363 } 364 365 inh boolean BreakStmt.insideLoop(); 366 inh boolean ContinueStmt.insideLoop(); 367 368 eq Program.getChild().insideLoop() = false; 369 eq TypeDecl.getBodyDecl(int i).insideLoop() = false; 370 eq ForStmt.getStmt().insideLoop() = true; 371 eq WhileStmt.getStmt().insideLoop() = true; 372 eq DoStmt.getStmt().insideLoop() = true; 373 374 inh boolean BreakStmt.insideSwitch(); 375 eq Program.getChild().insideSwitch() = false; 376 eq TypeDecl.getBodyDecl(int i).insideSwitch() = false; 377 eq SwitchStmt.getBlock().insideSwitch() = true; 378 379 public void BreakStmt.nameCheck() { 380 if(!hasLabel() && !insideLoop() && !insideSwitch()) 381 error("break outside switch or loop"); 382 else if(hasLabel()) { 383 LabeledStmt label = lookupLabel(getLabel()); 384 if(label == null) 385 error("labeled break must have visible matching label"); 386 } 387 } 388 389 public void ContinueStmt.nameCheck() { 390 if(!insideLoop()) 391 error("continue outside loop"); 392 else if(hasLabel()) { 393 LabeledStmt label = lookupLabel(getLabel()); 394 if(label == null) 395 error("labeled continue must have visible matching label"); 396 else if(!label.getStmt().continueLabel()) 397 error(getLabel() + " is not a loop label"); 398 } 399 } 400 401 syn boolean Stmt.continueLabel() = false; 402 eq ForStmt.continueLabel() = true; 403 eq WhileStmt.continueLabel() = true; 404 eq DoStmt.continueLabel() = true; 405 406 public void ConstCase.nameCheck() { 407 if(getValue().isConstant() && bind(this) != this) { 408 error("constant expression " + getValue() + " is multiply declared in two case statements"); 409 } 410 } 411 public void DefaultCase.nameCheck() { 412 if(bind(this) != this) { 413 error("only one default case statement allowed"); 414 } 415 } 416 417 inh lazy Case Case.bind(Case c); 418 eq SwitchStmt.getBlock().bind(Case c) { 419 Block b = getBlock(); 420 for(int i = 0; i < b.getNumStmt(); i++) 421 if(b.getStmt(i) instanceof Case && ((Case)b.getStmt(i)).constValue(c)) 422 return (Case)b.getStmt(i); 423 return null; 424 } 425 eq Program.getChild().bind(Case c) = null; 426 427 syn boolean TypeDecl.assignableToInt() = false; 428 eq IntegralType.assignableToInt() = true; 429 eq LongType.assignableToInt() = false; 430 431 syn boolean Case.constValue(Case c); 432 eq ConstCase.constValue(Case c) { 433 if(!(c instanceof ConstCase) || !getValue().isConstant()) 434 return false; 435 if(!getValue().type().assignableToInt() || !((ConstCase)c).getValue().type().assignableToInt()) 436 return false; 437 return getValue().constant().intValue() == ((ConstCase)c).getValue().constant().intValue(); 438 } 439 eq DefaultCase.constValue(Case c) = c instanceof DefaultCase; 440 }