Lines 7-13
Link Here
|
7 |
* |
7 |
* |
8 |
* Contributors: |
8 |
* Contributors: |
9 |
* IBM Corporation - initial API and implementation |
9 |
* IBM Corporation - initial API and implementation |
10 |
* Stephen Herrmann <stephan@cs.tu-berlin.de> - Contributions for bugs 133125, 292478 |
10 |
* Stephen Herrmann <stephan@cs.tu-berlin.de> - Contributions for |
|
|
11 |
* bug 133125 - [compiler][null] need to report the null status of expressions and analyze them simultaneously |
12 |
* bug 292478 - Report potentially null across variable assignment |
13 |
* bug 324178 - [null] ConditionalExpression.nullStatus(..) doesn't take into account the analysis of condition itself |
11 |
*******************************************************************************/ |
14 |
*******************************************************************************/ |
12 |
package org.eclipse.jdt.internal.compiler.ast; |
15 |
package org.eclipse.jdt.internal.compiler.ast; |
13 |
|
16 |
|
Lines 29-34
Link Here
|
29 |
int trueInitStateIndex = -1; |
32 |
int trueInitStateIndex = -1; |
30 |
int falseInitStateIndex = -1; |
33 |
int falseInitStateIndex = -1; |
31 |
int mergedInitStateIndex = -1; |
34 |
int mergedInitStateIndex = -1; |
|
|
35 |
|
36 |
// remember flow infos of true/false branches for nullStatus (see comment in analyseCode): |
37 |
private FlowInfo trueBranchInfo; |
38 |
private FlowInfo falseBranchInfo; |
32 |
|
39 |
|
33 |
public ConditionalExpression( |
40 |
public ConditionalExpression( |
34 |
Expression condition, |
41 |
Expression condition, |
Lines 84-90
Link Here
|
84 |
} else if (isConditionOptimizedFalse) { |
91 |
} else if (isConditionOptimizedFalse) { |
85 |
mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); |
92 |
mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); |
86 |
} else { |
93 |
} else { |
87 |
// if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok |
94 |
// this block must meet two conflicting requirements (see https://bugs.eclipse.org/324178): |
|
|
95 |
// (1) For null analysis of "Object o2 = (o1 != null) ? o1 : new Object();" we need to distinguish |
96 |
// the paths *originating* from the evaluation of the condition to true/false respectively. |
97 |
// This is used to determine the possible null status of the entire conditional expression. |
98 |
// (2) For definite assignment analysis (JLS 16.1.5) of boolean conditional expressions of the form |
99 |
// "if (c1 ? expr1 : expr2) use(v);" we need to check whether any variable v will be definitely |
100 |
// assigned whenever the entire conditional expression evaluates to true (to reach the then branch). |
101 |
// I.e., we need to collect flowInfo *towards* the overall outcome true/false |
102 |
// (regardless of the evaluation of the condition). |
103 |
|
104 |
// to support (1) save the branches originating from the condition (for use by nullStatus): |
105 |
this.trueBranchInfo = trueFlowInfo; |
106 |
this.falseBranchInfo = falseFlowInfo; |
107 |
|
108 |
// to support (2) we split the true/false branches according to their inner structure. Consider this: |
109 |
// if (b ? false : (true && (v = false))) return v; -- ok |
110 |
// - expr1 ("false") has no path towards true (mark as unreachable) |
111 |
// - expr2 ("(true && (v = false))") has a branch towards true on which v is assigned. |
112 |
// -> merging these two branches yields: v is assigned |
113 |
// - the paths towards false are irrelevant since the enclosing if has no else. |
88 |
cst = this.optimizedIfTrueConstant; |
114 |
cst = this.optimizedIfTrueConstant; |
89 |
boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; |
115 |
boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; |
90 |
boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; |
116 |
boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; |
Lines 93-118
Link Here
|
93 |
boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; |
119 |
boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; |
94 |
boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; |
120 |
boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; |
95 |
|
121 |
|
96 |
UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy(); |
122 |
UnconditionalFlowInfo trueFlowTowardsTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy(); |
97 |
UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy(); |
123 |
UnconditionalFlowInfo falseFlowTowardsTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy(); |
98 |
UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().unconditionalInits(); |
124 |
UnconditionalFlowInfo trueFlowTowardsFalse = trueFlowInfo.initsWhenFalse().unconditionalInits(); |
99 |
UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().unconditionalInits(); |
125 |
UnconditionalFlowInfo falseFlowTowardsFalse = falseFlowInfo.initsWhenFalse().unconditionalInits(); |
100 |
if (isValueIfTrueOptimizedFalse) { |
126 |
if (isValueIfTrueOptimizedFalse) { |
101 |
trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); |
127 |
trueFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE); |
102 |
} |
128 |
} |
103 |
if (isValueIfFalseOptimizedFalse) { |
129 |
if (isValueIfFalseOptimizedFalse) { |
104 |
falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); |
130 |
falseFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE); |
105 |
} |
131 |
} |
106 |
if (isValueIfTrueOptimizedTrue) { |
132 |
if (isValueIfTrueOptimizedTrue) { |
107 |
trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); |
133 |
trueFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE); |
108 |
} |
134 |
} |
109 |
if (isValueIfFalseOptimizedTrue) { |
135 |
if (isValueIfFalseOptimizedTrue) { |
110 |
falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); |
136 |
falseFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE); |
111 |
} |
137 |
} |
112 |
mergedInfo = |
138 |
mergedInfo = |
113 |
FlowInfo.conditional( |
139 |
FlowInfo.conditional( |
114 |
trueInfoWhenTrue.mergedWith(falseInfoWhenTrue), |
140 |
trueFlowTowardsTrue.mergedWith(falseFlowTowardsTrue), |
115 |
trueInfoWhenFalse.mergedWith(falseInfoWhenFalse)); |
141 |
trueFlowTowardsFalse.mergedWith(falseFlowTowardsFalse)); |
116 |
} |
142 |
} |
117 |
this.mergedInitStateIndex = |
143 |
this.mergedInitStateIndex = |
118 |
currentScope.methodScope().recordInitializationStates(mergedInfo); |
144 |
currentScope.methodScope().recordInitializationStates(mergedInfo); |
Lines 314-321
Link Here
|
314 |
} |
340 |
} |
315 |
return this.valueIfFalse.nullStatus(flowInfo); |
341 |
return this.valueIfFalse.nullStatus(flowInfo); |
316 |
} |
342 |
} |
317 |
int ifTrueNullStatus = this.valueIfTrue.nullStatus(flowInfo), |
343 |
int ifTrueNullStatus = |
318 |
ifFalseNullStatus = this.valueIfFalse.nullStatus(flowInfo); |
344 |
this.valueIfTrue.nullStatus(this.trueBranchInfo != null ? this.trueBranchInfo : flowInfo.initsWhenTrue()); |
|
|
345 |
int ifFalseNullStatus = |
346 |
this.valueIfFalse.nullStatus(this.falseBranchInfo != null ? this.falseBranchInfo : flowInfo.initsWhenFalse()); |
347 |
|
319 |
if (ifTrueNullStatus == ifFalseNullStatus) { |
348 |
if (ifTrueNullStatus == ifFalseNullStatus) { |
320 |
return ifTrueNullStatus; |
349 |
return ifTrueNullStatus; |
321 |
} |
350 |
} |