Lines 19-31
Link Here
|
19 |
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; |
19 |
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; |
20 |
|
20 |
|
21 |
public class SingleNameReference extends NameReference implements OperatorIds { |
21 |
public class SingleNameReference extends NameReference implements OperatorIds { |
22 |
|
22 |
|
23 |
public static final int READ = 0; |
23 |
public static final int READ = 0; |
24 |
public static final int WRITE = 1; |
24 |
public static final int WRITE = 1; |
25 |
public char[] token; |
25 |
public char[] token; |
26 |
public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor |
26 |
public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor |
27 |
public TypeBinding genericCast; |
27 |
public TypeBinding genericCast; |
28 |
|
28 |
|
29 |
public SingleNameReference(char[] source, long pos) { |
29 |
public SingleNameReference(char[] source, long pos) { |
30 |
super(); |
30 |
super(); |
31 |
token = source; |
31 |
token = source; |
Lines 33-46
Link Here
|
33 |
sourceEnd = (int) pos; |
33 |
sourceEnd = (int) pos; |
34 |
} |
34 |
} |
35 |
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { |
35 |
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { |
36 |
|
36 |
|
37 |
boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0; |
37 |
boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0; |
38 |
// compound assignment extra work |
38 |
// compound assignment extra work |
39 |
if (isCompound) { // check the variable part is initialized if blank final |
39 |
if (isCompound) { // check the variable part is initialized if blank final |
40 |
switch (bits & RestrictiveFlagMASK) { |
40 |
switch (bits & RestrictiveFlagMASK) { |
41 |
case Binding.FIELD : // reading a field |
41 |
case Binding.FIELD : // reading a field |
42 |
FieldBinding fieldBinding; |
42 |
FieldBinding fieldBinding; |
43 |
if ((fieldBinding = (FieldBinding) binding).isBlankFinal() |
43 |
if ((fieldBinding = (FieldBinding) binding).isBlankFinal() |
44 |
&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { |
44 |
&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { |
45 |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { |
45 |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { |
46 |
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); |
46 |
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); |
Lines 68-74
Link Here
|
68 |
switch (bits & RestrictiveFlagMASK) { |
68 |
switch (bits & RestrictiveFlagMASK) { |
69 |
case Binding.FIELD : // assigning to a field |
69 |
case Binding.FIELD : // assigning to a field |
70 |
manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); |
70 |
manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); |
71 |
|
71 |
|
72 |
FieldBinding fieldBinding = (FieldBinding) binding; |
72 |
FieldBinding fieldBinding = (FieldBinding) binding; |
73 |
ReferenceBinding declaringClass = fieldBinding.declaringClass; |
73 |
ReferenceBinding declaringClass = fieldBinding.declaringClass; |
74 |
// check if accessing enum static field in initializer |
74 |
// check if accessing enum static field in initializer |
Lines 82-88
Link Here
|
82 |
&& methodScope.isInsideInitializerOrConstructor()) { |
82 |
&& methodScope.isInsideInitializerOrConstructor()) { |
83 |
currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); |
83 |
currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); |
84 |
} |
84 |
} |
85 |
} |
85 |
} |
86 |
// check if assigning a final field |
86 |
// check if assigning a final field |
87 |
if (fieldBinding.isFinal()) { |
87 |
if (fieldBinding.isFinal()) { |
88 |
// inside a context where allowed |
88 |
// inside a context where allowed |
Lines 90-96
Link Here
|
90 |
if (flowInfo.isPotentiallyAssigned(fieldBinding)) { |
90 |
if (flowInfo.isPotentiallyAssigned(fieldBinding)) { |
91 |
currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); |
91 |
currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); |
92 |
} else { |
92 |
} else { |
93 |
flowContext.recordSettingFinal(fieldBinding, this, flowInfo); |
93 |
flowContext.recordSettingFinal(fieldBinding, this, flowInfo); |
94 |
} |
94 |
} |
95 |
flowInfo.markAsDefinitelyAssigned(fieldBinding); |
95 |
flowInfo.markAsDefinitelyAssigned(fieldBinding); |
96 |
} else { |
96 |
} else { |
Lines 98-104
Link Here
|
98 |
} |
98 |
} |
99 |
} |
99 |
} |
100 |
break; |
100 |
break; |
101 |
case Binding.LOCAL : // assigning to a local variable |
101 |
case Binding.LOCAL : // assigning to a local variable |
102 |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; |
102 |
LocalVariableBinding localBinding = (LocalVariableBinding) binding; |
103 |
if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes |
103 |
if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes |
104 |
bits |= FirstAssignmentToLocal; |
104 |
bits |= FirstAssignmentToLocal; |
Lines 113-119
Link Here
|
113 |
} else if (flowInfo.isPotentiallyAssigned(localBinding)) { |
113 |
} else if (flowInfo.isPotentiallyAssigned(localBinding)) { |
114 |
currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); |
114 |
currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); |
115 |
} else { |
115 |
} else { |
116 |
flowContext.recordSettingFinal(localBinding, this, flowInfo); |
116 |
flowContext.recordSettingFinal(localBinding, this, flowInfo); |
117 |
} |
117 |
} |
118 |
} else { |
118 |
} else { |
119 |
currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); |
119 |
currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); |
Lines 131-137
Link Here
|
131 |
return analyseCode(currentScope, flowContext, flowInfo, true); |
131 |
return analyseCode(currentScope, flowContext, flowInfo, true); |
132 |
} |
132 |
} |
133 |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { |
133 |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { |
134 |
|
134 |
|
135 |
switch (bits & RestrictiveFlagMASK) { |
135 |
switch (bits & RestrictiveFlagMASK) { |
136 |
case Binding.FIELD : // reading a field |
136 |
case Binding.FIELD : // reading a field |
137 |
if (valueRequired) { |
137 |
if (valueRequired) { |
Lines 150-156
Link Here
|
150 |
&& methodScope.isInsideInitializerOrConstructor()) { |
150 |
&& methodScope.isInsideInitializerOrConstructor()) { |
151 |
currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); |
151 |
currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); |
152 |
} |
152 |
} |
153 |
} |
153 |
} |
154 |
// check if reading a final blank field |
154 |
// check if reading a final blank field |
155 |
if (fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { |
155 |
if (fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { |
156 |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { |
156 |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { |
Lines 174-184
Link Here
|
174 |
} |
174 |
} |
175 |
return flowInfo; |
175 |
return flowInfo; |
176 |
} |
176 |
} |
177 |
|
177 |
|
178 |
public TypeBinding checkFieldAccess(BlockScope scope) { |
178 |
public TypeBinding checkFieldAccess(BlockScope scope) { |
179 |
|
179 |
|
180 |
FieldBinding fieldBinding = (FieldBinding) binding; |
180 |
FieldBinding fieldBinding = (FieldBinding) binding; |
181 |
|
181 |
|
182 |
bits &= ~RestrictiveFlagMASK; // clear bits |
182 |
bits &= ~RestrictiveFlagMASK; // clear bits |
183 |
bits |= Binding.FIELD; |
183 |
bits |= Binding.FIELD; |
184 |
MethodScope methodScope = scope.methodScope(); |
184 |
MethodScope methodScope = scope.methodScope(); |
Lines 192-201
Link Here
|
192 |
} |
192 |
} |
193 |
} |
193 |
} |
194 |
this.constant = fieldBinding.constant(); |
194 |
this.constant = fieldBinding.constant(); |
195 |
|
195 |
|
196 |
if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) !=0)) |
196 |
if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) !=0)) |
197 |
scope.problemReporter().deprecatedField(fieldBinding, this); |
197 |
scope.problemReporter().deprecatedField(fieldBinding, this); |
198 |
|
198 |
|
199 |
if ((this.bits & IsStrictlyAssigned) == 0 |
199 |
if ((this.bits & IsStrictlyAssigned) == 0 |
200 |
&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass |
200 |
&& methodScope.enclosingSourceType() == fieldBinding.original().declaringClass |
201 |
&& methodScope.lastVisibleFieldID >= 0 |
201 |
&& methodScope.lastVisibleFieldID >= 0 |
Lines 205-240
Link Here
|
205 |
this.bits |= ASTNode.IgnoreNoEffectAssignCheck; |
205 |
this.bits |= ASTNode.IgnoreNoEffectAssignCheck; |
206 |
} |
206 |
} |
207 |
return fieldBinding.type; |
207 |
return fieldBinding.type; |
208 |
|
208 |
|
209 |
} |
209 |
} |
210 |
|
210 |
|
211 |
/** |
211 |
/** |
212 |
* @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) |
212 |
* @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) |
213 |
*/ |
213 |
*/ |
214 |
public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { |
214 |
public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { |
215 |
if (runtimeTimeType == null || compileTimeType == null) |
215 |
if (runtimeTimeType == null || compileTimeType == null) |
216 |
return; |
216 |
return; |
217 |
if ((bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) { |
217 |
if ((bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) { |
218 |
// set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) |
218 |
// set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) |
219 |
FieldBinding field = (FieldBinding) this.binding; |
219 |
FieldBinding field = (FieldBinding) this.binding; |
220 |
FieldBinding originalBinding = field.original(); |
220 |
FieldBinding originalBinding = field.original(); |
221 |
TypeBinding originalType = originalBinding.type; |
221 |
TypeBinding originalType = originalBinding.type; |
222 |
// extra cast needed if method return type is type variable |
222 |
// extra cast needed if method return type is type variable |
223 |
if (originalBinding != field |
223 |
if (originalBinding != field |
224 |
&& originalType != field.type |
224 |
&& originalType != field.type |
225 |
&& runtimeTimeType.id != T_JavaLangObject |
225 |
&& runtimeTimeType.id != T_JavaLangObject |
226 |
&& (originalType.tagBits & TagBits.HasTypeVariable) != 0) { |
226 |
&& (originalType.tagBits & TagBits.HasTypeVariable) != 0) { |
227 |
TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) |
227 |
TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) |
228 |
? compileTimeType // unboxing: checkcast before conversion |
228 |
? compileTimeType // unboxing: checkcast before conversion |
229 |
: runtimeTimeType; |
229 |
: runtimeTimeType; |
230 |
this.genericCast = originalType.genericCast(scope.boxing(targetType)); |
230 |
this.genericCast = originalType.genericCast(scope.boxing(targetType)); |
231 |
} |
231 |
} |
232 |
} |
232 |
} |
233 |
super.computeConversion(scope, runtimeTimeType, compileTimeType); |
233 |
super.computeConversion(scope, runtimeTimeType, compileTimeType); |
234 |
} |
234 |
} |
235 |
|
235 |
|
236 |
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { |
236 |
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { |
237 |
|
237 |
|
238 |
// optimizing assignment like: i = i + 1 or i = 1 + i |
238 |
// optimizing assignment like: i = i + 1 or i = 1 + i |
239 |
if (assignment.expression.isCompactableOperation()) { |
239 |
if (assignment.expression.isCompactableOperation()) { |
240 |
BinaryExpression operation = (BinaryExpression) assignment.expression; |
240 |
BinaryExpression operation = (BinaryExpression) assignment.expression; |
Lines 245-253
Link Here
|
245 |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, operator, operation.implicitConversion, valueRequired); |
245 |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, operator, operation.implicitConversion, valueRequired); |
246 |
if (valueRequired) { |
246 |
if (valueRequired) { |
247 |
codeStream.generateImplicitConversion(assignment.implicitConversion); |
247 |
codeStream.generateImplicitConversion(assignment.implicitConversion); |
248 |
} |
248 |
} |
249 |
return; |
249 |
return; |
250 |
} |
250 |
} |
251 |
if ((operation.right instanceof SingleNameReference) |
251 |
if ((operation.right instanceof SingleNameReference) |
252 |
&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations |
252 |
&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations |
253 |
&& ((variableReference = (SingleNameReference) operation.right).binding == binding) |
253 |
&& ((variableReference = (SingleNameReference) operation.right).binding == binding) |
Lines 258-264
Link Here
|
258 |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.implicitConversion, valueRequired); |
258 |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.implicitConversion, valueRequired); |
259 |
if (valueRequired) { |
259 |
if (valueRequired) { |
260 |
codeStream.generateImplicitConversion(assignment.implicitConversion); |
260 |
codeStream.generateImplicitConversion(assignment.implicitConversion); |
261 |
} |
261 |
} |
262 |
return; |
262 |
return; |
263 |
} |
263 |
} |
264 |
} |
264 |
} |
Lines 309-322
Link Here
|
309 |
} |
309 |
} |
310 |
return; |
310 |
return; |
311 |
} |
311 |
} |
312 |
// 26903, need extra cast to store null in array local var |
312 |
// 26903, need extra cast to store null in array local var |
313 |
if (localBinding.type.isArrayType() |
313 |
if (localBinding.type.isArrayType() |
314 |
&& (assignment.expression.resolvedType == TypeBinding.NULL // arrayLoc = null |
314 |
&& (assignment.expression.resolvedType == TypeBinding.NULL // arrayLoc = null |
315 |
|| ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null |
315 |
|| ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null |
316 |
&& (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == TypeBinding.NULL)))){ |
316 |
&& (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == TypeBinding.NULL)))){ |
317 |
codeStream.checkcast(localBinding.type); |
317 |
codeStream.checkcast(localBinding.type); |
318 |
} |
318 |
} |
319 |
|
319 |
|
320 |
// normal local assignment (since cannot store in outer local which are final locations) |
320 |
// normal local assignment (since cannot store in outer local which are final locations) |
321 |
codeStream.store(localBinding, valueRequired); |
321 |
codeStream.store(localBinding, valueRequired); |
322 |
if ((bits & FirstAssignmentToLocal) != 0) { // for local variable debug attributes |
322 |
if ((bits & FirstAssignmentToLocal) != 0) { // for local variable debug attributes |
Lines 354-367
Link Here
|
354 |
break; |
354 |
break; |
355 |
} |
355 |
} |
356 |
} |
356 |
} |
357 |
// managing private access |
357 |
// managing private access |
358 |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { |
358 |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { |
359 |
codeStream.getstatic(fieldBinding); |
359 |
codeStream.getstatic(fieldBinding); |
360 |
} else { |
360 |
} else { |
361 |
codeStream.invokestatic(syntheticAccessors[READ]); |
361 |
codeStream.invokestatic(syntheticAccessors[READ]); |
362 |
} |
362 |
} |
|
|
363 |
// required cast must occur even if no value is required |
364 |
if (this.genericCast != null) codeStream.checkcast(this.genericCast); |
363 |
if (valueRequired) { |
365 |
if (valueRequired) { |
364 |
if (this.genericCast != null) codeStream.checkcast(this.genericCast); |
|
|
365 |
codeStream.generateImplicitConversion(implicitConversion); |
366 |
codeStream.generateImplicitConversion(implicitConversion); |
366 |
} else { |
367 |
} else { |
367 |
if ((implicitConversion & TypeIds.UNBOXING) != 0) { |
368 |
if ((implicitConversion & TypeIds.UNBOXING) != 0) { |
Lines 376-384
Link Here
|
376 |
default : |
377 |
default : |
377 |
codeStream.pop(); |
378 |
codeStream.pop(); |
378 |
} |
379 |
} |
379 |
} |
380 |
} |
380 |
} else { |
381 |
} else { |
381 |
if (!valueRequired && ((implicitConversion & TypeIds.UNBOXING) == 0)) { |
382 |
if (!valueRequired |
|
|
383 |
&& ((implicitConversion & TypeIds.UNBOXING) == 0) |
384 |
&& this.genericCast == null) { // required cast must occur even if no value is required |
382 |
// if no valueRequired, optimize out entire gen |
385 |
// if no valueRequired, optimize out entire gen |
383 |
break; |
386 |
break; |
384 |
} |
387 |
} |
Lines 390-404
Link Here
|
390 |
} else { |
393 |
} else { |
391 |
generateReceiver(codeStream); |
394 |
generateReceiver(codeStream); |
392 |
} |
395 |
} |
393 |
// managing private access |
396 |
// managing private access |
394 |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { |
397 |
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { |
395 |
codeStream.getfield(fieldBinding); |
398 |
codeStream.getfield(fieldBinding); |
396 |
} else { |
399 |
} else { |
397 |
codeStream.invokestatic(syntheticAccessors[READ]); |
400 |
codeStream.invokestatic(syntheticAccessors[READ]); |
398 |
} |
401 |
} |
399 |
// managing generic cast |
402 |
// managing generic cast |
400 |
if (this.genericCast != null) codeStream.checkcast(this.genericCast); |
403 |
if (this.genericCast != null) codeStream.checkcast(this.genericCast); |
401 |
codeStream.generateImplicitConversion(implicitConversion); |
404 |
codeStream.generateImplicitConversion(implicitConversion); |
|
|
405 |
if (!valueRequired) { |
406 |
switch (fieldBinding.type.id) { |
407 |
case T_long : |
408 |
case T_double : |
409 |
codeStream.pop2(); |
410 |
break; |
411 |
default : |
412 |
codeStream.pop(); |
413 |
} |
414 |
} |
402 |
} |
415 |
} |
403 |
break; |
416 |
break; |
404 |
case Binding.LOCAL : // reading a local |
417 |
case Binding.LOCAL : // reading a local |
Lines 415-421
Link Here
|
415 |
} |
428 |
} |
416 |
codeStream.generateImplicitConversion(implicitConversion); |
429 |
codeStream.generateImplicitConversion(implicitConversion); |
417 |
} else if ((implicitConversion & TypeIds.UNBOXING) != 0) { |
430 |
} else if ((implicitConversion & TypeIds.UNBOXING) != 0) { |
418 |
|
|
|
419 |
// outer local? |
431 |
// outer local? |
420 |
if ((bits & DepthMASK) != 0) { |
432 |
if ((bits & DepthMASK) != 0) { |
421 |
// outer local can be reached either through a synthetic arg or a synthetic field |
433 |
// outer local can be reached either through a synthetic arg or a synthetic field |
Lines 426-435
Link Here
|
426 |
codeStream.load(localBinding); |
438 |
codeStream.load(localBinding); |
427 |
} |
439 |
} |
428 |
codeStream.generateImplicitConversion(implicitConversion); |
440 |
codeStream.generateImplicitConversion(implicitConversion); |
429 |
if ((localBinding.type == TypeBinding.LONG) || (localBinding.type == TypeBinding.DOUBLE)) { |
441 |
switch (localBinding.type.id) { |
430 |
codeStream.pop2(); |
442 |
case T_long : |
431 |
} else { |
443 |
case T_double : |
432 |
codeStream.pop(); |
444 |
codeStream.pop2(); |
|
|
445 |
break; |
446 |
default : |
447 |
codeStream.pop(); |
433 |
} |
448 |
} |
434 |
} |
449 |
} |
435 |
} |
450 |
} |
Lines 443-456
Link Here
|
443 |
* are optimized in one access: e.g "a = a + 1" optimized into "a++". |
458 |
* are optimized in one access: e.g "a = a + 1" optimized into "a++". |
444 |
*/ |
459 |
*/ |
445 |
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { |
460 |
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { |
446 |
|
461 |
|
447 |
this.generateCompoundAssignment( |
462 |
this.generateCompoundAssignment( |
448 |
currentScope, |
463 |
currentScope, |
449 |
codeStream, |
464 |
codeStream, |
450 |
syntheticAccessors == null ? null : syntheticAccessors[WRITE], |
465 |
syntheticAccessors == null ? null : syntheticAccessors[WRITE], |
451 |
expression, |
466 |
expression, |
452 |
operator, |
467 |
operator, |
453 |
assignmentImplicitConversion, |
468 |
assignmentImplicitConversion, |
454 |
valueRequired); |
469 |
valueRequired); |
455 |
} |
470 |
} |
456 |
/* |
471 |
/* |
Lines 497-503
Link Here
|
497 |
codeStream.store(localBinding, false); |
512 |
codeStream.store(localBinding, false); |
498 |
return; |
513 |
return; |
499 |
case T_int : |
514 |
case T_int : |
500 |
if (((assignConstant = expression.constant) != Constant.NotAConstant) |
515 |
if (((assignConstant = expression.constant) != Constant.NotAConstant) |
501 |
&& (assignConstant.typeID() != T_float) // only for integral types |
516 |
&& (assignConstant.typeID() != T_float) // only for integral types |
502 |
&& (assignConstant.typeID() != T_double) |
517 |
&& (assignConstant.typeID() != T_double) |
503 |
&& ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value |
518 |
&& ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value |
Lines 526-536
Link Here
|
526 |
case T_JavaLangString : |
541 |
case T_JavaLangString : |
527 |
case T_JavaLangObject : |
542 |
case T_JavaLangObject : |
528 |
case T_undefined : |
543 |
case T_undefined : |
529 |
// we enter here if the single name reference is a field of type java.lang.String or if the type of the |
544 |
// we enter here if the single name reference is a field of type java.lang.String or if the type of the |
530 |
// operation is java.lang.Object |
545 |
// operation is java.lang.Object |
531 |
// For example: o = o + ""; // where the compiled type of o is java.lang.Object. |
546 |
// For example: o = o + ""; // where the compiled type of o is java.lang.Object. |
532 |
codeStream.generateStringConcatenationAppend(currentScope, null, expression); |
547 |
codeStream.generateStringConcatenationAppend(currentScope, null, expression); |
533 |
// no need for generic cast on previous #getfield since using Object string buffer methods. |
548 |
// no need for generic cast on previous #getfield since using Object string buffer methods. |
534 |
break; |
549 |
break; |
535 |
default : |
550 |
default : |
536 |
// promote the array reference to the suitable operation type |
551 |
// promote the array reference to the suitable operation type |
Lines 539-548
Link Here
|
539 |
codeStream.generateImplicitConversion(this.implicitConversion); |
554 |
codeStream.generateImplicitConversion(this.implicitConversion); |
540 |
// generate the increment value (will by itself be promoted to the operation value) |
555 |
// generate the increment value (will by itself be promoted to the operation value) |
541 |
if (expression == IntLiteral.One){ // prefix operation |
556 |
if (expression == IntLiteral.One){ // prefix operation |
542 |
codeStream.generateConstant(expression.constant, this.implicitConversion); |
557 |
codeStream.generateConstant(expression.constant, this.implicitConversion); |
543 |
} else { |
558 |
} else { |
544 |
expression.generateCode(currentScope, codeStream, true); |
559 |
expression.generateCode(currentScope, codeStream, true); |
545 |
} |
560 |
} |
546 |
// perform the operation |
561 |
// perform the operation |
547 |
codeStream.sendOperator(operator, operationTypeID); |
562 |
codeStream.sendOperator(operator, operationTypeID); |
548 |
// cast the value back to the array reference type |
563 |
// cast the value back to the array reference type |
Lines 566-572
Link Here
|
566 |
codeStream.store(localBinding, false); |
581 |
codeStream.store(localBinding, false); |
567 |
} |
582 |
} |
568 |
} |
583 |
} |
569 |
|
584 |
|
570 |
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { |
585 |
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { |
571 |
switch (bits & RestrictiveFlagMASK) { |
586 |
switch (bits & RestrictiveFlagMASK) { |
572 |
case Binding.FIELD : // assigning to a field |
587 |
case Binding.FIELD : // assigning to a field |
Lines 607-620
Link Here
|
607 |
} |
622 |
} |
608 |
} |
623 |
} |
609 |
} |
624 |
} |
610 |
if (this.genericCast != null) |
625 |
if (this.genericCast != null) |
611 |
codeStream.checkcast(this.genericCast); |
626 |
codeStream.checkcast(this.genericCast); |
612 |
codeStream.generateImplicitConversion(this.implicitConversion); |
627 |
codeStream.generateImplicitConversion(this.implicitConversion); |
613 |
codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); |
628 |
codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); |
614 |
codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); |
629 |
codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); |
615 |
codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); |
630 |
codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); |
616 |
fieldStore(codeStream, fieldBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], false); |
631 |
fieldStore(codeStream, fieldBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], false); |
617 |
// no need for generic cast |
632 |
// no need for generic cast |
618 |
return; |
633 |
return; |
619 |
case Binding.LOCAL : // assigning to a local variable |
634 |
case Binding.LOCAL : // assigning to a local variable |
620 |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; |
635 |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; |
Lines 641-656
Link Here
|
641 |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); |
656 |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); |
642 |
codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); |
657 |
codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); |
643 |
codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); |
658 |
codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); |
644 |
|
659 |
|
645 |
codeStream.store(localBinding, false); |
660 |
codeStream.store(localBinding, false); |
646 |
} |
661 |
} |
647 |
} |
662 |
} |
648 |
} |
663 |
} |
649 |
|
664 |
|
650 |
public void generateReceiver(CodeStream codeStream) { |
665 |
public void generateReceiver(CodeStream codeStream) { |
651 |
codeStream.aload_0(); |
666 |
codeStream.aload_0(); |
652 |
} |
667 |
} |
653 |
|
668 |
|
654 |
/** |
669 |
/** |
655 |
* @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() |
670 |
* @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() |
656 |
*/ |
671 |
*/ |
Lines 671-696
Link Here
|
671 |
} |
686 |
} |
672 |
return null; |
687 |
return null; |
673 |
} |
688 |
} |
674 |
|
689 |
|
675 |
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { |
690 |
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { |
676 |
|
691 |
|
677 |
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { |
692 |
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { |
678 |
//If inlinable field, forget the access emulation, the code gen will directly target it |
693 |
//If inlinable field, forget the access emulation, the code gen will directly target it |
679 |
if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) return; |
694 |
if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) return; |
680 |
|
695 |
|
681 |
if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) { |
696 |
if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) { |
682 |
currentScope.emulateOuterAccess((LocalVariableBinding) binding); |
697 |
currentScope.emulateOuterAccess((LocalVariableBinding) binding); |
683 |
} |
698 |
} |
684 |
} |
699 |
} |
685 |
} |
700 |
} |
686 |
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { |
701 |
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { |
687 |
|
702 |
|
688 |
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; |
703 |
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; |
689 |
|
704 |
|
690 |
//If inlinable field, forget the access emulation, the code gen will directly target it |
705 |
//If inlinable field, forget the access emulation, the code gen will directly target it |
691 |
if (constant != Constant.NotAConstant) |
706 |
if (constant != Constant.NotAConstant) |
692 |
return; |
707 |
return; |
693 |
|
708 |
|
694 |
if ((bits & Binding.FIELD) != 0) { |
709 |
if ((bits & Binding.FIELD) != 0) { |
695 |
FieldBinding fieldBinding = (FieldBinding) binding; |
710 |
FieldBinding fieldBinding = (FieldBinding) binding; |
696 |
FieldBinding codegenField = fieldBinding.original(); |
711 |
FieldBinding codegenField = fieldBinding.original(); |
Lines 701-707
Link Here
|
701 |
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) { |
716 |
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) { |
702 |
if (syntheticAccessors == null) |
717 |
if (syntheticAccessors == null) |
703 |
syntheticAccessors = new MethodBinding[2]; |
718 |
syntheticAccessors = new MethodBinding[2]; |
704 |
syntheticAccessors[isReadAccess ? READ : WRITE] = |
719 |
syntheticAccessors[isReadAccess ? READ : WRITE] = |
705 |
((SourceTypeBinding)currentScope.enclosingSourceType(). |
720 |
((SourceTypeBinding)currentScope.enclosingSourceType(). |
706 |
enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess); |
721 |
enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess); |
707 |
currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess); |
722 |
currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess); |
Lines 710-716
Link Here
|
710 |
// if the binding declaring class is not visible, need special action |
725 |
// if the binding declaring class is not visible, need special action |
711 |
// for runtime compatibility on 1.2 VMs : change the declaring class of the binding |
726 |
// for runtime compatibility on 1.2 VMs : change the declaring class of the binding |
712 |
// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type |
727 |
// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type |
713 |
// and not from Object or implicit static field access. |
728 |
// and not from Object or implicit static field access. |
714 |
if (fieldBinding.declaringClass != this.actualReceiverType |
729 |
if (fieldBinding.declaringClass != this.actualReceiverType |
715 |
&& !this.actualReceiverType.isArrayType() |
730 |
&& !this.actualReceiverType.isArrayType() |
716 |
&& fieldBinding.declaringClass != null // array.length |
731 |
&& fieldBinding.declaringClass != null // array.length |
Lines 720-732
Link Here
|
720 |
&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !fieldBinding.isStatic()) |
735 |
&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !fieldBinding.isStatic()) |
721 |
&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields |
736 |
&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields |
722 |
|| !fieldBinding.declaringClass.canBeSeenBy(currentScope)) { |
737 |
|| !fieldBinding.declaringClass.canBeSeenBy(currentScope)) { |
723 |
|
738 |
|
724 |
this.codegenBinding = |
739 |
this.codegenBinding = |
725 |
currentScope.enclosingSourceType().getUpdatedFieldBinding( |
740 |
currentScope.enclosingSourceType().getUpdatedFieldBinding( |
726 |
codegenField, |
741 |
codegenField, |
727 |
(ReferenceBinding)this.actualReceiverType.erasure()); |
742 |
(ReferenceBinding)this.actualReceiverType.erasure()); |
728 |
} |
743 |
} |
729 |
} |
744 |
} |
730 |
} |
745 |
} |
731 |
} |
746 |
} |
732 |
|
747 |
|
Lines 747-753
Link Here
|
747 |
return FlowInfo.UNKNOWN; |
762 |
return FlowInfo.UNKNOWN; |
748 |
} |
763 |
} |
749 |
} |
764 |
} |
750 |
return FlowInfo.NON_NULL; // never get there |
765 |
return FlowInfo.NON_NULL; // never get there |
751 |
} |
766 |
} |
752 |
|
767 |
|
753 |
/** |
768 |
/** |
Lines 755-761
Link Here
|
755 |
*/ |
770 |
*/ |
756 |
public TypeBinding postConversionType(Scope scope) { |
771 |
public TypeBinding postConversionType(Scope scope) { |
757 |
TypeBinding convertedType = this.resolvedType; |
772 |
TypeBinding convertedType = this.resolvedType; |
758 |
if (this.genericCast != null) |
773 |
if (this.genericCast != null) |
759 |
convertedType = this.genericCast; |
774 |
convertedType = this.genericCast; |
760 |
int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4; |
775 |
int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4; |
761 |
switch (runtimeType) { |
776 |
switch (runtimeType) { |
Lines 784-802
Link Here
|
784 |
convertedType = TypeBinding.DOUBLE; |
799 |
convertedType = TypeBinding.DOUBLE; |
785 |
break; |
800 |
break; |
786 |
default : |
801 |
default : |
787 |
} |
802 |
} |
788 |
if ((this.implicitConversion & BOXING) != 0) { |
803 |
if ((this.implicitConversion & BOXING) != 0) { |
789 |
convertedType = scope.environment().computeBoxingType(convertedType); |
804 |
convertedType = scope.environment().computeBoxingType(convertedType); |
790 |
} |
805 |
} |
791 |
return convertedType; |
806 |
return convertedType; |
792 |
} |
807 |
} |
793 |
|
808 |
|
794 |
public StringBuffer printExpression(int indent, StringBuffer output){ |
809 |
public StringBuffer printExpression(int indent, StringBuffer output){ |
795 |
|
810 |
|
796 |
return output.append(token); |
811 |
return output.append(token); |
797 |
} |
812 |
} |
798 |
public TypeBinding reportError(BlockScope scope) { |
813 |
public TypeBinding reportError(BlockScope scope) { |
799 |
|
814 |
|
800 |
//=====error cases======= |
815 |
//=====error cases======= |
801 |
constant = Constant.NotAConstant; |
816 |
constant = Constant.NotAConstant; |
802 |
if (binding instanceof ProblemFieldBinding) { |
817 |
if (binding instanceof ProblemFieldBinding) { |
Lines 808-817
Link Here
|
808 |
} |
823 |
} |
809 |
return null; |
824 |
return null; |
810 |
} |
825 |
} |
811 |
|
826 |
|
812 |
public TypeBinding resolveType(BlockScope scope) { |
827 |
public TypeBinding resolveType(BlockScope scope) { |
813 |
// for code gen, harm the restrictiveFlag |
828 |
// for code gen, harm the restrictiveFlag |
814 |
|
829 |
|
815 |
if (this.actualReceiverType != null) { |
830 |
if (this.actualReceiverType != null) { |
816 |
this.binding = scope.getField(this.actualReceiverType, token, this); |
831 |
this.binding = scope.getField(this.actualReceiverType, token, this); |
817 |
} else { |
832 |
} else { |
Lines 834-840
Link Here
|
834 |
TypeBinding fieldType = variable.type; |
849 |
TypeBinding fieldType = variable.type; |
835 |
if ((this.bits & IsStrictlyAssigned) == 0) { |
850 |
if ((this.bits & IsStrictlyAssigned) == 0) { |
836 |
constant = variable.constant(); |
851 |
constant = variable.constant(); |
837 |
if (fieldType != null) |
852 |
if (fieldType != null) |
838 |
fieldType = fieldType.capture(scope, this.sourceEnd); // perform capture conversion if read access |
853 |
fieldType = fieldType.capture(scope, this.sourceEnd); // perform capture conversion if read access |
839 |
} else { |
854 |
} else { |
840 |
constant = Constant.NotAConstant; |
855 |
constant = Constant.NotAConstant; |
Lines 848-859
Link Here
|
848 |
} |
863 |
} |
849 |
// perform capture conversion if read access |
864 |
// perform capture conversion if read access |
850 |
TypeBinding fieldType = checkFieldAccess(scope); |
865 |
TypeBinding fieldType = checkFieldAccess(scope); |
851 |
return this.resolvedType = |
866 |
return this.resolvedType = |
852 |
(((this.bits & IsStrictlyAssigned) == 0) |
867 |
(((this.bits & IsStrictlyAssigned) == 0) |
853 |
? fieldType.capture(scope, this.sourceEnd) |
868 |
? fieldType.capture(scope, this.sourceEnd) |
854 |
: fieldType); |
869 |
: fieldType); |
855 |
} |
870 |
} |
856 |
|
871 |
|
857 |
// thus it was a type |
872 |
// thus it was a type |
858 |
bits &= ~RestrictiveFlagMASK; // clear bits |
873 |
bits &= ~RestrictiveFlagMASK; // clear bits |
859 |
bits |= Binding.TYPE; |
874 |
bits |= Binding.TYPE; |
Lines 867-889
Link Here
|
867 |
return this.resolvedType = type; |
882 |
return this.resolvedType = type; |
868 |
} |
883 |
} |
869 |
} |
884 |
} |
870 |
|
885 |
|
871 |
// error scenarii |
886 |
// error scenarii |
872 |
return this.resolvedType = this.reportError(scope); |
887 |
return this.resolvedType = this.reportError(scope); |
873 |
} |
888 |
} |
874 |
|
889 |
|
875 |
public void traverse(ASTVisitor visitor, BlockScope scope) { |
890 |
public void traverse(ASTVisitor visitor, BlockScope scope) { |
876 |
visitor.visit(this, scope); |
891 |
visitor.visit(this, scope); |
877 |
visitor.endVisit(this, scope); |
892 |
visitor.endVisit(this, scope); |
878 |
} |
893 |
} |
879 |
|
894 |
|
880 |
public void traverse(ASTVisitor visitor, ClassScope scope) { |
895 |
public void traverse(ASTVisitor visitor, ClassScope scope) { |
881 |
visitor.visit(this, scope); |
896 |
visitor.visit(this, scope); |
882 |
visitor.endVisit(this, scope); |
897 |
visitor.endVisit(this, scope); |
883 |
} |
898 |
} |
884 |
|
899 |
|
885 |
public String unboundReferenceErrorName(){ |
900 |
public String unboundReferenceErrorName(){ |
886 |
|
901 |
|
887 |
return new String(token); |
902 |
return new String(token); |
888 |
} |
903 |
} |
889 |
} |
904 |
} |