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