• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.github.javaparser.symbolsolver.resolution.typeinference;
2 
3 import com.github.javaparser.ast.Node;
4 import com.github.javaparser.ast.body.ConstructorDeclaration;
5 import com.github.javaparser.ast.body.InitializerDeclaration;
6 import com.github.javaparser.ast.body.MethodDeclaration;
7 import com.github.javaparser.ast.expr.VariableDeclarationExpr;
8 import com.github.javaparser.ast.stmt.*;
9 import com.github.javaparser.ast.visitor.GenericVisitor;
10 import com.github.javaparser.ast.visitor.GenericVisitorAdapter;
11 
12 import java.util.List;
13 
14 /**
15  * Consider Control Flow to determine which statements are reachable.
16  *
17  * Except for the special treatment of while, do, and for statements whose condition expression has the constant value
18  * true, the values of expressions are not taken into account in the flow analysis.
19  *
20  * See JLS 14.21
21  *
22  * @author Federico Tomassetti
23  */
24 public class ControlFlowLogic {
25 
26     private static ControlFlowLogic instance = new ControlFlowLogic();
27 
getInstance()28     public static ControlFlowLogic getInstance() {
29         return instance;
30     }
31 
ControlFlowLogic()32     private ControlFlowLogic() {
33 
34     }
35 
36     /**
37      * A break statement with no label attempts to transfer control to the innermost enclosing switch, while, do, or
38      * for statement of the immediately enclosing method or initializer; this statement, which is called the break
39      * target, then immediately completes normally.
40      *
41      *
42      * A break statement with label Identifier attempts to transfer control to the enclosing labeled statement (§14.7)
43      * that has the same Identifier as its label; this statement, which is called the break target, then immediately
44      * completes normally. In this case, the break target need not be a switch, while, do, or for statement.
45      */
breakTarget(BreakStmt breakStmt)46     public Statement breakTarget(BreakStmt breakStmt) {
47         throw new UnsupportedOperationException();
48     }
49 
50     /**
51      * A reachable break statement exits a statement if, within the break target, either there are no try statements
52      * whose try blocks contain the break statement, or there are try statements whose try blocks contain the break
53      * statement and all finally clauses of those try statements can complete normally.
54      */
exitTheStatement(BreakStmt breakStmt)55     public boolean exitTheStatement(BreakStmt breakStmt) {
56         if (!isReachable(breakStmt)) {
57             return false;
58         }
59         Statement breakTarget = breakTarget(breakStmt);
60         for (TryStmt tryStmt : containedTryStmts(breakTarget)) {
61             if (contains(tryStmt.getTryBlock(), breakStmt)) {
62                 if (!tryStmt.getFinallyBlock().isPresent() && !canCompleteNormally(tryStmt.getFinallyBlock().get())) {
63                     return false;
64                 }
65             }
66         }
67         return true;
68     }
69 
continueADoStatement(ContinueStmt continueStmt, DoStmt doStmt)70     public boolean continueADoStatement(ContinueStmt continueStmt, DoStmt doStmt) {
71         for (TryStmt tryStmt : containedTryStmts(continueStmt)) {
72             if (contains(tryStmt.getTryBlock(), continueStmt)) {
73                 if (!tryStmt.getFinallyBlock().isPresent() && !canCompleteNormally(tryStmt.getFinallyBlock().get())) {
74                     return false;
75                 }
76             }
77         }
78         return true;
79     }
80 
contains(Statement container, Statement contained)81     private boolean contains(Statement container, Statement contained) {
82         throw new UnsupportedOperationException();
83     }
84 
containedTryStmts(Statement statement)85     private List<TryStmt> containedTryStmts(Statement statement) {
86         throw new UnsupportedOperationException();
87     }
88 
parentIs(Node node, Class<P> parentClass)89     private <P extends Node> boolean parentIs(Node node, Class<P> parentClass) {
90         if (node.getParentNode().isPresent()) {
91             return parentClass.isInstance(node.getParentNode().get());
92         } else {
93             return false;
94         }
95     }
96 
97     // See JLS 14.21
canCompleteNormally(Statement statement)98     public boolean canCompleteNormally(Statement statement) {
99         if (!isReachable(statement)) {
100             return false;
101         }
102         GenericVisitor<Boolean, Void> visitor = new GenericVisitorAdapter<Boolean, Void>(){
103             @Override
104             public Boolean visit(BlockStmt n, Void arg) {
105                 // An empty block that is not a switch block can complete normally iff it is reachable
106                 if (n.isEmpty() && !parentIs(statement, SwitchStmt.class)) {
107                     return isReachable(statement);
108                 }
109                 // A non-empty block that is not a switch block can complete normally iff the last statement in
110                 // it can complete normally.
111                 if (!n.isEmpty() && !parentIs(statement, SwitchStmt.class)) {
112                     return canCompleteNormally(n.getStatement(n.getStatements().size() - 1));
113                 }
114                 throw new UnsupportedOperationException();
115             }
116 
117             @Override
118             public Boolean visit(LabeledStmt n, Void arg) {
119                 // A labeled statement can complete normally if at least one of the following is true:
120                 // – The contained statement can complete normally.
121                 // – There is a reachable break statement that exits the labeled statement.
122                 throw new UnsupportedOperationException();
123             }
124 
125             @Override
126             public Boolean visit(EmptyStmt n, Void arg) {
127                 // An empty statement can complete normally iff it is reachable.
128                 return isReachable(n);
129             }
130 
131             @Override
132             public Boolean visit(LocalClassDeclarationStmt n, Void arg) {
133                 // A local class declaration statement can complete normally iff it is reachable.
134                 return isReachable(n);
135             }
136 
137             @Override
138             public Boolean visit(IfStmt n, Void arg) {
139                 if (n.getElseStmt().isPresent()) {
140                     // An if-then-else statement can complete normally iff the then-statement can
141                     // complete normally or the else-statement can complete normally.
142                     return canCompleteNormally(n.getThenStmt()) || canCompleteNormally(n.getElseStmt().get());
143                 } else {
144                     // An if-then statement can complete normally iff it is reachable.
145                     return isReachable(n);
146                 }
147             }
148 
149             @Override
150             public Boolean visit(AssertStmt n, Void arg) {
151                 // An assert statement can complete normally iff it is reachable.
152                 return isReachable(n);
153             }
154 
155             @Override
156             public Boolean visit(ExpressionStmt n, Void arg) {
157                 // A local variable declaration statement can complete normally iff it is reachable.
158                 if (n.getExpression() instanceof VariableDeclarationExpr) {
159                     VariableDeclarationExpr expr = (VariableDeclarationExpr) n.getExpression();
160                     return isReachable(n);
161                 }
162                 // An expression statement can complete normally iff it is reachable.
163                 return isReachable(n);
164             }
165         };
166         return statement.accept(visitor, null);
167     }
168 
isReachableBecauseOfPosition(Statement statement)169     private boolean isReachableBecauseOfPosition(Statement statement) {
170         // The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.
171 
172         // Every other statement S in a non-empty block that is not a switch block is reachable iff the statement
173         // preceding S can complete normally.
174 
175         // The contained statement of a Labelled Statement is reachable iff the labeled statement is reachable.
176 
177         // The then-statement of an if-then statement is reachable iff the if-then statement is reachable.
178 
179         // The then-statement of an if-then-else  statement is reachable iff the if-then-else statement is reachable.
180         // The else-statement is reachable iff the if-then-else statement is reachable.
181 
182         throw new UnsupportedOperationException();
183     }
184 
isReachable(Statement statement)185     public boolean isReachable(Statement statement) {
186 
187         GenericVisitor<Boolean, Void> visitor = new GenericVisitorAdapter<Boolean, Void>(){
188             @Override
189             public Boolean visit(BlockStmt n, Void arg) {
190                 // The block that is the body of a constructor, method, instance initializer, or static initializer is
191                 // reachable
192                 if (statement.getParentNode().isPresent()) {
193                     if (statement.getParentNode().get() instanceof ConstructorDeclaration) {
194                         return true;
195                     }
196                     if (statement.getParentNode().get() instanceof MethodDeclaration) {
197                         return true;
198                     }
199                     if (statement.getParentNode().get() instanceof InitializerDeclaration) {
200                         return true;
201                     }
202                 }
203                 return isReachableBecauseOfPosition(statement);
204             }
205 
206             @Override
207             public Boolean visit(LocalClassDeclarationStmt n, Void arg) {
208                 return super.visit(n, arg);
209             }
210         };
211         return statement.accept(visitor, null);
212 
213         //
214         //
215         //
216         //        A switch statement can complete normally iff at least one of the following is
217         //true:
218         //– The switch block is empty or contains only switch labels.
219         //– The last statement in the switch block can complete normally.
220         //– There is at least one switch label after the last switch block statement group. – The switch block does not contain a default label.
221         //– There is a reachable break statement that exits the switch statement.
222         //        BLOCKS AND STATEMENTS Unreachable Statements 14.21
223         //
224         //A switch block is reachable iff its switch statement is reachable.
225         //
226         //        A statement in a switch block is reachable iff its switch statement is reachable
227         //and at least one of the following is true:
228         //– It bears a case or default label.
229         //– There is a statement preceding it in the switch block and that preceding statement can complete normally.
230         //
231         //A while statement can complete normally iff at least one of the following is true:
232         //– Thewhilestatementisreachableandtheconditionexpressionisnotaconstant
233         //expression (§15.28) with value true.
234         //– There is a reachable break statement that exits the while statement.
235         //        The contained statement is reachable iff the while statement is reachable and the condition expression is not a constant expression whose value is false.
236         //
237         //        A do statement can complete normally iff at least one of the following is true:
238         //– The contained statement can complete normally and the condition expression
239         //is not a constant expression (§15.28) with value true.
240         //– The do statement contains a reachable continue statement with no label, and the do statement is the innermost while, do, or for statement that contains that continue statement, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true.
241         //– The do statement contains a reachable continue statement with a label L, and the do statement has label L, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true.
242         //– There is a reachable break statement that exits the do statement.
243         //        The contained statement is reachable iff the do statement is reachable.
244         //
245         //        A basic for statement can complete normally iff at least one of the following
246         //is true:
247         //– The for statement is reachable, there is a condition expression, and the
248         //condition expression is not a constant expression (§15.28) with value true.
249         //– There is a reachable break statement that exits the for statement.
250         //        The contained statement is reachable iff the for statement is reachable and the condition expression is not a constant expression whose value is false.
251         //
252         //• An enhanced for statement can complete normally iff it is reachable.
253         //
254         //• A break, continue, return, or throw statement cannot complete normally.
255         //
256         //• A synchronized statement can complete normally iff the contained statement can complete normally.
257         //        The contained statement is reachable iff the synchronized statement is reachable.
258         //
259         //• A try statement can complete normally iff both of the following are true:
260         //– The try block can complete normally or any catch block can complete
261         //normally.
262         //– Ifthetrystatementhasafinallyblock,thenthefinallyblockcancomplete normally.
263         //
264         //• The try block is reachable iff the try statement is reachable.
265         //
266         //• A catch block C is reachable iff both of the following are true:
267         //– Either the type of C's parameter is an unchecked exception type or Exception or a superclass of Exception, or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the type of C's parameter. (An expression is reachable iff the innermost statement containing it is reachable.)
268         //See §15.6 for normal and abrupt completion of expressions.
269         //– There is no earlier catch block A in the try statement such that the type of C's
270         //parameter is the same as or a subclass of the type of A's parameter.
271         //• The Block of a catch block is reachable iff the catch block is reachable.
272         //• If a finally block is present, it is reachable iff the try statement is reachable.
273         //        One might expect the if statement to be handled in the following manner:
274         //• An if-then statement can complete normally iff at least one of the following is true:
275         //– The if-then statement is reachable and the condition expression is not a constant expression whose value is true.
276         //– The then-statement can complete normally.
277         //        The then-statement is reachable iff the if-then statement is reachable and the
278         //condition expression is not a constant expression whose value is false.
279         //• An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally.
280         //        BLOCKS AND STATEMENTS Unreachable Statements 14.21
281         //The then-statement is reachable iff the if-then-else statement is reachable and the condition expression is not a constant expression whose value is false.
282         //        The else-statement is reachable iff the if-then-else statement is reachable and the condition expression is not a constant expression whose value is true.
283         //        This approach would be consistent with the treatment of other control structures. However, in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules differ.
284 
285         // FIXME
286         //throw new UnsupportedOperationException();
287     }
288 
289 
290 }
291