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 net.sourceforge.pmd.lang.DataFlowHandler;
7   import net.sourceforge.pmd.lang.ast.Node;
8   import net.sourceforge.pmd.lang.dfa.Linker;
9   import net.sourceforge.pmd.lang.dfa.LinkerException;
10  import net.sourceforge.pmd.lang.dfa.NodeType;
11  import net.sourceforge.pmd.lang.dfa.SequenceException;
12  import net.sourceforge.pmd.lang.dfa.Structure;
13  import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
14  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
15  import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
16  import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
17  import net.sourceforge.pmd.lang.java.ast.ASTExpression;
18  import net.sourceforge.pmd.lang.java.ast.ASTForInit;
19  import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
20  import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
21  import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
22  import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
23  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
24  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
25  import net.sourceforge.pmd.lang.java.ast.ASTStatement;
26  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
27  import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
28  import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
29  import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
30  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
31  import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
32  import net.sourceforge.pmd.lang.java.ast.JavaNode;
33  import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
34  
35  /**
36   * @author raik
37   *         <p/>
38   *         Sublayer of DataFlowFacade. Finds all data flow nodes and stores the
39   *         type information (@see StackObject). At last it uses this information to
40   *         link the nodes.
41   */
42  public class StatementAndBraceFinder extends JavaParserVisitorAdapter {
43  
44      private final DataFlowHandler dataFlowHandler;
45      private Structure dataFlow;
46      
47      public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) {
48  	this.dataFlowHandler = dataFlowHandler;
49      }
50  
51      public void buildDataFlowFor(JavaNode node) {
52          if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTConstructorDeclaration)) {
53              throw new RuntimeException("Can't build a data flow for anything other than a method or a constructor");
54          }
55  
56          this.dataFlow = new Structure(dataFlowHandler);
57          this.dataFlow.createStartNode(node.getBeginLine());
58          this.dataFlow.createNewNode(node);
59  
60          node.jjtAccept(this, dataFlow);
61  
62          this.dataFlow.createEndNode(node.getEndLine());
63  
64          Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
65          try {
66              linker.computePaths();
67          } catch (LinkerException e) {
68              e.printStackTrace();
69          } catch (SequenceException e) {
70              e.printStackTrace();
71          }
72      }
73  
74      public Object visit(ASTStatementExpression node, Object data) {
75          if (!(data instanceof Structure)) {
76              return data;
77          }
78          Structure dataFlow = (Structure) data;
79          dataFlow.createNewNode(node);
80          return super.visit(node, data);
81      }
82  
83      public Object visit(ASTVariableDeclarator node, Object data) {
84          if (!(data instanceof Structure)) {
85              return data;
86          }
87          Structure dataFlow = (Structure) data;
88          dataFlow.createNewNode(node);
89          return super.visit(node, data);
90      }
91  
92      public Object visit(ASTExpression node, Object data) {
93          if (!(data instanceof Structure)) {
94              return data;
95          }
96          Structure dataFlow = (Structure) data;
97  
98          // TODO what about throw stmts?
99          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 }