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
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
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 }