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