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