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    
011    aspect StaticImports {
012      /* 7.5.3 A single-static-import declaration imports all accessible (�6.6) static members
013      with a given simple name from a type. This makes these static members available
014      under their simple name in the class and interface declarations of the
015      compilation unit in which the single-static import declaration appears.*/
016      /* 7.5.4 A static-import-on-demand declaration allows all accessible (�6.6) static
017      members declared in the type named by a canonical name to be imported as
018      needed.*/
019    
020      // The attribute is declared in original type lookup.
021      eq StaticImportDecl.importedTypes(String name) {
022        SimpleSet set = SimpleSet.emptySet;
023        for(Iterator iter = type().memberTypes(name).iterator(); iter.hasNext(); ) {
024          TypeDecl decl = (TypeDecl)iter.next();
025          if(decl.isStatic() && decl.accessibleFromPackage(packageName()))
026            set = set.add(decl);
027        }
028        return set;
029      }
030      syn lazy SimpleSet ImportDecl.importedFields(String name) = SimpleSet.emptySet;
031      eq StaticImportDecl.importedFields(String name) {
032        SimpleSet set = SimpleSet.emptySet;
033        for(Iterator iter = type().memberFields(name).iterator(); iter.hasNext(); ) {
034          FieldDeclaration decl = (FieldDeclaration)iter.next();
035          if(decl.isStatic() &&
036             (decl.isPublic() || (!decl.isPrivate() && decl.hostType().topLevelType().packageName().equals(packageName()))))
037            set = set.add(decl);
038        }
039        return set;
040      }
041      syn lazy Collection ImportDecl.importedMethods(String name) = Collections.EMPTY_LIST;
042      eq StaticImportDecl.importedMethods(String name) {
043        Collection set = new HashSet();
044        for(Iterator iter = type().memberMethods(name).iterator(); iter.hasNext(); ) {
045          MethodDecl decl = (MethodDecl)iter.next();
046          if(decl.isStatic() &&
047             (decl.isPublic() || (!decl.isPrivate() && decl.hostType().topLevelType().packageName().equals(packageName()))))
048            set.add(decl);
049        }
050        return set;
051      }
052      
053      syn TypeDecl StaticImportDecl.type();
054      eq SingleStaticImportDecl.type() = getAccess().type(); 
055      eq StaticImportOnDemandDecl.type() = getAccess().type(); 
056    
057      // The isOnDemand attribute is used to make non-demand imports shadow demand imports.
058      eq StaticImportOnDemandDecl.isOnDemand() = true;
059    
060      /* The TypeName must be the canonical name of a class or interface type*/
061      public void SingleStaticImportDecl.typeCheck() { 
062        if(!getAccess().type().typeName().equals(typeName()) && !getAccess().type().isUnknown())
063          error("Single-type import " + typeName() + " is not the canonical name of type " + getAccess().type().typeName());
064      }
065    
066      /* 7.5.3 A compile-time error occurs if the named type does not exist. The named type must
067      be accessible (�6.6) or a compile-time error occurs.
068      Comment: Taken care of by name and type analysis */
069    
070      /* 7.5.4 It is a compile-time error for a static-import-on-demand declaration to name a
071      type that does not exist or a type that is not accessible. Two or more
072      static-import-on-demand declarations in the same compilation unit may name the
073      same type or package; the effect is as if there was exactly one such
074      declaration. Two or more static-import-on-demand declarations in the same
075      compilation unit may name the same member; the effect is as if the member was
076      imported exactly once.
077    
078      Note that it is permissable for one static-import-on-demand declaration to
079      import several fields or types with the same name, or several methods with the
080      same name and signature.
081    
082      If a compilation unit contains both a static-import-on-demand declaration and a
083      type-import-on-demand (�7.5.2) declaration that name the same type, the effect
084      is as if the static member types of that type were imported only once.
085    
086      A static-import-on-demand declaration never causes any other declaration to be shadowed.
087    
088      Comment: Taken care of by the name and type analysis operating on sets */
089      
090      /* 7.5.3 The Identifier must name at least one static member of the named type; a 
091      compile-time error occurs if there is no member of that name or if all of the named
092      members are not accessible.*/
093      public void SingleStaticImportDecl.nameCheck() {
094        if(importedFields(name()).isEmpty() && importedMethods(name()).isEmpty() && importedTypes(name()).isEmpty() &&
095           !getAccess().type().isUnknown()) {
096          error("Semantic Error: At least one static member named " + name() + " must be available in static imported type " + type().fullName());
097        }
098      }
099      syn String SingleStaticImportDecl.name() = getID();
100    
101      /* A single-static-import declaration d in a compilation unit c of package p that
102      imports a field named n shadows the declaration of any static field named n
103      imported by a static-import-on-demand declaration in c, throughout c.*/
104      eq CompilationUnit.getTypeDecl().lookupVariable(String name) {
105        SimpleSet set = importedFields(name);
106        if(!set.isEmpty()) return set;
107        set = importedFieldsOnDemand(name);
108        if(!set.isEmpty()) return set;
109        return lookupVariable(name);
110      }
111      inh SimpleSet CompilationUnit.lookupVariable(String name);
112      syn SimpleSet CompilationUnit.importedFields(String name) {
113        SimpleSet set = SimpleSet.emptySet;
114        for(int i = 0; i < getNumImportDecl(); i++)
115          if(!getImportDecl(i).isOnDemand())
116            for(Iterator iter = getImportDecl(i).importedFields(name).iterator(); iter.hasNext(); )
117              set = set.add(iter.next());
118        return set;
119      }
120      syn SimpleSet CompilationUnit.importedFieldsOnDemand(String name) {
121        SimpleSet set = SimpleSet.emptySet;
122        for(int i = 0; i < getNumImportDecl(); i++)
123          if(getImportDecl(i).isOnDemand())
124            for(Iterator iter = getImportDecl(i).importedFields(name).iterator(); iter.hasNext(); )
125              set = set.add(iter.next());
126        return set;
127      }
128    
129      /* A single-static-import declaration d in a compilation unit c of package p that
130      imports a method named n with signature s shadows the declaration of any static
131      method named n with signature s imported by a static-import-on-demand
132      declaration in c, throughout c.*/
133      eq CompilationUnit.getTypeDecl().lookupMethod(String name) {
134        Collection list = importedMethods(name);
135        if(!list.isEmpty()) return list;
136        list = importedMethodsOnDemand(name);
137        if(!list.isEmpty()) return list;
138        return lookupMethod(name);
139      }
140      inh Collection CompilationUnit.lookupMethod(String name);
141      syn Collection CompilationUnit.importedMethods(String name) {
142        Collection list = new ArrayList();
143        for(int i = 0; i < getNumImportDecl(); i++)
144          if(!getImportDecl(i).isOnDemand())
145            list.addAll(getImportDecl(i).importedMethods(name));
146        return list;
147      }
148      syn Collection CompilationUnit.importedMethodsOnDemand(String name) {
149        Collection list = new ArrayList();
150        for(int i = 0; i < getNumImportDecl(); i++)
151          if(getImportDecl(i).isOnDemand())
152            list.addAll(getImportDecl(i).importedMethods(name));
153        return list;
154      }
155    
156      /* A single-static-import declaration d in a compilation unit c of package p that
157      imports a type named n shadows the declarations of:
158        * any static type named n imported by a static-import-on-demand declaration in c.
159        * any top level type (�7.6) named n declared in another compilation unit (�7.3) of p.
160        * any type named n imported by a type-import-on-demand declaration (�7.5.2) in c. 
161      throughout c.
162      Comment: already implemented by original type lookup
163      */
164    
165      /* Note that it is permissable for one single-static-import declaration to import
166      several fields or types with the same name, or several methods with the same
167      name and signature.
168      Comment: Name analysis already deals with sets*/
169    
170      /* If a compilation unit contains both a single-static-import (�7.5.3) declaration
171      that imports a type whose simple name is n, and a single-type-import
172      declaration (�7.5.1) that imports a type whose simple name is n, a compile-time
173      error occurs.
174      Comment: javac6 interprets this as "another" type whose simple name is n. Then
175      nothing needs to be done.
176      */
177    
178      /* If a single-static-import declaration imports a type whose simple name is n,
179      and the compilation unit also declares a top level type (�7.6) whose simple
180      name is n, a compile-time error occurs.*/
181      refine NameCheck public void CompilationUnit.nameCheck() {
182        refined();
183        for(int i = 0; i < getNumImportDecl(); i++) {
184          if(getImportDecl(i) instanceof SingleStaticImportDecl) {
185            SingleStaticImportDecl decl = (SingleStaticImportDecl)getImportDecl(i);
186            String name = decl.name();
187            if(!decl.importedTypes(name).isEmpty()) {
188              TypeDecl type = (TypeDecl)decl.importedTypes(name).iterator().next();
189              if(localLookupType(name).contains(type))
190                decl.error(packageName() + "." + name + " is already defined in this compilation unit");
191            }
192          }
193        }
194      }
195      // Implement additional analyses for new language constructs
196    
197      // Exception handling
198      eq CompilationUnit.getImportDecl().handlesException(TypeDecl exceptionType) {
199        return !exceptionType.isUncheckedException();
200      }
201    
202      // Expect a type name in this context
203      eq SingleStaticImportDecl.getAccess().nameType() = NameType.TYPE_NAME;
204      eq StaticImportOnDemandDecl.getAccess().nameType() = NameType.TYPE_NAME;
205    
206      // PrettyPrinting
207      public void SingleStaticImportDecl.toString(StringBuffer s) {
208        s.append("import static ");
209        getAccess().toString(s);
210        s.append("." + getID());
211        s.append(";\n");
212      }
213      public void StaticImportOnDemandDecl.toString(StringBuffer s) {
214        s.append("import static ");
215        getAccess().toString(s);
216        s.append(".*;\n");
217      }
218    
219    }