001 /* Copyright (c) 2005-2008, Torbjorn Ekman 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 import java.util.*; 032 033 // 5.1 Kinds of Conversion 034 aspect TypeConversion { 035 // 5.1.1 Identity Conversion 036 syn boolean TypeDecl.identityConversionTo(TypeDecl type) = this == type; 037 038 syn boolean TypeDecl.wideningConversionTo(TypeDecl type) = instanceOf(type); 039 syn lazy boolean TypeDecl.narrowingConversionTo(TypeDecl type) = instanceOf(type); 040 041 // 5.1.2 Widening Primitive Conversions 042 eq PrimitiveType.wideningConversionTo(TypeDecl type) = instanceOf(type); 043 044 //eq IntType.wideningConversionTo(TypeDecl type) = type.isLong() || type.isFloat() || type.isDouble(); 045 //eq FloatType.wideningConversionTo(TypeDecl type) = type.isLong(); 046 047 // 5.1.3 Narrowing Primitive Conversion 048 eq PrimitiveType.narrowingConversionTo(TypeDecl type) = type.instanceOf(this); 049 eq ShortType.narrowingConversionTo(TypeDecl type) = type.isByte() || type.isChar(); 050 eq CharType.narrowingConversionTo(TypeDecl type) = type.isByte() || type.isShort(); 051 eq ByteType.narrowingConversionTo(TypeDecl type) = type.isChar(); 052 053 // 5.1.4 Widening Reference Conversions 054 eq ReferenceType.wideningConversionTo(TypeDecl type) = instanceOf(type); 055 056 // 5.1.5 Narrowing Reference Conversions 057 eq ReferenceType.narrowingConversionTo(TypeDecl type) { 058 if (type.instanceOf(this)) { 059 return true; 060 } 061 if (isClassDecl() && !getModifiers().isFinal() && type.isInterfaceDecl()) { 062 return true; 063 } 064 if (isInterfaceDecl() && type.isClassDecl() && !type.getModifiers().isFinal()) { 065 return true; 066 } 067 if (isInterfaceDecl() && type.instanceOf(this)) { 068 return true; 069 } 070 if (fullName().equals("java.lang.Object") && type.isInterfaceDecl()) { 071 return true; 072 } 073 // Dragons 074 // TODO: Check if both are interfaces with compatible methods 075 if (isArrayDecl() && type.isArrayDecl() && elementType().instanceOf(type.elementType())) { 076 return true; 077 } 078 return false; 079 } 080 081 // 5.1.6 String Conversions 082 syn boolean TypeDecl.stringConversion() = true; 083 eq VoidType.stringConversion() = false; 084 085 // 5.2 Assignment Conversion 086 syn boolean TypeDecl.assignConversionTo(TypeDecl type, Expr expr) { 087 //System.out.println("@@@ " + fullName() + " assign conversion to " + type.fullName() + ", expr: " + expr); 088 boolean sourceIsConstant = expr != null ? expr.isConstant() : false; 089 //System.out.println("@@@ sourceIsConstant: " + sourceIsConstant); 090 if (identityConversionTo(type) || wideningConversionTo(type)) { 091 return true; 092 } 093 //System.out.println("@@@ narrowing conversion needed"); 094 //System.out.println("@@@ value: " + expr.value()); 095 if (sourceIsConstant && (isInt() || isChar() || isShort() || isByte()) && 096 (type.isByte() || type.isShort() || type.isChar()) && 097 narrowingConversionTo(type) && expr.representableIn(type)) 098 return true; 099 //System.out.println("@@@ false"); 100 return false; 101 } 102 103 // 5.3 Method Invocation Conversion 104 syn lazy boolean TypeDecl.methodInvocationConversionTo(TypeDecl type) { 105 return identityConversionTo(type) || wideningConversionTo(type); 106 } 107 108 // 5.5 Casting Conversion 109 syn lazy boolean TypeDecl.castingConversionTo(TypeDecl type) = identityConversionTo(type) || 110 wideningConversionTo(type) || narrowingConversionTo(type); 111 112 eq ClassDecl.castingConversionTo(TypeDecl type) { 113 if (type.isArrayDecl()) { 114 return isObject(); 115 } else if (type.isClassDecl()) { 116 return this == type || instanceOf(type) || type.instanceOf(this); 117 } else if (type.isInterfaceDecl()) { 118 return !isFinal() || instanceOf(type); 119 } else return super.castingConversionTo(type); 120 } 121 122 inh MethodDecl InterfaceDecl.unknownMethod(); 123 124 eq InterfaceDecl.castingConversionTo(TypeDecl type) { 125 if (type.isArrayDecl()) { 126 return type.instanceOf(this); 127 } else if (type.isClassDecl()) { 128 return !type.isFinal() || type.instanceOf(this); 129 } else if (type.isInterfaceDecl()) { 130 for (Iterator i1 = methodsIterator(); i1.hasNext(); ) { 131 MethodDecl m = (MethodDecl) i1.next(); 132 for (Iterator iter = type.methodsSignature(m.signature()).iterator(); iter.hasNext(); ) { 133 MethodDecl n = (MethodDecl) iter.next(); 134 if (n.type() != m.type()) { 135 return false; 136 } 137 } 138 } 139 return true; 140 } else return super.castingConversionTo(type); 141 } 142 143 eq ArrayDecl.castingConversionTo(TypeDecl type) { 144 if (type.isArrayDecl()) { 145 TypeDecl SC = componentType(); 146 TypeDecl TC = type.componentType(); 147 if (SC.isPrimitiveType() && TC.isPrimitiveType() && SC == TC) { 148 return true; 149 } 150 if (SC.isReferenceType() && TC.isReferenceType()) { 151 return SC.castingConversionTo(TC); 152 } 153 return false; 154 } else if (type.isClassDecl()) { 155 return type.isObject(); 156 } else if (type.isInterfaceDecl()) { 157 return type == typeSerializable() || type == typeCloneable(); 158 } else return super.castingConversionTo(type); 159 } 160 161 inh TypeDecl ArrayDecl.typeSerializable(); 162 inh TypeDecl ArrayDecl.typeCloneable(); 163 164 } 165 166 aspect NumericPromotion { 167 syn TypeDecl TypeDecl.unaryNumericPromotion() = this; // not unknown since this would be 168 // 5.6.1 Unary Numeric Promotion 169 syn lazy TypeDecl NumericType.unaryNumericPromotion() = this; 170 eq ByteType.unaryNumericPromotion() = typeInt(); 171 eq ShortType.unaryNumericPromotion() = typeInt(); 172 eq CharType.unaryNumericPromotion() = typeInt(); 173 174 // 5.6.2 Binary Numeric Promotion 175 syn TypeDecl TypeDecl.binaryNumericPromotion(TypeDecl type) = unknownType(); 176 syn lazy TypeDecl NumericType.binaryNumericPromotion(TypeDecl type) { 177 if (!type.isNumericType()) { 178 return unknownType(); 179 } 180 return unaryNumericPromotion().instanceOf(type) ? type : unaryNumericPromotion(); 181 } 182 183 } 184 185 aspect TypeAnalysis { 186 // 4.1 The Kinds of Types and Values 187 syn boolean TypeDecl.isReferenceType() = false; 188 eq ReferenceType.isReferenceType() = true; 189 eq UnknownType.isReferenceType() = true; 190 syn boolean TypeDecl.isPrimitiveType() = false; 191 eq PrimitiveType.isPrimitiveType() = true; 192 eq UnknownType.isPrimitiveType() = true; 193 194 // 4.2 Primitive Types and Values 195 syn boolean TypeDecl.isNumericType() = false; 196 eq NumericType.isNumericType() = true; 197 eq UnknownType.isNumericType() = true; 198 199 syn boolean TypeDecl.isIntegralType() = false; 200 eq IntegralType.isIntegralType() = true; 201 eq UnknownType.isIntegralType() = true; 202 203 syn boolean TypeDecl.isBoolean() = false; 204 eq BooleanType.isBoolean() = true; 205 eq UnknownType.isBoolean() = true; 206 207 syn boolean TypeDecl.isByte() = false; 208 eq ByteType.isByte() = true; 209 syn boolean TypeDecl.isChar() = false; 210 eq CharType.isChar() = true; 211 syn boolean TypeDecl.isShort() = false; 212 eq ShortType.isShort() = true; 213 syn boolean TypeDecl.isInt() = false; 214 eq IntType.isInt() = true; 215 eq UnknownType.isInt() = true; 216 217 syn boolean TypeDecl.isFloat() = false; 218 eq FloatType.isFloat() = true; 219 syn boolean TypeDecl.isLong() = false; 220 eq LongType.isLong() = true; 221 syn boolean TypeDecl.isDouble() = false; 222 eq DoubleType.isDouble() = true; 223 224 syn boolean TypeDecl.isVoid() = false; 225 eq VoidType.isVoid() = true; 226 227 syn boolean TypeDecl.isNull() = false; 228 eq NullType.isNull() = true; 229 230 // 4.3 Reference Types and Values 231 syn boolean TypeDecl.isClassDecl() = false; 232 eq ClassDecl.isClassDecl() = true; 233 eq ArrayDecl.isClassDecl() = false; 234 235 syn boolean TypeDecl.isInterfaceDecl() = false; 236 eq InterfaceDecl.isInterfaceDecl() = true; 237 syn boolean TypeDecl.isArrayDecl() = false; 238 eq ArrayDecl.isArrayDecl() = true; 239 240 inh lazy boolean TypeDecl.isAnonymous(); 241 eq ClassInstanceExpr.getTypeDecl().isAnonymous() = true; 242 eq TypeDecl.getChild().isAnonymous() = false; 243 eq Program.getChild().isAnonymous() = false; 244 245 syn boolean TypeDecl.isPrimitive() = false; 246 eq PrimitiveType.isPrimitive() = true; 247 248 syn lazy boolean TypeDecl.isString() = false; 249 eq ClassDecl.isString() = fullName().equals("java.lang.String"); 250 251 syn lazy boolean TypeDecl.isObject() = false; 252 eq ClassDecl.isObject() = name().equals("Object") && packageName().equals("java.lang"); 253 254 syn boolean TypeDecl.isUnknown() = false; 255 eq UnknownType.isUnknown() = true; 256 257 eq Program.getChild().unknownField() = unknownType().findSingleVariable("unknown"); 258 public FieldDeclaration TypeDecl.findSingleVariable(String name) { 259 return (FieldDeclaration) memberFields(name).iterator().next(); 260 } 261 eq Program.getChild().unknownMethod() { 262 for (Iterator iter = unknownType().memberMethods("unknown").iterator(); iter.hasNext(); ) { 263 MethodDecl m = (MethodDecl) iter.next(); 264 return m; 265 } 266 throw new Error("Could not find method unknown in type Unknown"); 267 } 268 eq Program.getChild().unknownConstructor() = unknownConstructor(); 269 syn lazy ConstructorDecl Program.unknownConstructor() { 270 return (ConstructorDecl) unknownType().constructors().iterator().next(); 271 } 272 273 eq AbstractDot.type() = lastAccess().type(); 274 275 syn TypeDecl FieldDeclaration.type() = getTypeAccess().type(); 276 syn TypeDecl VariableDeclaration.type() = getTypeAccess().type(); 277 syn lazy TypeDecl ParameterDeclaration.type() = getTypeAccess().type(); 278 279 syn TypeDecl VarDeclStmt.type() = getTypeAccess().type(); 280 281 inh lazy TypeDecl ArrayInit.declType(); 282 eq Program.getChild(int i).declType() = null; 283 eq FieldDecl.getVariableDecl().declType() = null; 284 eq VarDeclStmt.getVariableDecl().declType() = null; 285 286 eq FieldDeclaration.getInit().declType() = type(); 287 eq VariableDeclaration.getInit().declType() = type(); 288 eq ArrayCreationExpr.getArrayInit().declType() = type(); 289 eq ArrayInit.getInit().declType() = declType().componentType(); 290 291 eq ArrayInit.type() = declType(); 292 293 inh TypeDecl ConstructorDecl.unknownType(); 294 syn TypeDecl ConstructorDecl.type() = unknownType(); 295 syn lazy TypeDecl MethodDecl.type() = getTypeAccess().type(); 296 297 syn boolean BodyDecl.isVoid() = false; 298 eq MethodDecl.isVoid() = type().isVoid(); 299 eq FieldDeclaration.isVoid() = type().isVoid(); 300 eq ConstructorDecl.isVoid() = true; 301 302 syn lazy TypeDecl Expr.type(); 303 304 eq Access.type() = unknownType(); 305 eq TypeAccess.type() = decl(); 306 eq ArrayAccess.type() = isQualified() ? qualifier().type().componentType() : unknownType(); 307 inh TypeDecl ArrayAccess.unknownType(); 308 309 eq VarAccess.type() = decl().type(); 310 eq MethodAccess.type() = decl().type(); 311 eq ConstructorAccess.type() = decl().type(); 312 313 eq ThisAccess.type() = decl(); 314 eq SuperAccess.type() { 315 TypeDecl typeDecl = decl(); 316 if (!typeDecl.isClassDecl()) { 317 return unknownType(); 318 } 319 ClassDecl classDecl = (ClassDecl) typeDecl; 320 return classDecl.superclass(); 321 } 322 323 eq AssignExpr.type() = getDest().type(); 324 325 eq IntegerLiteral.type() = typeInt(); 326 eq LongLiteral.type() = typeLong(); 327 eq FloatingPointLiteral.type() = typeFloat(); 328 eq DoubleLiteral.type() = typeDouble(); 329 eq BooleanLiteral.type() = typeBoolean(); 330 eq CharacterLiteral.type() = typeChar(); 331 eq StringLiteral.type() = typeString(); 332 eq NullLiteral.type() = typeNull(); 333 334 eq ParExpr.type() = getExpr().isTypeAccess() ? unknownType() : getExpr().type(); 335 336 eq ClassInstanceExpr.type() = hasTypeDecl() ? getTypeDecl() : getAccess().type(); 337 eq ArrayCreationExpr.type() = getTypeAccess().type(); 338 339 eq Unary.type() = getOperand().type(); 340 eq PlusExpr.type() = getOperand().type().unaryNumericPromotion(); 341 eq MinusExpr.type() = getOperand().type().unaryNumericPromotion(); 342 eq BitNotExpr.type() = getOperand().type().unaryNumericPromotion(); 343 eq LogNotExpr.type() = typeBoolean(); 344 345 eq CastExpr.type() = getTypeAccess().type(); 346 347 // 15.17 348 eq MultiplicativeExpr.type() = getLeftOperand().type().binaryNumericPromotion(getRightOperand().type()); 349 // 15.18 350 eq AdditiveExpr.type() = getLeftOperand().type().binaryNumericPromotion(getRightOperand().type()); 351 // 15.18 352 eq AddExpr.type() { 353 TypeDecl left = getLeftOperand().type(); 354 TypeDecl right = getRightOperand().type(); 355 if (!left.isString() && !right.isString()) { 356 return super.type(); 357 } else { 358 if (left.isVoid() || right.isVoid()) { 359 return unknownType(); 360 } 361 // pick the string type 362 return left.isString() ? left : right; 363 } 364 } 365 366 // 15.19 367 eq ShiftExpr.type() = getLeftOperand().type().unaryNumericPromotion(); 368 369 // 15.20, 15.21 370 eq RelationalExpr.type() = typeBoolean(); 371 372 // 15.23, 15.24 373 eq LogicalExpr.type() = typeBoolean(); 374 375 // 15.22 376 eq BitwiseExpr.type() { 377 if (getLeftOperand().type().isIntegralType() && getRightOperand().type().isIntegralType()) { 378 // 15.22.1 379 return getLeftOperand().type().binaryNumericPromotion(getRightOperand().type()); 380 } else if (getLeftOperand().type().isBoolean() && getRightOperand().type().isBoolean()) { 381 // 15.22.2 382 return typeBoolean(); 383 } 384 return unknownType(); 385 } 386 387 // 15.20.2 388 eq InstanceOfExpr.type() = typeBoolean(); 389 390 // 15.25 391 eq ConditionalExpr.type() { 392 TypeDecl trueType = getTrueExpr().type(); 393 TypeDecl falseType = getFalseExpr().type(); 394 395 if (trueType == falseType) { 396 return trueType; 397 } 398 399 if (trueType.isNumericType() && falseType.isNumericType()) { 400 if (trueType.isByte() && falseType.isShort()) { 401 return falseType; 402 } 403 if (trueType.isShort() && falseType.isByte()) { 404 return trueType; 405 } 406 if ((trueType.isByte() || trueType.isShort() || trueType.isChar()) 407 && falseType.isInt() && getFalseExpr().isConstant() 408 && getFalseExpr().representableIn(trueType)) { 409 return trueType; 410 } 411 if ((falseType.isByte() || falseType.isShort() || falseType.isChar()) 412 && trueType.isInt() && getTrueExpr().isConstant() 413 && getTrueExpr().representableIn(falseType)) { 414 return falseType; 415 } 416 return trueType.binaryNumericPromotion(falseType); 417 } else if (trueType.isBoolean() && falseType.isBoolean()) { 418 return trueType; 419 } else if (trueType.isReferenceType() && falseType.isNull()) { 420 return trueType; 421 } else if (trueType.isNull() && falseType.isReferenceType()) { 422 return falseType; 423 } else if (trueType.isReferenceType() && falseType.isReferenceType()) { 424 if (trueType.assignConversionTo(falseType, null)) { 425 return falseType; 426 } 427 if (falseType.assignConversionTo(trueType, null)) { 428 return trueType; 429 } 430 return unknownType(); 431 } else { 432 return unknownType(); 433 } 434 } 435 436 eq ClassAccess.type() = lookupType("java.lang", "Class"); 437 438 } 439 440 aspect TypeWideningAndIdentity { 441 442 syn lazy boolean TypeDecl.instanceOf(TypeDecl type); 443 eq TypeDecl.instanceOf(TypeDecl type) = type == this; 444 eq ClassDecl.instanceOf(TypeDecl type) = type.isSupertypeOfClassDecl(this); 445 eq InterfaceDecl.instanceOf(TypeDecl type) = type.isSupertypeOfInterfaceDecl(this); 446 eq ArrayDecl.instanceOf(TypeDecl type) = type.isSupertypeOfArrayDecl(this); 447 eq PrimitiveType.instanceOf(TypeDecl type) = type.isSupertypeOfPrimitiveType(this); 448 eq NullType.instanceOf(TypeDecl type) = type.isSupertypeOfNullType(this); 449 eq VoidType.instanceOf(TypeDecl type) = type.isSupertypeOfVoidType(this); 450 451 eq UnknownType.instanceOf(TypeDecl type) = true; 452 eq UnknownType.isSupertypeOfClassDecl(ClassDecl type) = true; 453 eq UnknownType.isSupertypeOfInterfaceDecl(InterfaceDecl type) = true; 454 eq UnknownType.isSupertypeOfArrayDecl(ArrayDecl type) = true; 455 eq UnknownType.isSupertypeOfPrimitiveType(PrimitiveType type) = true; 456 eq UnknownType.isSupertypeOfNullType(NullType type) = true; 457 458 syn boolean TypeDecl.isSupertypeOfClassDecl(ClassDecl type) = type == this; 459 eq ClassDecl.isSupertypeOfClassDecl(ClassDecl type) { 460 if (super.isSupertypeOfClassDecl(type)) { 461 return true; 462 } 463 return type.hasSuperclass() && type.superclass().instanceOf(this); 464 } 465 eq InterfaceDecl.isSupertypeOfClassDecl(ClassDecl type) { 466 if (super.isSupertypeOfClassDecl(type)) { 467 return true; 468 } 469 for (Iterator<TypeDecl> iter = type.interfacesIterator(); iter.hasNext(); ) { 470 TypeDecl typeDecl = (TypeDecl) iter.next(); 471 if (typeDecl.instanceOf(this)) { 472 return true; 473 } 474 } 475 return type.hasSuperclass() && type.superclass().instanceOf(this); 476 } 477 478 syn boolean TypeDecl.isSupertypeOfInterfaceDecl(InterfaceDecl type) = type == this; 479 eq ClassDecl.isSupertypeOfInterfaceDecl(InterfaceDecl type) = isObject(); 480 eq InterfaceDecl.isSupertypeOfInterfaceDecl(InterfaceDecl type) { 481 if (super.isSupertypeOfInterfaceDecl(type)) { 482 return true; 483 } 484 for (Iterator<TypeDecl> iter = type.interfacesIterator(); iter.hasNext(); ) { 485 TypeDecl superinterface = (TypeDecl) iter.next(); 486 if (superinterface.instanceOf(this)) { 487 return true; 488 } 489 } 490 return false; 491 } 492 493 syn boolean TypeDecl.isSupertypeOfArrayDecl(ArrayDecl type) = this == type; 494 eq ClassDecl.isSupertypeOfArrayDecl(ArrayDecl type) { 495 if (super.isSupertypeOfArrayDecl(type)) { 496 return true; 497 } 498 return type.hasSuperclass() && type.superclass().instanceOf(this); 499 } 500 eq InterfaceDecl.isSupertypeOfArrayDecl(ArrayDecl type) { 501 if (super.isSupertypeOfArrayDecl(type)) { 502 return true; 503 } 504 for (Iterator<TypeDecl> iter = type.interfacesIterator(); iter.hasNext(); ) { 505 TypeDecl typeDecl = (TypeDecl) iter.next(); 506 if (typeDecl.instanceOf(this)) { 507 return true; 508 } 509 } 510 return false; 511 } 512 eq ArrayDecl.isSupertypeOfArrayDecl(ArrayDecl type) { 513 if (type.elementType().isPrimitive() && elementType().isPrimitive()) { 514 return type.dimension() == dimension() && type.elementType() == elementType(); 515 } 516 return type.componentType().instanceOf(componentType()); 517 } 518 519 syn boolean TypeDecl.isSupertypeOfPrimitiveType(PrimitiveType type) = type == this; 520 eq PrimitiveType.isSupertypeOfPrimitiveType(PrimitiveType type) { 521 if (super.isSupertypeOfPrimitiveType(type)) { 522 return true; 523 } 524 return type.hasSuperclass() && type.superclass().isPrimitive() && type.superclass().instanceOf(this); 525 } 526 527 syn boolean TypeDecl.isSupertypeOfNullType(NullType type) = false; 528 eq ReferenceType.isSupertypeOfNullType(NullType type) = true; 529 eq NullType.isSupertypeOfNullType(NullType type) = true; 530 531 syn boolean TypeDecl.isSupertypeOfVoidType(VoidType type) = false; 532 eq VoidType.isSupertypeOfVoidType(VoidType type) = true; 533 } 534 535 aspect NestedTypes { 536 537 538 eq CompilationUnit.getChild().enclosingType() = null; 539 540 eq TypeDecl.getBodyDecl().enclosingType() = this; 541 542 eq ClassDecl.getImplicitConstructor().enclosingType() = this; 543 544 inh TypeDecl TypeDecl.enclosingType(); 545 syn TypeDecl TypeDecl.topLevelType() { 546 if (isTopLevelType()) { 547 return this; 548 } 549 return enclosingType().topLevelType(); 550 } 551 552 syn Stmt Expr.enclosingStmt() { 553 ASTNode node = this; 554 while (node != null && !(node instanceof Stmt)) { 555 node = node.getParent(); 556 } 557 return (Stmt) node; 558 } 559 560 inh BodyDecl Expr.enclosingBodyDecl(); 561 inh BodyDecl Stmt.enclosingBodyDecl(); 562 inh BodyDecl TypeDecl.enclosingBodyDecl(); 563 inh BodyDecl VariableDeclaration.enclosingBodyDecl(); 564 eq Program.getChild().enclosingBodyDecl() = null; 565 eq BodyDecl.getChild().enclosingBodyDecl() = this; 566 567 568 // 8 569 inh boolean TypeDecl.isNestedType(); 570 eq CompilationUnit.getChild().isNestedType() = false; 571 eq TypeDecl.getBodyDecl().isNestedType() = true; 572 573 // 8 574 syn boolean TypeDecl.isTopLevelType() = !isNestedType(); 575 576 // 8.5 577 inh boolean TypeDecl.isMemberType(); 578 eq MemberClassDecl.getClassDecl().isMemberType() = true; 579 eq MemberInterfaceDecl.getInterfaceDecl().isMemberType() = true; 580 eq CompilationUnit.getTypeDecl().isMemberType() = false; 581 eq ClassInstanceExpr.getTypeDecl().isMemberType() = false; 582 eq Program.getChild().isMemberType() = false; 583 584 // 8.1.2 585 syn boolean TypeDecl.isInnerClass() = false; 586 eq ClassDecl.isInnerClass() = isNestedType() && !isStatic() && enclosingType().isClassDecl(); 587 syn boolean TypeDecl.isInnerType() = (isLocalClass() || isAnonymous() || (isMemberType() && !isStatic())) && !inStaticContext(); 588 589 syn boolean TypeDecl.isInnerTypeOf(TypeDecl typeDecl) = typeDecl == this || (isInnerType() && enclosingType().isInnerTypeOf(typeDecl)); 590 591 inh boolean TypeDecl.isLocalClass(); 592 eq CompilationUnit.getChild().isLocalClass() = false; 593 eq TypeDecl.getBodyDecl().isLocalClass() = false; 594 eq LocalClassDeclStmt.getClassDecl().isLocalClass() = true; 595 596 syn TypeDecl TypeDecl.withinBodyThatSubclasses(TypeDecl type) { 597 if (instanceOf(type)) { 598 return this; 599 } 600 if (!isTopLevelType()) { 601 return enclosingType().withinBodyThatSubclasses(type); 602 } 603 return null; 604 } 605 606 syn boolean TypeDecl.encloses(TypeDecl type) = type.enclosedBy(this); 607 608 syn boolean TypeDecl.enclosedBy(TypeDecl type) { 609 if (this == type) { 610 return true; 611 } 612 if (isTopLevelType()) { 613 return false; 614 } 615 return enclosingType().enclosedBy(type); 616 } 617 618 eq CompilationUnit.getChild().hostPackage() = packageName(); 619 620 inh String TypeDecl.hostPackage(); 621 inh String BodyDecl.hostPackage(); 622 inh String Expr.hostPackage(); 623 624 syn TypeDecl TypeDecl.hostType() = this; 625 626 eq TypeDecl.getChild().hostType() = this; 627 628 eq ClassInstanceExpr.getTypeDecl().hostType() = hostType(); 629 eq PrimitiveType.getSuperClass().hostType() = hostType(); 630 eq ClassDecl.getSuperClass().hostType() = hostType(); 631 eq ClassDecl.getImplements().hostType() = hostType(); 632 eq InterfaceDecl.getSuperInterface().hostType() = hostType(); 633 634 eq Program.getChild().hostType() = null; 635 eq CompilationUnit.getImportDecl().hostType() = null; 636 637 inh TypeDecl BodyDecl.hostType(); 638 inh TypeDecl Expr.hostType(); 639 inh TypeDecl Stmt.hostType(); 640 inh TypeDecl VariableDeclaration.hostType(); 641 inh TypeDecl ParameterDeclaration.hostType(); 642 643 } 644 645 aspect SuperClasses { 646 647 public boolean ClassDecl.hasSuperclass() { 648 return !isObject(); 649 } 650 651 public TypeDecl ClassDecl.superclass() { 652 if (isObject()) { 653 return unknownType(); 654 } else if (hasSuperClass() && !isCircular() && getSuperClass().type().isClassDecl()) { 655 return getSuperClass().type(); 656 } else { 657 return typeObject(); 658 } 659 } 660 661 public boolean PrimitiveType.hasSuperclass() { 662 return !isObject(); 663 } 664 665 syn TypeDecl PrimitiveType.superclass() = getSuperClass().type(); 666 667 /** 668 * Iterate over interfaces which this type implements. 669 * @return interface iterator 670 */ 671 public Iterator<TypeDecl> TypeDecl.interfacesIterator() { 672 return new Iterator<TypeDecl>() { 673 @Override 674 public boolean hasNext() { 675 return false; 676 } 677 @Override 678 public TypeDecl next() { 679 throw new NoSuchElementException("empty iterator"); 680 } 681 @Override 682 public void remove() { 683 throw new UnsupportedOperationException("empty iterator"); 684 } 685 }; 686 } 687 688 public Iterator<TypeDecl> ClassDecl.interfacesIterator() { 689 return new Iterator<TypeDecl>() { 690 public boolean hasNext() { 691 computeNextCurrent(); 692 return current != null; 693 } 694 public TypeDecl next() { 695 return current; 696 } 697 public void remove() { 698 throw new UnsupportedOperationException(); 699 } 700 private int index = 0; 701 private TypeDecl current = null; 702 private void computeNextCurrent() { 703 current = null; 704 if (isObject() || isCircular()) { 705 return; 706 } 707 while (index < getNumImplements()) { 708 TypeDecl typeDecl = getImplements(index++).type(); 709 if (!typeDecl.isCircular() && typeDecl.isInterfaceDecl()) { 710 current = typeDecl; 711 return; 712 } 713 } 714 } 715 }; 716 } 717 718 public Iterator<TypeDecl> InterfaceDecl.interfacesIterator() { 719 return new Iterator<TypeDecl>() { 720 public boolean hasNext() { 721 computeNextCurrent(); 722 return current != null; 723 } 724 public TypeDecl next() { 725 return current; 726 } 727 public void remove() { 728 throw new UnsupportedOperationException(); 729 } 730 private int index = 0; 731 private TypeDecl current = null; 732 private void computeNextCurrent() { 733 current = null; 734 if (isCircular()) { 735 return; 736 } 737 while (index < getNumSuperInterface()) { 738 TypeDecl typeDecl = getSuperInterface(index++).type(); 739 if (!typeDecl.isCircular() && typeDecl.isInterfaceDecl()) { 740 current = typeDecl; 741 return; 742 } 743 } 744 } 745 }; 746 } 747 748 } 749 750 aspect Circularity { 751 inh lazy TypeDecl TypeDecl.unknownType(); 752 syn lazy boolean TypeDecl.isCircular() circular [true] = false; 753 eq ClassDecl.isCircular() { 754 if (hasSuperClass()) { 755 Access a = getSuperClass().lastAccess(); 756 while (a != null) { 757 if (a.type().isCircular()) { 758 return true; 759 } 760 a = (a.isQualified() && a.qualifier().isTypeAccess()) ? (Access) a.qualifier() : null; 761 } 762 } 763 for (int i = 0; i < getNumImplements(); i++) { 764 Access a = getImplements(i).lastAccess(); 765 while (a != null) { 766 if (a.type().isCircular()) { 767 return true; 768 } 769 a = (a.isQualified() && a.qualifier().isTypeAccess()) ? (Access) a.qualifier() : null; 770 } 771 } 772 return false; 773 } 774 eq InterfaceDecl.isCircular() { 775 for (int i = 0; i < getNumSuperInterface(); i++) { 776 Access a = getSuperInterface(i).lastAccess(); 777 while (a != null) { 778 if (a.type().isCircular()) { 779 return true; 780 } 781 a = (a.isQualified() && a.qualifier().isTypeAccess()) ? (Access) a.qualifier() : null; 782 } 783 } 784 return false; 785 } 786 } 787