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