001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     *               2014-2015, 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    import java.util.*;
033    import java.util.zip.*;
034    import java.io.*;
035    
036    aspect SpecialClasses {
037      syn lazy TypeDecl Program.typeObject() = lookupType("java.lang", "Object");
038      syn lazy TypeDecl Program.typeCloneable() = lookupType("java.lang", "Cloneable");
039      syn lazy TypeDecl Program.typeSerializable() = lookupType("java.io", "Serializable");
040    
041      eq Program.getChild().typeObject() = typeObject();
042      eq Program.getChild().typeCloneable() = typeCloneable();
043      eq Program.getChild().typeSerializable() = typeSerializable();
044    
045      syn lazy TypeDecl Program.typeBoolean() = getPrimitiveCompilationUnit().typeBoolean();
046      syn lazy TypeDecl Program.typeByte() = getPrimitiveCompilationUnit().typeByte();
047      syn lazy TypeDecl Program.typeShort() = getPrimitiveCompilationUnit().typeShort();
048      syn lazy TypeDecl Program.typeChar() = getPrimitiveCompilationUnit().typeChar();
049      syn lazy TypeDecl Program.typeInt() = getPrimitiveCompilationUnit().typeInt();
050      syn lazy TypeDecl Program.typeLong() = getPrimitiveCompilationUnit().typeLong();
051      syn lazy TypeDecl Program.typeFloat() = getPrimitiveCompilationUnit().typeFloat();
052      syn lazy TypeDecl Program.typeDouble() = getPrimitiveCompilationUnit().typeDouble();
053      syn lazy TypeDecl Program.typeString() = lookupType("java.lang", "String");
054    
055      eq Program.getChild().typeBoolean() = typeBoolean();
056      eq Program.getChild().typeByte() = typeByte();
057      eq Program.getChild().typeShort() = typeShort();
058      eq Program.getChild().typeChar() = typeChar();
059      eq Program.getChild().typeInt() = typeInt();
060      eq Program.getChild().typeLong() = typeLong();
061      eq Program.getChild().typeFloat() = typeFloat();
062      eq Program.getChild().typeDouble() = typeDouble();
063      eq Program.getChild().typeString() = typeString();
064    
065      syn lazy TypeDecl Program.typeVoid() = getPrimitiveCompilationUnit().typeVoid();
066      eq Program.getChild().typeVoid() = typeVoid();
067    
068      syn lazy TypeDecl Program.typeNull() = getPrimitiveCompilationUnit().typeNull();
069      eq Program.getChild().typeNull() = typeNull();
070    
071      syn lazy TypeDecl Program.unknownType() = getPrimitiveCompilationUnit().unknownType();
072      eq Program.getChild().unknownType() = unknownType();
073    
074      inh TypeDecl Expr.typeBoolean();
075      inh TypeDecl Expr.typeByte();
076      inh TypeDecl Expr.typeShort();
077      inh TypeDecl Expr.typeChar();
078      inh TypeDecl Expr.typeInt();
079      inh TypeDecl Expr.typeLong();
080      inh TypeDecl Expr.typeFloat();
081      inh TypeDecl Expr.typeDouble();
082      inh TypeDecl Expr.typeString();
083      inh TypeDecl Expr.typeVoid();
084      inh TypeDecl Expr.typeNull();
085    
086      inh lazy TypeDecl SwitchStmt.typeInt();
087      inh TypeDecl TypeDecl.typeInt();
088      inh lazy TypeDecl SwitchStmt.typeLong();
089    
090      inh lazy TypeDecl TypeDecl.typeObject();
091    
092      inh lazy TypeDecl ThrowStmt.typeThrowable();
093      inh lazy TypeDecl CatchClause.typeThrowable();
094    
095      inh lazy TypeDecl ThrowStmt.typeNull();
096    
097      inh TypeDecl Expr.unknownType();
098    
099    }
100    
101    aspect LookupFullyQualifiedTypes {
102      syn lazy boolean Program.hasPackage(String packageName) =
103          isPackage(packageName);
104    
105      /**
106       * The scope of a declaration of an observable top level package is all
107       * observable compilation units
108       */
109      eq Program.getChild().hasPackage(String packageName) = hasPackage(packageName);
110      eq AbstractDot.getRight().hasPackage(String packageName) =
111          getLeft().hasQualifiedPackage(packageName);
112      syn boolean Expr.hasQualifiedPackage(String packageName) = false;
113      eq PackageAccess.hasQualifiedPackage(String packageName) =
114          hasPackage(packageName() + "." + packageName);
115      inh boolean Expr.hasPackage(String packageName);
116      eq MethodAccess.getArg().hasPackage(String packageName) =
117          unqualifiedScope().hasPackage(packageName);
118      eq ConstructorAccess.getArg().hasPackage(String packageName) =
119          unqualifiedScope().hasPackage(packageName);
120      eq SuperConstructorAccess.getArg().hasPackage(String packageName) =
121          unqualifiedScope().hasPackage(packageName);
122      eq ArrayAccess.getExpr().hasPackage(String packageName) =
123          unqualifiedScope().hasPackage(packageName);
124      eq ArrayTypeWithSizeAccess.getExpr().hasPackage(String packageName) =
125          unqualifiedScope().hasPackage(packageName);
126      eq ClassInstanceExpr.getArg().hasPackage(String packageName) =
127          unqualifiedScope().hasPackage(packageName);
128    
129      inh TypeDecl Expr.lookupType(String packageName, String typeName);
130      inh TypeDecl Stmt.lookupType(String packageName, String typeName);
131      inh TypeDecl BodyDecl.lookupType(String packageName, String typeName);
132      inh TypeDecl TypeDecl.lookupType(String packageName, String typeName);
133      inh TypeDecl CompilationUnit.lookupType(String packageName, String typeName);
134    
135      public int Program.classFileReadTime;
136    
137      /**
138       * Defers the lookup to the synthesized attribute.
139       */
140      eq Program.getChild().lookupType(String packageName, String typeName) =
141          lookupType(packageName, typeName);
142    
143      /**
144       * Checks from-source compilation units for the given type.
145       * If no matching compilation unit is found the library compliation units
146       * will be searched.
147       */
148      syn lazy TypeDecl Program.lookupType(String packageName, String typeName) {
149        // Look for a matching source type.
150        TypeDecl sourceType = lookupSourceType(packageName, typeName);
151        if (!sourceType.isUnknown()) {
152          return sourceType;
153        }
154    
155        // Look for a matching library type.
156        return lookupLibraryType(packageName, typeName);
157      }
158    
159      /**
160       * Extra cache for source type lookups. This cache is important in order to
161       * make all source types shadow library types with matching names, even when
162       * the source type lives in a compilation unit with a different simple name.
163       */
164      private final Map<String, TypeDecl> Program.sourceTypeMap = new HashMap<String, TypeDecl>();
165      private boolean Program.sourceTypeMapInitialized = false;
166    
167      /**
168       * Lookup a type among source classes.
169       * <p>
170       * Invoking this method may cause more than just the specified type to be loaded, for
171       * example if there exists other types in the same source file, the additional
172       * types are also loaded and cached for the next lookup.
173       * <p>
174       * This method is not an attribute due to the necessary side-effects caused
175       * by loading and caching of extra types.
176       */
177      protected TypeDecl Program.lookupSourceType(String packageName, String typeName) {
178        String fullName = packageName.equals("") ? typeName : packageName + "." + typeName;
179    
180        if (!sourceTypeMapInitialized) {
181          initializeSourceTypeMap();
182          sourceTypeMapInitialized = true;
183        }
184    
185        if (sourceTypeMap.containsKey(fullName)) {
186          return sourceTypeMap.get(fullName);
187        } else {
188          sourceTypeMap.put(fullName, unknownType());
189        }
190    
191        // Look for a matching library type.
192        return unknownType();
193      }
194    
195      /**
196       * Initialize source types in the source type map.  This puts all the types provided by
197       * Program.addSourceFile() in a map for lookup by Program.lookupSourceType.
198       */
199      private void Program.initializeSourceTypeMap() {
200        // Initialize source type map with the compilation units supplied by Program.addSourceFile.
201        for (int i = 0; i < getNumCompilationUnit(); i++) {
202          CompilationUnit unit = getCompilationUnit(i);
203          for (int j = 0; j < unit.getNumTypeDecl(); j++) {
204            TypeDecl type = unit.getTypeDecl(j);
205            sourceTypeMap.put(type.fullName(), type);
206          }
207        }
208      }
209    
210      /**
211       * Extra cache for library type lookups. This cache does not have a big
212       * effect on performance due to the caching of the parameterized
213       * lookupLibraryType attribute. The cache is needed to be able to track library types
214       * that are declared in compilation units with a different simple name than the type itself.
215       */
216      private final Map<String, TypeDecl> Program.libraryTypeMap = new HashMap<String, TypeDecl>();
217      private boolean Program.libraryTypeMapInitialized = false;
218    
219      /**
220       * Lookup a type among library classes. The lookup includes Jar and source files.
221       * <p>
222       * Invoking this method may cause more than just the specified type to be loaded, for
223       * example if there exists other types in the same source file, the additional
224       * types are also loaded and cached for the next lookup.
225       * <p>
226       * This method is not an attribute due to the necessary side-effects caused
227       * by loading and caching of extra types.
228       */
229      protected TypeDecl Program.lookupLibraryType(String packageName, String typeName) {
230        String fullName = packageName.equals("") ? typeName : packageName + "." + typeName;
231    
232        if (!libraryTypeMapInitialized) {
233          initializeLibraryTypeMap();
234          libraryTypeMapInitialized = true;
235        }
236    
237        if (libraryTypeMap.containsKey(fullName)) {
238          return libraryTypeMap.get(fullName);
239        }
240    
241        // Lookup the type in the library class path.
242        CompilationUnit libraryUnit = getLibCompilationUnit(fullName);
243    
244        // Add all types from the compilation unit in the library type map so that we can find them on
245        // the next type lookup. If we don't do this lookup might incorrectly miss a type that is not
246        // declared in a Java source file with a matching name.
247        for (int j = 0; j < libraryUnit.getNumTypeDecl(); j++) {
248          TypeDecl type = libraryUnit.getTypeDecl(j);
249          if (!libraryTypeMap.containsKey(type.fullName())) {
250            libraryTypeMap.put(type.fullName(), type);
251          }
252        }
253    
254        if (libraryTypeMap.containsKey(fullName)) {
255          return libraryTypeMap.get(fullName);
256        } else {
257          libraryTypeMap.put(fullName, unknownType());
258          return unknownType();
259        }
260      }
261    
262      /** Initialize primitive types in the library type map.  */
263      private void Program.initializeLibraryTypeMap() {
264          PrimitiveCompilationUnit unit = getPrimitiveCompilationUnit();
265          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".boolean", unit.typeBoolean());
266          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".byte", unit.typeByte());
267          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".short", unit.typeShort());
268          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".char", unit.typeChar());
269          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".int", unit.typeInt());
270          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".long", unit.typeLong());
271          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".float", unit.typeFloat());
272          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".double", unit.typeDouble());
273          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".null", unit.typeNull());
274          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".void", unit.typeVoid());
275          libraryTypeMap.put(PRIMITIVE_PACKAGE_NAME + ".Unknown", unit.unknownType());
276      }
277    
278      /**
279       * This attribute is used to cache library compilation units, by storing the compilation units in
280       * a parameterized NTA.
281       */
282      syn nta CompilationUnit Program.getLibCompilationUnit(String typeName) =
283          getCompilationUnit(typeName);
284    
285      syn nta CompilationUnit Program.emptyCompilationUnit() = new CompilationUnit();
286    }
287    
288    aspect TypeScopePropagation {
289      inh TypeDecl Access.unknownType();
290    
291      syn lazy SimpleSet TypeAccess.decls() =
292          packageName().equals("")
293          ? lookupType(name())
294          : lookupType(packageName(), name()).asSet();
295    
296      /**
297       * @return a set containing this type, unless this is the unknown type in
298       * which case an empty set is returned
299       */
300      syn SimpleSet TypeDecl.asSet() = this;
301      eq UnknownType.asSet() = SimpleSet.emptySet;
302    
303      syn lazy SimpleSet PrimitiveTypeAccess.decls() = lookupType(PRIMITIVE_PACKAGE_NAME, name());
304      syn lazy String PrimitiveTypeAccess.getPackage() = PRIMITIVE_PACKAGE_NAME;
305      syn lazy String PrimitiveTypeAccess.getID() = getName();
306    
307      syn lazy TypeDecl TypeAccess.decl() {
308        SimpleSet decls = decls();
309        if (decls.size() == 1) {
310          return (TypeDecl) decls.iterator().next();
311        }
312        return unknownType();
313      }
314    
315      syn lazy TypeDecl ArrayTypeAccess.decl() = getAccess().type().arrayType();
316    
317      syn SimpleSet ThisAccess.decls() = SimpleSet.emptySet;
318      syn SimpleSet SuperAccess.decls() = SimpleSet.emptySet;
319    
320      /**
321       * @return the type which this access references
322       */
323      syn lazy TypeDecl ThisAccess.decl() = isQualified() ? qualifier().type() : hostType();
324    
325      /**
326       * @return the type whose supertype this super access references
327       */
328      syn lazy TypeDecl SuperAccess.decl() = isQualified() ? qualifier().type() : hostType();
329    
330      eq MethodAccess.getArg().lookupType(String name) = unqualifiedScope().lookupType(name);
331      eq ConstructorAccess.getArg().lookupType(String name) = unqualifiedScope().lookupType(name);
332      eq ArrayAccess.getExpr().lookupType(String name) = unqualifiedScope().lookupType(name);
333      eq ArrayTypeWithSizeAccess.getExpr().lookupType(String name) = unqualifiedScope().lookupType(name);
334      eq ClassInstanceExpr.getArg().lookupType(String name) = unqualifiedScope().lookupType(name);
335    
336      inh lazy SimpleSet CompilationUnit.lookupType(String name);
337      inh lazy SimpleSet TypeDecl.lookupType(String name);
338      inh SimpleSet BodyDecl.lookupType(String name);
339      inh SimpleSet Stmt.lookupType(String name);
340      inh lazy SimpleSet Block.lookupType(String name);
341      inh SimpleSet Expr.lookupType(String name);
342    
343      eq Program.getChild().lookupType(String name) = SimpleSet.emptySet;
344    
345      // The scope of a type import declaration is all the class and interface type declarations in
346      // the compilation unit in which the import declaration appears.
347      eq CompilationUnit.getChild().lookupType(String name) {
348        // Locally declared types in the compilation unit.
349        SimpleSet set = localLookupType(name);
350        if (!set.isEmpty()) {
351          return set;
352        }
353    
354        // Imported types.
355        set = importedTypes(name);
356        if (!set.isEmpty()) {
357          return set;
358        }
359    
360        // Types in the same package.
361        TypeDecl result = lookupType(packageName(), name);
362        if (result.accessibleFromPackage(packageName())) {
363          return result;
364        }
365    
366        // Types imported on demand.
367        set = importedTypesOnDemand(name);
368        if (!set.isEmpty()) {
369          return set;
370        }
371    
372        // Include primitive types.
373        result = lookupType(PRIMITIVE_PACKAGE_NAME, name);
374        if (!result.isUnknown()) {
375          return result;
376        }
377    
378        // 7.5.5 Automatic Imports
379        result = lookupType("java.lang", name);
380        if (result.accessibleFromPackage(packageName())) {
381          return result;
382        }
383        return lookupType(name);
384      }
385    
386      /** Searches for a type with the given simple name in this compilation unit. */
387      syn SimpleSet CompilationUnit.localLookupType(String name) {
388        for (int i = 0; i < getNumTypeDecl(); i++) {
389          if (getTypeDecl(i).name().equals(name)) {
390            return SimpleSet.emptySet.add(getTypeDecl(i));
391          }
392        }
393        return SimpleSet.emptySet;
394      }
395    
396      syn SimpleSet CompilationUnit.importedTypes(String name) {
397        SimpleSet set = SimpleSet.emptySet;
398        for (int i = 0; i < getNumImportDecl(); i++) {
399          if (!getImportDecl(i).isOnDemand()) {
400            for (Iterator iter = getImportDecl(i).importedTypes(name).iterator(); iter.hasNext(); ) {
401              set = set.add(iter.next());
402            }
403          }
404        }
405        return set;
406      }
407    
408      syn SimpleSet CompilationUnit.importedTypesOnDemand(String name) {
409        SimpleSet set = SimpleSet.emptySet;
410        for (int i = 0; i < getNumImportDecl(); i++) {
411          if (getImportDecl(i).isOnDemand()) {
412            for (Iterator iter = getImportDecl(i).importedTypes(name).iterator(); iter.hasNext(); ) {
413              set = set.add(iter.next());
414            }
415          }
416        }
417        return set;
418      }
419    
420      syn lazy SimpleSet ImportDecl.importedTypes(String name) = SimpleSet.emptySet;
421    
422      eq SingleTypeImportDecl.importedTypes(String name) {
423        SimpleSet set = SimpleSet.emptySet;
424        TypeDecl type = getAccess().type();
425        if (type.name().equals(name)) {
426          set = set.add(type);
427        }
428        return set;
429      }
430    
431      /**
432       * For a single-import declaration this will return a SimpleSet
433       * containing the TypeDecl for the imported type. For dynamic
434       * import declarations this returns the empty set.
435       * @return TypeDecl of imported type wrapped in SimpleSet
436       */
437      syn lazy SimpleSet ImportDecl.importedTypes() = SimpleSet.emptySet;
438    
439      eq SingleTypeImportDecl.importedTypes() = SimpleSet.emptySet.add(getAccess().type());
440    
441      eq TypeImportOnDemandDecl.importedTypes(String name) {
442        SimpleSet set = SimpleSet.emptySet;
443        if (getAccess() instanceof PackageAccess) {
444          String packageName = ((PackageAccess) getAccess()).getPackage();
445          TypeDecl typeDecl = lookupType(packageName, name);
446          if (typeDecl.accessibleFromPackage(packageName()) &&
447             typeDecl.typeName().equals(packageName + "." + name)) {
448            // Canonical names match.
449            set = set.add(typeDecl);
450          }
451        } else {
452          for (Iterator iter = getAccess().type().memberTypes(name).iterator(); iter.hasNext(); ) {
453            TypeDecl decl = (TypeDecl) iter.next();
454            if (decl.accessibleFromPackage(packageName()) &&
455               decl.typeName().equals(getAccess().typeName() + "." + name)) {
456              // Canonical names match.
457              set = set.add(decl);
458            }
459          }
460        }
461        return set;
462      }
463      inh TypeDecl TypeImportOnDemandDecl.lookupType(String packageName, String typeName);
464      inh String ImportDecl.packageName();
465    
466      syn boolean ImportDecl.isOnDemand() = false;
467      eq TypeImportOnDemandDecl.isOnDemand() = true;
468    
469      // Imports are not themselves affected by imports.
470      eq CompilationUnit.getImportDecl().lookupType(String name) = lookupType(name);
471    
472      eq TypeDecl.getBodyDecl(int index).lookupType(String name) = localLookupType(name);
473    
474      eq ClassDecl.getImplicitConstructor().lookupType(String name) = localLookupType(name);
475    
476      syn SimpleSet TypeDecl.localLookupType(String name) {
477        SimpleSet c = memberTypes(name);
478        if (!c.isEmpty()) {
479          return c;
480        }
481        if (name().equals(name)) {
482          return SimpleSet.emptySet.add(this);
483        }
484    
485        c = lookupType(name);
486        // 8.5.2
487        if (isClassDecl() && isStatic() && !isTopLevelType()) {
488          SimpleSet newSet = SimpleSet.emptySet;
489          for (Iterator iter = c.iterator(); iter.hasNext(); ) {
490            TypeDecl d = (TypeDecl) iter.next();
491            //if (d.isStatic() || d.isTopLevelType() || this.instanceOf(d.enclosingType())) {
492              newSet = newSet.add(d);
493            //}
494          }
495          c = newSet;
496        }
497        return c;
498      }
499    
500      eq Block.getStmt(int index).lookupType(String name) {
501        SimpleSet c = SimpleSet.emptySet;
502        for (int i = index; i >= 0 && !(getStmt(i) instanceof Case); i--) {
503          if (getStmt(i) instanceof LocalClassDeclStmt) {
504            TypeDecl t = ((LocalClassDeclStmt) getStmt(i)).getClassDecl();
505            if (t.name().equals(name)) {
506              c = c.add(t);
507            }
508          }
509        }
510        if (!c.isEmpty()) {
511          return c;
512        }
513        return lookupType(name);
514      }
515    
516      eq ClassInstanceExpr.getAccess().lookupType(String name) {
517        SimpleSet c = lookupType(name);
518        if (c.size() == 1) {
519          if (isQualified()) {
520            c = keepInnerClasses(c);
521          }
522        }
523        return c;
524      }
525    
526      eq ClassInstanceExpr.getTypeDecl().lookupType(String name) {
527        SimpleSet c = localLookupType(name);
528        if (!c.isEmpty()) {
529          return c;
530        }
531        c = lookupType(name);
532        if (!c.isEmpty()) {
533          return c;
534        }
535        return unqualifiedScope().lookupType(name);
536      }
537    
538      public SimpleSet ClassInstanceExpr.keepInnerClasses(SimpleSet c) {
539        SimpleSet newSet = SimpleSet.emptySet;
540        for (Iterator iter = c.iterator(); iter.hasNext(); ) {
541          TypeDecl t = (TypeDecl) iter.next();
542          if (t.isInnerType() && t.isClassDecl()) {
543            newSet = newSet.add(c);
544          }
545        }
546        return newSet;
547      }
548    
549      eq ParseName.qualifiedLookupType(String name) = SimpleSet.emptySet;
550    
551      eq AbstractDot.getRight().lookupType(String name) = getLeft().qualifiedLookupType(name);
552    
553      syn SimpleSet Expr.qualifiedLookupType(String name) =
554          keepAccessibleTypes(type().memberTypes(name));
555    
556      eq ClassInstanceExpr.qualifiedLookupType(String name) {
557        SimpleSet c = keepAccessibleTypes(type().memberTypes(name));
558        if (!c.isEmpty()) {
559          return c;
560        }
561        if (type().name().equals(name)) {
562          return SimpleSet.emptySet.add(type());
563        }
564        return SimpleSet.emptySet;
565      }
566    
567      eq PackageAccess.qualifiedLookupType(String name) {
568        SimpleSet c = SimpleSet.emptySet;
569        TypeDecl typeDecl = lookupType(packageName(), name);
570        if (!typeDecl.isUnknown()) {
571          if (hostType() != null && typeDecl.accessibleFrom(hostType())) {
572            c = c.add(typeDecl);
573          } else if (hostType() == null && typeDecl.accessibleFromPackage(hostPackage())) {
574            c = c.add(typeDecl);
575          }
576        }
577        return c;
578      }
579    
580      public SimpleSet Expr.keepAccessibleTypes(SimpleSet oldSet) {
581        SimpleSet newSet = SimpleSet.emptySet;
582        TypeDecl hostType = hostType();
583        for (Iterator iter = oldSet.iterator(); iter.hasNext(); ) {
584          TypeDecl t = (TypeDecl) iter.next();
585          if ((hostType != null && t.accessibleFrom(hostType))
586              || (hostType == null && t.accessibleFromPackage(hostPackage()))) {
587            newSet = newSet.add(t);
588          }
589        }
590        return newSet;
591      }
592    
593      syn lazy SimpleSet ClassInstanceExpr.localLookupType(String name) =
594          hasTypeDecl() && getTypeDecl().name().equals(name)
595          ? SimpleSet.emptySet.add(getTypeDecl())
596          : SimpleSet.emptySet;
597    
598      syn boolean TypeDecl.hasType(String name) = !memberTypes(name).isEmpty();
599      syn boolean BodyDecl.declaresType(String name) = false;
600      eq MemberTypeDecl.declaresType(String name) = typeDecl().name().equals(name);
601      syn TypeDecl BodyDecl.type(String name) = null;
602      eq MemberTypeDecl.type(String name) = declaresType(name) ? typeDecl() : null;
603    
604      syn TypeDecl MemberTypeDecl.typeDecl();
605      eq MemberClassDecl.typeDecl() = getClassDecl();
606      eq MemberInterfaceDecl.typeDecl() = getInterfaceDecl();
607    
608    
609      syn lazy SimpleSet TypeDecl.localTypeDecls(String name) {
610        SimpleSet set = SimpleSet.emptySet;
611        for (int i = 0; i < getNumBodyDecl(); i++) {
612          if (getBodyDecl(i).declaresType(name)) {
613            set = set.add(getBodyDecl(i).type(name));
614          }
615        }
616        return set;
617      }
618    
619      syn lazy SimpleSet TypeDecl.memberTypes(String name) = SimpleSet.emptySet;
620    
621      eq UnknownType.memberTypes(String name) = SimpleSet.emptySet;
622    
623      eq ClassDecl.memberTypes(String name) {
624        SimpleSet set = localTypeDecls(name);
625        if (!set.isEmpty()) {
626          return set;
627        }
628        for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) {
629          TypeDecl type = outerIter.next();
630          for (Iterator iter = type.memberTypes(name).iterator(); iter.hasNext(); ) {
631            TypeDecl decl = (TypeDecl) iter.next();
632            if (!decl.isPrivate() && decl.accessibleFrom(this)) {
633              set = set.add(decl);
634            }
635          }
636        }
637        if (hasSuperclass()) {
638          for (Iterator iter = superclass().memberTypes(name).iterator(); iter.hasNext(); ) {
639            TypeDecl decl = (TypeDecl) iter.next();
640            if (!decl.isPrivate() && decl.accessibleFrom(this)) {
641              set = set.add(decl);
642            }
643          }
644        }
645        return set;
646      }
647    
648      eq InterfaceDecl.memberTypes(String name) {
649        SimpleSet set = localTypeDecls(name);
650        if (!set.isEmpty()) {
651          return set;
652        }
653        for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) {
654          TypeDecl typeDecl = outerIter.next();
655          for (Iterator iter = typeDecl.memberTypes(name).iterator(); iter.hasNext(); ) {
656            TypeDecl decl = (TypeDecl) iter.next();
657            if (!decl.isPrivate()) {
658              set = set.add(decl);
659            }
660          }
661        }
662        return set;
663      }
664    }