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 |
// we compute and store the null status during analyseCode (https://bugs.eclipse.org/324178): |
37 |
private int nullStatus = FlowInfo.UNKNOWN; |
32 |
|
38 |
|
33 |
public ConditionalExpression( |
39 |
public ConditionalExpression( |
34 |
Expression condition, |
40 |
Expression condition, |
Lines 81-90
Link Here
|
81 |
FlowInfo mergedInfo; |
87 |
FlowInfo mergedInfo; |
82 |
if (isConditionOptimizedTrue){ |
88 |
if (isConditionOptimizedTrue){ |
83 |
mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo); |
89 |
mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo); |
|
|
90 |
this.nullStatus = this.valueIfTrue.nullStatus(trueFlowInfo); |
84 |
} else if (isConditionOptimizedFalse) { |
91 |
} else if (isConditionOptimizedFalse) { |
85 |
mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); |
92 |
mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); |
|
|
93 |
this.nullStatus = this.valueIfFalse.nullStatus(falseFlowInfo); |
86 |
} else { |
94 |
} else { |
87 |
// if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok |
95 |
// this block must meet two conflicting requirements (see https://bugs.eclipse.org/324178): |
|
|
96 |
// (1) For null analysis of "Object o2 = (o1 != null) ? o1 : new Object();" we need to distinguish |
97 |
// the paths *originating* from the evaluation of the condition to true/false respectively. |
98 |
// This is used to determine the possible null status of the entire conditional expression. |
99 |
// (2) For definite assignment analysis (JLS 16.1.5) of boolean conditional expressions of the form |
100 |
// "if (c1 ? expr1 : expr2) use(v);" we need to check whether any variable v will be definitely |
101 |
// assigned whenever the entire conditional expression evaluates to true (to reach the then branch). |
102 |
// I.e., we need to collect flowInfo *towards* the overall outcome true/false |
103 |
// (regardless of the evaluation of the condition). |
104 |
|
105 |
// to support (1) use the infos of both branches originating from the condition for computing the nullStatus: |
106 |
computeNullStatus(trueFlowInfo, 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_OR_DEAD); |
127 |
trueFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
102 |
} |
128 |
} |
103 |
if (isValueIfFalseOptimizedFalse) { |
129 |
if (isValueIfFalseOptimizedFalse) { |
104 |
falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
130 |
falseFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
105 |
} |
131 |
} |
106 |
if (isValueIfTrueOptimizedTrue) { |
132 |
if (isValueIfTrueOptimizedTrue) { |
107 |
trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
133 |
trueFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
108 |
} |
134 |
} |
109 |
if (isValueIfFalseOptimizedTrue) { |
135 |
if (isValueIfFalseOptimizedTrue) { |
110 |
falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
136 |
falseFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); |
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 120-125
Link Here
|
120 |
return mergedInfo; |
146 |
return mergedInfo; |
121 |
} |
147 |
} |
122 |
|
148 |
|
|
|
149 |
private void computeNullStatus(FlowInfo trueBranchInfo, FlowInfo falseBranchInfo) { |
150 |
// given that the condition cannot be optimized to a constant |
151 |
// we now merge the nullStatus from both branches: |
152 |
int ifTrueNullStatus = this.valueIfTrue.nullStatus(trueBranchInfo); |
153 |
int ifFalseNullStatus = this.valueIfFalse.nullStatus(falseBranchInfo); |
154 |
|
155 |
if (ifTrueNullStatus == ifFalseNullStatus) { |
156 |
this.nullStatus = ifTrueNullStatus; |
157 |
return; |
158 |
} |
159 |
// is there a chance of null (or non-null)? -> potentially null etc. |
160 |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125 |
161 |
int status = 0; |
162 |
int combinedStatus = ifTrueNullStatus|ifFalseNullStatus; |
163 |
if ((combinedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL)) != 0) |
164 |
status |= FlowInfo.POTENTIALLY_NULL; |
165 |
if ((combinedStatus & (FlowInfo.NON_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) |
166 |
status |= FlowInfo.POTENTIALLY_NON_NULL; |
167 |
if ((combinedStatus & (FlowInfo.UNKNOWN|FlowInfo.POTENTIALLY_UNKNOWN)) != 0) |
168 |
status |= FlowInfo.POTENTIALLY_UNKNOWN; |
169 |
if (status > 0) |
170 |
this.nullStatus = status; |
171 |
} |
172 |
|
123 |
/** |
173 |
/** |
124 |
* Code generation for the conditional operator ?: |
174 |
* Code generation for the conditional operator ?: |
125 |
* |
175 |
* |
Lines 306-338
Link Here
|
306 |
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position); |
356 |
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position); |
307 |
} |
357 |
} |
308 |
|
358 |
|
309 |
public int nullStatus(FlowInfo flowInfo) { |
359 |
public int nullStatus(FlowInfo flowInfo) { |
310 |
Constant cst = this.condition.optimizedBooleanConstant(); |
360 |
return this.nullStatus; |
311 |
if (cst != Constant.NotAConstant) { |
|
|
312 |
if (cst.booleanValue()) { |
313 |
return this.valueIfTrue.nullStatus(flowInfo); |
314 |
} |
315 |
return this.valueIfFalse.nullStatus(flowInfo); |
316 |
} |
361 |
} |
317 |
int ifTrueNullStatus = this.valueIfTrue.nullStatus(flowInfo), |
|
|
318 |
ifFalseNullStatus = this.valueIfFalse.nullStatus(flowInfo); |
319 |
if (ifTrueNullStatus == ifFalseNullStatus) { |
320 |
return ifTrueNullStatus; |
321 |
} |
322 |
// is there a chance of null (or non-null)? -> potentially null etc. |
323 |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125 |
324 |
int status = 0; |
325 |
int combinedStatus = ifTrueNullStatus|ifFalseNullStatus; |
326 |
if ((combinedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL)) != 0) |
327 |
status |= FlowInfo.POTENTIALLY_NULL; |
328 |
if ((combinedStatus & (FlowInfo.NON_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) |
329 |
status |= FlowInfo.POTENTIALLY_NON_NULL; |
330 |
if ((combinedStatus & (FlowInfo.UNKNOWN|FlowInfo.POTENTIALLY_UNKNOWN)) != 0) |
331 |
status |= FlowInfo.POTENTIALLY_UNKNOWN; |
332 |
if (status > 0) |
333 |
return status; |
334 |
return FlowInfo.UNKNOWN; |
335 |
} |
336 |
|
362 |
|
337 |
public Constant optimizedBooleanConstant() { |
363 |
public Constant optimizedBooleanConstant() { |
338 |
|
364 |
|