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