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