1 /*******************************************************************************
2 * Copyright (c) 2000, 2013 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
11 * bug 185682 - Increment/decrement operators mark local variables as read
12 * bug 186342 - [compiler][null] Using annotations for null checking
13 * bug 365519 - editorial cleanup after bug 186342 and bug 365387
14 * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK
15 * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
16 * Bug 414380 - [compiler][internal] QualifiedNameReference#indexOfFirstFieldBinding does not point to the first field
17 * Jesper S Moller - Contributions for
18 * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
19 * bug 331649 - [compiler][null] consider null annotations for fields
20 * bug 383368 - [compiler][null] syntactic null analysis for field references
21 * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check
22 * Jesper S Moller <jesper@selskabet.org> - Contributions for
23 * bug 378674 - "The method can be declared as static" is wrong
24 *******************************************************************************/
25 package org.eclipse.jdt.internal.compiler.ast;
26
27 import org.eclipse.jdt.core.compiler.CharOperation;
28 import org.eclipse.jdt.internal.compiler.ASTVisitor;
29 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
30 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
31 import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
32 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
33 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
34 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
35 import org.eclipse.jdt.internal.compiler.impl.Constant;
36 import org.eclipse.jdt.internal.compiler.lookup.Binding;
37 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
38 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
39 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
40 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
41 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
42 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
43 import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
44 import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
45 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
46 import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
47 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
48 import org.eclipse.jdt.internal.compiler.lookup.Scope;
49 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
50 import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
51 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
52 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
53 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
54 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
55 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
56
57 public class QualifiedNameReference extends NameReference {
58
59 public char[][] tokens;
60 public long[] sourcePositions;
61 public FieldBinding[] otherBindings;
62 int[] otherDepths;
63 public int indexOfFirstFieldBinding; // points into tokens & sourcePositions for the first token that corresponds to first FieldBinding
64 // *** the index is 1-based ***
65 // during BlockScope#getBinding(..) it will walk through positions until it finds the first field
66 public SyntheticMethodBinding syntheticWriteAccessor;
67 public SyntheticMethodBinding[] syntheticReadAccessors;
68 public TypeBinding genericCast;
69 public TypeBinding[] otherGenericCasts;
70
QualifiedNameReference(char[][] tokens, long[] positions, int sourceStart, int sourceEnd)71 public QualifiedNameReference(char[][] tokens, long[] positions, int sourceStart, int sourceEnd) {
72 this.tokens = tokens;
73 this.sourcePositions = positions;
74 this.sourceStart = sourceStart;
75 this.sourceEnd = sourceEnd;
76 }
77
analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound)78 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
79 // determine the rank until which we now we do not need any actual value for the field access
80 int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
81 boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
82 boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
83 FieldBinding lastFieldBinding = null;
84 switch (this.bits & ASTNode.RestrictiveFlagMASK) {
85 case Binding.FIELD : // reading a field
86 lastFieldBinding = (FieldBinding) this.binding;
87 if (needValue || complyTo14) {
88 manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, 0, flowInfo);
89 }
90 // check if final blank field
91 if (lastFieldBinding.isBlankFinal()
92 && this.otherBindings != null // the last field binding is only assigned
93 && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) {
94 FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(lastFieldBinding.declaringClass.original(), flowInfo);
95 if (!fieldInits.isDefinitelyAssigned(lastFieldBinding)) {
96 currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this);
97 }
98 }
99 break;
100 case Binding.LOCAL :
101 // first binding is a local variable
102 LocalVariableBinding localBinding;
103 if (!flowInfo
104 .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
105 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
106 }
107 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
108 localBinding.useFlag = LocalVariableBinding.USED;
109 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
110 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
111 }
112 if (needValue) {
113 checkInternalNPE(currentScope, flowContext, flowInfo, true);
114 }
115 }
116
117 if (needValue) {
118 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
119 // only for first binding
120 }
121 // all intermediate field accesses are read accesses
122 if (this.otherBindings != null) {
123 for (int i = 0; i < otherBindingsCount-1; i++) {
124 lastFieldBinding = this.otherBindings[i];
125 needValue = !this.otherBindings[i+1].isStatic();
126 if (needValue || complyTo14) {
127 manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, i + 1, flowInfo);
128 }
129 }
130 lastFieldBinding = this.otherBindings[otherBindingsCount-1];
131 }
132
133 if (isCompound) {
134 if (otherBindingsCount == 0
135 && lastFieldBinding.isBlankFinal()
136 && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) {
137 FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(lastFieldBinding.declaringClass, flowInfo);
138 if (!fieldInits.isDefinitelyAssigned(lastFieldBinding)) {
139 currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this);
140 }
141 }
142 manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, otherBindingsCount, flowInfo);
143 }
144
145 if (assignment.expression != null) {
146 flowInfo =
147 assignment
148 .expression
149 .analyseCode(currentScope, flowContext, flowInfo)
150 .unconditionalInits();
151 }
152
153 // the last field access is a write access
154 if (lastFieldBinding.isFinal()) {
155 // in a context where it can be assigned?
156 if (otherBindingsCount == 0
157 && this.indexOfFirstFieldBinding == 1
158 && lastFieldBinding.isBlankFinal()
159 && !isCompound
160 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
161 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
162 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
163 } else {
164 flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo);
165 }
166 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
167 } else {
168 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
169 if (otherBindingsCount == 0 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
170 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
171 }
172 }
173 }
174 // note: not covering def.assign for @NonNull: QNR cannot provably refer to a variable of the current object
175 manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, -1 /*write-access*/, flowInfo);
176
177 return flowInfo;
178 }
179
analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)180 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
181 return analyseCode(currentScope, flowContext, flowInfo, true);
182 }
183
analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired)184 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
185 // determine the rank until which we now we do not need any actual value for the field access
186 int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
187
188 boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
189 boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
190 switch (this.bits & ASTNode.RestrictiveFlagMASK) {
191 case Binding.FIELD : // reading a field
192 if (needValue || complyTo14) {
193 manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) this.binding, 0, flowInfo);
194 }
195 FieldBinding fieldBinding = (FieldBinding) this.binding;
196 if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
197 // check if reading a final blank field
198 if (fieldBinding.isBlankFinal()
199 && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
200 FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo);
201 if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
202 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
203 }
204 }
205 }
206 break;
207 case Binding.LOCAL : // reading a local variable
208 LocalVariableBinding localBinding;
209 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
210 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
211 }
212 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
213 localBinding.useFlag = LocalVariableBinding.USED;
214 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
215 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
216 }
217 }
218 if (needValue) {
219 checkInternalNPE(currentScope, flowContext, flowInfo, true);
220 }
221 if (needValue) {
222 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
223 // only for first binding (if value needed only)
224 }
225 if (this.otherBindings != null) {
226 for (int i = 0; i < otherBindingsCount; i++) {
227 needValue = i < otherBindingsCount-1 ? !this.otherBindings[i+1].isStatic() : valueRequired;
228 if (needValue || complyTo14) {
229 manageSyntheticAccessIfNecessary(currentScope, this.otherBindings[i], i + 1, flowInfo);
230 }
231 }
232 }
233 return flowInfo;
234 }
235
236 /* check if any dot in this QNR may trigger an NPE. */
237 private void checkInternalNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, boolean checkString) {
238 if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
239 LocalVariableBinding local = (LocalVariableBinding) this.binding;
240 if (local != null &&
241 (local.type.tagBits & TagBits.IsBaseType) == 0 &&
242 (checkString || local.type.id != TypeIds.T_JavaLangString)) {
243 if ((this.bits & ASTNode.IsNonNull) == 0) {
244 flowContext.recordUsingNullReference(scope, local, this,
245 FlowContext.MAY_NULL, flowInfo);
246 }
247 flowInfo.markAsComparedEqualToNonNull(local);
248 // from thereon it is set
249 flowContext.markFinallyNullStatus(local, FlowInfo.NON_NULL);
250 }
251 }
252 if (this.otherBindings != null) {
253 if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
254 // is the first field dereferenced annotated Nullable? If so, report immediately
255 checkNullableFieldDereference(scope, (FieldBinding) this.binding, this.sourcePositions[this.indexOfFirstFieldBinding-1]);
256 }
257 // look for annotated fields, they do not depend on flow context -> check immediately:
258 int length = this.otherBindings.length - 1; // don't check the last binding
259 for (int i = 0; i < length; i++) {
260 checkNullableFieldDereference(scope, this.otherBindings[i], this.sourcePositions[this.indexOfFirstFieldBinding+i]);
261 }
262 }
263 }
264
265 public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
266 if (super.checkNPE(scope, flowContext, flowInfo)) {
267 return true;
268 }
269 FieldBinding fieldBinding = null;
270 long position = 0L;
271 if (this.otherBindings == null) {
272 if ((this.bits & RestrictiveFlagMASK) == Binding.FIELD) {
273 fieldBinding = (FieldBinding) this.binding;
274 position = this.sourcePositions[0];
275 }
276 } else {
277 fieldBinding = this.otherBindings[this.otherBindings.length - 1];
278 position = this.sourcePositions[this.sourcePositions.length - 1];
279 }
280 if (fieldBinding != null) {
281 return checkNullableFieldDereference(scope, fieldBinding, position);
282 }
283 return false;
284 }
285
286 /**
287 * @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)
288 */
289 public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
290 if (runtimeTimeType == null || compileTimeType == null)
291 return;
292 // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
293 FieldBinding field = null;
294 int length = this.otherBindings == null ? 0 : this.otherBindings.length;
295 if (length == 0) {
296 if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
297 field = (FieldBinding) this.binding;
298 }
299 } else {
300 field = this.otherBindings[length-1];
301 }
302 if (field != null) {
303 FieldBinding originalBinding = field.original();
304 TypeBinding originalType = originalBinding.type;
305 // extra cast needed if field type is type variable
306 if (originalType.leafComponentType().isTypeVariable()) {
307 TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType())
308 ? compileTimeType // unboxing: checkcast before conversion
309 : runtimeTimeType;
310 TypeBinding typeCast = originalType.genericCast(targetType);
311 setGenericCast(length, typeCast);
312 if (typeCast instanceof ReferenceBinding) {
313 ReferenceBinding referenceCast = (ReferenceBinding) typeCast;
314 if (!referenceCast.canBeSeenBy(scope)) {
315 scope.problemReporter().invalidType(this,
316 new ProblemReferenceBinding(
317 CharOperation.splitOn('.', referenceCast.shortReadableName()),
318 referenceCast,
319 ProblemReasons.NotVisible));
320 }
321 }
322 }
323 }
324 super.computeConversion(scope, runtimeTimeType, compileTimeType);
325 }
326
327 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
328 int pc = codeStream.position;
329 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
330 codeStream.recordPositionsFrom(pc , this.sourceStart);
331 assignment.expression.generateCode(currentScope, codeStream, true);
332 fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, valueRequired);
333 // equivalent to valuesRequired[maxOtherBindings]
334 if (valueRequired) {
335 codeStream.generateImplicitConversion(assignment.implicitConversion);
336 }
337 }
338
339 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
340 int pc = codeStream.position;
341 if (this.constant != Constant.NotAConstant) {
342 if (valueRequired) {
343 codeStream.generateConstant(this.constant, this.implicitConversion);
344 }
345 } else {
346 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
347 if (lastFieldBinding != null) {
348 boolean isStatic = lastFieldBinding.isStatic();
349 Constant fieldConstant = lastFieldBinding.constant();
350 if (fieldConstant != Constant.NotAConstant) {
351 if (!isStatic){
352 codeStream.invokeObjectGetClass();
353 codeStream.pop();
354 }
355 if (valueRequired) { // inline the last field constant
356 codeStream.generateConstant(fieldConstant, this.implicitConversion);
357 }
358 } else {
359 boolean isFirst = lastFieldBinding == this.binding
360 && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType()))
361 && this.otherBindings == null; // could be dup: next.next.next
362 TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length);
363 if (valueRequired
364 || (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
365 || ((this.implicitConversion & TypeIds.UNBOXING) != 0)
366 || requiredGenericCast != null) {
367 int lastFieldPc = codeStream.position;
368 if (lastFieldBinding.declaringClass == null) { // array length
369 codeStream.arraylength();
370 if (valueRequired) {
371 codeStream.generateImplicitConversion(this.implicitConversion);
372 } else {
373 // could occur if !valueRequired but compliance >= 1.4
374 codeStream.pop();
375 }
376 } else {
377 SyntheticMethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
378 if (accessor == null) {
379 TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst);
380 if (isStatic) {
381 codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass);
382 } else {
383 codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass);
384 }
385 } else {
386 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
387 }
388 if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
389 if (valueRequired) {
390 codeStream.generateImplicitConversion(this.implicitConversion);
391 } else {
392 boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
393 // conversion only generated if unboxing
394 if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion);
395 switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) {
396 case T_long :
397 case T_double :
398 codeStream.pop2();
399 break;
400 default :
401 codeStream.pop();
402 break;
403 }
404 }
405 }
406
407 int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32);
408 codeStream.recordPositionsFrom(lastFieldPc, fieldPosition);
409 } else {
410 if (!isStatic){
411 codeStream.invokeObjectGetClass(); // perform null check
412 codeStream.pop();
413 }
414 }
415 }
416 }
417 }
codeStream.recordPositionsFrom(pc, this.sourceStart)418 codeStream.recordPositionsFrom(pc, this.sourceStart);
419 }
420
421 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
422 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
423 // check if compound assignment is the only usage of a private field
424 reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
425 boolean isFirst = lastFieldBinding == this.binding
426 && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType()))
427 && this.otherBindings == null; // could be dup: next.next.next
428 TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst);
429 SyntheticMethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
430 if (lastFieldBinding.isStatic()) {
431 if (accessor == null) {
432 codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass);
433 } else {
434 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
435 }
436 } else {
437 codeStream.dup();
438 if (accessor == null) {
439 codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass);
440 } else {
441 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
442 }
443 }
444 // the last field access is a write access
445 // perform the actual compound operation
446 int operationTypeID;
447 switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
448 case T_JavaLangString :
449 case T_JavaLangObject :
450 case T_undefined :
451 codeStream.generateStringConcatenationAppend(currentScope, null, expression);
452 break;
453 default :
454 TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length);
455 if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
456 // promote the array reference to the suitable operation type
457 codeStream.generateImplicitConversion(this.implicitConversion);
458 // generate the increment value (will by itself be promoted to the operation value)
459 if (expression == IntLiteral.One) { // prefix operation
460 codeStream.generateConstant(expression.constant, this.implicitConversion);
461 } else {
462 expression.generateCode(currentScope, codeStream, true);
463 }
464 // perform the operation
465 codeStream.sendOperator(operator, operationTypeID);
466 // cast the value back to the array reference type
467 codeStream.generateImplicitConversion(assignmentImplicitConversion);
468 }
469 // actual assignment
470 fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, valueRequired);
471 // equivalent to valuesRequired[maxOtherBindings]
472 }
473
474 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
475 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
476 // check if this post increment is the only usage of a private field
477 reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
478 boolean isFirst = lastFieldBinding == this.binding
479 && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType()))
480 && this.otherBindings == null; // could be dup: next.next.next
481 TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst);
482 SyntheticMethodBinding accessor = this.syntheticReadAccessors == null
483 ? null
484 : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1];
485 if (lastFieldBinding.isStatic()) {
486 if (accessor == null) {
487 codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass);
488 } else {
489 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, constantPoolDeclaringClass);
490 }
491 } else {
492 codeStream.dup();
493 if (accessor == null) {
494 codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, null /* default declaringClass */);
495 } else {
496 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
497 }
498 }
499 TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length);
500 TypeBinding operandType;
501 if (requiredGenericCast != null) {
502 codeStream.checkcast(requiredGenericCast);
503 operandType = requiredGenericCast;
504 } else {
505 operandType = lastFieldBinding.type;
506 }
507 // duplicate the old field value
508 if (valueRequired) {
509 if (lastFieldBinding.isStatic()) {
510 switch (operandType.id) {
511 case TypeIds.T_long :
512 case TypeIds.T_double :
513 codeStream.dup2();
514 break;
515 default:
516 codeStream.dup();
517 break;
518 }
519 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
520 switch (operandType.id) {
521 case TypeIds.T_long :
522 case TypeIds.T_double :
523 codeStream.dup2_x1();
524 break;
525 default:
526 codeStream.dup_x1();
527 break;
528 }
529 }
530 }
531 codeStream.generateImplicitConversion(this.implicitConversion);
532 codeStream.generateConstant(
533 postIncrement.expression.constant,
534 this.implicitConversion);
535 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
536 codeStream.generateImplicitConversion(
537 postIncrement.preAssignImplicitConversion);
538 fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, false);
539 }
540
541 /*
542 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
543 * for a read or write access.
544 */
545 public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) {
546 // determine the rank until which we now we do not need any actual value for the field access
547 int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
548 boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
549 FieldBinding lastFieldBinding;
550 TypeBinding lastGenericCast;
551 TypeBinding lastReceiverType;
552 boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
553
554 switch (this.bits & ASTNode.RestrictiveFlagMASK) {
555 case Binding.FIELD :
556 lastFieldBinding = ((FieldBinding) this.binding).original();
557 lastGenericCast = this.genericCast;
558 lastReceiverType = this.actualReceiverType;
559 // if first field is actually constant, we can inline it
560 if (lastFieldBinding.constant() != Constant.NotAConstant) {
561 break;
562 }
563 if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) {
564 int pc = codeStream.position;
565 if ((this.bits & ASTNode.DepthMASK) != 0) {
566 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
567 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
568 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
569 } else {
570 generateReceiver(codeStream);
571 }
572 codeStream.recordPositionsFrom(pc, this.sourceStart);
573 }
574 break;
575 case Binding.LOCAL : // reading the first local variable
576 lastFieldBinding = null;
577 lastGenericCast = null;
578 LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
579 lastReceiverType = localBinding.type;
580 if (!needValue) break; // no value needed
581 // regular local variable read
582 Constant localConstant = localBinding.constant();
583 if (localConstant != Constant.NotAConstant) {
584 codeStream.generateConstant(localConstant, 0);
585 // no implicit conversion
586 } else {
587 // outer local?
588 if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
589 checkEffectiveFinality(localBinding, currentScope);
590 // outer local can be reached either through a synthetic arg or a synthetic field
591 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
592 codeStream.generateOuterAccess(path, this, localBinding, currentScope);
593 } else {
594 codeStream.load(localBinding);
595 }
596 }
597 break;
598 default : // should not occur
599 return null;
600 }
601
602 // all intermediate field accesses are read accesses
603 // only the last field binding is a write access
604 int positionsLength = this.sourcePositions.length;
605 FieldBinding initialFieldBinding = lastFieldBinding; // can be null if initial was a local binding
606 if (this.otherBindings != null) {
607 for (int i = 0; i < otherBindingsCount; i++) {
608 int pc = codeStream.position;
609 FieldBinding nextField = this.otherBindings[i].original();
610 TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i];
611 if (lastFieldBinding != null) {
612 needValue = !nextField.isStatic();
613 Constant fieldConstant = lastFieldBinding.constant();
614 if (fieldConstant != Constant.NotAConstant) {
615 if (i > 0 && !lastFieldBinding.isStatic()) {
616 codeStream.invokeObjectGetClass(); // perform null check
617 codeStream.pop();
618 }
619 if (needValue) {
620 codeStream.generateConstant(fieldConstant, 0);
621 }
622 } else {
623 if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) {
624 MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i];
625 if (accessor == null) {
626 TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, lastReceiverType, i == 0 && this.indexOfFirstFieldBinding == 1);
627 if (lastFieldBinding.isStatic()) {
628 codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass);
629 } else {
630 codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass);
631 }
632 } else {
633 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
634 }
635 if (lastGenericCast != null) {
636 codeStream.checkcast(lastGenericCast);
637 lastReceiverType = lastGenericCast;
638 } else {
639 lastReceiverType = lastFieldBinding.type;
640 }
641 if (!needValue) codeStream.pop();
642 } else {
643 if (lastFieldBinding == initialFieldBinding) {
644 if (lastFieldBinding.isStatic()){
645 // if no valueRequired, still need possible side-effects of <clinit> invocation, if field belongs to different class
646 if (TypeBinding.notEquals(initialFieldBinding.declaringClass, this.actualReceiverType.erasure())) {
647 MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i];
648 if (accessor == null) {
649 TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, lastReceiverType, i == 0 && this.indexOfFirstFieldBinding == 1);
650 codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass);
651 } else {
652 codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */);
653 }
654 codeStream.pop();
655 }
656 }
657 } else if (!lastFieldBinding.isStatic()){
658 codeStream.invokeObjectGetClass(); // perform null check
659 codeStream.pop();
660 }
661 lastReceiverType = lastFieldBinding.type;
662 }
663 if ((positionsLength - otherBindingsCount + i - 1) >= 0) {
664 int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32);
665 codeStream.recordPositionsFrom(pc, fieldPosition);
666 }
667 }
668 }
669 lastFieldBinding = nextField;
670 lastGenericCast = nextGenericCast;
671 }
672 }
673 return lastFieldBinding;
674 }
675
676 public void generateReceiver(CodeStream codeStream) {
677 codeStream.aload_0();
678 }
679
680 /**
681 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
682 */
683 public TypeBinding[] genericTypeArguments() {
684 return null;
685 }
686
687 protected FieldBinding getCodegenBinding(int index) {
688 if (index == 0){
689 return ((FieldBinding)this.binding).original();
690 } else {
691 return this.otherBindings[index-1].original();
692 }
693 }
694
695 /**
696 * Returns the receiver type for the final field in sequence (i.e. the return type of the previous binding)
697 * @return receiver type for the final field in sequence
698 */
699 protected TypeBinding getFinalReceiverType() {
700 int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
701 switch (otherBindingsCount) {
702 case 0 :
703 return this.actualReceiverType;
704 case 1 :
705 return this.genericCast != null ? this.genericCast : ((VariableBinding)this.binding).type;
706 default:
707 TypeBinding previousGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[otherBindingsCount-2];
708 return previousGenericCast != null ? previousGenericCast : this.otherBindings[otherBindingsCount-2].type;
709 }
710 }
711
712 // get the matching generic cast
713 protected TypeBinding getGenericCast(int index) {
714 if (index == 0){
715 return this.genericCast;
716 } else {
717 if (this.otherGenericCasts == null) return null;
718 return this.otherGenericCasts[index-1];
719 }
720 }
721 public TypeBinding getOtherFieldBindings(BlockScope scope) {
722 // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
723 int length = this.tokens.length;
724 FieldBinding field = ((this.bits & Binding.FIELD) != 0) ? (FieldBinding) this.binding : null;
725 TypeBinding type = ((VariableBinding) this.binding).type;
726 int index = this.indexOfFirstFieldBinding;
727 if (index == length) { // restrictiveFlag == FIELD
728 this.constant = ((FieldBinding) this.binding).constant();
729 // perform capture conversion if read access
730 return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0)
731 ? type.capture(scope, this.sourceEnd)
732 : type;
733 }
734 // allocation of the fieldBindings array and its respective constants
735 int otherBindingsLength = length - index;
736 this.otherBindings = new FieldBinding[otherBindingsLength];
737 this.otherDepths = new int[otherBindingsLength];
738
739 // fill the first constant (the one of the binding)
740 this.constant = ((VariableBinding) this.binding).constant();
741 // save first depth, since will be updated by visibility checks of other bindings
742 int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
743 // iteration on each field
744 while (index < length) {
745 char[] token = this.tokens[index];
746 if (type == null)
747 return null; // could not resolve type prior to this point
748
749 this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any
750 FieldBinding previousField = field;
751 field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this);
752 int place = index - this.indexOfFirstFieldBinding;
753 this.otherBindings[place] = field;
754 this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
755 if (field.isValidBinding()) {
756 // set generic cast of for previous field (if any)
757 if (previousField != null) {
758 TypeBinding fieldReceiverType = type;
759 TypeBinding oldReceiverType = fieldReceiverType;
760 fieldReceiverType = fieldReceiverType.getErasureCompatibleType(field.declaringClass);// handle indirect inheritance thru variable secondary bound
761 FieldBinding originalBinding = previousField.original();
762 if (TypeBinding.notEquals(fieldReceiverType, oldReceiverType) || originalBinding.type.leafComponentType().isTypeVariable()) { // record need for explicit cast at codegen
763 setGenericCast(index-1,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case
764 }
765 }
766 // only last field is actually a write access if any
767 if (isFieldUseDeprecated(field, scope, index+1 == length ? this.bits : 0)) {
768 scope.problemReporter().deprecatedField(field, this);
769 }
770 // constant propagation can only be performed as long as the previous one is a constant too.
771 if (this.constant != Constant.NotAConstant) {
772 this.constant = field.constant();
773 }
774
775 if (field.isStatic()) {
776 if ((field.modifiers & ClassFileConstants.AccEnum) != 0) { // enum constants are checked even when qualified)
777 ReferenceBinding declaringClass = field.original().declaringClass;
778 MethodScope methodScope = scope.methodScope();
779 SourceTypeBinding sourceType = methodScope.enclosingSourceType();
780 if ((this.bits & ASTNode.IsStrictlyAssigned) == 0
781 && TypeBinding.equalsEquals(sourceType, declaringClass)
782 && methodScope.lastVisibleFieldID >= 0
783 && field.id >= methodScope.lastVisibleFieldID
784 && (!field.isStatic() || methodScope.isStatic)) {
785 scope.problemReporter().forwardReference(this, index, field);
786 }
787 // check if accessing enum static field in initializer
788 if ((TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body
789 && field.constant() == Constant.NotAConstant
790 && !methodScope.isStatic
791 && methodScope.isInsideInitializerOrConstructor()) {
792 scope.problemReporter().enumStaticFieldUsedDuringInitialization(field, this);
793 }
794 }
795 // static field accessed through receiver? legal but unoptimal (optional warning)
796 scope.problemReporter().nonStaticAccessToStaticField(this, field, index);
797 // indirect static reference ?
798 if (TypeBinding.notEquals(field.declaringClass, type)) {
799 scope.problemReporter().indirectAccessToStaticField(this, field);
800 }
801 }
802 type = field.type;
803 index++;
804 } else {
805 this.constant = Constant.NotAConstant; //don't fill other constants slots...
806 scope.problemReporter().invalidField(this, field, index, type);
807 setDepth(firstDepth);
808 return null;
809 }
810 }
811 setDepth(firstDepth);
812 type = (this.otherBindings[otherBindingsLength - 1]).type;
813 // perform capture conversion if read access
814 return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0)
815 ? type.capture(scope, this.sourceEnd)
816 : type;
817 }
818
819 public boolean isEquivalent(Reference reference) {
820 if (reference instanceof FieldReference) {
821 return reference.isEquivalent(this); // comparison FR <-> QNR is implemented only once
822 }
823 if (!(reference instanceof QualifiedNameReference)) return false;
824 // straight-forward test of equality of two QNRs:
825 QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference;
826 if (this.tokens.length != qualifiedReference.tokens.length) return false;
827 if (this.binding != qualifiedReference.binding) return false;
828 if (this.otherBindings != null) {
829 if (qualifiedReference.otherBindings == null) return false;
830 int len = this.otherBindings.length;
831 if (len != qualifiedReference.otherBindings.length) return false;
832 for (int i=0; i<len; i++) {
833 if (this.otherBindings[i] != qualifiedReference.otherBindings[i]) return false;
834 }
835 } else if (qualifiedReference.otherBindings != null) {
836 return false;
837 }
838 return true;
839 }
840
841 public boolean isFieldAccess() {
842 if (this.otherBindings != null) {
843 return true;
844 }
845 return (this.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD;
846 }
847
848 public FieldBinding lastFieldBinding() {
849 if (this.otherBindings != null) {
850 return this.otherBindings[this.otherBindings.length - 1];
851 } else if (this.binding != null && (this.bits & RestrictiveFlagMASK) == Binding.FIELD) {
852 return (FieldBinding) this.binding;
853 }
854 return null;
855 }
856
857 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
858 //If inlinable field, forget the access emulation, the code gen will directly target it
859 if (((this.bits & ASTNode.DepthMASK) == 0 && (this.bits & ASTNode.IsCapturedOuterLocal) == 0) || (this.constant != Constant.NotAConstant)) {
860 return;
861 }
862 if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
863 LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding;
864 if (localVariableBinding != null) {
865 if ((localVariableBinding.tagBits & TagBits.NotInitialized) != 0) {
866 // local was tagged as uninitialized
867 return;
868 }
869 switch(localVariableBinding.useFlag) {
870 case LocalVariableBinding.FAKE_USED :
871 case LocalVariableBinding.USED :
872 currentScope.emulateOuterAccess(localVariableBinding);
873 }
874 }
875 }
876 }
877
878 /**
879 * index is <0 to denote write access emulation
880 */
881 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FieldBinding fieldBinding, int index, FlowInfo flowInfo) {
882 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;
883 // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
884 if (fieldBinding.constant() != Constant.NotAConstant)
885 return;
886
887 if (fieldBinding.isPrivate()) { // private access
888 FieldBinding codegenField = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
889 ReferenceBinding declaringClass = codegenField.declaringClass;
890 if (TypeBinding.notEquals(declaringClass, currentScope.enclosingSourceType())) {
891 setSyntheticAccessor(fieldBinding, index, ((SourceTypeBinding) declaringClass).addSyntheticMethod(codegenField, index >= 0 /*read-access?*/, false /*not super access*/));
892 currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, index >= 0 /*read-access?*/);
893 return;
894 }
895 } else if (fieldBinding.isProtected()){
896 int depth = (index == 0 || (index < 0 && this.otherDepths == null))
897 ? (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT
898 : this.otherDepths[index < 0 ? this.otherDepths.length-1 : index-1];
899
900 // implicit protected access
901 if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
902 FieldBinding codegenField = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
903 setSyntheticAccessor(fieldBinding, index,
904 ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(codegenField, index >= 0 /*read-access?*/, false /*not super access*/));
905 currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, index >= 0 /*read-access?*/);
906 return;
907 }
908 }
909 }
910
911 public Constant optimizedBooleanConstant() {
912 switch (this.resolvedType.id) {
913 case T_boolean :
914 case T_JavaLangBoolean :
915 if (this.constant != Constant.NotAConstant) return this.constant;
916 switch (this.bits & ASTNode.RestrictiveFlagMASK) {
917 case Binding.FIELD : // reading a field
918 if (this.otherBindings == null)
919 return ((FieldBinding)this.binding).constant();
920 //$FALL-THROUGH$
921 case Binding.LOCAL : // reading a local variable
922 return this.otherBindings[this.otherBindings.length-1].constant();
923 }
924 }
925 return Constant.NotAConstant;
926 }
927
928 /**
929 * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
930 */
931 public TypeBinding postConversionType(Scope scope) {
932 TypeBinding convertedType = this.resolvedType;
933 TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length);
934 if (requiredGenericCast != null)
935 convertedType = requiredGenericCast;
936 int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
937 switch (runtimeType) {
938 case T_boolean :
939 convertedType = TypeBinding.BOOLEAN;
940 break;
941 case T_byte :
942 convertedType = TypeBinding.BYTE;
943 break;
944 case T_short :
945 convertedType = TypeBinding.SHORT;
946 break;
947 case T_char :
948 convertedType = TypeBinding.CHAR;
949 break;
950 case T_int :
951 convertedType = TypeBinding.INT;
952 break;
953 case T_float :
954 convertedType = TypeBinding.FLOAT;
955 break;
956 case T_long :
957 convertedType = TypeBinding.LONG;
958 break;
959 case T_double :
960 convertedType = TypeBinding.DOUBLE;
961 break;
962 default :
963 }
964 if ((this.implicitConversion & TypeIds.BOXING) != 0) {
965 convertedType = scope.environment().computeBoxingType(convertedType);
966 }
967 return convertedType;
968 }
969
970 public StringBuffer printExpression(int indent, StringBuffer output) {
971 for (int i = 0; i < this.tokens.length; i++) {
972 if (i > 0) output.append('.');
973 output.append(this.tokens[i]);
974 }
975 return output;
976 }
977
978 /**
979 * Normal field binding did not work, try to bind to a field of the delegate receiver.
980 */
981 public TypeBinding reportError(BlockScope scope) {
982 if (this.binding instanceof ProblemFieldBinding) {
983 scope.problemReporter().invalidField(this, (FieldBinding) this.binding);
984 } else if (this.binding instanceof ProblemReferenceBinding || this.binding instanceof MissingTypeBinding) {
985 scope.problemReporter().invalidType(this, (TypeBinding) this.binding);
986 } else {
987 scope.problemReporter().unresolvableReference(this, this.binding);
988 }
989 return null;
990 }
991
992 public TypeBinding resolveType(BlockScope scope) {
993 // field and/or local are done before type lookups
994 // the only available value for the restrictiveFlag BEFORE
995 // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
996 this.actualReceiverType = scope.enclosingReceiverType();
997 this.constant = Constant.NotAConstant;
998 if ((this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
999 switch (this.bits & ASTNode.RestrictiveFlagMASK) {
1000 case Binding.VARIABLE : //============only variable===========
1001 case Binding.TYPE | Binding.VARIABLE :
1002 if (this.binding instanceof LocalVariableBinding) {
1003 this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1004 this.bits |= Binding.LOCAL;
1005 LocalVariableBinding local = (LocalVariableBinding) this.binding;
1006 if (!local.isFinal() && (this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
1007 if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) // for 8, defer till effective finality could be ascertained.
1008 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding) this.binding, this);
1009 }
1010 if (local.type != null && (local.type.tagBits & TagBits.HasMissingType) != 0) {
1011 // only complain if field reference (for local, its type got flagged already)
1012 return null;
1013 }
1014 this.resolvedType = getOtherFieldBindings(scope);
1015 if (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) != 0) {
1016 FieldBinding lastField = this.otherBindings[this.otherBindings.length - 1];
1017 scope.problemReporter().invalidField(this, new ProblemFieldBinding(lastField.declaringClass, lastField.name, ProblemReasons.NotFound), this.tokens.length, this.resolvedType.leafComponentType());
1018 return null;
1019 }
1020 return this.resolvedType;
1021 }
1022 if (this.binding instanceof FieldBinding) {
1023 this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1024 this.bits |= Binding.FIELD;
1025 FieldBinding fieldBinding = (FieldBinding) this.binding;
1026 MethodScope methodScope = scope.methodScope();
1027 ReferenceBinding declaringClass = fieldBinding.original().declaringClass;
1028 SourceTypeBinding sourceType = methodScope.enclosingSourceType();
1029 // check for forward references
1030 if ((this.indexOfFirstFieldBinding == 1 || (fieldBinding.modifiers & ClassFileConstants.AccEnum) != 0 || (!fieldBinding.isFinal() && declaringClass.isEnum())) // enum constants are checked even when qualified
1031 && TypeBinding.equalsEquals(sourceType, declaringClass)
1032 && methodScope.lastVisibleFieldID >= 0
1033 && fieldBinding.id >= methodScope.lastVisibleFieldID
1034 && (!fieldBinding.isStatic() || methodScope.isStatic)) {
1035 if (methodScope.insideTypeAnnotation && fieldBinding.id == methodScope.lastVisibleFieldID) {
1036 // false alarm, location is NOT a field initializer but the value in a memberValuePair
1037 } else {
1038 scope.problemReporter().forwardReference(this, this.indexOfFirstFieldBinding-1, fieldBinding);
1039 }
1040 }
1041 if (isFieldUseDeprecated(fieldBinding, scope, this.indexOfFirstFieldBinding == this.tokens.length ? this.bits : 0)) {
1042 scope.problemReporter().deprecatedField(fieldBinding, this);
1043 }
1044 if (fieldBinding.isStatic()) {
1045 // only last field is actually a write access if any
1046 // check if accessing enum static field in initializer
1047 if (declaringClass.isEnum()) {
1048 if ((TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body
1049 && fieldBinding.constant() == Constant.NotAConstant
1050 && !methodScope.isStatic
1051 && methodScope.isInsideInitializerOrConstructor()) {
1052 scope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
1053 }
1054 }
1055 if (this.indexOfFirstFieldBinding > 1
1056 && TypeBinding.notEquals(fieldBinding.declaringClass, this.actualReceiverType)
1057 && fieldBinding.declaringClass.canBeSeenBy(scope)) {
1058 scope.problemReporter().indirectAccessToStaticField(this, fieldBinding);
1059 }
1060 } else {
1061 boolean inStaticContext = scope.methodScope().isStatic;
1062 if (this.indexOfFirstFieldBinding == 1) {
1063 if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
1064 scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
1065 }
1066 if (!inStaticContext) {
1067 scope.tagAsAccessingEnclosingInstanceStateOf(fieldBinding.declaringClass, false /* type variable access */);
1068 }
1069 }
1070 //must check for the static status....
1071 if (this.indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field
1072 || inStaticContext) { // the field is the first token of the qualified reference....
1073 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
1074 return null;
1075 }
1076 }
1077
1078 this.resolvedType = getOtherFieldBindings(scope);
1079 if (this.resolvedType != null
1080 && (this.resolvedType.tagBits & TagBits.HasMissingType) != 0) {
1081 FieldBinding lastField = this.indexOfFirstFieldBinding == this.tokens.length ? (FieldBinding)this.binding : this.otherBindings[this.otherBindings.length - 1];
1082 scope.problemReporter().invalidField(this, new ProblemFieldBinding(lastField.declaringClass, lastField.name, ProblemReasons.NotFound), this.tokens.length, this.resolvedType.leafComponentType());
1083 return null;
1084 }
1085 return this.resolvedType;
1086 }
1087 // thus it was a type
1088 this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1089 this.bits |= Binding.TYPE;
1090 //$FALL-THROUGH$
1091 case Binding.TYPE : //=============only type ==============
1092 TypeBinding type = (TypeBinding) this.binding;
1093 // if (isTypeUseDeprecated(type, scope))
1094 // scope.problemReporter().deprecatedType(type, this);
1095 type = scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/);
1096 return this.resolvedType = type;
1097 }
1098 }
1099 //========error cases===============
1100 return this.resolvedType = reportError(scope);
1101 }
1102
1103 public void setFieldIndex(int index) {
1104 this.indexOfFirstFieldBinding = index;
1105 }
1106
1107 // set the matching codegenBinding and generic cast
1108 protected void setGenericCast(int index, TypeBinding someGenericCast) {
1109 if (someGenericCast == null) return;
1110 if (index == 0){
1111 this.genericCast = someGenericCast;
1112 } else {
1113 if (this.otherGenericCasts == null) {
1114 this.otherGenericCasts = new TypeBinding[this.otherBindings.length];
1115 }
1116 this.otherGenericCasts[index-1] = someGenericCast;
1117 }
1118 }
1119
1120 // set the matching synthetic accessor
1121 protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) {
1122 if (index < 0) { // write-access ?
1123 this.syntheticWriteAccessor = syntheticAccessor;
1124 } else {
1125 if (this.syntheticReadAccessors == null) {
1126 this.syntheticReadAccessors = new SyntheticMethodBinding[this.otherBindings == null ? 1 : this.otherBindings.length + 1];
1127 }
1128 this.syntheticReadAccessors[index] = syntheticAccessor;
1129 }
1130 }
1131
1132 public void traverse(ASTVisitor visitor, BlockScope scope) {
1133 visitor.visit(this, scope);
1134 visitor.endVisit(this, scope);
1135 }
1136
1137 public void traverse(ASTVisitor visitor, ClassScope scope) {
1138 visitor.visit(this, scope);
1139 visitor.endVisit(this, scope);
1140 }
1141
1142 public String unboundReferenceErrorName() {
1143 return new String(this.tokens[0]);
1144 }
1145
1146 public char[][] getName() {
1147 return this.tokens;
1148 }
1149
1150 public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) {
1151 if (this.binding != null && isFieldAccess()) {
1152 FieldBinding fieldBinding;
1153 if (this.otherBindings == null) {
1154 fieldBinding = (FieldBinding) this.binding;
1155 } else {
1156 fieldBinding = this.otherBindings[this.otherBindings.length - 1];
1157 }
1158 if (supportTypeAnnotations || fieldBinding.isNullable() || fieldBinding.isNonNull()) {
1159 return fieldBinding;
1160 }
1161 }
1162 return null;
1163 }
1164 }
1165