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 }