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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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;
21 public class QualifiedNameReference extends NameReference {
23 public char[][] tokens;
24 public long[] sourcePositions;
25 public FieldBinding[] otherBindings, otherCodegenBindings;
27 public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
28 SyntheticMethodBinding syntheticWriteAccessor;
29 SyntheticMethodBinding[] syntheticReadAccessors;
30 public TypeBinding genericCast;
31 public TypeBinding[] otherGenericCasts;
33 public QualifiedNameReference(
39 this.tokens = sources;
40 this.sourcePositions = positions;
41 this.sourceStart = sourceStart;
42 this.sourceEnd = sourceEnd;
45 public FlowInfo analyseAssignment(
46 BlockScope currentScope,
47 FlowContext flowContext,
49 Assignment assignment,
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 Binding.FIELD : // reading a field
58 lastFieldBinding = (FieldBinding) binding;
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(
73 // first binding is a local variable
74 LocalVariableBinding localBinding;
76 .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
77 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
79 if (flowInfo.isReachable()) {
80 localBinding.useFlag = LocalVariableBinding.USED;
81 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
82 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
84 this.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
88 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
89 // only for first binding
91 // all intermediate field accesses are read accesses
92 if (otherBindings != null) {
93 for (int i = 0; i < otherBindingsCount-1; i++) {
94 lastFieldBinding = otherBindings[i];
95 needValue = !otherBindings[i+1].isStatic();
97 manageSyntheticAccessIfNecessary(
101 ? ((VariableBinding)binding).type
102 : otherBindings[i-1].type,
107 lastFieldBinding = otherBindings[otherBindingsCount-1];
111 if (binding == lastFieldBinding
112 && lastFieldBinding.isBlankFinal()
113 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
114 && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
115 currentScope.problemReporter().uninitializedBlankFinalField(
119 TypeBinding lastReceiverType;
120 if (lastFieldBinding == binding){
121 lastReceiverType = this.actualReceiverType;
122 } else if (otherBindingsCount == 1){
123 lastReceiverType = ((VariableBinding)this.binding).type;
125 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
127 manageSyntheticAccessIfNecessary(
131 lastFieldBinding == binding
133 : otherBindingsCount,
137 if (assignment.expression != null) {
141 .analyseCode(currentScope, flowContext, flowInfo)
142 .unconditionalInits();
145 // the last field access is a write access
146 if (lastFieldBinding.isFinal()) {
147 // in a context where it can be assigned?
148 if (lastFieldBinding.isBlankFinal()
150 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
151 && indexOfFirstFieldBinding == 1) {
152 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
153 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
155 flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo);
157 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
159 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
160 if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
161 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
165 // equivalent to valuesRequired[maxOtherBindings]
166 TypeBinding lastReceiverType;
167 if (lastFieldBinding == binding){
168 lastReceiverType = this.actualReceiverType;
169 } else if (otherBindingsCount == 1){
170 lastReceiverType = ((VariableBinding)this.binding).type;
172 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
174 manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, -1 /*write-access*/, flowInfo);
179 public FlowInfo analyseCode(
180 BlockScope currentScope,
181 FlowContext flowContext,
184 return analyseCode(currentScope, flowContext, flowInfo, true);
187 public FlowInfo analyseCode(
188 BlockScope currentScope,
189 FlowContext flowContext,
191 boolean valueRequired) {
193 // determine the rank until which we now we do not need any actual value for the field access
194 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
196 boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
197 switch (bits & RestrictiveFlagMASK) {
198 case Binding.FIELD : // reading a field
200 manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo);
202 // check if reading a final blank field
203 FieldBinding fieldBinding;
204 if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
205 && (indexOfFirstFieldBinding == 1)
206 // was an implicit reference to the first field binding
207 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)
208 && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
209 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
212 case Binding.LOCAL : // reading a local variable
213 LocalVariableBinding localBinding;
215 .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
216 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
218 if (flowInfo.isReachable()) {
219 localBinding.useFlag = LocalVariableBinding.USED;
220 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
221 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
223 this.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
226 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
227 // only for first binding
229 if (otherBindings != null) {
230 for (int i = 0; i < otherBindingsCount; i++) {
231 needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired;
233 manageSyntheticAccessIfNecessary(
236 i == 0 ? ((VariableBinding)binding).type : otherBindings[i-1].type,
245 * Check and/or redirect the field access to the delegate receiver if any
247 public TypeBinding checkFieldAccess(BlockScope scope) {
248 // check for forward references
249 FieldBinding fieldBinding = (FieldBinding) binding;
250 MethodScope methodScope = scope.methodScope();
251 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
252 && methodScope.lastVisibleFieldID >= 0
253 && fieldBinding.id >= methodScope.lastVisibleFieldID) {
254 if ((!fieldBinding.isStatic() || methodScope.isStatic)
255 && this.indexOfFirstFieldBinding == 1)
256 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
258 bits &= ~RestrictiveFlagMASK; // clear bits
259 bits |= Binding.FIELD;
260 return getOtherFieldBindings(scope);
264 * @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)
266 public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
267 if (runtimeTimeType == null || compileTimeType == null)
269 // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
270 FieldBinding field = null;
271 int length = this.otherBindings == null ? 0 : this.otherBindings.length;
273 if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
274 field = (FieldBinding) this.binding;
277 field = this.otherBindings[length-1];
280 FieldBinding originalBinding = field.original();
281 if (originalBinding != field) {
282 // extra cast needed if method return type has type variable
283 if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && runtimeTimeType.id != T_JavaLangObject) {
284 setGenericCast(length,originalBinding.type.genericCast(scope.boxing(runtimeTimeType))); // runtimeType could be base type in boxing case
288 super.computeConversion(scope, runtimeTimeType, compileTimeType);
291 public void generateAssignment(
292 BlockScope currentScope,
293 CodeStream codeStream,
294 Assignment assignment,
295 boolean valueRequired) {
297 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
298 assignment.expression.generateCode(currentScope, codeStream, true);
299 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
300 // equivalent to valuesRequired[maxOtherBindings]
302 codeStream.generateImplicitConversion(assignment.implicitConversion);
305 public void generateCode(
306 BlockScope currentScope,
307 CodeStream codeStream,
308 boolean valueRequired) {
310 int pc = codeStream.position;
311 if (constant != NotAConstant) {
313 codeStream.generateConstant(constant, implicitConversion);
316 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
318 if (lastFieldBinding.declaringClass == null) { // array length
319 codeStream.arraylength();
320 codeStream.generateImplicitConversion(implicitConversion);
322 if (lastFieldBinding.isConstantValue()) {
323 if (!lastFieldBinding.isStatic()){
324 codeStream.invokeObjectGetClass();
327 // inline the last field constant
328 codeStream.generateConstant(lastFieldBinding.constant(), implicitConversion);
330 SyntheticMethodBinding accessor =
331 syntheticReadAccessors == null
333 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
334 if (accessor == null) {
335 if (lastFieldBinding.isStatic()) {
336 codeStream.getstatic(lastFieldBinding);
338 codeStream.getfield(lastFieldBinding);
341 codeStream.invokestatic(accessor);
343 TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
344 if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
345 codeStream.generateImplicitConversion(implicitConversion);
349 if (lastFieldBinding != null && !lastFieldBinding.isStatic()){
350 codeStream.invokeObjectGetClass(); // perform null check
356 codeStream.recordPositionsFrom(pc, this.sourceStart);
358 public void generateCompoundAssignment(
359 BlockScope currentScope,
360 CodeStream codeStream,
361 Expression expression,
363 int assignmentImplicitConversion,
364 boolean valueRequired) {
366 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
367 SyntheticMethodBinding accessor =
368 syntheticReadAccessors == null
370 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
371 if (lastFieldBinding.isStatic()) {
372 if (accessor == null) {
373 codeStream.getstatic(lastFieldBinding);
375 codeStream.invokestatic(accessor);
379 if (accessor == null) {
380 codeStream.getfield(lastFieldBinding);
382 codeStream.invokestatic(accessor);
385 // the last field access is a write access
386 // perform the actual compound operation
388 switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
389 case T_JavaLangString :
390 case T_JavaLangObject :
392 codeStream.generateStringConcatenationAppend(currentScope, null, expression);
395 // promote the array reference to the suitable operation type
396 codeStream.generateImplicitConversion(implicitConversion);
397 // generate the increment value (will by itself be promoted to the operation value)
398 if (expression == IntLiteral.One) { // prefix operation
399 codeStream.generateConstant(expression.constant, implicitConversion);
401 expression.generateCode(currentScope, codeStream, true);
403 // perform the operation
404 codeStream.sendOperator(operator, operationTypeID);
405 // cast the value back to the array reference type
406 codeStream.generateImplicitConversion(assignmentImplicitConversion);
409 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
410 // equivalent to valuesRequired[maxOtherBindings]
412 public void generatePostIncrement(
413 BlockScope currentScope,
414 CodeStream codeStream,
415 CompoundAssignment postIncrement,
416 boolean valueRequired) {
418 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
419 SyntheticMethodBinding accessor =
420 syntheticReadAccessors == null
422 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
423 if (lastFieldBinding.isStatic()) {
424 if (accessor == null) {
425 codeStream.getstatic(lastFieldBinding);
427 codeStream.invokestatic(accessor);
431 if (accessor == null) {
432 codeStream.getfield(lastFieldBinding);
434 codeStream.invokestatic(accessor);
437 // duplicate the old field value
439 if (lastFieldBinding.isStatic()) {
440 if ((lastFieldBinding.type == LongBinding)
441 || (lastFieldBinding.type == DoubleBinding)) {
446 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
447 if ((lastFieldBinding.type == LongBinding)
448 || (lastFieldBinding.type == DoubleBinding)) {
449 codeStream.dup2_x1();
455 codeStream.generateImplicitConversion(implicitConversion);
456 codeStream.generateConstant(
457 postIncrement.expression.constant,
459 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
460 codeStream.generateImplicitConversion(
461 postIncrement.assignmentImplicitConversion);
462 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
465 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
466 * for a read or write access.
468 public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) {
470 // determine the rank until which we now we do not need any actual value for the field access
471 int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length;
472 boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
473 FieldBinding lastFieldBinding = null;
474 TypeBinding lastGenericCast = null;
476 switch (bits & RestrictiveFlagMASK) {
478 lastFieldBinding = (FieldBinding) this.codegenBinding;
479 lastGenericCast = this.genericCast;
480 // if first field is actually constant, we can inline it
481 if (lastFieldBinding.isConstantValue()) {
484 if (needValue && !lastFieldBinding.isStatic()) {
485 if ((bits & DepthMASK) != 0) {
486 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
487 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
488 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
490 generateReceiver(codeStream);
494 case Binding.LOCAL : // reading the first local variable
495 if (!needValue) break; // no value needed
496 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
497 // regular local variable read
498 if (localBinding.isConstantValue()) {
499 codeStream.generateConstant(localBinding.constant(), 0);
500 // no implicit conversion
503 if ((bits & DepthMASK) != 0) {
504 // outer local can be reached either through a synthetic arg or a synthetic field
505 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
506 codeStream.generateOuterAccess(path, this, localBinding, currentScope);
508 codeStream.load(localBinding);
513 // all intermediate field accesses are read accesses
514 // only the last field binding is a write access
515 if (this.otherCodegenBindings != null) {
516 for (int i = 0; i < otherBindingsCount; i++) {
517 FieldBinding nextField = this.otherCodegenBindings[i];
518 TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i];
519 if (lastFieldBinding != null) {
520 needValue = !nextField.isStatic();
522 MethodBinding accessor =
523 syntheticReadAccessors == null ? null : syntheticReadAccessors[i];
524 if (accessor == null) {
525 if (lastFieldBinding.isConstantValue()) {
526 if (lastFieldBinding != this.codegenBinding && !lastFieldBinding.isStatic()) {
527 codeStream.invokeObjectGetClass(); // perform null check
530 codeStream.generateConstant(lastFieldBinding.constant(), 0);
531 } else if (lastFieldBinding.isStatic()) {
532 codeStream.getstatic(lastFieldBinding);
534 codeStream.getfield(lastFieldBinding);
537 codeStream.invokestatic(accessor);
539 if (lastGenericCast != null) codeStream.checkcast(lastGenericCast);
541 if (this.codegenBinding != lastFieldBinding && !lastFieldBinding.isStatic()){
542 codeStream.invokeObjectGetClass(); // perform null check
547 lastFieldBinding = nextField;
548 lastGenericCast = nextGenericCast;
551 return lastFieldBinding;
553 public void generateReceiver(CodeStream codeStream) {
554 codeStream.aload_0();
558 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
560 public TypeBinding[] genericTypeArguments() {
564 // get the matching codegenBinding
565 protected FieldBinding getCodegenBinding(int index) {
567 return (FieldBinding)this.codegenBinding;
569 return this.otherCodegenBindings[index-1];
573 // get the matching generic cast
574 protected TypeBinding getGenericCast(int index) {
576 return this.genericCast;
578 if (this.otherGenericCasts == null) return null;
579 return this.otherGenericCasts[index-1];
583 public TypeBinding getOtherFieldBindings(BlockScope scope) {
584 // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
585 int length = tokens.length;
587 if ((bits & Binding.FIELD) != 0) {
588 field = (FieldBinding) this.binding;
589 if (!field.isStatic()) {
590 //must check for the static status....
591 if (indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field
592 || scope.methodScope().isStatic) { // the field is the first token of the qualified reference....
593 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field);
597 // indirect static reference ?
598 if (indexOfFirstFieldBinding > 1
599 && field.declaringClass != actualReceiverType) {
600 scope.problemReporter().indirectAccessToStaticField(this, field);
603 // only last field is actually a write access if any
604 if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && indexOfFirstFieldBinding == length))
605 scope.problemReporter().deprecatedField(field, this);
609 TypeBinding type = ((VariableBinding) binding).type;
610 int index = indexOfFirstFieldBinding;
611 if (index == length) { // restrictiveFlag == FIELD
612 this.constant = FieldReference.getConstantFor((FieldBinding) binding, this, false, scope);
615 // allocation of the fieldBindings array and its respective constants
616 int otherBindingsLength = length - index;
617 otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
618 otherDepths = new int[otherBindingsLength];
620 // fill the first constant (the one of the binding)
621 this.constant = field != null
622 ? FieldReference.getConstantFor((FieldBinding) binding, this, false, scope)
623 : ((VariableBinding) binding).constant();
624 // save first depth, since will be updated by visibility checks of other bindings
625 int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
626 // iteration on each field
627 while (index < length) {
628 char[] token = tokens[index];
630 return null; // could not resolve type prior to this point
632 // set generic cast of for previous field (if any)
634 FieldBinding originalBinding = field.original();
635 if (originalBinding != field) {
636 // extra cast needed if method return type has type variable
637 if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && type.id != T_JavaLangObject) {
638 setGenericCast(index-1,originalBinding.type.genericCast(type)); // type cannot be base-type even in boxing case
642 bits &= ~DepthMASK; // flush previous depth if any
643 field = scope.getField(type, token, this);
644 int place = index - indexOfFirstFieldBinding;
645 otherBindings[place] = field;
646 otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
647 if (field.isValidBinding()) {
648 // only last field is actually a write access if any
649 if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && index+1 == length)) {
650 scope.problemReporter().deprecatedField(field, this);
652 Constant someConstant = FieldReference.getConstantFor(field, this, false, scope);
653 // constant propagation can only be performed as long as the previous one is a constant too.
654 if (this.constant != NotAConstant) {
655 this.constant = someConstant;
658 if (field.isStatic()) {
659 // static field accessed through receiver? legal but unoptimal (optional warning)
660 scope.problemReporter().nonStaticAccessToStaticField(this, field);
661 // indirect static reference ?
662 if (field.declaringClass != type) {
663 scope.problemReporter().indirectAccessToStaticField(this, field);
669 constant = NotAConstant; //don't fill other constants slots...
670 scope.problemReporter().invalidField(this, field, index, type);
671 setDepth(firstDepth);
675 setDepth(firstDepth);
676 return (otherBindings[otherBindingsLength - 1]).type;
678 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
679 if (!flowInfo.isReachable()) return;
680 //If inlinable field, forget the access emulation, the code gen will directly target it
681 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
684 if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
685 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
689 * index is <0 to denote write access emulation
691 public void manageSyntheticAccessIfNecessary(
692 BlockScope currentScope,
693 FieldBinding fieldBinding,
694 TypeBinding lastReceiverType,
698 if (!flowInfo.isReachable()) return;
699 // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
700 if (fieldBinding.isConstantValue())
703 // if field from parameterized type got found, use the original field at codegen time
704 FieldBinding originalField = fieldBinding.original();
705 if (originalField != fieldBinding) {
706 setCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index, originalField);
709 if (fieldBinding.isPrivate()) { // private access
710 FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
711 if (someCodegenBinding.declaringClass != currentScope.enclosingSourceType()) {
712 setSyntheticAccessor(fieldBinding, index,
713 ((SourceTypeBinding) someCodegenBinding.declaringClass).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
714 currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
717 } else if (fieldBinding.isProtected()){
718 int depth = fieldBinding == binding
719 ? (bits & DepthMASK) >> DepthSHIFT
720 : otherDepths[index < 0 ? otherDepths.length-1 : index-1];
722 // implicit protected access
723 if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
724 FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index);
725 setSyntheticAccessor(fieldBinding, index,
726 ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(someCodegenBinding, index >= 0 /*read-access?*/));
727 currentScope.problemReporter().needToEmulateFieldAccess(someCodegenBinding, this, index >= 0 /*read-access?*/);
731 // if the binding declaring class is not visible, need special action
732 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
733 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
734 if (fieldBinding.declaringClass != lastReceiverType
735 && !lastReceiverType.isArrayType()
736 && fieldBinding.declaringClass != null
737 && !fieldBinding.isConstantValue()
738 && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
739 && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
740 && fieldBinding.declaringClass.id != T_JavaLangObject)
741 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
743 index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index,
744 currentScope.enclosingSourceType().getUpdatedFieldBinding(
745 getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index),
746 (ReferenceBinding)lastReceiverType.erasure()));
750 public StringBuffer printExpression(int indent, StringBuffer output) {
752 for (int i = 0; i < tokens.length; i++) {
753 if (i > 0) output.append('.');
754 output.append(tokens[i]);
760 * Normal field binding did not work, try to bind to a field of the delegate receiver.
762 public TypeBinding reportError(BlockScope scope) {
763 if (binding instanceof ProblemFieldBinding) {
764 scope.problemReporter().invalidField(this, (FieldBinding) binding);
765 } else if (binding instanceof ProblemReferenceBinding) {
766 scope.problemReporter().invalidType(this, (TypeBinding) binding);
768 scope.problemReporter().unresolvableReference(this, binding);
772 public TypeBinding resolveType(BlockScope scope) {
773 // field and/or local are done before type lookups
774 // the only available value for the restrictiveFlag BEFORE
775 // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
776 this.actualReceiverType = scope.enclosingSourceType();
777 constant = Constant.NotAConstant;
778 if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
779 switch (bits & RestrictiveFlagMASK) {
780 case Binding.VARIABLE : //============only variable===========
781 case Binding.TYPE | Binding.VARIABLE :
782 if (binding instanceof LocalVariableBinding) {
783 if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
784 scope.problemReporter().cannotReferToNonFinalOuterLocal(
785 (LocalVariableBinding) binding,
787 bits &= ~RestrictiveFlagMASK; // clear bits
788 bits |= Binding.LOCAL;
789 return this.resolvedType = getOtherFieldBindings(scope);
791 if (binding instanceof FieldBinding) {
792 // check for forward references
793 FieldBinding fieldBinding = (FieldBinding) binding;
794 MethodScope methodScope = scope.methodScope();
795 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
796 && methodScope.lastVisibleFieldID >= 0
797 && fieldBinding.id >= methodScope.lastVisibleFieldID) {
798 if ((!fieldBinding.isStatic() || methodScope.isStatic)
799 && this.indexOfFirstFieldBinding == 1) {
800 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
803 if (!fieldBinding.isStatic()
804 && this.indexOfFirstFieldBinding == 1
805 && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
806 scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
808 bits &= ~RestrictiveFlagMASK; // clear bits
809 bits |= Binding.FIELD;
811 // check for deprecated receiver type
812 // deprecation check for receiver type if not first token
813 if (indexOfFirstFieldBinding > 1) {
814 if (isTypeUseDeprecated(this.actualReceiverType, scope))
815 scope.problemReporter().deprecatedType(this.actualReceiverType, this);
818 return this.resolvedType = getOtherFieldBindings(scope);
820 // thus it was a type
821 bits &= ~RestrictiveFlagMASK; // clear bits
822 bits |= Binding.TYPE;
823 case Binding.TYPE : //=============only type ==============
824 TypeBinding type = (TypeBinding) binding;
825 if (isTypeUseDeprecated(type, scope))
826 scope.problemReporter().deprecatedType(type, this);
827 return this.resolvedType = scope.convertToRawType(type);
830 //========error cases===============
831 return this.resolvedType = this.reportError(scope);
834 // set the matching codegenBinding and generic cast
835 protected void setCodegenBinding(int index, FieldBinding someCodegenBinding) {
838 this.codegenBinding = someCodegenBinding;
840 int length = this.otherBindings.length;
841 if (this.otherCodegenBindings == this.otherBindings){
842 System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[length], 0, length);
844 this.otherCodegenBindings[index-1] = someCodegenBinding;
848 // set the matching codegenBinding and generic cast
849 protected void setGenericCast(int index, TypeBinding someGenericCast) {
852 this.genericCast = someGenericCast;
854 if (this.otherGenericCasts == null) {
855 this.otherGenericCasts = new TypeBinding[this.otherBindings.length];
857 this.otherGenericCasts[index-1] = someGenericCast;
861 // set the matching synthetic accessor
862 protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) {
863 if (index < 0) { // write-access ?
864 syntheticWriteAccessor = syntheticAccessor;
866 if (syntheticReadAccessors == null) {
867 syntheticReadAccessors = new SyntheticMethodBinding[otherBindings == null ? 1 : otherBindings.length + 1];
869 syntheticReadAccessors[index] = syntheticAccessor;
873 public void setFieldIndex(int index) {
874 this.indexOfFirstFieldBinding = index;
877 public void traverse(ASTVisitor visitor, BlockScope scope) {
878 visitor.visit(this, scope);
879 visitor.endVisit(this, scope);
881 public String unboundReferenceErrorName() {
882 return new String(tokens[0]);