View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.dfa;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   
9   /**
10   * @author raik
11   *         <p/>
12   *         Computes the first sequence in a list.
13   *         <p/>
14   *         e.g.
15   *         IF_START			0
16   *         WHILE_EXPR		1
17   *         WHILE_END		2
18   *         IF_END			3
19   *         <p/>
20   *         The first sequence is WHILE_EXPR und WHILE_END. It returns always the
21   *         first inner nested scope.
22   */
23  public class SequenceChecker {
24  
25      /*
26       * Element of logical structure of brace nodes.
27       * */
28      private static class Status {
29          public static final int ROOT = -1;
30  
31          private List<Status> nextSteps = new ArrayList<Status>();
32          private int type; //NOPMD type is used, but PMD seems to no be able to spot it
33          private boolean lastStep;
34  
35  
36          public Status(int type) {
37              this(type, false);
38          }
39  
40          public Status(int type, boolean lastStep) {
41              this.type = type;
42              this.lastStep = lastStep;
43          }
44  
45          public void addStep(Status type) {
46              nextSteps.add(type);
47          }
48  
49          public Status step(int type) {
50              for (int i = 0; i < this.nextSteps.size(); i++) {
51                  if (type == nextSteps.get(i).type) {
52                      return nextSteps.get(i);
53                  }
54              }
55              return null;
56          }
57  
58          public boolean isLastStep() {
59              return this.lastStep;
60          }
61  
62          public boolean hasMoreSteps() {
63              return this.nextSteps.size() > 1;
64          }
65      }
66  
67      private static Status root;
68  
69      static {
70          root = new Status(Status.ROOT);
71          Status ifNode = new Status(NodeType.IF_EXPR);
72          Status ifSt = new Status(NodeType.IF_LAST_STATEMENT);
73          Status ifStWithoutElse = new Status(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, true);
74          Status elseSt = new Status(NodeType.ELSE_LAST_STATEMENT, true);
75          Status whileNode = new Status(NodeType.WHILE_EXPR);
76          Status whileSt = new Status(NodeType.WHILE_LAST_STATEMENT, true);
77          Status switchNode = new Status(NodeType.SWITCH_START);
78          Status caseSt = new Status(NodeType.CASE_LAST_STATEMENT);
79          Status switchDefault = new Status(NodeType.SWITCH_LAST_DEFAULT_STATEMENT);
80          Status switchEnd = new Status(NodeType.SWITCH_END, true);
81  
82          Status forInit = new Status(NodeType.FOR_INIT);
83          Status forExpr = new Status(NodeType.FOR_EXPR);
84          Status forUpdate = new Status(NodeType.FOR_UPDATE);
85          Status forSt = new Status(NodeType.FOR_BEFORE_FIRST_STATEMENT);
86          Status forEnd = new Status(NodeType.FOR_END, true);
87  
88          Status doSt = new Status(NodeType.DO_BEFORE_FIRST_STATEMENT);
89          Status doExpr = new Status(NodeType.DO_EXPR, true);
90  
91          Status labelNode = new Status(NodeType.LABEL_STATEMENT);
92          Status labelEnd = new Status(NodeType.LABEL_LAST_STATEMENT, true);
93  
94          root.addStep(ifNode);
95          root.addStep(whileNode);
96          root.addStep(switchNode);
97          root.addStep(forInit);
98          root.addStep(forExpr);
99          root.addStep(forUpdate);
100         root.addStep(forSt);
101         root.addStep(doSt);
102         root.addStep(labelNode);
103 
104         ifNode.addStep(ifSt);
105         ifNode.addStep(ifStWithoutElse);
106         ifSt.addStep(elseSt);
107         ifStWithoutElse.addStep(root);
108         elseSt.addStep(root);
109 
110         labelNode.addStep(labelEnd);
111         labelEnd.addStep(root);
112 
113         whileNode.addStep(whileSt);
114         whileSt.addStep(root);
115 
116         switchNode.addStep(caseSt);
117         switchNode.addStep(switchDefault);
118         switchNode.addStep(switchEnd);
119         caseSt.addStep(caseSt);
120         caseSt.addStep(switchDefault);
121         caseSt.addStep(switchEnd);
122         switchDefault.addStep(switchEnd);
123         switchDefault.addStep(caseSt);
124         switchEnd.addStep(root);
125 
126         forInit.addStep(forExpr);
127         forInit.addStep(forUpdate);
128         forInit.addStep(forSt);
129         forExpr.addStep(forUpdate);
130         forExpr.addStep(forSt);
131         forUpdate.addStep(forSt);
132         forSt.addStep(forEnd);
133         forEnd.addStep(root);
134 
135         doSt.addStep(doExpr);
136         doExpr.addStep(root);
137     }
138 
139     private Status aktStatus;
140     private List bracesList;
141 
142     private int firstIndex = -1;
143     private int lastIndex = -1;
144 
145     /*
146      * Defines the logical structure.
147      * */
148     public SequenceChecker(List bracesList) {
149         this.aktStatus = root;
150         this.bracesList = bracesList;
151     }
152 
153     /**
154      * Finds the first most inner sequence e.g IFStart & IFEnd. If no sequence
155      * is found or the list is empty the method returns false.
156      */
157     public boolean run() {
158         this.aktStatus = root;
159         this.firstIndex = 0;
160         this.lastIndex = 0;
161         boolean lookAhead = false;
162 
163         for (int i = 0; i < this.bracesList.size(); i++) {
164             StackObject so = (StackObject) bracesList.get(i);
165             aktStatus = this.aktStatus.step(so.getType());
166 
167             if (aktStatus == null) {
168                 if (lookAhead) {
169                     this.lastIndex = i - 1;
170                     return false;
171                 }
172                 this.aktStatus = root;
173                 this.firstIndex = i;
174                 i--;
175                 continue;
176             } else {
177                 if (aktStatus.isLastStep() && !aktStatus.hasMoreSteps()) {
178                     this.lastIndex = i;
179                     return false;
180                 } else if (aktStatus.isLastStep() && aktStatus.hasMoreSteps()) {
181                     lookAhead = true;
182                     this.lastIndex = i;
183                 }
184             }
185         }
186         return this.firstIndex == this.lastIndex;
187     }
188 
189     public int getFirstIndex() {
190         return this.firstIndex;
191     }
192 
193     public int getLastIndex() {
194         return this.lastIndex;
195     }
196 
197 }