View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.dfa;
5   
6   import java.util.logging.Level;
7   import java.util.logging.Logger;
8   
9   import net.sourceforge.pmd.lang.DataFlowHandler;
10  import net.sourceforge.pmd.lang.ast.Node;
11  import net.sourceforge.pmd.lang.dfa.Linker;
12  import net.sourceforge.pmd.lang.dfa.LinkerException;
13  import net.sourceforge.pmd.lang.dfa.NodeType;
14  import net.sourceforge.pmd.lang.dfa.SequenceException;
15  import net.sourceforge.pmd.lang.dfa.Structure;
16  import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
17  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
18  import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
19  import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
20  import net.sourceforge.pmd.lang.java.ast.ASTExpression;
21  import net.sourceforge.pmd.lang.java.ast.ASTForInit;
22  import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
23  import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
24  import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
25  import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
26  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
27  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
28  import net.sourceforge.pmd.lang.java.ast.ASTStatement;
29  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
30  import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
31  import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
32  import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
33  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
34  import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
35  import net.sourceforge.pmd.lang.java.ast.JavaNode;
36  import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
37  
38  /**
39   * @author raik
40   *         <p/>
41   *         Sublayer of DataFlowFacade. Finds all data flow nodes and stores the
42   *         type information (@see StackObject). At last it uses this information to
43   *         link the nodes.
44   */
45  public class StatementAndBraceFinder extends JavaParserVisitorAdapter {
46      private final static Logger LOGGER = Logger.getLogger(StatementAndBraceFinder.class.getName()); 
47  
48      private final DataFlowHandler dataFlowHandler;
49      private Structure dataFlow;
50      
51      public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) {
52          this.dataFlowHandler = dataFlowHandler;
53      }
54  
55      public void buildDataFlowFor(JavaNode node) {
56          if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTConstructorDeclaration)) {
57              throw new RuntimeException("Can't build a data flow for anything other than a method or a constructor");
58          }
59  
60          this.dataFlow = new Structure(dataFlowHandler);
61          this.dataFlow.createStartNode(node.getBeginLine());
62          this.dataFlow.createNewNode(node);
63  
64          node.jjtAccept(this, dataFlow);
65  
66          this.dataFlow.createEndNode(node.getEndLine());
67          if (LOGGER.isLoggable(Level.FINE)) {
68              LOGGER.fine("DataFlow is " + this.dataFlow.dump() ); // @TODO SRT Remove after development  
69          }
70          Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
71          try {
72              linker.computePaths();
73          } catch (LinkerException e) {
74              e.printStackTrace();
75          } catch (SequenceException e) {
76              e.printStackTrace();
77          }
78      }
79  
80      public Object visit(ASTStatementExpression node, Object data) {
81          if (!(data instanceof Structure)) {
82              return data;
83          }
84          Structure dataFlow = (Structure) data;
85          if (LOGGER.isLoggable(Level.FINEST)) {
86              LOGGER.finest("createNewNode ASTStatementExpression: line " + node.getBeginLine() +", column " + node.getBeginColumn());
87          }
88          dataFlow.createNewNode(node);
89          return super.visit(node, data);
90      }
91  
92      public Object visit(ASTVariableDeclarator node, Object data) {
93          if (!(data instanceof Structure)) {
94              return data;
95          }
96          Structure dataFlow = (Structure) data;
97          if (LOGGER.isLoggable(Level.FINEST)) {
98              LOGGER.finest("createNewNode ASTVariableDeclarator: line " + node.getBeginLine() +", column " + node.getBeginColumn());
99          }
100         dataFlow.createNewNode(node);
101         return super.visit(node, data);
102     }
103 
104     public Object visit(ASTExpression node, Object data) {
105         if (!(data instanceof Structure)) {
106             return data;
107         }
108         Structure dataFlow = (Structure) data;
109 
110         // TODO what about throw stmts?
111         if (node.jjtGetParent() instanceof ASTIfStatement) {
112             dataFlow.createNewNode(node); // START IF
113             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
114             if (LOGGER.isLoggable(Level.FINEST)) {
115                 LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
116             }
117         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
118             dataFlow.createNewNode(node); // START WHILE
119             dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
120             if (LOGGER.isLoggable(Level.FINEST)) {
121                 LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
122             }
123         } else if (node.jjtGetParent() instanceof ASTSwitchStatement) {
124             dataFlow.createNewNode(node); // START SWITCH
125             dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
126             if (LOGGER.isLoggable(Level.FINEST)) {
127                 LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() +", column " + node.getBeginColumn());
128             }
129         } else if (node.jjtGetParent() instanceof ASTForStatement) {
130             dataFlow.createNewNode(node); // FOR EXPR
131             dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
132             if (LOGGER.isLoggable(Level.FINEST)) {
133                 LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
134             }
135         } else if (node.jjtGetParent() instanceof ASTDoStatement) {
136             dataFlow.createNewNode(node); // DO EXPR
137             dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
138             if (LOGGER.isLoggable(Level.FINEST)) {
139                 LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
140             }
141         }
142 
143         return super.visit(node, data);
144     }
145 
146     public Object visit(ASTForInit node, Object data) {
147         if (!(data instanceof Structure)) {
148             return data;
149         }
150         Structure dataFlow = (Structure) data;
151         super.visit(node, data);
152         dataFlow.pushOnStack(NodeType.FOR_INIT, dataFlow.getLast());
153         if (LOGGER.isLoggable(Level.FINEST)) {
154             LOGGER.finest("pushOnStack FOR_INIT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
155         }
156         this.addForExpressionNode(node, dataFlow);
157         return data;
158     }
159 
160     public Object visit(ASTLabeledStatement node, Object data) {
161         dataFlow.createNewNode(node);
162         dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
163         if (LOGGER.isLoggable(Level.FINEST)) {
164             LOGGER.finest("pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
165         }
166         return super.visit(node, data);
167     }
168 
169     public Object visit(ASTForUpdate node, Object data) {
170         if (!(data instanceof Structure)) {
171             return data;
172         }
173         Structure dataFlow = (Structure) data;
174         this.addForExpressionNode(node, dataFlow);
175         super.visit(node, data);
176         dataFlow.pushOnStack(NodeType.FOR_UPDATE, dataFlow.getLast());
177         if (LOGGER.isLoggable(Level.FINEST)) {
178             LOGGER.finest("pushOnStack FOR_UPDATE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
179         }
180         return data;
181     }
182 
183 // 	----------------------------------------------------------------------------
184 //  BRANCH OUT
185 
186     public Object visit(ASTStatement node, Object data) {
187         if (!(data instanceof Structure)) {
188             return data;
189         }
190         Structure dataFlow = (Structure) data;
191 
192         if (node.jjtGetParent() instanceof ASTForStatement) {
193             this.addForExpressionNode(node, dataFlow);
194             dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
195             if (LOGGER.isLoggable(Level.FINEST)) {
196                 LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
197             }
198         } else if (node.jjtGetParent() instanceof ASTDoStatement) {
199             dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
200             dataFlow.createNewNode(node.jjtGetParent());
201             if (LOGGER.isLoggable(Level.FINEST)) {
202                 LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
203             }
204         }
205 
206         super.visit(node, data);
207 
208         if (node.jjtGetParent() instanceof ASTIfStatement) {
209             ASTIfStatement st = (ASTIfStatement) node.jjtGetParent();
210             if (!st.hasElse()) {
211                 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
212                 if (LOGGER.isLoggable(Level.FINEST)) {
213                     LOGGER.finest("pushOnStack IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
214                 }
215             } else if (st.hasElse() && !st.jjtGetChild(1).equals(node)) {
216                 dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
217                 if (LOGGER.isLoggable(Level.FINEST)) {
218                     LOGGER.finest("pushOnStack ELSE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
219                 }
220             } else {
221                 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
222                 if (LOGGER.isLoggable(Level.FINEST)) {
223                     LOGGER.finest("pushOnStack IF_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
224                 }
225             }
226         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
227             dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
228             if (LOGGER.isLoggable(Level.FINEST)) {
229                 LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
230             }
231         } else if (node.jjtGetParent() instanceof ASTForStatement) {
232             dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
233             if (LOGGER.isLoggable(Level.FINEST)) {
234                 LOGGER.finest("pushOnStack FOR_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
235             }
236         } else if (node.jjtGetParent() instanceof ASTLabeledStatement) {
237             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
238             if (LOGGER.isLoggable(Level.FINEST)) {
239                 LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
240             }
241         }
242         return data;
243     }
244 
245     public Object visit(ASTSwitchStatement node, Object data) {
246         if (!(data instanceof Structure)) {
247             return data;
248         }
249         Structure dataFlow = (Structure) data;
250         super.visit(node, data);
251         dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
252         if (LOGGER.isLoggable(Level.FINEST)) {
253             LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
254         }
255         return data;
256     }
257 
258     public Object visit(ASTSwitchLabel node, Object data) {
259         if (!(data instanceof Structure)) {
260             return data;
261         }
262         Structure dataFlow = (Structure) data;
263         //super.visit(node, data);
264         if (node.jjtGetNumChildren() == 0) {
265             dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
266             if (LOGGER.isLoggable(Level.FINEST)) {
267                 LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
268             }
269         } else {
270             dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
271             if (LOGGER.isLoggable(Level.FINEST)) {
272                 LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
273             }
274         }
275         return data;
276     }
277 
278     public Object visit(ASTBreakStatement node, Object data) {
279         if (!(data instanceof Structure)) {
280             return data;
281         }
282         Structure dataFlow = (Structure) data;
283         dataFlow.createNewNode(node);
284         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
285         if (LOGGER.isLoggable(Level.FINEST)) {
286             LOGGER.finest("pushOnStack BREAK_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
287         }
288         return super.visit(node, data);
289     }
290 
291 
292     public Object visit(ASTContinueStatement node, Object data) {
293         if (!(data instanceof Structure)) {
294             return data;
295         }
296         Structure dataFlow = (Structure) data;
297         dataFlow.createNewNode(node);
298         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
299         if (LOGGER.isLoggable(Level.FINEST)) {
300             LOGGER.finest("pushOnStack CONTINUE_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
301         }
302         return super.visit(node, data);
303     }
304 
305     public Object visit(ASTReturnStatement node, Object data) {
306         if (!(data instanceof Structure)) {
307             return data;
308         }
309         Structure dataFlow = (Structure) data;
310         dataFlow.createNewNode(node);
311         dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
312         if (LOGGER.isLoggable(Level.FINEST)) {
313             LOGGER.finest("pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
314         }
315         return super.visit(node, data);
316     }
317 
318     public Object visit(ASTThrowStatement node, Object data) {
319         if (!(data instanceof Structure)) {
320             return data;
321         }
322         Structure dataFlow = (Structure) data;
323         dataFlow.createNewNode(node);
324         dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
325         if (LOGGER.isLoggable(Level.FINEST)) {
326             LOGGER.finest("pushOnStack THROW_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
327         }
328         return super.visit(node, data);
329     }
330 
331     /*
332      * The method handles the special "for" loop. It creates always an
333      * expression node even if the loop looks like for(;;).
334      * */
335     private void addForExpressionNode(Node node, Structure dataFlow) {
336         ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
337         boolean hasExpressionChild = false;
338         boolean hasForInitNode = false;
339         boolean hasForUpdateNode = false;
340 
341         for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
342             if (parent.jjtGetChild(i) instanceof ASTExpression) {
343                 hasExpressionChild = true;
344             } else if (parent.jjtGetChild(i) instanceof ASTForUpdate) {
345                 hasForUpdateNode = true;
346             } else if (parent.jjtGetChild(i) instanceof ASTForInit) {
347                 hasForInitNode = true;
348             }
349         }
350         if (!hasExpressionChild) {
351             if (node instanceof ASTForInit) {
352                 dataFlow.createNewNode(node);
353                 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
354                 if (LOGGER.isLoggable(Level.FINEST)) {
355                     LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
356                 }
357             } else if (node instanceof ASTForUpdate) {
358                 if (!hasForInitNode) {
359                     dataFlow.createNewNode(node);
360                     dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
361                     if (LOGGER.isLoggable(Level.FINEST)) {
362                         LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
363                     }
364                 }
365             } else if (node instanceof ASTStatement) {
366                 if (!hasForInitNode && !hasForUpdateNode) {
367                     dataFlow.createNewNode(node);
368                     dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
369                     if (LOGGER.isLoggable(Level.FINEST)) {
370                         LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
371                     }
372                 }
373             }
374         }
375     }
376 }