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 }