KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > classgen > JSRVariableScopeCodeVisitor


1 /*
2  * $Id: JSRVariableScopeCodeVisitor.java,v 1.16 2005/06/13 20:50:50 blackdrag Exp $
3  *
4  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5  *
6  * Redistribution and use of this software and associated documentation
7  * ("Software"), with or without modification, are permitted provided that the
8  * following conditions are met: 1. Redistributions of source code must retain
9  * copyright statements and notices. Redistributions must also contain a copy
10  * of this document. 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer in
12  * the documentation and/or other materials provided with the distribution. 3.
13  * The name "groovy" must not be used to endorse or promote products derived
14  * from this Software without prior written permission of The Codehaus. For
15  * written permission, please contact info@codehaus.org. 4. Products derived
16  * from this Software may not be called "groovy" nor may "groovy" appear in
17  * their names without prior written permission of The Codehaus. "groovy" is a
18  * registered trademark of The Codehaus. 5. Due credit should be given to The
19  * Codehaus - http://groovy.codehaus.org/
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  *
33  */

34
35 package org.codehaus.groovy.classgen;
36
37 import java.lang.reflect.Modifier JavaDoc;
38 import java.lang.reflect.Field JavaDoc;
39 import java.lang.reflect.Method JavaDoc;
40 import java.util.HashMap JavaDoc;
41 import java.util.HashSet JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.Set JavaDoc;
44 import java.util.List JavaDoc;
45 import org.codehaus.groovy.ast.ASTNode;
46 import org.codehaus.groovy.ast.ClassNode;
47 import org.codehaus.groovy.ast.CodeVisitorSupport;
48 import org.codehaus.groovy.ast.CompileUnit;
49 import org.codehaus.groovy.ast.ConstructorNode;
50 import org.codehaus.groovy.ast.FieldNode;
51 import org.codehaus.groovy.ast.GroovyClassVisitor;
52 import org.codehaus.groovy.ast.MethodNode;
53 import org.codehaus.groovy.ast.Parameter;
54 import org.codehaus.groovy.ast.PropertyNode;
55 import org.codehaus.groovy.ast.expr.ClosureExpression;
56 import org.codehaus.groovy.ast.expr.DeclarationExpression;
57 import org.codehaus.groovy.ast.expr.Expression;
58 import org.codehaus.groovy.ast.expr.FieldExpression;
59 import org.codehaus.groovy.ast.expr.PropertyExpression;
60 import org.codehaus.groovy.ast.expr.VariableExpression;
61 import org.codehaus.groovy.ast.stmt.BlockStatement;
62 import org.codehaus.groovy.ast.stmt.CatchStatement;
63 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
64 import org.codehaus.groovy.ast.stmt.ForStatement;
65 import org.codehaus.groovy.ast.stmt.Statement;
66 import org.codehaus.groovy.ast.stmt.WhileStatement;
67 import org.codehaus.groovy.control.SourceUnit;
68 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
69 import org.codehaus.groovy.syntax.SyntaxException;
70
71 public class JSRVariableScopeCodeVisitor extends CodeVisitorSupport implements GroovyClassVisitor {
72
73     private static class Var {
74         //TODO: support final and native
75
boolean isStatic=false, isFinal=false, isDynamicTyped=false;
76         String JavaDoc name, type=null;
77         Class JavaDoc typeClass=null;
78         boolean isInStaticContext=false;
79         
80         public boolean equals(Object JavaDoc o){
81             Var v = (Var) o;
82             return v.name.equals(name);
83         }
84         
85         public int hashCode() {
86             return name.hashCode();
87         }
88         
89         public Var(String JavaDoc name) {
90             // a Variable without type and other modifiers
91
// make it dynamic type, non final and non static
92
this.name=name;
93         }
94         
95         public Var(VariableExpression ve, VarScope scope) {
96             name = ve.getVariable();
97             if(ve.isDynamic()) {
98                 isDynamicTyped=true;
99             } else {
100                 type = ve.getType();
101                 typeClass = ve.getTypeClass();
102             }
103             isInStaticContext = scope.isInStaticContext;
104         }
105         
106         public Var(Parameter par, boolean staticContext) {
107             name = par.getName();
108             if (par.isDynamicType()) {
109                 isDynamicTyped=true;
110             } else {
111                 type = par.getType();
112             }
113             isInStaticContext = staticContext;
114         }
115
116         public Var(FieldNode f) {
117             name = f.getName();
118             if (f.isDynamicType()) {
119                 isDynamicTyped=true;
120             } else {
121                 type = f.getType();
122             }
123             isStatic=f.isStatic();
124             isInStaticContext = isStatic;
125         }
126
127         public Var(String JavaDoc pName, MethodNode f) {
128             name = pName;
129             if (f.isDynamicReturnType()) {
130                 isDynamicTyped=true;
131             } else {
132                 type = f.getReturnType();
133             }
134             isStatic=f.isStatic();
135             isInStaticContext = isStatic;
136         }
137         
138         public Var(String JavaDoc pName, Method JavaDoc m) {
139             name = pName;
140             typeClass = m.getReturnType();
141             isStatic=Modifier.isStatic(m.getModifiers());
142             isFinal=Modifier.isFinal(m.getModifiers());
143             isInStaticContext = isStatic;
144         }
145
146         public Var(PropertyNode f) {
147             //TODO: no static? What about read-/write-only? abstract?
148
isInStaticContext = false;
149             name = f.getName();
150             if (f.isDynamicType()) {
151                 isDynamicTyped=true;
152             } else {
153                 type = f.getType();
154             }
155             isInStaticContext = false;
156         }
157
158         public Var(Field JavaDoc f) {
159             name = f.getName();
160             typeClass = f.getType();
161             isStatic=Modifier.isStatic(f.getModifiers());
162             isInStaticContext = isStatic;
163             isFinal=Modifier.isFinal(f.getModifiers());
164             isInStaticContext = isStatic;
165         }
166
167         public Var(Var v) {
168             isStatic=v.isStatic;
169             isFinal=v.isFinal;
170             isDynamicTyped=v.isDynamicTyped;
171             name=v.name;
172             type=v.type;
173             typeClass=v.typeClass;
174             isInStaticContext=v.isInStaticContext;
175         }
176     }
177     
178     private static class VarScope {
179         boolean isClass=true;
180         boolean isInStaticContext = false;
181         
182         VarScope parent;
183         HashMap JavaDoc declares = new HashMap JavaDoc();
184         HashMap JavaDoc visibles = new HashMap JavaDoc();
185         
186         public VarScope(boolean isClass, VarScope parent, boolean staticContext) {
187             this.isClass=isClass;
188             this.parent = parent;
189             isInStaticContext = staticContext;
190         }
191         
192         public VarScope(VarScope parent, boolean staticContext) {
193             this(false,parent,staticContext);
194         }
195         
196         public VarScope(VarScope parent) {
197             this(false,parent,parent!=null?parent.isInStaticContext:false);
198         }
199     }
200     
201     private static class JRoseCheck extends CodeVisitorSupport{
202         boolean closureStarted=false;
203         boolean itUsed=false;
204         
205         public void visitClosureExpression(ClosureExpression expression) {
206             // don't visit subclosures if already in a closure
207
if (closureStarted) return;
208             closureStarted=true;
209             Parameter[] param = expression.getParameters();
210             for (int i=0; i<param.length; i++) {
211                 itUsed = (param[i].getName().equals("it")) && closureStarted || itUsed;
212             }
213             super.visitClosureExpression(expression);
214         }
215         
216         public void visitVariableExpression(VariableExpression expression) {
217             itUsed = (expression.getVariable().equals("it")) && closureStarted || itUsed;
218         }
219         
220     }
221     
222     
223     private VarScope currentScope = null;
224     private CompileUnit unit;
225     private SourceUnit source;
226     private boolean scriptMode=false;
227     private ClassNode currentClass=null;
228     
229     private boolean jroseRule=false;
230     
231     public JSRVariableScopeCodeVisitor(VarScope scope, SourceUnit source) {
232         //System.out.println("scope check enabled");
233
if ("true".equals(System.getProperty("groovy.jsr.check.rule.jrose"))) {
234             jroseRule=true;
235             //System.out.println("jrose check enabled");
236
}
237         currentScope = scope;
238         this.source = source;
239         if (source.getAST() == null) return;
240         this.unit = source.getAST().getUnit();
241     }
242
243     public void visitBlockStatement(BlockStatement block) {
244         VarScope scope = currentScope;
245         currentScope = new VarScope(currentScope);
246         super.visitBlockStatement(block);
247         currentScope = scope;
248     }
249
250     public void visitForLoop(ForStatement forLoop) {
251         VarScope scope = currentScope;
252         // TODO: always define a variable here? What about type?
253
currentScope = new VarScope(currentScope);
254         declare(new Var(forLoop.getVariable()), forLoop);
255         super.visitForLoop(forLoop);
256         currentScope = scope;
257     }
258
259     public void visitWhileLoop(WhileStatement loop) {
260         //TODO: check while loop variables
261
VarScope scope = currentScope;
262         currentScope = new VarScope(currentScope);
263         super.visitWhileLoop(loop);
264         currentScope = scope;
265     }
266
267     public void visitDoWhileLoop(DoWhileStatement loop) {
268         //TODO: still existant?
269
VarScope scope = currentScope;
270         currentScope = new VarScope(currentScope);
271         super.visitDoWhileLoop(loop);
272         currentScope = scope;
273     }
274
275     public void visitDeclarationExpression(DeclarationExpression expression) {
276         // visit right side first to avoid the usage of a
277
// variable before its declaration
278
expression.getRightExpression().visit(this);
279         // no need to visit left side, just get the variable name
280
VariableExpression vex = expression.getVariableExpression();
281         if (!jroseRule && "it".equals(vex.getVariable())) {
282             // we are not in jrose mode, so don't allow variables
283
// of the name 'it'
284
addError("'it' is a keyword in this mode.",vex);
285         } else {
286             declare(vex);
287         }
288     }
289     
290     private void addError(String JavaDoc msg, ASTNode expr) {
291         int line = expr.getLineNumber();
292         int col = expr.getColumnNumber();
293         source.getErrorCollector().addErrorAndContinue(
294           new SyntaxErrorMessage(new SyntaxException(msg + '\n', line, col), source)
295         );
296     }
297
298     private void declare(VariableExpression expr) {
299         declare(new Var(expr,currentScope),expr);
300     }
301     
302     private void declare(Var var, ASTNode expr) {
303         String JavaDoc scopeType = "scope";
304         String JavaDoc variableType = "variable";
305         
306         if (expr.getClass()==FieldNode.class){
307             scopeType = "class";
308             variableType = "field";
309         } else if (expr.getClass()==PropertyNode.class){
310             scopeType = "class";
311             variableType = "property";
312         }
313         
314         StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
315         msg.append("The current ").append(scopeType);
316         msg.append(" does already contain a ").append(variableType);
317         msg.append(" of the name ").append(var.name);
318         
319         if (currentScope.declares.get(var.name)!=null) {
320             addError(msg.toString(),expr);
321             return;
322         }
323         
324         //TODO: this case is not visited I think
325
if (currentScope.isClass) {
326             currentScope.declares.put(var.name,var);
327         }
328         
329         for (VarScope scope = currentScope.parent; scope!=null; scope = scope.parent) {
330             HashMap JavaDoc declares = scope.declares;
331             if (scope.isClass) break;
332             if (declares.get(var.name)!=null) {
333                 // variable already declared
334
addError(msg.toString(), expr);
335                 break;
336             }
337         }
338         // declare the variable even if there was an error to allow more checks
339
currentScope.declares.put(var.name,var);
340         var.isInStaticContext = currentScope.isInStaticContext;
341     }
342
343     /*
344      * public void visitBinaryExpression(BinaryExpression expression) {
345      * // evaluate right first because for an expression like "def a = a"
346      * // we need first to know if the a on the rhs is defined, before
347      * // defining a new a for the lhs
348      *
349      * Expression right = expression.getRightExpression();
350      *
351      * right.visit(this);
352      *
353      * Expression left = expression.getLeftExpression();
354      *
355      * left.visit(this);
356      * }
357      */

358     
359     public void visitVariableExpression(VariableExpression expression) {
360         String JavaDoc name = expression.getVariable();
361         Var v = checkVariableNameForDeclaration(name,expression);
362         if (v==null) return;
363         checkVariableContextAccess(v,expression);
364     }
365     
366     
367     public void visitFieldExpression(FieldExpression expression) {
368         String JavaDoc name = expression.getFieldName();
369         //TODO: change that to get the correct scope
370
Var v = checkVariableNameForDeclaration(name,expression);
371         checkVariableContextAccess(v,expression);
372     }
373     
374     private void checkAbstractDeclaration(MethodNode methodNode) {
375         if (!Modifier.isAbstract(methodNode.getModifiers())) return;
376         if (Modifier.isAbstract(currentClass.getModifiers())) return;
377         addError("Can't have an abstract method in a non abstract class." +
378                  " The class '" + currentClass.getName() + "' must be declared abstract or the method '" +
379                  methodNode.getName() + "' must not be abstract.",methodNode);
380     }
381     
382     private String JavaDoc getTypeName(String JavaDoc name) {
383         if (!name.endsWith("[]")) return name;
384         
385         String JavaDoc prefix = "";
386         while (name.endsWith("[]")) {
387             name = name.substring(0,name.length()-2);
388             prefix = "[";
389         }
390         
391         if (name.equals("int")) {
392             return prefix + "I";
393         }
394         else if (name.equals("long")) {
395             return prefix + "J";
396         }
397         else if (name.equals("short")) {
398             return prefix + "S";
399         }
400         else if (name.equals("float")) {
401             return prefix + "F";
402         }
403         else if (name.equals("double")) {
404             return prefix + "D";
405         }
406         else if (name.equals("byte")) {
407             return prefix + "B";
408         }
409         else if (name.equals("char")) {
410             return prefix + "C";
411         }
412         else if (name.equals("boolean")) {
413             return prefix + "Z";
414         }
415         
416         throw new AssertionError JavaDoc(false);
417     }
418     
419     private boolean hasEqualParameterTypes(Parameter[] first, Parameter[] second) {
420         if (first.length!=second.length) return false;
421         for (int i=0; i<first.length; i++) {
422             String JavaDoc ft = getTypeName(first[i].getType());
423             String JavaDoc st = getTypeName(second[i].getType());
424             if (ft.equals(st)) continue;
425             return false;
426         }
427         return true;
428     }
429     
430     private void checkClassForOverwritingFinal(ClassNode cn) {
431         ClassNode superCN = cn.getSuperClassNode();
432         if (superCN==null) return;
433         if (!Modifier.isFinal(superCN.getModifiers())) return;
434         StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
435         msg.append("you are not allowed to overwrite the final class ");
436         msg.append(superCN.getName());
437         msg.append(".");
438         addError(msg.toString(),cn);
439         
440     }
441     
442     private void checkMethodsForOverwritingFinal(ClassNode cn) {
443         List JavaDoc l = cn.getMethods();
444         for (Iterator JavaDoc cnIter = l.iterator(); cnIter.hasNext();) {
445             MethodNode method =(MethodNode) cnIter.next();
446             Parameter[] parameters = method.getParameters();
447             for (ClassNode superCN = cn.getSuperClassNode(); superCN!=null; superCN=superCN.getSuperClassNode()){
448                 List JavaDoc methods = superCN.getMethods(method.getName());
449                 for (Iterator JavaDoc iter = methods.iterator(); iter.hasNext();) {
450                     MethodNode m = (MethodNode) iter.next();
451                     Parameter[] np = m.getParameters();
452                     if (!hasEqualParameterTypes(parameters,np)) continue;
453                     if (!Modifier.isFinal(m.getModifiers())) return;
454                     
455                     StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
456                     msg.append("you are not allowed to overwrite the final method ").append(method.getName());
457                     msg.append("(");
458                     boolean semi = false;
459                     for (int i=0; i<parameters.length;i++) {
460                         if (semi) {
461                             msg.append(",");
462                         } else {
463                             semi = true;
464                         }
465                         msg.append(parameters[i].getType());
466                     }
467                     msg.append(")");
468                     msg.append(" from class ").append(superCN.getName());
469                     msg.append(".");
470                     addError(msg.toString(),method);
471                     return;
472                 }
473             }
474         }
475     }
476     
477     private void checkVariableContextAccess(Var v, Expression expr) {
478         if (v.isInStaticContext || !currentScope.isInStaticContext) return;
479         
480         String JavaDoc msg = v.name+
481                       " is declared in a dynamic context, but you tried to"+
482                       " access it from a static context.";
483         addError(msg,expr);
484         
485         // decalre a static variable to be able to continue the check
486
Var v2 = new Var(v);
487         v2.isInStaticContext = true;
488         currentScope.declares.put(v2.name,v2);
489     }
490     
491     private Var checkVariableNameForDeclaration(VariableExpression expression) {
492         if (expression == VariableExpression.THIS_EXPRESSION) return null;
493         String JavaDoc name = expression.getVariable();
494         return checkVariableNameForDeclaration(name,expression);
495     }
496     
497     private Var checkVariableNameForDeclaration(String JavaDoc name, Expression expression) {
498         Var var = new Var(name);
499         
500         // TODO: this line is not working
501
// if (expression==VariableExpression.SUPER_EXPRESSION) return;
502
if ("super".equals(var.name) || "this".equals(var.name)) return null;
503         
504         VarScope scope = currentScope;
505         while (scope != null) {
506             if (scope.declares.get(var.name)!=null) {
507                 var = (Var) scope.declares.get(var.name);
508                 break;
509             }
510             if (scope.visibles.get(var.name)!=null) {
511                 var = (Var) scope.visibles.get(var.name);
512                 break;
513             }
514             // scope.getReferencedVariables().add(name);
515
scope = scope.parent;
516         }
517
518         VarScope end = scope;
519
520         if (scope == null) {
521             //TODO add a check to be on the lhs!
522
ClassNode vn = unit.getClass(var.name);
523             // vn==null means there is no class of that name
524
// note: we need to do this check because it's possible in groovy to access
525
// Classes without the .class known from Java. Example: def type = String;
526
if (vn==null) {
527                 declare(var,expression);
528                 // don't create an error when inside a script body
529
if (!scriptMode) addError("The variable " + var.name +
530                                           " is undefined in the current scope", expression);
531             }
532         } else {
533             scope = currentScope;
534             while (scope != end) {
535                 scope.visibles.put(var.name,var);
536                 scope = scope.parent;
537             }
538         }
539         
540         return var;
541     }
542
543     public void visitClosureExpression(ClosureExpression expression) {
544         VarScope scope = currentScope;
545         currentScope = new VarScope(false,currentScope,scope.isInStaticContext);
546     
547         // TODO: set scope
548
// expression.setVarScope(currentScope);
549

550         if (expression.isParameterSpecified()) {
551             Parameter[] parameters = expression.getParameters();
552             for (int i = 0; i < parameters.length; i++) {
553                 declare(new Var(parameters[i],scope.isInStaticContext),expression);
554             }
555         } else {
556             Var var = new Var("it");
557             var.isInStaticContext = scope.isInStaticContext;
558             // TODO: when to add "it" and when not?
559
// John's rule is to add it only to the closures using 'it'
560
// and only to the closure itself, not to subclosures
561
if (jroseRule) {
562                 JRoseCheck check = new JRoseCheck();
563                 expression.visit(check);
564                 if (check.itUsed) declare(var,expression);
565             } else {
566                 currentScope.declares.put("it",var);
567             }
568         }
569
570         // currentScope = new VarScope(currentScope);
571
super.visitClosureExpression(expression);
572         currentScope = scope;
573     }
574
575     public void visitClass(ClassNode node) {
576         checkClassForOverwritingFinal(node);
577         checkMethodsForOverwritingFinal(node);
578         VarScope scope = currentScope;
579         currentScope = new VarScope(true,currentScope,false);
580         boolean scriptModeBackup = scriptMode;
581         scriptMode = node.isScript();
582         ClassNode classBackup = currentClass;
583         currentClass = node;
584         
585         HashMap JavaDoc declares = currentScope.declares;
586         // first pass, add all possible variable names (properies and fields)
587
// TODO: handle interfaces
588
// TODO: handle static imports
589
try {
590             addVarNames(node);
591             addVarNames(node.getOuterClass(), currentScope.visibles, true);
592             addVarNames(node.getSuperClass(), currentScope.visibles, true);
593         } catch (ClassNotFoundException JavaDoc cnfe) {
594             //TODO: handle this case properly
595
// throw new GroovyRuntimeException("couldn't find super
596
// class",cnfe);
597
cnfe.printStackTrace();
598         }
599        
600         // second pass, check contents
601
node.visitContents(this);
602         
603         currentClass = classBackup;
604         currentScope = scope;
605         scriptMode = scriptModeBackup;
606     }
607
608     private void addVarNames(Class JavaDoc c, HashMap JavaDoc refs, boolean visitParent)
609             throws ClassNotFoundException JavaDoc
610     {
611         if (c == null) return;
612         // to prefer compiled code try to get a ClassNode via name first
613
addVarNames(c.getName(), refs, visitParent);
614     }
615     
616     private void addVarNames(ClassNode cn) {
617         //TODO: change test for currentScope.declares
618
//TODO: handle indexed properties
619
if (cn == null) return;
620         List JavaDoc l = cn.getFields();
621         Set JavaDoc fields = new HashSet JavaDoc();
622         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
623             FieldNode f = (FieldNode) iter.next();
624             Var var = new Var(f);
625             if (fields.contains(var)) {
626                 declare(var,f);
627             } else {
628                 fields.add(var);
629                 currentScope.declares.put(var.name,var);
630             }
631         }
632
633         //TODO: ignore double delcaration of methods for the moment
634
l = cn.getMethods();
635         Set JavaDoc setter = new HashSet JavaDoc();
636         Set JavaDoc getter = new HashSet JavaDoc();
637         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
638             MethodNode f =(MethodNode) iter.next();
639             String JavaDoc methodName = f.getName();
640             String JavaDoc pName = getPropertyName(methodName);
641             if (pName == null) continue;
642             Var var = new Var(pName,f);
643             currentScope.declares.put(var.name,var);
644         }
645
646         l = cn.getProperties();
647         Set JavaDoc props = new HashSet JavaDoc();
648         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
649             PropertyNode f = (PropertyNode) iter.next();
650             Var var = new Var(f);
651             if (props.contains(var)) {
652                 declare(var,f);
653             } else {
654                 props.add(var);
655                 currentScope.declares.put(var.name,var);
656             }
657         }
658     }
659
660     private void addVarNames(ClassNode cn, HashMap JavaDoc refs, boolean visitParent)
661             throws ClassNotFoundException JavaDoc {
662         if (cn == null) return;
663         List JavaDoc l = cn.getFields();
664         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
665             FieldNode f = (FieldNode) iter.next();
666             if (visitParent && Modifier.isPrivate(f.getModifiers()))
667                 continue;
668             refs.put(f.getName(),new Var(f));
669         }
670         l = cn.getMethods();
671         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
672             MethodNode f = (MethodNode) iter.next();
673             if (visitParent && Modifier.isPrivate(f.getModifiers()))
674                 continue;
675             String JavaDoc name = getPropertyName(f.getName());
676             if (name == null) continue;
677             refs.put(name, new Var(name,f));
678         }
679
680         l = cn.getProperties();
681         for (Iterator JavaDoc iter = l.iterator(); iter.hasNext();) {
682             PropertyNode f = (PropertyNode) iter.next();
683             if (visitParent && Modifier.isPrivate(f.getModifiers()))
684                 continue;
685             refs.put(f.getName(),new Var(f));
686         }
687
688         if (!visitParent) return;
689
690         addVarNames(cn.getSuperClass(), refs, visitParent);
691         MethodNode enclosingMethod = cn.getEnclosingMethod();
692
693         if (enclosingMethod == null) return;
694
695         Parameter[] params = enclosingMethod.getParameters();
696         for (int i = 0; i < params.length; i++) {
697             refs.put(params[i].getName(),new Var(params[i],enclosingMethod.isStatic()));
698         }
699
700         if (visitParent)
701             addVarNames(enclosingMethod.getDeclaringClass(), refs, visitParent);
702
703         addVarNames(cn.getOuterClass(), refs, visitParent);
704     }
705
706     private void addVarNames(String JavaDoc superclassName, HashMap JavaDoc refs, boolean visitParent)
707       throws ClassNotFoundException JavaDoc
708     {
709
710         if (superclassName == null) return;
711
712         ClassNode cn = unit.getClass(superclassName);
713         if (cn != null) {
714             addVarNames(cn, refs, visitParent);
715             return;
716         }
717
718         Class JavaDoc c = unit.getClassLoader().loadClass(superclassName);
719         Field JavaDoc[] fields = c.getFields();
720         for (int i = 0; i < fields.length; i++) {
721             Field JavaDoc f = fields[i];
722             if (visitParent && Modifier.isPrivate(f.getModifiers()))
723                 continue;
724             refs.put(f.getName(),new Var(f));
725         }
726
727         Method JavaDoc[] methods = c.getMethods();
728         for (int i = 0; i < methods.length; i++) {
729             Method JavaDoc m = methods[i];
730             if (visitParent && Modifier.isPrivate(m.getModifiers()))
731                 continue;
732             String JavaDoc name = getPropertyName(m.getName());
733             if (name == null) continue;
734             refs.put(name,new Var(name,m));
735         }
736
737         if (!visitParent) return;
738
739         addVarNames(c.getSuperclass(), refs, visitParent);
740
741         // it's not possible to know the variable names used for an enclosing
742
// method
743

744         // addVarNames(c.getEnclosingClass(),refs,visitParent);
745
}
746     
747     private String JavaDoc getPropertyName(String JavaDoc name) {
748         if (!(name.startsWith("set") || name.startsWith("get"))) return null;
749         String JavaDoc pname = name.substring(3);
750         if (pname.length() == 0) return null;
751         String JavaDoc s = pname.substring(0, 1).toLowerCase();
752         String JavaDoc rest = pname.substring(1);
753         return s + rest;
754     }
755
756     public void visitConstructor(ConstructorNode node) {
757         VarScope scope = currentScope;
758         currentScope = new VarScope(currentScope);
759         
760         // TODO: set scope
761
// node.setVarScope(currentScope);
762

763         HashMap JavaDoc declares = currentScope.declares;
764         Parameter[] parameters = node.getParameters();
765         for (int i = 0; i < parameters.length; i++) {
766             // a constructor is never static
767
declare(new Var(parameters[i],false),node);
768         }
769         currentScope = new VarScope(currentScope);
770         Statement code = node.getCode();
771         if (code != null) code.visit(this);
772         currentScope = scope;
773     }
774     
775     public void visitMethod(MethodNode node) {
776         checkAbstractDeclaration(node);
777         
778         VarScope scope = currentScope;
779         currentScope = new VarScope(currentScope,node.isStatic());
780         
781         // TODO: set scope
782
// node.setVarScope(currentScope);
783

784         HashMap JavaDoc declares = currentScope.declares;
785         Parameter[] parameters = node.getParameters();
786         for (int i = 0; i < parameters.length; i++) {
787             declares.put(parameters[i].getName(),new Var(parameters[i],node.isStatic()));
788         }
789
790         currentScope = new VarScope(currentScope);
791         Statement code = node.getCode();
792         if (code!=null) code.visit(this);
793         currentScope = scope;
794     }
795
796     public void visitField(FieldNode node) {
797         Expression init = node.getInitialValueExpression();
798         if (init != null) init.visit(this);
799     }
800
801     public void visitProperty(PropertyNode node) {
802         Statement statement = node.getGetterBlock();
803         if (statement != null) statement.visit(this);
804         
805         statement = node.getSetterBlock();
806         if (statement != null) statement.visit(this);
807         
808         Expression init = node.getInitialValueExpression();
809         if (init != null) init.visit(this);
810     }
811
812     public void visitPropertyExpression(PropertyExpression expression) {
813
814     }
815
816     public void visitCatchStatement(CatchStatement statement) {
817         VarScope scope = currentScope;
818         currentScope = new VarScope(currentScope);
819         declare(new Var(statement.getVariable()), statement);
820         super.visitCatchStatement(statement);
821         currentScope = scope;
822     }
823 }
824
Popular Tags