View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.symboltable;
5   
6   import net.sourceforge.pmd.ast.ASTBlock;
7   import net.sourceforge.pmd.ast.ASTCatchStatement;
8   import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
9   import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
10  import net.sourceforge.pmd.ast.ASTCompilationUnit;
11  import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
12  import net.sourceforge.pmd.ast.ASTEnumDeclaration;
13  import net.sourceforge.pmd.ast.ASTFinallyStatement;
14  import net.sourceforge.pmd.ast.ASTForStatement;
15  import net.sourceforge.pmd.ast.ASTIfStatement;
16  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
17  import net.sourceforge.pmd.ast.ASTMethodDeclarator;
18  import net.sourceforge.pmd.ast.ASTPackageDeclaration;
19  import net.sourceforge.pmd.ast.ASTSwitchStatement;
20  import net.sourceforge.pmd.ast.ASTTryStatement;
21  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
22  import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
23  import net.sourceforge.pmd.ast.Node;
24  import net.sourceforge.pmd.ast.SimpleNode;
25  
26  import java.util.List;
27  import java.util.Stack;
28  
29  /***
30   * Visitor for scope creation.
31   * Visits all nodes of an AST and creates scope objects for nodes representing
32   * syntactic entities which may contain declarations. For example, a block 
33   * may contain variable definitions (which are declarations) and 
34   * therefore needs a scope object where these declarations can be associated, 
35   * whereas an expression can't contain declarations and therefore doesn't need
36   * a scope object.
37   * With the exception of global scopes, each scope object is linked to its
38   * parent scope, which is the scope object of the next embedding syntactic 
39   * entity that has a scope. 
40   */
41  public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
42  
43      /***
44       * A stack of scopes reflecting the scope hierarchy when a node is visited.
45       * This is used to set the parents of the created scopes correctly.
46       */
47      private Stack scopes = new Stack();
48  
49      /***
50       * Sets the scope of a node and adjustes the scope stack accordingly.
51       * The scope on top of the stack is set as the parent of the given scope,
52       * which is then also stored on the scope stack.
53       * @param newScope the scope for the node.
54       * @param node the AST node for which the scope is to be set.
55       * @throws java.util.EmptyStackException if the scope stack is empty.
56       */
57      private void addScope(Scope newScope, SimpleNode node) {
58          newScope.setParent((Scope)scopes.peek());
59          scopes.push(newScope);
60          node.setScope(newScope);
61      }
62      
63      /***
64       * Creates a new local scope for an AST node.
65       * The scope on top of the stack is set as the parent of the new scope,
66       * which is then also stored on the scope stack.
67       * @param node the AST node for which the scope has to be created.
68       * @throws java.util.EmptyStackException if the scope stack is empty.
69       */
70      private void createLocalScope(SimpleNode node) {
71          addScope(new LocalScope(), node);
72      }
73  
74      /***
75       * Creates a new method scope for an AST node.
76       * The scope on top of the stack is set as the parent of the new scope,
77       * which is then also stored on the scope stack.
78       * @param node the AST node for which the scope has to be created.
79       * @throws java.util.EmptyStackException if the scope stack is empty.
80       */
81      private void createMethodScope(SimpleNode node) {
82          addScope(new MethodScope(node), node);
83      }
84  
85      /***
86       * Creates a new class scope for an AST node.
87       * The scope on top of the stack is set as the parent of the new scope,
88       * which is then also stored on the scope stack.
89       * @param node the AST node for which the scope has to be created.
90       * @throws java.util.EmptyStackException if the scope stack is empty.
91       */
92      private void createClassScope(SimpleNode node) {
93         if (node instanceof ASTClassOrInterfaceBodyDeclaration){
94             addScope(new ClassScope(), node);
95         }
96         else {
97             addScope(new ClassScope(node.getImage()), node);
98         }
99      }
100 
101     /***
102      * Creates a new global scope for an AST node.
103      * The new scope is stored on the scope stack.
104      * @param node the AST node for which the scope has to be created.
105      */
106     private void createSourceFileScope(SimpleNode node) {
107         // When we do full symbol resolution, we'll need to add a truly top-level GlobalScope.
108         Scope scope;
109         List packages = node.findChildrenOfType(ASTPackageDeclaration.class);
110         if</strong> (!packages.isEmpty()) {
111             Node n = (Node)packages/get(0)/package-summary.html">Node n = (Node)packages.get(0);
112             scope = new SourceFileScope(((SimpleNode)n.jjtGetChild(0)).getImage());
113         } else {
114             scope = new SourceFileScope();
115         }
116         scopes.push(scope);
117         node.setScope(scope);
118     }
119     
120     public Object visit(ASTCompilationUnit node, Object data) {
121         createSourceFileScope(node);
122         cont(node);
123         return data;
124     }
125 
126     public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
127         createClassScope(node);     
128         Scope s = ((SimpleNode)node.jjtGetParent()).getScope();
129         s.addDeclaration(new ClassNameDeclaration(node));
130         cont(node);
131         return data;
132     }
133 
134     public Object visit(ASTEnumDeclaration node, Object data) {
135         createClassScope(node);
136         cont(node);
137         return data;
138     }
139 
140     public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
141         if (node.isAnonymousInnerClass()) {
142             createClassScope(node);
143             cont(node);
144         } else {
145             super.visit(node, data);
146         }
147         return data;
148     }
149 
150     public Object visit(ASTBlock node, Object data) {
151         createLocalScope(node);
152         cont(node);
153         return data;
154     }
155 
156     public Object visit(ASTCatchStatement node, Object data) {
157         createLocalScope(node);
158         cont(node);
159         return data;
160     }
161 
162     public Object visit(ASTFinallyStatement node, Object data) {
163         createLocalScope(node);
164         cont(node);
165         return data;
166     }
167 
168     public Object visit(ASTConstructorDeclaration node, Object data) {
169         createMethodScope(node);
170         cont(node);
171         return data;
172     }
173 
174     public Object visit(ASTMethodDeclaration node, Object data) {
175         createMethodScope(node);
176         ASTMethodDeclarator md = (ASTMethodDeclarator)node.getFirstChildOfType(ASTMethodDeclarator.class);
177         node.getScope().getEnclosingClassScope().addDeclaration(new MethodNameDeclaration(md));
178         cont(node);
179         return data;
180     }
181 
182     public Object visit(ASTTryStatement node, Object data) {
183         createLocalScope(node);
184         cont(node);
185         return data;
186     }
187 
188     // TODO - what about while loops and do loops?
189     public Object visit(ASTForStatement node, Object data) {
190         createLocalScope(node);
191         cont(node);
192         return data;
193     }
194 
195     public Object visit(ASTIfStatement node, Object data) {
196         createLocalScope(node);
197         cont(node);
198         return data;
199     }
200 
201     public Object visit(ASTVariableDeclaratorId node, Object data) {
202         node.getScope().addDeclaration(new VariableNameDeclaration(node));
203         return super.visit(node, data);
204     }
205 
206     public Object visit(ASTSwitchStatement node, Object data) {
207         createLocalScope(node);
208         cont(node);
209         return data;
210     }
211 
212     private void cont(SimpleNode node) {
213         super.visit(node, null);
214         scopes.pop();
215     }
216 }