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