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    
032    aspect StaticImports {
033      /* 7.5.3 A single-static-import declaration imports all accessible (�6.6) static members
034      with a given simple name from a type. This makes these static members available
035      under their simple name in the class and interface declarations of the
036      compilation unit in which the single-static import declaration appears.*/
037      /* 7.5.4 A static-import-on-demand declaration allows all accessible (�6.6) static
038      members declared in the type named by a canonical name to be imported as
039      needed.*/
040    
041      // The attribute is declared in original type lookup.
042      eq StaticImportDecl.importedTypes(String name) {
043        SimpleSet set = SimpleSet.emptySet;
044        for (Iterator iter = type().memberTypes(name).iterator(); iter.hasNext(); ) {
045          TypeDecl decl = (TypeDecl) iter.next();
046          if (decl.isStatic() && decl.accessibleFromPackage(packageName())) {
047            set = set.add(decl);
048          }
049        }
050        return set;
051      }
052    
053      eq SingleStaticImportDecl.importedTypes() = getAccess().type().memberTypes(getID());
054    
055      syn lazy SimpleSet ImportDecl.importedFields(String name) = SimpleSet.emptySet;
056      eq StaticImportDecl.importedFields(String name) {
057        SimpleSet set = SimpleSet.emptySet;
058        for (Iterator iter = type().memberFields(name).iterator(); iter.hasNext(); ) {
059          FieldDeclaration decl = (FieldDeclaration) iter.next();
060          if (decl.isStatic() &&
061             (decl.isPublic() || (!decl.isPrivate() && decl.hostType().topLevelType().packageName().equals(packageName()))))
062            set = set.add(decl);
063        }
064        return set;
065      }
066    
067      eq SingleStaticImportDecl.importedFields(String name) {
068        if (name.equals(getID())) {
069          return super.importedFields(name);
070        } else {
071          return SimpleSet.emptySet;
072        }
073      }
074    
075      syn lazy Collection ImportDecl.importedMethods(String name) = Collections.EMPTY_LIST;
076      eq StaticImportDecl.importedMethods(String name) {
077        Collection set = new HashSet();
078        for (Iterator iter = type().memberMethods(name).iterator(); iter.hasNext(); ) {
079          MethodDecl decl = (MethodDecl) iter.next();
080          if (decl.isStatic() &&
081             (decl.isPublic() || (!decl.isPrivate() && decl.hostType().topLevelType().packageName().equals(packageName()))))
082            set.add(decl);
083        }
084        return set;
085      }
086    
087      eq SingleStaticImportDecl.importedMethods(String name) {
088        if (name.equals(getID())) {
089          return super.importedMethods(name);
090        } else {
091          return Collections.EMPTY_LIST;
092        }
093      }
094    
095      syn TypeDecl StaticImportDecl.type();
096      eq SingleStaticImportDecl.type() = getAccess().type();
097      eq StaticImportOnDemandDecl.type() = getAccess().type();
098    
099      // The isOnDemand attribute is used to make non-demand imports shadow demand imports.
100      eq StaticImportOnDemandDecl.isOnDemand() = true;
101    
102      /**
103       * The TypeName must be the canonical name of a class or interface type
104       */
105      public void SingleStaticImportDecl.typeCheck() {
106        if (!getAccess().type().typeName().equals(typeName()) &&
107            !getAccess().type().isUnknown()) {
108          errorf("Single-type import %s is not the canonical name of type %s",
109              typeName(), getAccess().type().typeName());
110        } else if (allImportedTypes(getID()).size() > 1) {
111          errorf("%s is imported multiple times", getID());
112        }
113      }
114    
115      /**
116       * The TypeName must be the canonical name of a class or interface type
117       */
118      public void StaticImportOnDemandDecl.nameCheck() {
119        if (!getAccess().type().typeName().equals(typeName())) {
120          errorf("In on-demand import: %s is not the canonical name of type %s",
121              typeName(), getAccess().type().typeName());
122        }
123      }
124    
125      /* 7.5.3 A compile-time error occurs if the named type does not exist. The named type must
126      be accessible (�6.6) or a compile-time error occurs.
127      Comment: Taken care of by name and type analysis */
128    
129      /* 7.5.4 It is a compile-time error for a static-import-on-demand declaration to name a
130      type that does not exist or a type that is not accessible. Two or more
131      static-import-on-demand declarations in the same compilation unit may name the
132      same type or package; the effect is as if there was exactly one such
133      declaration. Two or more static-import-on-demand declarations in the same
134      compilation unit may name the same member; the effect is as if the member was
135      imported exactly once.
136    
137      Note that it is permissable for one static-import-on-demand declaration to
138      import several fields or types with the same name, or several methods with the
139      same name and signature.
140    
141      If a compilation unit contains both a static-import-on-demand declaration and a
142      type-import-on-demand (�7.5.2) declaration that name the same type, the effect
143      is as if the static member types of that type were imported only once.
144    
145      A static-import-on-demand declaration never causes any other declaration to be shadowed.
146    
147      Comment: Taken care of by the name and type analysis operating on sets */
148    
149      /* 7.5.3 The Identifier must name at least one static member of the named type; a
150      compile-time error occurs if there is no member of that name or if all of the named
151      members are not accessible.*/
152    
153      /**
154       * Check for single static import errors.
155       */
156      public void SingleStaticImportDecl.nameCheck() {
157        if (importedFields(name()).isEmpty()
158            && importedMethods(name()).isEmpty()
159            && importedTypes(name()).isEmpty()
160            && !getAccess().type().isUnknown()) {
161          errorf("Semantic Error: At least one static member named %s must"
162              + " be available in static imported type %s",
163              name(), type().fullName());
164        }
165      }
166    
167      syn String SingleStaticImportDecl.name() = getID();
168    
169      /* A single-static-import declaration d in a compilation unit c of package p that
170      imports a field named n shadows the declaration of any static field named n
171      imported by a static-import-on-demand declaration in c, throughout c.*/
172      eq CompilationUnit.getTypeDecl().lookupVariable(String name) {
173        SimpleSet set = importedFields(name);
174        if (!set.isEmpty()) {
175          return set;
176        }
177        set = importedFieldsOnDemand(name);
178        if (!set.isEmpty()) {
179          return set;
180        }
181        return lookupVariable(name);
182      }
183    
184      inh SimpleSet CompilationUnit.lookupVariable(String name);
185    
186      syn SimpleSet CompilationUnit.importedFields(String name) {
187        SimpleSet set = SimpleSet.emptySet;
188        for (int i = 0; i < getNumImportDecl(); i++) {
189          if (!getImportDecl(i).isOnDemand()) {
190            for (Iterator iter = getImportDecl(i).importedFields(name).iterator(); iter.hasNext(); ) {
191              set = set.add(iter.next());
192            }
193          }
194        }
195        return set;
196      }
197    
198      syn SimpleSet CompilationUnit.importedFieldsOnDemand(String name) {
199        SimpleSet set = SimpleSet.emptySet;
200        for (int i = 0; i < getNumImportDecl(); i++) {
201          if (getImportDecl(i).isOnDemand()) {
202            for (Iterator iter = getImportDecl(i).importedFields(name).iterator(); iter.hasNext(); ) {
203              set = set.add(iter.next());
204            }
205          }
206        }
207        return set;
208      }
209    
210      /* A single-static-import declaration d in a compilation unit c of package p that
211      imports a method named n with signature s shadows the declaration of any static
212      method named n with signature s imported by a static-import-on-demand
213      declaration in c, throughout c.*/
214      eq CompilationUnit.getTypeDecl().lookupMethod(String name) {
215        Collection list = importedMethods(name);
216        if (!list.isEmpty()) {
217          return list;
218        }
219        list = importedMethodsOnDemand(name);
220        if (!list.isEmpty()) {
221          return list;
222        }
223        return lookupMethod(name);
224      }
225    
226      inh Collection CompilationUnit.lookupMethod(String name);
227    
228      syn Collection CompilationUnit.importedMethods(String name) {
229        Collection list = new ArrayList();
230        for (int i = 0; i < getNumImportDecl(); i++) {
231          if (!getImportDecl(i).isOnDemand()) {
232            list.addAll(getImportDecl(i).importedMethods(name));
233          }
234        }
235        return list;
236      }
237    
238      syn Collection CompilationUnit.importedMethodsOnDemand(String name) {
239        Collection list = new ArrayList();
240        for (int i = 0; i < getNumImportDecl(); i++) {
241          if (getImportDecl(i).isOnDemand()) {
242            list.addAll(getImportDecl(i).importedMethods(name));
243          }
244        }
245        return list;
246      }
247    
248      /* A single-static-import declaration d in a compilation unit c of package p that
249      imports a type named n shadows the declarations of:
250        * any static type named n imported by a static-import-on-demand declaration in c.
251        * any top level type (�7.6) named n declared in another compilation unit (�7.3) of p.
252        * any type named n imported by a type-import-on-demand declaration (�7.5.2) in c.
253      throughout c.
254      Comment: already implemented by original type lookup
255      */
256    
257      /* Note that it is permissable for one single-static-import declaration to import
258      several fields or types with the same name, or several methods with the same
259      name and signature.
260      Comment: Name analysis already deals with sets*/
261    
262      /* If a compilation unit contains both a single-static-import (�7.5.3) declaration
263      that imports a type whose simple name is n, and a single-type-import
264      declaration (�7.5.1) that imports a type whose simple name is n, a compile-time
265      error occurs.
266      Comment: javac6 interprets this as "another" type whose simple name is n. Then
267      nothing needs to be done.
268      */
269    
270      /* If a single-static-import declaration imports a type whose simple name is n,
271      and the compilation unit also declares a top level type (�7.6) whose simple
272      name is n, a compile-time error occurs.*/
273      refine NameCheck public void CompilationUnit.nameCheck() {
274        refined();
275        for (int i = 0; i < getNumImportDecl(); i++) {
276          if (getImportDecl(i) instanceof SingleStaticImportDecl) {
277            SingleStaticImportDecl decl = (SingleStaticImportDecl) getImportDecl(i);
278            String name = decl.name();
279            if (!decl.importedTypes(name).isEmpty()) {
280              TypeDecl type = (TypeDecl) decl.importedTypes(name).iterator().next();
281              if (localLookupType(name).contains(type)) {
282                decl.errorf("the imported name %s.%s is already declared in this compilation unit",
283                    packageName(), name);
284              }
285            }
286          }
287        }
288      }
289      // Implement additional analyses for new language constructs
290    
291      // Exception handling
292      eq CompilationUnit.getImportDecl().handlesException(TypeDecl exceptionType) = false;
293    
294      // Expect a type name in this context
295      eq SingleStaticImportDecl.getAccess().nameType() = NameType.TYPE_NAME;
296      eq StaticImportOnDemandDecl.getAccess().nameType() = NameType.TYPE_NAME;
297    
298    }