001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * 2013, Jesper Öqvist <jesper.oqvist@cs.lth.se> 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions are met: 007 * 008 * 1. Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * 2. Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * 3. Neither the name of the copyright holder nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 * POSSIBILITY OF SUCH DAMAGE. 030 */ 031 032 aspect NameCheck { 033 public void ASTNode.nameCheck() { 034 } 035 036 public TypeDecl ASTNode.extractSingleType(SimpleSet c) { 037 if (c.size() != 1) { 038 return null; 039 } 040 return (TypeDecl) c.iterator().next(); 041 } 042 043 public void SingleTypeImportDecl.nameCheck() { 044 if (!getAccess().type().typeName().equals(typeName()) && !getAccess().type().isUnknown()) { 045 errorf("Single-type import %s is not the canonical name of type %s", 046 typeName(), getAccess().type().typeName()); 047 } else if (allImportedTypes(getAccess().type().name()).size() > 1) { 048 errorf("%s is imported multiple times", getAccess().type().name()); 049 } 050 } 051 052 inh SimpleSet ImportDecl.allImportedTypes(String name); 053 eq CompilationUnit.getImportDecl().allImportedTypes(String name) = importedTypes(name); 054 055 public void TypeImportOnDemandDecl.nameCheck() { 056 if (getAccess().lastAccess().isTypeAccess() 057 && !getAccess().type().typeName().equals(typeName())) { 058 errorf("On demand type import %s.* is not the canonical name of type %s", 059 typeName(), getAccess().type().typeName()); 060 } 061 } 062 063 public void CompilationUnit.nameCheck() { 064 for (int i = 0; i < getNumImportDecl(); i++) { 065 ImportDecl decl = getImportDecl(i); 066 if (!decl.isOnDemand()) { 067 Iterator importIter = decl.importedTypes().iterator(); 068 while (importIter.hasNext()) { 069 TypeDecl importedType = (TypeDecl) importIter.next(); 070 Iterator iter = localLookupType(importedType.name()).iterator(); 071 while (iter.hasNext()) { 072 TypeDecl local = (TypeDecl) iter.next(); 073 if (local != importedType) { 074 errorf("imported type %s conflicts with visible type", decl.typeName()); 075 } 076 } 077 } 078 } 079 } 080 } 081 082 public void PackageAccess.nameCheck() { 083 if (!hasPackage(packageName())) { 084 errorf("package %s not found", packageName()); 085 } 086 } 087 088 syn boolean MethodAccess.validArgs() { 089 for (int i = 0; i < getNumArg(); i++) { 090 if (getArg(i).type().isUnknown()) { 091 return false; 092 } 093 } 094 return true; 095 } 096 097 public void ConstructorDecl.nameCheck() { 098 super.nameCheck(); 099 // 8.8 100 if (!hostType().name().equals(name())) { 101 errorf("constructor %s does not have the same name as the simple name of the host class %s", 102 name(), hostType().name()); 103 } 104 105 // 8.8.2 106 if (hostType().lookupConstructor(this) != this) { 107 errorf("constructor with signature %s is multiply declared in type %s", signature(), 108 hostType().typeName()); 109 } 110 111 if (circularThisInvocation(this)) { 112 errorf("The constructor %s may not directly or indirectly invoke itself", signature()); 113 } 114 } 115 116 // 8.8.5 117 syn lazy boolean ConstructorDecl.circularThisInvocation(ConstructorDecl decl) circular [true] { 118 if (hasConstructorInvocation()) { 119 Expr e = ((ExprStmt) getConstructorInvocation()).getExpr(); 120 if (e instanceof ConstructorAccess) { 121 ConstructorDecl constructorDecl = ((ConstructorAccess) e).decl(); 122 if (constructorDecl == decl) { 123 return true; 124 } 125 return constructorDecl.circularThisInvocation(decl); 126 } 127 } 128 return false; 129 } 130 131 public void MethodDecl.nameCheck() { 132 // 8.4 133 // 8.4.2 134 if (hostType().methodsSignature(signature()).size() > 1) { 135 errorf("method with signature %s is multiply declared in type %s", signature(), 136 hostType().typeName()); 137 } 138 // 8.4.3.4 139 if (isNative() && hasBlock()) { 140 error("native methods must have an empty semicolon body"); 141 } 142 // 8.4.5 143 if (isAbstract() && hasBlock()) { 144 error("abstract methods must have an empty semicolon body"); 145 } 146 // 8.4.5 147 if (!hasBlock() && !(isNative() || isAbstract())) { 148 error("only abstract and native methods may have an empty semicolon body"); 149 } 150 } 151 152 public void ConstructorAccess.nameCheck() { 153 super.nameCheck(); 154 ConstructorDecl decl = (ConstructorDecl) enclosingBodyDecl(); 155 if (((ExprStmt) decl.getConstructorInvocation()).getExpr() == this) { 156 // don't error-check the parsed constructor invocation in case it is not the used one 157 if (decls().isEmpty()) { 158 errorf("no constructor matches %s", this.prettyPrint()); 159 } else if (decls().size() > 1 && validArgs()) { 160 errorf("several most specific constructors for %s", this.prettyPrint()); 161 for (Iterator iter = decls().iterator(); iter.hasNext(); ) { 162 errorf(" %s", ((ConstructorDecl) iter.next()).signature()); 163 } 164 } 165 } 166 } 167 168 syn boolean ConstructorAccess.validArgs() { 169 for (int i = 0; i < getNumArg(); i++) { 170 if (getArg(i).type().isUnknown()) { 171 return false; 172 } 173 } 174 return true; 175 } 176 177 syn boolean ClassInstanceExpr.validArgs() { 178 for (int i = 0; i < getNumArg(); i++) { 179 if (getArg(i).type().isUnknown()) { 180 return false; 181 } 182 } 183 return true; 184 } 185 186 public void ClassInstanceExpr.nameCheck() { 187 super.nameCheck(); 188 if (decls().isEmpty()) { 189 errorf("can not instantiate %s no matching constructor found in %s", type().typeName(), 190 type().typeName()); 191 } else if (decls().size() > 1 && validArgs()) { 192 error("several most specific constructors found"); 193 for (Iterator iter = decls().iterator(); iter.hasNext(); ) { 194 errorf(" %s", ((ConstructorDecl) iter.next()).signature()); 195 } 196 } else if (!hasTypeDecl()) { 197 // check if the constructor is accessible (stricter when not in a class instance expression) 198 // if constructor is private it can not be accessed outside the host class or a subtype of it 199 ConstructorDecl decl = decl(); 200 if (decl.isProtected() && !hostPackage().equals(decl.hostPackage()) && 201 !hostType().instanceOf(decl.hostType())) { 202 errorf("can not access the constructor %s", this.prettyPrint()); 203 } 204 } 205 } 206 207 public void ArrayTypeAccess.nameCheck() { 208 if (decl().elementType().isUnknown()) { 209 errorf("no type named %s", decl().elementType().typeName()); 210 } 211 } 212 213 public void TypeAccess.nameCheck() { 214 if (isQualified() && !qualifier().isTypeAccess() && !qualifier().isPackageAccess()) { 215 errorf("can not access the type named %s in this context", decl().typeName()); 216 } 217 if (decls().isEmpty()) { 218 errorf("no visible type named %s", typeName()); 219 } 220 if (decls().size() > 1) { 221 StringBuilder sb = new StringBuilder(); 222 sb.append("several types named " + name() + ":"); 223 for (Iterator iter = decls().iterator(); iter.hasNext(); ) { 224 TypeDecl t = (TypeDecl) iter.next(); 225 sb.append(" " + t.typeName()); 226 } 227 error(sb.toString()); 228 } 229 } 230 231 232 public void ClassAccess.nameCheck() { 233 if (isQualified() && !qualifier().isTypeAccess()) { 234 error("class literal may only contain type names"); 235 } 236 } 237 238 public void VarAccess.nameCheck() { 239 if (decls().isEmpty() && (!isQualified() || !qualifier().type().isUnknown() || qualifier().isPackageAccess())) { 240 errorf("no field named %s is accessible", name()); 241 } 242 if (decls().size() > 1) { 243 StringBuffer sb = new StringBuffer(); 244 sb.append("several fields named " + name()); 245 for (Iterator iter = decls().iterator(); iter.hasNext(); ) { 246 Variable v = (Variable) iter.next(); 247 sb.append("\n " + v.type().typeName() + "." + v.name() + " declared in " + v.hostType().typeName()); 248 } 249 error(sb.toString()); 250 } 251 252 // 8.8.5.1 253 if (inExplicitConstructorInvocation() && !isQualified() && decl().isInstanceVariable() && hostType() == decl().hostType()) { 254 errorf("instance variable %s may not be accessed in an explicit constructor invocation", name()); 255 } 256 257 Variable v = decl(); 258 if (!v.isFinal() && !v.isClassVariable() && !v.isInstanceVariable() && v.hostType() != hostType()) { 259 error("A parameter/variable used but not declared in an inner class must be declared final"); 260 } 261 262 // 8.3.2.3 263 if ((decl().isInstanceVariable() || decl().isClassVariable()) && !isQualified()) { 264 if (hostType() != null && !hostType().declaredBeforeUse(decl(), this)) { 265 if (inSameInitializer() && !simpleAssignment() && inDeclaringClass()) { 266 BodyDecl b = closestBodyDecl(hostType()); 267 errorf("variable %s is used in %s before it is declared", decl().name(), b.prettyPrint()); 268 } 269 } 270 } 271 272 } 273 274 // find the bodydecl declared in t in which this construct is nested 275 public BodyDecl VarAccess.closestBodyDecl(TypeDecl t) { 276 ASTNode node = this; 277 while (!(node.getParent().getParent() instanceof Program) && node.getParent().getParent() != t) { 278 node = node.getParent(); 279 } 280 if (node instanceof BodyDecl) { 281 return (BodyDecl) node; 282 } 283 return null; 284 } 285 286 syn boolean VarAccess.inSameInitializer() { 287 BodyDecl b = closestBodyDecl(decl().hostType()); 288 if (b == null) { 289 return false; 290 } 291 if (b instanceof FieldDeclaration && ((FieldDeclaration) b).isStatic() == decl().isStatic()) { 292 return true; 293 } 294 if (b instanceof InstanceInitializer && !decl().isStatic()) { 295 return true; 296 } 297 if (b instanceof StaticInitializer && decl().isStatic()) { 298 return true; 299 } 300 return false; 301 } 302 303 syn boolean VarAccess.simpleAssignment() = isDest() && getParent() instanceof AssignSimpleExpr; 304 305 syn boolean VarAccess.inDeclaringClass() = hostType() == decl().hostType(); 306 307 inh boolean TypeDecl.hasPackage(String packageName); 308 inh boolean PackageAccess.hasPackage(String packageName); 309 310 inh ASTNode TypeDecl.enclosingBlock(); 311 eq MethodDecl.getBlock().enclosingBlock() = this; 312 eq ConstructorDecl.getBlock().enclosingBlock() = this; 313 eq InstanceInitializer.getBlock().enclosingBlock() = this; 314 eq Program.getChild().enclosingBlock() = null; 315 316 public void TypeDecl.nameCheck() { 317 if (isTopLevelType() && lookupType(packageName(), name()) != this) { 318 errorf("duplicate type %s in package %s", name(), packageName()); 319 } 320 321 if (!isTopLevelType() && !isAnonymous() && !isLocalClass() && extractSingleType(enclosingType().memberTypes(name())) != this) { 322 errorf("duplicate member type %s in type %s", name(), enclosingType().typeName()); 323 } 324 325 // 14.3 326 if (isLocalClass()) { 327 TypeDecl typeDecl = extractSingleType(lookupType(name())); 328 if (typeDecl != null && typeDecl != this && typeDecl.isLocalClass() && enclosingBlock() == typeDecl.enclosingBlock()) { 329 errorf("local class named %s may not be redeclared as a local class in the same block", 330 name()); 331 } 332 } 333 334 if (!packageName().equals("") && hasPackage(fullName())) { 335 errorf("type name conflicts with a package using the same name: %s", name()); 336 } 337 338 // 8.1 & 9.1 339 if (hasEnclosingTypeDecl(name())) { 340 error("type may not have the same simple name as an enclosing type declaration"); 341 } 342 } 343 344 syn boolean TypeDecl.hasEnclosingTypeDecl(String name) { 345 TypeDecl enclosingType = enclosingType(); 346 if (enclosingType != null) { 347 return enclosingType.name().equals(name) || enclosingType.hasEnclosingTypeDecl(name); 348 } 349 return false; 350 } 351 352 public void FieldDeclaration.nameCheck() { 353 super.nameCheck(); 354 // 8.3 355 for (Iterator iter = hostType().memberFields(name()).iterator(); iter.hasNext(); ) { 356 Variable v = (Variable) iter.next(); 357 if (v != this && v.hostType() == hostType()) { 358 errorf("field named %s is multiply declared in type %s", name(), hostType().typeName()); 359 } 360 } 361 362 } 363 364 inh VariableScope ParameterDeclaration.outerScope(); 365 inh VariableScope VariableDeclaration.outerScope(); 366 eq BasicCatch.getParameter().outerScope() = this; 367 eq Block.getStmt().outerScope() = this; 368 eq TypeDecl.getChild().outerScope() = this; 369 eq ForStmt.getInitStmt().outerScope() = this; 370 eq ForStmt.getStmt().outerScope() = this; 371 eq Program.getChild().outerScope() { 372 throw new UnsupportedOperationException("outerScope() not defined"); 373 } 374 375 public void VariableDeclaration.nameCheck() { 376 SimpleSet decls = outerScope().lookupVariable(name()); 377 for (Iterator iter = decls.iterator(); iter.hasNext(); ) { 378 Variable var = (Variable) iter.next(); 379 if (var instanceof VariableDeclaration) { 380 VariableDeclaration decl = (VariableDeclaration) var; 381 if (decl != this && decl.enclosingBodyDecl() == enclosingBodyDecl()) { 382 errorf("duplicate declaration of local variable %s in enclosing scope", name()); 383 } 384 } 385 // 8.4.1 386 else if (var instanceof ParameterDeclaration) { 387 ParameterDeclaration decl = (ParameterDeclaration) var; 388 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 389 errorf("duplicate declaration of local variable and parameter %s", name()); 390 } 391 } 392 } 393 if (getParent().getParent() instanceof Block) { 394 Block block = (Block) getParent().getParent(); 395 for (int i = 0; i < block.getNumStmt(); i++) { 396 if (block.getStmt(i) instanceof Variable) { 397 Variable v = (Variable) block.getStmt(i); 398 if (v.name().equals(name()) && v != this) { 399 errorf("duplicate declaration of local variable %s", name()); 400 } 401 } 402 } 403 } 404 } 405 406 public void ParameterDeclaration.nameCheck() { 407 SimpleSet decls = outerScope().lookupVariable(name()); 408 for (Iterator iter = decls.iterator(); iter.hasNext(); ) { 409 Variable var = (Variable) iter.next(); 410 if (var instanceof VariableDeclaration) { 411 VariableDeclaration decl = (VariableDeclaration) var; 412 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 413 errorf("duplicate declaration of local variable %s", name()); 414 } 415 } else if (var instanceof ParameterDeclaration) { 416 ParameterDeclaration decl = (ParameterDeclaration) var; 417 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 418 errorf("duplicate declaration of local variable %s", name()); 419 } 420 } 421 } 422 423 // 8.4.1 424 if (!lookupVariable(name()).contains(this)) { 425 errorf("duplicate declaration of parameter %s", name()); 426 } 427 } 428 429 inh BodyDecl ParameterDeclaration.enclosingBodyDecl(); 430 431 public void LabeledStmt.nameCheck() { 432 LabeledStmt stmt = lookupLabel(getLabel()); 433 if (stmt != null) { 434 if (stmt.enclosingBodyDecl() == enclosingBodyDecl()) { 435 error("Labels can not shadow labels in the same member"); 436 } 437 } 438 } 439 440 inh boolean BreakStmt.insideLoop(); 441 inh boolean ContinueStmt.insideLoop(); 442 443 eq Program.getChild().insideLoop() = false; 444 eq TypeDecl.getBodyDecl(int i).insideLoop() = false; 445 eq ForStmt.getStmt().insideLoop() = true; 446 eq WhileStmt.getStmt().insideLoop() = true; 447 eq DoStmt.getStmt().insideLoop() = true; 448 449 inh boolean BreakStmt.insideSwitch(); 450 eq Program.getChild().insideSwitch() = false; 451 eq TypeDecl.getBodyDecl(int i).insideSwitch() = false; 452 eq SwitchStmt.getBlock().insideSwitch() = true; 453 454 public void BreakStmt.nameCheck() { 455 if (!hasLabel() && !insideLoop() && !insideSwitch()) { 456 error("break outside switch or loop"); 457 } else if (hasLabel()) { 458 LabeledStmt label = lookupLabel(getLabel()); 459 if (label == null) { 460 error("labeled break must have visible matching label"); 461 } 462 } 463 } 464 465 public void ContinueStmt.nameCheck() { 466 if (!insideLoop()) { 467 error("continue outside loop"); 468 } else if (hasLabel()) { 469 LabeledStmt label = lookupLabel(getLabel()); 470 if (label == null) { 471 error("labeled continue must have visible matching label"); 472 } else if (!label.getStmt().continueLabel()) { 473 errorf("%s is not a loop label", getLabel()); 474 } 475 } 476 } 477 478 syn boolean Stmt.continueLabel() = false; 479 eq ForStmt.continueLabel() = true; 480 eq WhileStmt.continueLabel() = true; 481 eq DoStmt.continueLabel() = true; 482 483 public void ConstCase.nameCheck() { 484 if (getValue().isConstant() && bind(this) != this) { 485 errorf("constant expression %s is multiply declared in two case statements", 486 getValue().prettyPrint()); 487 } 488 } 489 490 public void DefaultCase.nameCheck() { 491 if (bind(this) != this) { 492 error("only one default case statement allowed"); 493 } 494 } 495 496 inh lazy Case Case.bind(Case c); 497 eq SwitchStmt.getBlock().bind(Case c) { 498 Block b = getBlock(); 499 for (int i = 0; i < b.getNumStmt(); i++) { 500 if (b.getStmt(i) instanceof Case && ((Case) b.getStmt(i)).constValue(c)) { 501 return (Case) b.getStmt(i); 502 } 503 } 504 return null; 505 } 506 eq Program.getChild().bind(Case c) = null; 507 508 syn boolean TypeDecl.assignableToInt() = false; 509 eq IntegralType.assignableToInt() = true; 510 eq LongType.assignableToInt() = false; 511 512 syn boolean Case.constValue(Case c); 513 eq ConstCase.constValue(Case c) { 514 if (!(c instanceof ConstCase) || !getValue().isConstant()) { 515 return false; 516 } 517 if (!getValue().type().assignableToInt() || !((ConstCase) c).getValue().type().assignableToInt()) { 518 return false; 519 } 520 return getValue().constant().intValue() == ((ConstCase) c).getValue().constant().intValue(); 521 } 522 eq DefaultCase.constValue(Case c) = c instanceof DefaultCase; 523 524 inh SimpleSet LocalClassDeclStmt.otherLocalClassDecls(String name); 525 inh SimpleSet Block.otherLocalClassDecls(String name); 526 527 eq BodyDecl.getChild().otherLocalClassDecls(String name) = SimpleSet.emptySet; 528 529 eq Block.getStmt(int index).otherLocalClassDecls(String name) { 530 SimpleSet local = SimpleSet.emptySet; 531 for (int i = index-1; i >= 0 && !(getStmt(i) instanceof Case); --i) { 532 if (getStmt(i) instanceof LocalClassDeclStmt) { 533 TypeDecl t = ((LocalClassDeclStmt) getStmt(i)).getClassDecl(); 534 if (t.name().equals(name)) { 535 local = local.add(t); 536 } 537 } 538 } 539 if (!local.isEmpty()) { 540 return local; 541 } else { 542 return otherLocalClassDecls(name); 543 } 544 } 545 546 /** 547 * Checks that this local class declaration does not conflict with a previous 548 * declaration in the local scope. 549 */ 550 public void LocalClassDeclStmt.nameCheck() { 551 TypeDecl decl = getClassDecl(); 552 SimpleSet decls = otherLocalClassDecls(decl.name()); 553 if (!decls.isEmpty()) { 554 errorf("another local class %s has already been declared in this scope", decl.name()); 555 } 556 } 557 }