1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12 
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.*;
17 import org.eclipse.jdt.internal.compiler.flow.*;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
20 
21 public class QualifiedNameReference extends NameReference {
22 
23 	public char[][] tokens;
24 	public long[] sourcePositions;
25 	public FieldBinding[] otherBindings, otherCodegenBindings;
26 	int[] otherDepths;
27 	public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
28 	SyntheticAccessMethodBinding syntheticWriteAccessor;
29 	SyntheticAccessMethodBinding[] syntheticReadAccessors;
30 	public TypeBinding genericCast;
31 	public TypeBinding[] otherGenericCasts;
32 
QualifiedNameReference( char[][] sources, long[] positions, int sourceStart, int sourceEnd)33 	public QualifiedNameReference(
34 		char[][] sources,
35 		long[] positions,
36 		int sourceStart,
37 		int sourceEnd) {
38 		super();
39 		this.tokens = sources;
40 		this.sourcePositions = positions;
41 		this.sourceStart = sourceStart;
42 		this.sourceEnd = sourceEnd;
43 	}
44 
analyseAssignment( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound)45 	public FlowInfo analyseAssignment(
46 		BlockScope currentScope,
47 		FlowContext flowContext,
48 		FlowInfo flowInfo,
49 		Assignment assignment,
50 		boolean isCompound) {
51 
52 		// determine the rank until which we now we do not need any actual value for the field access
53 		int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
54 		boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
55 		FieldBinding lastFieldBinding = null;
56 		switch (bits & RestrictiveFlagMASK) {
57 			case FIELD : // reading a field
58 				lastFieldBinding = (FieldBinding) binding;
59 				if (needValue) {
60 					manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo);
61 				}				// check if final blank field
62 				if (lastFieldBinding.isBlankFinal()
63 				    && this.otherBindings != null // the last field binding is only assigned
64 	 				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
65 					if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
66 						currentScope.problemReporter().uninitializedBlankFinalField(
67 							lastFieldBinding,
68 							this);
69 					}
70 				}
71 				break;
72 			case LOCAL :
73 				// first binding is a local variable
74 				LocalVariableBinding localBinding;
75 				if (!flowInfo
76 					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
77 					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
78 				}
79 				if (flowInfo.isReachable()) {
80 					localBinding.useFlag = LocalVariableBinding.USED;
81 				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
82 					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
83 				}
84 		}
85 
86 		if (needValue) {
87 			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
88 			// only for first binding
89 		}
90 		// all intermediate field accesses are read accesses
91 		if (otherBindings != null) {
92 			for (int i = 0; i < otherBindingsCount-1; i++) {
93 				lastFieldBinding = otherBindings[i];
94 				needValue = !otherBindings[i+1].isStatic();
95 				if (needValue) {
96 					manageSyntheticAccessIfNecessary(
97 						currentScope,
98 						lastFieldBinding,
99 						i == 0
100 							? ((VariableBinding)binding).type
101 							: otherBindings[i-1].type,
102 						i + 1,
103 						flowInfo);
104 				}
105 			}
106 			lastFieldBinding = otherBindings[otherBindingsCount-1];
107 		}
108 
109 		if (isCompound) {
110 			if (binding == lastFieldBinding
111 				&& lastFieldBinding.isBlankFinal()
112 				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
113 				&& (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
114 				currentScope.problemReporter().uninitializedBlankFinalField(
115 					lastFieldBinding,
116 					this);
117 			}
118 			TypeBinding lastReceiverType;
119 			if (lastFieldBinding == binding){
120 				lastReceiverType = this.actualReceiverType;
121 			} else if (otherBindingsCount == 1){
122 				lastReceiverType = ((VariableBinding)this.binding).type;
123 			} else {
124 				lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
125 			}
126 			manageSyntheticAccessIfNecessary(
127 				currentScope,
128 				lastFieldBinding,
129 				lastReceiverType,
130 				lastFieldBinding == binding
131 					? 0
132 					: otherBindingsCount,
133 				flowInfo);
134 		}
135 
136 		if (assignment.expression != null) {
137 			flowInfo =
138 				assignment
139 					.expression
140 					.analyseCode(currentScope, flowContext, flowInfo)
141 					.unconditionalInits();
142 		}
143 
144 		// the last field access is a write access
145 		if (lastFieldBinding.isFinal()) {
146 			// in a context where it can be assigned?
147 			if (lastFieldBinding.isBlankFinal()
148 					&& !isCompound
149 					&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
150 					&& indexOfFirstFieldBinding == 1) {
151 				if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
152 					currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
153 				} else {
154 					flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo);
155 				}
156 				flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
157 			} else {
158 				currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
159 				if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
160 					flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
161 				}
162 			}
163 		}
164 		// equivalent to valuesRequired[maxOtherBindings]
165 		TypeBinding lastReceiverType;
166 		if (lastFieldBinding == binding){
167 			lastReceiverType = this.actualReceiverType;
168 		} else if (otherBindingsCount == 1){
169 			lastReceiverType = ((VariableBinding)this.binding).type;
170 		} else {
171 			lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
172 		}
173 		manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo);
174 
175 		return flowInfo;
176 	}
177 
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)178 	public FlowInfo analyseCode(
179 		BlockScope currentScope,
180 		FlowContext flowContext,
181 		FlowInfo flowInfo) {
182 
183 		return analyseCode(currentScope, flowContext, flowInfo, true);
184 	}
185 
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired)186 	public FlowInfo analyseCode(
187 		BlockScope currentScope,
188 		FlowContext flowContext,
189 		FlowInfo flowInfo,
190 		boolean valueRequired) {
191 
192 		// determine the rank until which we now we do not need any actual value for the field access
193 		int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
194 
195 		boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
196 		switch (bits & RestrictiveFlagMASK) {
197 			case FIELD : // reading a field
198 				if (needValue) {
199 					manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo);
200 				}
201 				// check if reading a final blank field
202 				FieldBinding fieldBinding;
203 					if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
204 						&& (indexOfFirstFieldBinding == 1)
205 					// was an implicit reference to the first field binding
206 						&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)
207 						&& (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
208 					currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
209 				}
210 				break;
211 			case LOCAL : // reading a local variable
212 				LocalVariableBinding localBinding;
213 				if (!flowInfo
214 					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
215 					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
216 				}
217 				if (flowInfo.isReachable()) {
218 					localBinding.useFlag = LocalVariableBinding.USED;
219 				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
220 					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
221 				}
222 		}
223 		if (needValue) {
224 			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
225 			// only for first binding
226 		}
227 		if (otherBindings != null) {
228 			for (int i = 0; i < otherBindingsCount; i++) {
229 				needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired;
230 				if (needValue) {
231 					manageSyntheticAccessIfNecessary(
232 						currentScope,
233 						otherBindings[i],
234 						i == 0 	? ((VariableBinding)binding).type : otherBindings[i-1].type,
235 						i + 1,
236 						flowInfo);
237 				}
238 			}
239 		}
240 		return flowInfo;
241 	}
242 	/**
243 	 * Check and/or redirect the field access to the delegate receiver if any
244 	 */
245 	public TypeBinding checkFieldAccess(BlockScope scope) {
246 		// check for forward references
247 		FieldBinding fieldBinding = (FieldBinding) binding;
248 		MethodScope methodScope = scope.methodScope();
249 		if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
250 			&& methodScope.lastVisibleFieldID >= 0
251 			&& fieldBinding.id >= methodScope.lastVisibleFieldID) {
252 			if ((!fieldBinding.isStatic() || methodScope.isStatic)
253 				&& this.indexOfFirstFieldBinding == 1)
254 				scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
255 		}
256 		bits &= ~RestrictiveFlagMASK; // clear bits
257 		bits |= FIELD;
258 		return getOtherFieldBindings(scope);
259 	}
260 
261 	/**
262 	 * @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)
263 	 */
computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType)264 	public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
265 		if (runtimeTimeType == null || compileTimeType == null)
266 			return;
267 		// set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
268 		FieldBinding field = null;
269 		int length = this.otherBindings == null ? 0 : this.otherBindings.length;
270 		if (length == 0) {
271 			if (this.binding != null && this.binding.isValidBinding()) {
272 				field = (FieldBinding) this.binding;
273 			}
274 		} else {
275 			field  = this.otherBindings[length-1];
276 		}
277 		if (field != null) {
278 			FieldBinding originalBinding = field.original();
279 			if (originalBinding != field) {
280 			    // extra cast needed if method return type has type variable
281 			    if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && runtimeTimeType.id != T_Object) {
282 			    	setGenericCast(length,originalBinding.type.genericCast(runtimeTimeType));
283 			    }
284 			}
285 		}
286 		super.computeConversion(scope, runtimeTimeType, compileTimeType);
287 	}
288 
generateAssignment( BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired)289 	public void generateAssignment(
290 		BlockScope currentScope,
291 		CodeStream codeStream,
292 		Assignment assignment,
293 		boolean valueRequired) {
294 
295 		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
296 		assignment.expression.generateCode(currentScope, codeStream, true);
297 		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
298 		// equivalent to valuesRequired[maxOtherBindings]
299 		if (valueRequired) {
300 			codeStream.generateImplicitConversion(assignment.implicitConversion);
301 		}
302 	}
generateCode( BlockScope currentScope, CodeStream codeStream, boolean valueRequired)303 	public void generateCode(
304 		BlockScope currentScope,
305 		CodeStream codeStream,
306 		boolean valueRequired) {
307 
308 		int pc = codeStream.position;
309 		if (constant != NotAConstant) {
310 			if (valueRequired) {
311 				codeStream.generateConstant(constant, implicitConversion);
312 			}
313 		} else {
314 			FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
315 			if (valueRequired) {
316 				if (lastFieldBinding.declaringClass == null) { // array length
317 					codeStream.arraylength();
318 					codeStream.generateImplicitConversion(implicitConversion);
319 				} else {
320 					if (lastFieldBinding.isConstantValue()) {
321 						if (!lastFieldBinding.isStatic()){
322 							codeStream.invokeObjectGetClass();
323 							codeStream.pop();
324 						}
325 						// inline the last field constant
326 						codeStream.generateConstant(lastFieldBinding.constant(), implicitConversion);
327 					} else {
328 						SyntheticAccessMethodBinding accessor =
329 							syntheticReadAccessors == null
330 								? null
331 								: syntheticReadAccessors[syntheticReadAccessors.length - 1];
332 						if (accessor == null) {
333 							if (lastFieldBinding.isStatic()) {
334 								codeStream.getstatic(lastFieldBinding);
335 							} else {
336 								codeStream.getfield(lastFieldBinding);
337 							}
338 						} else {
339 							codeStream.invokestatic(accessor);
340 						}
341 						codeStream.generateImplicitConversion(implicitConversion);
342 						TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
343 						if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
344 					}
345 				}
346 			} else {
347 				if (lastFieldBinding != null && !lastFieldBinding.isStatic()){
348 					codeStream.invokeObjectGetClass(); // perform null check
349 					codeStream.pop();
350 				}
351 
352 			}
353 		}
354 		codeStream.recordPositionsFrom(pc, this.sourceStart);
355 	}
generateCompoundAssignment( BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired)356 	public void generateCompoundAssignment(
357 		BlockScope currentScope,
358 		CodeStream codeStream,
359 		Expression expression,
360 		int operator,
361 		int assignmentImplicitConversion,
362 		boolean valueRequired) {
363 
364 		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
365 		SyntheticAccessMethodBinding accessor =
366 			syntheticReadAccessors == null
367 				? null
368 				: syntheticReadAccessors[syntheticReadAccessors.length - 1];
369 		if (lastFieldBinding.isStatic()) {
370 			if (accessor == null) {
371 				codeStream.getstatic(lastFieldBinding);
372 			} else {
373 				codeStream.invokestatic(accessor);
374 			}
375 		} else {
376 			codeStream.dup();
377 			if (accessor == null) {
378 				codeStream.getfield(lastFieldBinding);
379 			} else {
380 				codeStream.invokestatic(accessor);
381 			}
382 		}
383 		// the last field access is a write access
384 		// perform the actual compound operation
385 		int operationTypeID;
386 		if ((operationTypeID = implicitConversion >> 4) == T_String) {
387 			codeStream.generateStringConcatenationAppend(currentScope, null, expression);
388 		} else {
389 			// promote the array reference to the suitable operation type
390 			codeStream.generateImplicitConversion(implicitConversion);
391 			// generate the increment value (will by itself  be promoted to the operation value)
392 			if (expression == IntLiteral.One) { // prefix operation
393 				codeStream.generateConstant(expression.constant, implicitConversion);
394 			} else {
395 				expression.generateCode(currentScope, codeStream, true);
396 			}
397 			// perform the operation
398 			codeStream.sendOperator(operator, operationTypeID);
399 			// cast the value back to the array reference type
400 			codeStream.generateImplicitConversion(assignmentImplicitConversion);
401 		}
402 		// actual assignment
403 		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
404 		// equivalent to valuesRequired[maxOtherBindings]
405 	}
generatePostIncrement( BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired)406 	public void generatePostIncrement(
407 		BlockScope currentScope,
408 		CodeStream codeStream,
409 		CompoundAssignment postIncrement,
410 		boolean valueRequired) {
411 
412 		FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
413 		SyntheticAccessMethodBinding accessor =
414 			syntheticReadAccessors == null
415 				? null
416 				: syntheticReadAccessors[syntheticReadAccessors.length - 1];
417 		if (lastFieldBinding.isStatic()) {
418 			if (accessor == null) {
419 				codeStream.getstatic(lastFieldBinding);
420 			} else {
421 				codeStream.invokestatic(accessor);
422 			}
423 		} else {
424 			codeStream.dup();
425 			if (accessor == null) {
426 				codeStream.getfield(lastFieldBinding);
427 			} else {
428 				codeStream.invokestatic(accessor);
429 			}
430 		}
431 		// duplicate the old field value
432 		if (valueRequired) {
433 			if (lastFieldBinding.isStatic()) {
434 				if ((lastFieldBinding.type == LongBinding)
435 					|| (lastFieldBinding.type == DoubleBinding)) {
436 					codeStream.dup2();
437 				} else {
438 					codeStream.dup();
439 				}
440 			} else { // Stack:  [owner][old field value]  ---> [old field value][owner][old field value]
441 				if ((lastFieldBinding.type == LongBinding)
442 					|| (lastFieldBinding.type == DoubleBinding)) {
443 					codeStream.dup2_x1();
444 				} else {
445 					codeStream.dup_x1();
446 				}
447 			}
448 		}
449 		codeStream.generateConstant(
450 			postIncrement.expression.constant,
451 			implicitConversion);
452 		codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
453 		codeStream.generateImplicitConversion(
454 			postIncrement.assignmentImplicitConversion);
455 		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
456 	}
457 	/*
458 	 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
459 	 * for a read or write access.
460 	 */
generateReadSequence(BlockScope currentScope, CodeStream codeStream)461 	public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) {
462 
463 		// determine the rank until which we now we do not need any actual value for the field access
464 		int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length;
465 		boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
466 		FieldBinding lastFieldBinding = null;
467 		TypeBinding lastGenericCast = null;
468 
469 		switch (bits & RestrictiveFlagMASK) {
470 			case FIELD :
471 				lastFieldBinding = (FieldBinding) this.codegenBinding;
472 				lastGenericCast = this.genericCast;
473 				// if first field is actually constant, we can inline it
474 				if (lastFieldBinding.isConstantValue()) {
475 					break;
476 				}
477 				if (needValue && !lastFieldBinding.isStatic()) {
478 					if ((bits & DepthMASK) != 0) {
479 						ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
480 						Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
481 						codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
482 					} else {
483 						generateReceiver(codeStream);
484 					}
485 				}
486 				break;
487 			case LOCAL : // reading the first local variable
488 				if (!needValue) break; // no value needed
489 				LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
490 				// regular local variable read
491 				if (localBinding.isConstantValue()) {
492 					codeStream.generateConstant(localBinding.constant(), 0);
493 					// no implicit conversion
494 				} else {
495 					// outer local?
496 					if ((bits & DepthMASK) != 0) {
497 						// outer local can be reached either through a synthetic arg or a synthetic field
498 						VariableBinding[] path = currentScope.getEmulationPath(localBinding);
499 						codeStream.generateOuterAccess(path, this, localBinding, currentScope);
500 					} else {
501 						codeStream.load(localBinding);
502 					}
503 				}
504 		}
505 
506 		// all intermediate field accesses are read accesses
507 		// only the last field binding is a write access
508 		if (this.otherCodegenBindings != null) {
509 			for (int i = 0; i < otherBindingsCount; i++) {
510 				FieldBinding nextField = this.otherCodegenBindings[i];
511 				TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i];
512 				if (lastFieldBinding != null) {
513 					needValue = !nextField.isStatic();
514 					if (needValue) {
515 						MethodBinding accessor =
516 							syntheticReadAccessors == null ? null : syntheticReadAccessors[i];
517 						if (accessor == null) {
518 							if (lastFieldBinding.isConstantValue()) {
519 								if (lastFieldBinding != this.codegenBinding && !lastFieldBinding.isStatic()) {
520 									codeStream.invokeObjectGetClass(); // perform null check
521 									codeStream.pop();
522 								}
523 								codeStream.generateConstant(lastFieldBinding.constant(), 0);
524 							} else if (lastFieldBinding.isStatic()) {
525 								codeStream.getstatic(lastFieldBinding);
526 							} else {
527 								codeStream.getfield(lastFieldBinding);
528 							}
529 						} else {
530 							codeStream.invokestatic(accessor);
531 						}
532 						if (lastGenericCast != null) codeStream.checkcast(lastGenericCast);
533 					} else {
534 						if (this.codegenBinding != lastFieldBinding && !lastFieldBinding.isStatic()){
535 							codeStream.invokeObjectGetClass(); // perform null check
536 							codeStream.pop();
537 						}
538 					}
539 				}
540 				lastFieldBinding = nextField;
541 				lastGenericCast = nextGenericCast;
542 			}
543 		}
544 		return lastFieldBinding;
545 	}
generateReceiver(CodeStream codeStream)546 	public void generateReceiver(CodeStream codeStream) {
547 		codeStream.aload_0();
548 	}
549 
550 	/**
551 	 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
552 	 */
genericTypeArguments()553 	public TypeBinding[] genericTypeArguments() {
554 		return null;
555 	}
556 
557 	// get the matching codegenBinding
getCodegenBinding(int index)558 	protected FieldBinding getCodegenBinding(int index) {
559 	  if (index == 0){
560 			return (FieldBinding)this.codegenBinding;
561 		} else {
562 			return this.otherCodegenBindings[index-1];
563 		}
564 	}
565 
566 	// get the matching generic cast
getGenericCast(int index)567 	protected TypeBinding getGenericCast(int index) {
568 	   if (index == 0){
569 			return this.genericCast;
570 		} else {
571 		    if (this.otherGenericCasts == null) return null;
572 			return this.otherGenericCasts[index-1];
573 		}
574 	}
575 
getOtherFieldBindings(BlockScope scope)576 	public TypeBinding getOtherFieldBindings(BlockScope scope) {
577 		// At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
578 		int length = tokens.length;
579 		FieldBinding field;
580 		if ((bits & FIELD) != 0) {
581 			field = (FieldBinding) this.binding;
582 			if (!field.isStatic()) {
583 				//must check for the static status....
584 				if (indexOfFirstFieldBinding > 1  //accessing to a field using a type as "receiver" is allowed only with static field
585 						 || scope.methodScope().isStatic) { 	// the field is the first token of the qualified reference....
586 					scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field);
587 					return null;
588 				 }
589 			} else {
590 				// indirect static reference ?
591 				if (indexOfFirstFieldBinding > 1
592 						&& field.declaringClass != actualReceiverType) {
593 					scope.problemReporter().indirectAccessToStaticField(this, field);
594 				}
595 			}
596 			// only last field is actually a write access if any
597 			if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && indexOfFirstFieldBinding == length))
598 				scope.problemReporter().deprecatedField(field, this);
599 		} else {
600 			field = null;
601 		}
602 		TypeBinding type = ((VariableBinding) binding).type;
603 		int index = indexOfFirstFieldBinding;
604 		if (index == length) { //	restrictiveFlag == FIELD
605 			this.constant = FieldReference.getConstantFor((FieldBinding) binding, this, false, scope);
606 			return type;
607 		}
608 		// allocation of the fieldBindings array	and its respective constants
609 		int otherBindingsLength = length - index;
610 		otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
611 		otherDepths = new int[otherBindingsLength];
612 
613 		// fill the first constant (the one of the binding)
614 		this.constant = field != null
615 				? FieldReference.getConstantFor((FieldBinding) binding, this, false, scope)
616 				: ((VariableBinding) binding).constant();
617 		// save first depth, since will be updated by visibility checks of other bindings
618 		int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
619 		// iteration on each field
620 		while (index < length) {
621 			char[] token = tokens[index];
622 			if (type == null)
623 				return null; // could not resolve type prior to this point
624 
625 			// set generic cast of for previous field (if any)
626 			if (field != null) {
627 				FieldBinding originalBinding = field.original();
628 				if (originalBinding != field) {
629 				    // extra cast needed if method return type has type variable
630 				    if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && type.id != T_Object) {
631 				    	setGenericCast(index-1,originalBinding.type.genericCast(type));
632 				    }
633 				}
634 			}
635 			bits &= ~DepthMASK; // flush previous depth if any
636 			field = scope.getField(type, token, this);
637 			int place = index - indexOfFirstFieldBinding;
638 			otherBindings[place] = field;
639 			otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
640 			if (field.isValidBinding()) {
641 				// only last field is actually a write access if any
642 				if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && index+1 == length)) {
643 					scope.problemReporter().deprecatedField(field, this);
644 				}
645 				Constant someConstant = FieldReference.getConstantFor(field, this, false, scope);
646 				// constant propagation can only be performed as long as the previous one is a constant too.
647 				if (this.constant != NotAConstant) {
648 					this.constant = someConstant;
649 				}
650 
651 				if (field.isStatic()) {
652 					// static field accessed through receiver? legal but unoptimal (optional warning)
653 					scope.problemReporter().nonStaticAccessToStaticField(this, field);
654 					// indirect static reference ?
655 					if (field.declaringClass != type) {
656 						scope.problemReporter().indirectAccessToStaticField(this, field);
657 					}
658 				}
659 				type = field.type;
660 				index++;
661 			} else {
662 				constant = NotAConstant; //don't fill other constants slots...
663 				scope.problemReporter().invalidField(this, field, index, type);
664 				setDepth(firstDepth);
665 				return null;
666 			}
667 		}
668 		setDepth(firstDepth);
669 		return (otherBindings[otherBindingsLength - 1]).type;
670 	}
manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo)671 	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
672 		if (!flowInfo.isReachable()) return;
673 		//If inlinable field, forget the access emulation, the code gen will directly target it
674 		if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
675 			return;
676 		}
677 		if ((bits & RestrictiveFlagMASK) == LOCAL) {
678 			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
679 		}
680 	}
681 	/**
682 	 * index is <0 to denote write access emulation
683 	 */
manageSyntheticAccessIfNecessary( BlockScope currentScope, FieldBinding fieldBinding, TypeBinding lastReceiverType, int index, FlowInfo flowInfo)684 	public void manageSyntheticAccessIfNecessary(
685 			BlockScope currentScope,
686 			FieldBinding fieldBinding,
687 			TypeBinding lastReceiverType,
688 			int index,
689 			FlowInfo flowInfo) {
690 
691 		if (!flowInfo.isReachable()) return;
692 		// index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
693 		if (fieldBinding.isConstantValue())
694 			return;
695 
696 		// if field from parameterized type got found, use the original field at codegen time
697 		FieldBinding originalField = fieldBinding.original();
698 		if (originalField != fieldBinding) {
699 			setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField);
700 		}
701 
702 		if (fieldBinding.isPrivate()) { // private access
703 		    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
704 			if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) {
705 			    setSyntheticAccessor(fieldBinding, index,
706 			            ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
707 				currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
708 				return;
709 			}
710 		} else if (fieldBinding.isProtected()){
711 		    int depth = fieldBinding == binding
712 		    		? (bits & DepthMASK) >> DepthSHIFT
713 		    		 : otherDepths[index < 0 ? otherDepths.length-1 : index-1];
714 
715 			// implicit protected access
716 			if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
717 			    FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
718 			    setSyntheticAccessor(fieldBinding, index,
719 			            ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
720 				currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
721 				return;
722 			}
723 		}
724 		// if the binding declaring class is not visible, need special action
725 		// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
726 		// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
727 		if (fieldBinding.declaringClass != lastReceiverType
728 			&& !lastReceiverType.isArrayType()
729 			&& fieldBinding.declaringClass != null
730 			&& !fieldBinding.isConstantValue()
731 			&& ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
732 					&& (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
733 					&& fieldBinding.declaringClass.id != T_Object)
734 				|| !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
735 		    setCodegenBinding(
736 		            index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index,
737 		            currentScope.enclosingSourceType().getUpdatedFieldBinding(
738 		                    getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index),
739 		                    (ReferenceBinding)lastReceiverType.erasure()));
740 		}
741 	}
742 
743 	public StringBuffer printExpression(int indent, StringBuffer output) {
744 
745 		for (int i = 0; i < tokens.length; i++) {
746 			if (i > 0) output.append('.');
747 			output.append(tokens[i]);
748 		}
749 		return output;
750 	}
751 
752 	/**
753 	 * Normal field binding did not work, try to bind to a field of the delegate receiver.
754 	 */
755 	public TypeBinding reportError(BlockScope scope) {
756 		if (binding instanceof ProblemFieldBinding) {
757 			scope.problemReporter().invalidField(this, (FieldBinding) binding);
758 		} else if (binding instanceof ProblemReferenceBinding) {
759 			scope.problemReporter().invalidType(this, (TypeBinding) binding);
760 		} else {
761 			scope.problemReporter().unresolvableReference(this, binding);
762 		}
763 		return null;
764 	}
765 	public TypeBinding resolveType(BlockScope scope) {
766 		// field and/or local are done before type lookups
767 		// the only available value for the restrictiveFlag BEFORE
768 		// the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
769 		this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
770 		constant = Constant.NotAConstant;
771 		if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
772 			switch (bits & RestrictiveFlagMASK) {
773 				case VARIABLE : //============only variable===========
774 				case TYPE | VARIABLE :
775 					if (binding instanceof LocalVariableBinding) {
776 						if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
777 							scope.problemReporter().cannotReferToNonFinalOuterLocal(
778 								(LocalVariableBinding) binding,
779 								this);
780 						bits &= ~RestrictiveFlagMASK; // clear bits
781 						bits |= LOCAL;
782 						return this.resolvedType = getOtherFieldBindings(scope);
783 					}
784 					if (binding instanceof FieldBinding) {
785 						// check for forward references
786 						FieldBinding fieldBinding = (FieldBinding) binding;
787 						MethodScope methodScope = scope.methodScope();
788 						if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
789 								&& methodScope.lastVisibleFieldID >= 0
790 								&& fieldBinding.id >= methodScope.lastVisibleFieldID) {
791 							if ((!fieldBinding.isStatic() || methodScope.isStatic)
792 								&& this.indexOfFirstFieldBinding == 1) {
793 								scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
794 								}
795 						}
796 						if (!fieldBinding.isStatic()
797 								&& this.indexOfFirstFieldBinding == 1
798 								&& scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
799 							scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
800 						}
801 						bits &= ~RestrictiveFlagMASK; // clear bits
802 						bits |= FIELD;
803 
804 						// check for deprecated receiver type
805 						// deprecation check for receiver type if not first token
806 						if (indexOfFirstFieldBinding > 1) {
807 							if (isTypeUseDeprecated(this.actualReceiverType, scope))
808 								scope.problemReporter().deprecatedType(this.actualReceiverType, this);
809 						}
810 
811 						return this.resolvedType = getOtherFieldBindings(scope);
812 					}
813 					// thus it was a type
814 					bits &= ~RestrictiveFlagMASK; // clear bits
815 					bits |= TYPE;
816 				case TYPE : //=============only type ==============
817 				    TypeBinding type = (TypeBinding) binding;
818 					if (isTypeUseDeprecated(type, scope))
819 						scope.problemReporter().deprecatedType(type, this);
820 					return this.resolvedType = scope.convertToRawType(type);
821 			}
822 		}
823 		//========error cases===============
824 		return this.resolvedType = this.reportError(scope);
825 	}
826 
827 	// set the matching codegenBinding and generic cast
setCodegenBinding(int index, FieldBinding someCodegenBinding)828 	protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) {
829 
830 		if (index == 0){
831 			this.codegenBinding = someCodegenBinding;
832 		} else {
833 		    int length = this.otherBindings.length;
834 			if (this.otherCodegenBindings == this.otherBindings){
835 				System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length);
836 			}
837 			this.otherCodegenBindings[index-1] = someCodegenBinding;
838 		}
839 	}
840 
841 	// set the matching codegenBinding and generic cast
setGenericCast(int index, TypeBinding someGenericCast)842 	protected void setGenericCast(int index, TypeBinding someGenericCast) {
843 
844 		if (index == 0){
845 			this.genericCast = someGenericCast;
846 		} else {
847 		    if (this.otherGenericCasts == null) {
848 		        this.otherGenericCasts = new TypeBinding[this.otherBindings.length];
849 		    }
850 		    this.otherGenericCasts[index-1] = someGenericCast;
851 		}
852 	}
853 
854 	// set the matching synthetic accessor
setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticAccessMethodBinding syntheticAccessor)855 	protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticAccessMethodBinding syntheticAccessor) {
856 		if (index < 0) { // write-access ?
857 			syntheticWriteAccessor = syntheticAccessor;
858 	    } else {
859 			if (syntheticReadAccessors == null) {
860 				syntheticReadAccessors = new SyntheticAccessMethodBinding[otherBindings == null ? 1 : otherBindings.length + 1];
861 			}
862 			syntheticReadAccessors[index] = syntheticAccessor;
863 	    }
864 	}
865 
setFieldIndex(int index)866 	public void setFieldIndex(int index) {
867 		this.indexOfFirstFieldBinding = index;
868 	}
869 
traverse(ASTVisitor visitor, BlockScope scope)870 	public void traverse(ASTVisitor visitor, BlockScope scope) {
871 		visitor.visit(this, scope);
872 		visitor.endVisit(this, scope);
873 	}
unboundReferenceErrorName()874 	public String unboundReferenceErrorName() {
875 		return new String(tokens[0]);
876 	}
877 }
878