001 /**
002 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003 */
004 package net.sourceforge.pmd.lang.java.dfa;
005
006 import net.sourceforge.pmd.lang.DataFlowHandler;
007 import net.sourceforge.pmd.lang.ast.Node;
008 import net.sourceforge.pmd.lang.dfa.Linker;
009 import net.sourceforge.pmd.lang.dfa.LinkerException;
010 import net.sourceforge.pmd.lang.dfa.NodeType;
011 import net.sourceforge.pmd.lang.dfa.SequenceException;
012 import net.sourceforge.pmd.lang.dfa.Structure;
013 import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
014 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
015 import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
016 import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
017 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
018 import net.sourceforge.pmd.lang.java.ast.ASTForInit;
019 import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
020 import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
021 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
022 import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
023 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
024 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
025 import net.sourceforge.pmd.lang.java.ast.ASTStatement;
026 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
027 import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
028 import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
029 import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
030 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
031 import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
032 import net.sourceforge.pmd.lang.java.ast.JavaNode;
033 import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
034
035 /**
036 * @author raik
037 * <p/>
038 * Sublayer of DataFlowFacade. Finds all data flow nodes and stores the
039 * type information (@see StackObject). At last it uses this information to
040 * link the nodes.
041 */
042 public class StatementAndBraceFinder extends JavaParserVisitorAdapter {
043
044 private final DataFlowHandler dataFlowHandler;
045 private Structure dataFlow;
046
047 public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) {
048 this.dataFlowHandler = dataFlowHandler;
049 }
050
051 public void buildDataFlowFor(JavaNode node) {
052 if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTConstructorDeclaration)) {
053 throw new RuntimeException("Can't build a data flow for anything other than a method or a constructor");
054 }
055
056 this.dataFlow = new Structure(dataFlowHandler);
057 this.dataFlow.createStartNode(node.getBeginLine());
058 this.dataFlow.createNewNode(node);
059
060 node.jjtAccept(this, dataFlow);
061
062 this.dataFlow.createEndNode(node.getEndLine());
063
064 Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
065 try {
066 linker.computePaths();
067 } catch (LinkerException e) {
068 e.printStackTrace();
069 } catch (SequenceException e) {
070 e.printStackTrace();
071 }
072 }
073
074 public Object visit(ASTStatementExpression node, Object data) {
075 if (!(data instanceof Structure)) {
076 return data;
077 }
078 Structure dataFlow = (Structure) data;
079 dataFlow.createNewNode(node);
080 return super.visit(node, data);
081 }
082
083 public Object visit(ASTVariableDeclarator node, Object data) {
084 if (!(data instanceof Structure)) {
085 return data;
086 }
087 Structure dataFlow = (Structure) data;
088 dataFlow.createNewNode(node);
089 return super.visit(node, data);
090 }
091
092 public Object visit(ASTExpression node, Object data) {
093 if (!(data instanceof Structure)) {
094 return data;
095 }
096 Structure dataFlow = (Structure) data;
097
098 // TODO what about throw stmts?
099 if (node.jjtGetParent() instanceof ASTIfStatement) {
100 dataFlow.createNewNode(node); // START IF
101 dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
102 } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
103 dataFlow.createNewNode(node); // START WHILE
104 dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
105 } else if (node.jjtGetParent() instanceof ASTSwitchStatement) {
106 dataFlow.createNewNode(node); // START SWITCH
107 dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
108 } else if (node.jjtGetParent() instanceof ASTForStatement) {
109 dataFlow.createNewNode(node); // FOR EXPR
110 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
111 } else if (node.jjtGetParent() instanceof ASTDoStatement) {
112 dataFlow.createNewNode(node); // DO EXPR
113 dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
114 }
115
116 return super.visit(node, data);
117 }
118
119 public Object visit(ASTForInit node, Object data) {
120 if (!(data instanceof Structure)) {
121 return data;
122 }
123 Structure dataFlow = (Structure) data;
124 super.visit(node, data);
125 dataFlow.pushOnStack(NodeType.FOR_INIT, dataFlow.getLast());
126 this.addForExpressionNode(node, dataFlow);
127 return data;
128 }
129
130 public Object visit(ASTLabeledStatement node, Object data) {
131 dataFlow.createNewNode(node);
132 dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
133 return super.visit(node, data);
134 }
135
136 public Object visit(ASTForUpdate node, Object data) {
137 if (!(data instanceof Structure)) {
138 return data;
139 }
140 Structure dataFlow = (Structure) data;
141 this.addForExpressionNode(node, dataFlow);
142 super.visit(node, data);
143 dataFlow.pushOnStack(NodeType.FOR_UPDATE, dataFlow.getLast());
144 return data;
145 }
146
147 // ----------------------------------------------------------------------------
148 // BRANCH OUT
149
150 public Object visit(ASTStatement node, Object data) {
151 if (!(data instanceof Structure)) {
152 return data;
153 }
154 Structure dataFlow = (Structure) data;
155
156 if (node.jjtGetParent() instanceof ASTForStatement) {
157 this.addForExpressionNode(node, dataFlow);
158 dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
159 } else if (node.jjtGetParent() instanceof ASTDoStatement) {
160 dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
161 dataFlow.createNewNode(node.jjtGetParent());
162 }
163
164 super.visit(node, data);
165
166 if (node.jjtGetParent() instanceof ASTIfStatement) {
167 ASTIfStatement st = (ASTIfStatement) node.jjtGetParent();
168 if (!st.hasElse()) {
169 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
170 } else if (st.hasElse() && !st.jjtGetChild(1).equals(node)) {
171 dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
172 } else {
173 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
174 }
175 } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
176 dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
177 } else if (node.jjtGetParent() instanceof ASTForStatement) {
178 dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
179 } else if (node.jjtGetParent() instanceof ASTLabeledStatement) {
180 dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
181 }
182 return data;
183 }
184
185 public Object visit(ASTSwitchStatement node, Object data) {
186 if (!(data instanceof Structure)) {
187 return data;
188 }
189 Structure dataFlow = (Structure) data;
190 super.visit(node, data);
191 dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
192 return data;
193 }
194
195 public Object visit(ASTSwitchLabel node, Object data) {
196 if (!(data instanceof Structure)) {
197 return data;
198 }
199 Structure dataFlow = (Structure) data;
200 //super.visit(node, data);
201 if (node.jjtGetNumChildren() == 0) {
202 dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
203 } else {
204 dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
205 }
206 return data;
207 }
208
209 public Object visit(ASTBreakStatement node, Object data) {
210 if (!(data instanceof Structure)) {
211 return data;
212 }
213 Structure dataFlow = (Structure) data;
214 dataFlow.createNewNode(node);
215 dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
216 return super.visit(node, data);
217 }
218
219
220 public Object visit(ASTContinueStatement node, Object data) {
221 if (!(data instanceof Structure)) {
222 return data;
223 }
224 Structure dataFlow = (Structure) data;
225 dataFlow.createNewNode(node);
226 dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
227 return super.visit(node, data);
228 }
229
230 public Object visit(ASTReturnStatement node, Object data) {
231 if (!(data instanceof Structure)) {
232 return data;
233 }
234 Structure dataFlow = (Structure) data;
235 dataFlow.createNewNode(node);
236 dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
237 return super.visit(node, data);
238 }
239
240 public Object visit(ASTThrowStatement node, Object data) {
241 if (!(data instanceof Structure)) {
242 return data;
243 }
244 Structure dataFlow = (Structure) data;
245 dataFlow.createNewNode(node);
246 dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
247 return super.visit(node, data);
248 }
249
250 /*
251 * The method handles the special "for" loop. It creates always an
252 * expression node even if the loop looks like for(;;).
253 * */
254 private void addForExpressionNode(Node node, Structure dataFlow) {
255 ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
256 boolean hasExpressionChild = false;
257 boolean hasForInitNode = false;
258 boolean hasForUpdateNode = false;
259
260 for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
261 if (parent.jjtGetChild(i) instanceof ASTExpression) {
262 hasExpressionChild = true;
263 } else if (parent.jjtGetChild(i) instanceof ASTForUpdate) {
264 hasForUpdateNode = true;
265 } else if (parent.jjtGetChild(i) instanceof ASTForInit) {
266 hasForInitNode = true;
267 }
268 }
269 if (!hasExpressionChild) {
270 if (node instanceof ASTForInit) {
271 dataFlow.createNewNode(node);
272 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
273 } else if (node instanceof ASTForUpdate) {
274 if (!hasForInitNode) {
275 dataFlow.createNewNode(node);
276 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
277 }
278 } else if (node instanceof ASTStatement) {
279 if (!hasForInitNode && !hasForUpdateNode) {
280 dataFlow.createNewNode(node);
281 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
282 }
283 }
284 }
285 }
286 }
|