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 }