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 import java.util.*; 032 033 aspect VariableScope { 034 // lookupVariable(String name) shows the variables in scope named name 035 inh lazy SimpleSet TypeDecl.lookupVariable(String name); 036 inh lazy SimpleSet BodyDecl.lookupVariable(String name); 037 inh SimpleSet Stmt.lookupVariable(String name); 038 inh lazy SimpleSet Block.lookupVariable(String name); 039 inh lazy SimpleSet ForStmt.lookupVariable(String name); 040 inh SimpleSet Expr.lookupVariable(String name); 041 inh lazy SimpleSet CatchClause.lookupVariable(String name); 042 inh SimpleSet VariableDeclaration.lookupVariable(String name); 043 inh SimpleSet ParameterDeclaration.lookupVariable(String name); 044 045 eq Program.getChild().lookupVariable(String name) = SimpleSet.emptySet; 046 047 // 6.5.6.1 048 eq TypeDecl.getBodyDecl(int i).lookupVariable(String name) { 049 SimpleSet list = memberFields(name); 050 if (!list.isEmpty()) { 051 return list; 052 } 053 list = lookupVariable(name); 054 if (inStaticContext() || isStatic()) { 055 list = removeInstanceVariables(list); 056 } 057 return list; 058 } 059 060 // The scope of a parameter of a method is the entire body of the method 061 eq MethodDecl.getBlock().lookupVariable(String name) { 062 SimpleSet set = parameterDeclaration(name); 063 // A declaration of a method parameter name shadows any other variable declarations 064 if (!set.isEmpty()) { 065 return set; 066 } 067 // Delegate to other declarations in scope 068 return lookupVariable(name); 069 } 070 // A method declaration may only declare one parameter named name 071 // This is enforced by a check that the declaration in scope for a declaration is itself 072 eq MethodDecl.getParameter().lookupVariable(String name) = parameterDeclaration(name); 073 074 eq ConstructorDecl.getBlock().lookupVariable(String name) { 075 SimpleSet set = parameterDeclaration(name); 076 if (!set.isEmpty()) { 077 return set; 078 } 079 return lookupVariable(name); 080 } 081 082 eq ConstructorDecl.getParsedConstructorInvocation().lookupVariable(String name) { 083 SimpleSet set = parameterDeclaration(name); 084 if (!set.isEmpty()) { 085 return set; 086 } 087 for (Iterator iter = lookupVariable(name).iterator(); iter.hasNext(); ) { 088 Variable v = (Variable) iter.next(); 089 if (!hostType().memberFields(name).contains(v) || v.isStatic()) { 090 set = set.add(v); 091 } 092 } 093 return set; 094 } 095 096 eq ConstructorDecl.getImplicitConstructorInvocation().lookupVariable(String name) { 097 SimpleSet set = parameterDeclaration(name); 098 if (!set.isEmpty()) { 099 return set; 100 } 101 for (Iterator iter = lookupVariable(name).iterator(); iter.hasNext(); ) { 102 Variable v = (Variable) iter.next(); 103 if (!hostType().memberFields(name).contains(v) || v.isStatic()) { 104 set = set.add(v); 105 } 106 } 107 return set; 108 } 109 110 eq ConstructorDecl.getParameter().lookupVariable(String name) = parameterDeclaration(name); 111 112 eq VarDeclStmt.getSingleDecl(int index).lookupVariable(String name) { 113 for (int i = index; i >= 0; --i) { 114 if (getSingleDecl(i).declaresVariable(name)) { 115 return getSingleDecl(i); 116 } 117 } 118 return lookupVariable(name); 119 } 120 121 /** 122 * The scope of a local variable declaration in a block is the rest of 123 * the block in which the declaration appears 124 */ 125 eq Block.getStmt(int index).lookupVariable(String name) { 126 VariableDeclaration v = localVariableDeclaration(name); 127 // declare before use and shadowing 128 if (v != null && declaredBeforeUse(v, index)) { 129 return v; 130 } 131 return lookupVariable(name); 132 } 133 134 // The scope of the parameter of an exception handler that is declared in a 135 // catch clause of a try statement is the entire block associated with the catch 136 eq CatchClause.getBlock().lookupVariable(String name) { 137 SimpleSet set = parameterDeclaration(name); 138 if (!set.isEmpty()) { 139 return set; 140 } 141 return lookupVariable(name); 142 } 143 eq BasicCatch.getParameter().lookupVariable(String name) = parameterDeclaration(name); 144 145 // The scope of a local variable declared in the ForInit part of the for 146 // statement includes all of the following: 147 eq ForStmt.getInitStmt().lookupVariable(String name) = localLookup(name); 148 eq ForStmt.getCondition().lookupVariable(String name) = localLookup(name); 149 eq ForStmt.getUpdateStmt().lookupVariable(String name) = localLookup(name); 150 eq ForStmt.getStmt().lookupVariable(String name) = localLookup(name); 151 syn lazy SimpleSet ForStmt.localLookup(String name) { 152 VariableDeclaration v = localVariableDeclaration(name); 153 if (v != null) { 154 return v; 155 } 156 return lookupVariable(name); 157 } 158 159 // Return the first variable declaration named name 160 161 syn lazy SimpleSet MethodDecl.parameterDeclaration(String name) { 162 for (int i = 0; i < getNumParameter(); i++) { 163 if (getParameter(i).name().equals(name)) { 164 return (ParameterDeclaration) getParameter(i); 165 } 166 } 167 return SimpleSet.emptySet; 168 } 169 170 syn lazy SimpleSet ConstructorDecl.parameterDeclaration(String name) { 171 for (int i = 0; i < getNumParameter(); i++) { 172 if (getParameter(i).name().equals(name)) { 173 return (ParameterDeclaration) getParameter(i); 174 } 175 } 176 return SimpleSet.emptySet; 177 } 178 179 syn lazy SimpleSet CatchClause.parameterDeclaration(String name) = SimpleSet.emptySet; 180 eq BasicCatch.parameterDeclaration(String name) = 181 getParameter().name().equals(name) 182 ? getParameter() 183 : SimpleSet.emptySet; 184 185 syn lazy VariableDeclaration Block.localVariableDeclaration(String name) { 186 for (Stmt stmt: getStmtList()) { 187 VariableDeclaration decl = stmt.variableDeclaration(name); 188 if (decl != null) { 189 return decl; 190 } 191 } 192 return null; 193 } 194 195 syn lazy VariableDeclaration ForStmt.localVariableDeclaration(String name) { 196 for (Stmt stmt: getInitStmtList()) { 197 VariableDeclaration decl = stmt.variableDeclaration(name); 198 if (decl != null) { 199 return decl; 200 } 201 } 202 return null; 203 } 204 205 syn VariableDeclaration Stmt.variableDeclaration(String name) = null; 206 207 eq VarDeclStmt.variableDeclaration(String name) { 208 for (VariableDeclaration decl: getSingleDeclList()) { 209 if (decl.declaresVariable(name)) { 210 return decl; 211 } 212 } 213 return null; 214 } 215 216 syn boolean VariableDeclaration.declaresVariable(String name) = getID().equals(name); 217 218 eq MethodAccess.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); 219 eq ConstructorAccess.getArg().lookupVariable(String name) = 220 unqualifiedScope().lookupVariable(name); 221 eq SuperConstructorAccess.getArg().lookupVariable(String name) = 222 unqualifiedScope().lookupVariable(name); 223 eq ArrayAccess.getExpr().lookupVariable(String name) = 224 unqualifiedScope().lookupVariable(name); 225 eq ArrayTypeWithSizeAccess.getExpr().lookupVariable(String name) = 226 unqualifiedScope().lookupVariable(name); 227 eq ClassInstanceExpr.getArg().lookupVariable(String name) = 228 unqualifiedScope().lookupVariable(name); 229 230 eq AbstractDot.getRight().lookupVariable(String name) = getLeft().qualifiedLookupVariable(name); 231 232 eq ParseName.qualifiedLookupVariable(String name) = SimpleSet.emptySet; 233 234 // Access control specifies the part of a program where a declared entity can 235 // be referred to by a qualified name, field access expression, method 236 // invocation expression without a simple name 237 syn SimpleSet Expr.qualifiedLookupVariable(String name) { 238 if (type().accessibleFrom(hostType())) { 239 return keepAccessibleFields(type().memberFields(name)); 240 } 241 return SimpleSet.emptySet; 242 } 243 eq PackageAccess.qualifiedLookupVariable(String name) = SimpleSet.emptySet; 244 eq TypeAccess.qualifiedLookupVariable(String name) { 245 if (type().accessibleFrom(hostType())) { 246 SimpleSet c = type().memberFields(name); 247 c = keepAccessibleFields(c); 248 if (type().isClassDecl() && c.size() == 1) { 249 c = removeInstanceVariables(c); 250 } 251 return c; 252 } 253 return SimpleSet.emptySet; 254 } 255 256 /** 257 * Remove fields that are not accessible when using this Expr as qualifier 258 * @return a set containing the accessible fields 259 */ 260 public SimpleSet Expr.keepAccessibleFields(SimpleSet oldSet) { 261 SimpleSet newSet = SimpleSet.emptySet; 262 for (Iterator iter = oldSet.iterator(); iter.hasNext(); ) { 263 Variable v = (Variable) iter.next(); 264 if (v instanceof FieldDeclaration) { 265 FieldDeclaration f = (FieldDeclaration) v; 266 if (mayAccess(f)) { 267 newSet = newSet.add(f); 268 } 269 } 270 } 271 return newSet; 272 } 273 274 public SimpleSet ASTNode.removeInstanceVariables(SimpleSet oldSet) { 275 SimpleSet newSet = SimpleSet.emptySet; 276 for (Iterator iter = oldSet.iterator(); iter.hasNext(); ) { 277 Variable v = (Variable) iter.next(); 278 if (!v.isInstanceVariable()) { 279 newSet = newSet.add(v); 280 } 281 } 282 return newSet; 283 } 284 285 /** 286 * @see "JLS $6.6.2.1" 287 * @return true if the expression may access the given field 288 */ 289 public boolean Expr.mayAccess(FieldDeclaration f) { 290 if (f.isPublic()) { 291 return true; 292 } else if (f.isProtected()) { 293 if (f.hostPackage().equals(hostPackage())) { 294 return true; 295 } 296 return hostType().mayAccess(this, f); 297 } else if (f.isPrivate()) { 298 return f.hostType().topLevelType() == hostType().topLevelType(); 299 } else { 300 return f.hostPackage().equals(hostType().hostPackage()); 301 } 302 } 303 304 /** 305 * @return true if the expression may access the field 306 */ 307 public boolean TypeDecl.mayAccess(Expr expr, FieldDeclaration field) { 308 if (instanceOf(field.hostType())) { 309 if (!field.isInstanceVariable() 310 || expr.isSuperAccess() 311 || expr.type().instanceOf(this)) { 312 return true; 313 } 314 } 315 316 if (isNestedType()) { 317 return enclosingType().mayAccess(expr, field); 318 } else { 319 return false; 320 } 321 } 322 } 323 324 aspect VariableScopePropagation { 325 interface VariableScope { 326 public SimpleSet lookupVariable(String name); 327 } 328 329 CatchClause implements VariableScope; 330 Block implements VariableScope; 331 TypeDecl implements VariableScope; 332 ForStmt implements VariableScope; 333 334 inh Variable Access.unknownField(); 335 336 syn lazy SimpleSet VarAccess.decls() { 337 SimpleSet set = lookupVariable(name()); 338 if (set.size() == 1) { 339 Variable v = (Variable) set.iterator().next(); 340 if (!isQualified() && inStaticContext()) { 341 if (v.isInstanceVariable() && !hostType().memberFields(v.name()).isEmpty()) { 342 return SimpleSet.emptySet; 343 } 344 } else if (isQualified() && qualifier().staticContextQualifier()) { 345 if (v.isInstanceVariable()) { 346 return SimpleSet.emptySet; 347 } 348 } 349 } 350 return set; 351 } 352 syn lazy Variable VarAccess.decl() { 353 SimpleSet decls = decls(); 354 if (decls.size() == 1) { 355 return (Variable) decls.iterator().next(); 356 } 357 return unknownField(); 358 } 359 } 360 361 aspect Fields { 362 363 syn lazy SimpleSet TypeDecl.localFields(String name) = 364 localFieldsMap().containsKey(name) 365 ? (SimpleSet) localFieldsMap().get(name) 366 : SimpleSet.emptySet; 367 368 syn lazy HashMap TypeDecl.localFieldsMap() { 369 HashMap map = new HashMap(); 370 for (int i = 0; i < getNumBodyDecl(); i++) { 371 if (getBodyDecl(i) instanceof FieldDeclaration) { 372 FieldDeclaration decl = (FieldDeclaration) getBodyDecl(i); 373 SimpleSet fields = (SimpleSet) map.get(decl.name()); 374 if (fields == null) { 375 fields = SimpleSet.emptySet; 376 } 377 fields = fields.add(decl); 378 map.put(decl.name(), fields); 379 } 380 } 381 return map; 382 } 383 syn lazy HashMap TypeDecl.memberFieldsMap() = localFieldsMap(); 384 eq ClassDecl.memberFieldsMap() { 385 HashMap map = new HashMap(localFieldsMap()); 386 if (hasSuperclass()) { 387 for (Iterator iter = superclass().fieldsIterator(); iter.hasNext(); ) { 388 FieldDeclaration decl = (FieldDeclaration) iter.next(); 389 if (!decl.isPrivate() && decl.accessibleFrom(this) && !localFieldsMap().containsKey(decl.name())) { 390 putSimpleSetElement(map, decl.name(), decl); 391 } 392 } 393 } 394 for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) { 395 TypeDecl type = outerIter.next(); 396 for (Iterator iter = type.fieldsIterator(); iter.hasNext(); ) { 397 FieldDeclaration decl = (FieldDeclaration) iter.next(); 398 if (!decl.isPrivate() && decl.accessibleFrom(this) && !localFieldsMap().containsKey(decl.name())) { 399 putSimpleSetElement(map, decl.name(), decl); 400 } 401 } 402 } 403 return map; 404 } 405 eq InterfaceDecl.memberFieldsMap() { 406 HashMap map = new HashMap(localFieldsMap()); 407 for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) { 408 TypeDecl typeDecl = outerIter.next(); 409 for (Iterator iter = typeDecl.fieldsIterator(); iter.hasNext(); ) { 410 FieldDeclaration f = (FieldDeclaration) iter.next(); 411 if (f.accessibleFrom(this) && !f.isPrivate() && !localFieldsMap().containsKey(f.name())) { 412 putSimpleSetElement(map, f.name(), f); 413 } 414 } 415 } 416 return map; 417 } 418 public Iterator TypeDecl.fieldsIterator() { 419 return new Iterator() { 420 private Iterator outer = memberFieldsMap().values().iterator(); 421 private Iterator inner = null; 422 public boolean hasNext() { 423 if ((inner == null || !inner.hasNext()) && outer.hasNext()) { 424 inner = ((SimpleSet) outer.next()).iterator(); 425 } 426 return inner != null ? inner.hasNext() : false; 427 } 428 public Object next() { 429 return inner.next(); 430 } 431 public void remove() { throw new UnsupportedOperationException(); } 432 }; 433 } 434 435 syn lazy SimpleSet TypeDecl.memberFields(String name) = localFields(name); 436 437 // member fields 438 eq ClassDecl.memberFields(String name) { 439 SimpleSet fields = localFields(name); 440 if (!fields.isEmpty()) { 441 return fields; // this causes hiding of fields in superclass and interfaces 442 } 443 if (hasSuperclass()) { 444 for (Iterator iter = superclass().memberFields(name).iterator(); iter.hasNext(); ) { 445 FieldDeclaration decl = (FieldDeclaration) iter.next(); 446 if (!decl.isPrivate() && decl.accessibleFrom(this)) { 447 fields = fields.add(decl); 448 } 449 } 450 } 451 for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) { 452 TypeDecl type = outerIter.next(); 453 for (Iterator iter = type.memberFields(name).iterator(); iter.hasNext(); ) { 454 FieldDeclaration decl = (FieldDeclaration) iter.next(); 455 if (!decl.isPrivate() && decl.accessibleFrom(this)) { 456 fields = fields.add(decl); 457 } 458 } 459 } 460 return fields; 461 } 462 463 eq InterfaceDecl.memberFields(String name) { 464 SimpleSet fields = localFields(name); 465 if (!fields.isEmpty()) { 466 return fields; 467 } 468 for (Iterator<TypeDecl> outerIter = interfacesIterator(); outerIter.hasNext(); ) { 469 TypeDecl typeDecl = (TypeDecl) outerIter.next(); 470 for (Iterator iter = typeDecl.memberFields(name).iterator(); iter.hasNext(); ) { 471 FieldDeclaration f = (FieldDeclaration) iter.next(); 472 if (f.accessibleFrom(this) && !f.isPrivate()) { 473 fields = fields.add(f); 474 } 475 } 476 } 477 return fields; 478 } 479 } 480