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          {
69            LOGGER.fine("DataFlow is " + this.dataFlow.dump() ); // @TODO SRT Remove after development  
70          }
71          Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
72          try {
73              linker.computePaths();
74          } catch (LinkerException e) {
75              e.printStackTrace();
76          } catch (SequenceException e) {
77              e.printStackTrace();
78          }
79      }
80  
81      public Object visit(ASTStatementExpression node, Object data) {
82          if (!(data instanceof Structure)) {
83              return data;
84          }
85          Structure dataFlow = (Structure) data;
86          LOGGER.finest("createNewNode ASTStatementExpression: line " + node.getBeginLine() +", column " + node.getBeginColumn());
87          dataFlow.createNewNode(node);
88          return super.visit(node, data);
89      }
90  
91      public Object visit(ASTVariableDeclarator node, Object data) {
92          if (!(data instanceof Structure)) {
93              return data;
94          }
95          Structure dataFlow = (Structure) data;
96          LOGGER.finest("createNewNode ASTVariableDeclarator: line " + node.getBeginLine() +", column " + node.getBeginColumn());
97          dataFlow.createNewNode(node);
98          return super.visit(node, data);
99      }
100 
101     public Object visit(ASTExpression node, Object data) {
102         if (!(data instanceof Structure)) {
103             return data;
104         }
105         Structure dataFlow = (Structure) data;
106 
107         // TODO what about throw stmts?
108         if (node.jjtGetParent() instanceof ASTIfStatement) {
109             dataFlow.createNewNode(node); // START IF
110             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
111             LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
112         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
113             dataFlow.createNewNode(node); // START WHILE
114             dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
115             LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
116         } else if (node.jjtGetParent() instanceof ASTSwitchStatement) {
117             dataFlow.createNewNode(node); // START SWITCH
118             dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
119             LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() +", column " + node.getBeginColumn());
120         } else if (node.jjtGetParent() instanceof ASTForStatement) {
121             dataFlow.createNewNode(node); // FOR EXPR
122             dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
123             LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
124         } else if (node.jjtGetParent() instanceof ASTDoStatement) {
125             dataFlow.createNewNode(node); // DO EXPR
126             dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
127             LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
128         }
129 
130         return super.visit(node, data);
131     }
132 
133     public Object visit(ASTForInit node, Object data) {
134         if (!(data instanceof Structure)) {
135             return data;
136         }
137         Structure dataFlow = (Structure) data;
138         super.visit(node, data);
139         dataFlow.pushOnStack(NodeType.FOR_INIT, dataFlow.getLast());
140         LOGGER.finest("pushOnStack FOR_INIT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
141         this.addForExpressionNode(node, dataFlow);
142         return data;
143     }
144 
145     public Object visit(ASTLabeledStatement node, Object data) {
146         dataFlow.createNewNode(node);
147         dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
148         LOGGER.finest("pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
149         return super.visit(node, data);
150     }
151 
152     public Object visit(ASTForUpdate node, Object data) {
153         if (!(data instanceof Structure)) {
154             return data;
155         }
156         Structure dataFlow = (Structure) data;
157         this.addForExpressionNode(node, dataFlow);
158         super.visit(node, data);
159         dataFlow.pushOnStack(NodeType.FOR_UPDATE, dataFlow.getLast());
160         LOGGER.finest("pushOnStack FOR_UPDATE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
161         return data;
162     }
163 
164 // 	----------------------------------------------------------------------------
165 //  BRANCH OUT
166 
167     public Object visit(ASTStatement node, Object data) {
168         if (!(data instanceof Structure)) {
169             return data;
170         }
171         Structure dataFlow = (Structure) data;
172 
173         if (node.jjtGetParent() instanceof ASTForStatement) {
174             this.addForExpressionNode(node, dataFlow);
175             dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
176             LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
177         } else if (node.jjtGetParent() instanceof ASTDoStatement) {
178             dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
179             dataFlow.createNewNode(node.jjtGetParent());
180             LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
181         }
182 
183         super.visit(node, data);
184 
185         if (node.jjtGetParent() instanceof ASTIfStatement) {
186             ASTIfStatement st = (ASTIfStatement) node.jjtGetParent();
187             if (!st.hasElse()) {
188                 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
189                 LOGGER.finest("pushOnStack IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
190             } else if (st.hasElse() && !st.jjtGetChild(1).equals(node)) {
191                 dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
192                 LOGGER.finest("pushOnStack ELSE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
193             } else {
194                 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
195                 LOGGER.finest("pushOnStack IF_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
196             }
197         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
198             dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
199             LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
200         } else if (node.jjtGetParent() instanceof ASTForStatement) {
201             dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
202             LOGGER.finest("pushOnStack FOR_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
203         } else if (node.jjtGetParent() instanceof ASTLabeledStatement) {
204             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
205             LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
206         }
207         return data;
208     }
209 
210     public Object visit(ASTSwitchStatement node, Object data) {
211         if (!(data instanceof Structure)) {
212             return data;
213         }
214         Structure dataFlow = (Structure) data;
215         super.visit(node, data);
216         dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
217         LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
218         return data;
219     }
220 
221     public Object visit(ASTSwitchLabel node, Object data) {
222         if (!(data instanceof Structure)) {
223             return data;
224         }
225         Structure dataFlow = (Structure) data;
226         //super.visit(node, data);
227         if (node.jjtGetNumChildren() == 0) {
228             dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
229             LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
230         } else {
231             dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
232             LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
233         }
234         return data;
235     }
236 
237     public Object visit(ASTBreakStatement node, Object data) {
238         if (!(data instanceof Structure)) {
239             return data;
240         }
241         Structure dataFlow = (Structure) data;
242         dataFlow.createNewNode(node);
243         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
244         LOGGER.finest("pushOnStack BREAK_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
245         return super.visit(node, data);
246     }
247 
248 
249     public Object visit(ASTContinueStatement node, Object data) {
250         if (!(data instanceof Structure)) {
251             return data;
252         }
253         Structure dataFlow = (Structure) data;
254         dataFlow.createNewNode(node);
255         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
256         LOGGER.finest("pushOnStack CONTINUE_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
257         return super.visit(node, data);
258     }
259 
260     public Object visit(ASTReturnStatement node, Object data) {
261         if (!(data instanceof Structure)) {
262             return data;
263         }
264         Structure dataFlow = (Structure) data;
265         dataFlow.createNewNode(node);
266         dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
267         LOGGER.finest("pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
268         return super.visit(node, data);
269     }
270 
271     public Object visit(ASTThrowStatement node, Object data) {
272         if (!(data instanceof Structure)) {
273             return data;
274         }
275         Structure dataFlow = (Structure) data;
276         dataFlow.createNewNode(node);
277         dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
278         LOGGER.finest("pushOnStack THROW_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
279         return super.visit(node, data);
280     }
281 
282     /*
283      * The method handles the special "for" loop. It creates always an
284      * expression node even if the loop looks like for(;;).
285      * */
286     private void addForExpressionNode(Node node, Structure dataFlow) {
287         ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
288         boolean hasExpressionChild = false;
289         boolean hasForInitNode = false;
290         boolean hasForUpdateNode = false;
291 
292         for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
293             if (parent.jjtGetChild(i) instanceof ASTExpression) {
294                 hasExpressionChild = true;
295             } else if (parent.jjtGetChild(i) instanceof ASTForUpdate) {
296                 hasForUpdateNode = true;
297             } else if (parent.jjtGetChild(i) instanceof ASTForInit) {
298                 hasForInitNode = true;
299             }
300         }
301         if (!hasExpressionChild) {
302             if (node instanceof ASTForInit) {
303                 dataFlow.createNewNode(node);
304                 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
305                 LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
306             } else if (node instanceof ASTForUpdate) {
307                 if (!hasForInitNode) {
308                     dataFlow.createNewNode(node);
309                     dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
310                     LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
311                 }
312             } else if (node instanceof ASTStatement) {
313                 if (!hasForInitNode && !hasForUpdateNode) {
314                     dataFlow.createNewNode(node);
315                     dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
316                     LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
317                 }
318             }
319         }
320     }
321 }