0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
0011:
0012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
0013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
0014: import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
0015: import org.eclipse.jdt.internal.compiler.flow.FlowContext;
0016: import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
0017: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
0018: import org.eclipse.jdt.internal.compiler.impl.Constant;
0019: import org.eclipse.jdt.internal.compiler.lookup.Binding;
0020: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
0021: import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
0022: import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
0023: import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
0024: import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
0025: import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
0026: import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
0027: import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
0028: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
0029: import org.eclipse.jdt.internal.compiler.lookup.Scope;
0030: import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
0031: import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
0032: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
0033: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
0034: import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
0035: import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
0036: import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
0037:
0038: public class QualifiedNameReference extends NameReference {
0039:
0040: public char[][] tokens;
0041: public long[] sourcePositions;
0042: public FieldBinding[] otherBindings, otherCodegenBindings;
0043: int[] otherDepths;
0044: public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
0045: SyntheticMethodBinding syntheticWriteAccessor;
0046: SyntheticMethodBinding[] syntheticReadAccessors;
0047: public TypeBinding genericCast;
0048: public TypeBinding[] otherGenericCasts;
0049:
0050: public QualifiedNameReference(char[][] tokens, long[] positions,
0051: int sourceStart, int sourceEnd) {
0052: this .tokens = tokens;
0053: this .sourcePositions = positions;
0054: this .sourceStart = sourceStart;
0055: this .sourceEnd = sourceEnd;
0056: }
0057:
0058: public FlowInfo analyseAssignment(BlockScope currentScope,
0059: FlowContext flowContext, FlowInfo flowInfo,
0060: Assignment assignment, boolean isCompound) {
0061: // determine the rank until which we now we do not need any actual value for the field access
0062: int otherBindingsCount = this .otherBindings == null ? 0
0063: : this .otherBindings.length;
0064: boolean needValue = otherBindingsCount == 0
0065: || !this .otherBindings[0].isStatic();
0066: boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
0067: FieldBinding lastFieldBinding = null;
0068: switch (this .bits & ASTNode.RestrictiveFlagMASK) {
0069: case Binding.FIELD: // reading a field
0070: lastFieldBinding = (FieldBinding) this .binding;
0071: if (needValue || complyTo14) {
0072: manageSyntheticAccessIfNecessary(currentScope,
0073: lastFieldBinding, this .actualReceiverType, 0,
0074: flowInfo);
0075: }
0076: if (this .indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
0077: ReferenceBinding declaringClass = lastFieldBinding.declaringClass;
0078: // check if accessing enum static field in initializer
0079: if (declaringClass.isEnum()) {
0080: MethodScope methodScope = currentScope
0081: .methodScope();
0082: SourceTypeBinding sourceType = methodScope
0083: .enclosingSourceType();
0084: if (lastFieldBinding.isStatic()
0085: && (sourceType == declaringClass || sourceType.super class == declaringClass) // enum constant body
0086: && lastFieldBinding.constant() == Constant.NotAConstant
0087: && !methodScope.isStatic
0088: && methodScope
0089: .isInsideInitializerOrConstructor()) {
0090: currentScope
0091: .problemReporter()
0092: .enumStaticFieldUsedDuringInitialization(
0093: lastFieldBinding, this );
0094: }
0095: }
0096: }
0097: // check if final blank field
0098: if (lastFieldBinding.isBlankFinal()
0099: && this .otherBindings != null // the last field binding is only assigned
0100: && currentScope
0101: .needBlankFinalFieldInitializationCheck(lastFieldBinding)) {
0102: if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
0103: currentScope.problemReporter()
0104: .uninitializedBlankFinalField(
0105: lastFieldBinding, this );
0106: }
0107: }
0108: break;
0109: case Binding.LOCAL:
0110: // first binding is a local variable
0111: LocalVariableBinding localBinding;
0112: if (!flowInfo
0113: .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this .binding)) {
0114: currentScope.problemReporter()
0115: .uninitializedLocalVariable(localBinding, this );
0116: }
0117: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
0118: localBinding.useFlag = LocalVariableBinding.USED;
0119: } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
0120: localBinding.useFlag = LocalVariableBinding.FAKE_USED;
0121: }
0122: checkNPE(currentScope, flowContext, flowInfo, true);
0123: }
0124:
0125: if (needValue) {
0126: manageEnclosingInstanceAccessIfNecessary(currentScope,
0127: flowInfo);
0128: // only for first binding
0129: }
0130: // all intermediate field accesses are read accesses
0131: if (this .otherBindings != null) {
0132: for (int i = 0; i < otherBindingsCount - 1; i++) {
0133: lastFieldBinding = this .otherBindings[i];
0134: needValue = !this .otherBindings[i + 1].isStatic();
0135: if (needValue || complyTo14) {
0136: manageSyntheticAccessIfNecessary(
0137: currentScope,
0138: lastFieldBinding,
0139: i == 0 ? ((VariableBinding) this .binding).type
0140: : this .otherBindings[i - 1].type,
0141: i + 1, flowInfo);
0142: }
0143: }
0144: lastFieldBinding = this .otherBindings[otherBindingsCount - 1];
0145: }
0146:
0147: if (isCompound) {
0148: if (otherBindingsCount == 0
0149: && lastFieldBinding.isBlankFinal()
0150: && currentScope
0151: .needBlankFinalFieldInitializationCheck(lastFieldBinding)
0152: && (!flowInfo
0153: .isDefinitelyAssigned(lastFieldBinding))) {
0154: currentScope.problemReporter()
0155: .uninitializedBlankFinalField(lastFieldBinding,
0156: this );
0157: }
0158: TypeBinding lastReceiverType;
0159: switch (otherBindingsCount) {
0160: case 0:
0161: lastReceiverType = this .actualReceiverType;
0162: break;
0163: case 1:
0164: lastReceiverType = ((VariableBinding) this .binding).type;
0165: break;
0166: default:
0167: lastReceiverType = this .otherBindings[otherBindingsCount - 2].type;
0168: break;
0169: }
0170: manageSyntheticAccessIfNecessary(currentScope,
0171: lastFieldBinding, lastReceiverType,
0172: otherBindingsCount, flowInfo);
0173: }
0174:
0175: if (assignment.expression != null) {
0176: flowInfo = assignment.expression.analyseCode(currentScope,
0177: flowContext, flowInfo).unconditionalInits();
0178: }
0179:
0180: // the last field access is a write access
0181: if (lastFieldBinding.isFinal()) {
0182: // in a context where it can be assigned?
0183: if (otherBindingsCount == 0
0184: && this .indexOfFirstFieldBinding == 1
0185: && lastFieldBinding.isBlankFinal()
0186: && !isCompound
0187: && currentScope
0188: .allowBlankFinalFieldAssignment(lastFieldBinding)) {
0189: if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
0190: currentScope.problemReporter()
0191: .duplicateInitializationOfBlankFinalField(
0192: lastFieldBinding, this );
0193: } else {
0194: flowContext.recordSettingFinal(lastFieldBinding,
0195: this , flowInfo);
0196: }
0197: flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
0198: } else {
0199: currentScope.problemReporter()
0200: .cannotAssignToFinalField(lastFieldBinding,
0201: this );
0202: if (otherBindingsCount == 0
0203: && currentScope
0204: .allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
0205: flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
0206: }
0207: }
0208: }
0209: // equivalent to valuesRequired[maxOtherBindings]
0210: TypeBinding lastReceiverType;
0211: switch (otherBindingsCount) {
0212: case 0:
0213: lastReceiverType = this .actualReceiverType;
0214: break;
0215: case 1:
0216: lastReceiverType = ((VariableBinding) this .binding).type;
0217: break;
0218: default:
0219: lastReceiverType = this .otherBindings[otherBindingsCount - 2].type;
0220: break;
0221: }
0222: manageSyntheticAccessIfNecessary(currentScope,
0223: lastFieldBinding, lastReceiverType,
0224: -1 /*write-access*/, flowInfo);
0225:
0226: return flowInfo;
0227: }
0228:
0229: public FlowInfo analyseCode(BlockScope currentScope,
0230: FlowContext flowContext, FlowInfo flowInfo) {
0231: return analyseCode(currentScope, flowContext, flowInfo, true);
0232: }
0233:
0234: public FlowInfo analyseCode(BlockScope currentScope,
0235: FlowContext flowContext, FlowInfo flowInfo,
0236: boolean valueRequired) {
0237: // determine the rank until which we now we do not need any actual value for the field access
0238: int otherBindingsCount = this .otherBindings == null ? 0
0239: : this .otherBindings.length;
0240:
0241: boolean needValue = otherBindingsCount == 0 ? valueRequired
0242: : !this .otherBindings[0].isStatic();
0243: boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
0244: switch (this .bits & ASTNode.RestrictiveFlagMASK) {
0245: case Binding.FIELD: // reading a field
0246: if (needValue || complyTo14) {
0247: manageSyntheticAccessIfNecessary(currentScope,
0248: (FieldBinding) this .binding,
0249: this .actualReceiverType, 0, flowInfo);
0250: }
0251: if (this .indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
0252: FieldBinding fieldBinding = (FieldBinding) this .binding;
0253: ReferenceBinding declaringClass = fieldBinding.declaringClass;
0254: // check if accessing enum static field in initializer
0255: if (declaringClass.isEnum()) {
0256: MethodScope methodScope = currentScope
0257: .methodScope();
0258: SourceTypeBinding sourceType = methodScope
0259: .enclosingSourceType();
0260: if (fieldBinding.isStatic()
0261: && (sourceType == declaringClass || sourceType.super class == declaringClass) // enum constant body
0262: && fieldBinding.constant() == Constant.NotAConstant
0263: && !methodScope.isStatic
0264: && methodScope
0265: .isInsideInitializerOrConstructor()) {
0266: currentScope
0267: .problemReporter()
0268: .enumStaticFieldUsedDuringInitialization(
0269: fieldBinding, this );
0270: }
0271: }
0272: // check if reading a final blank field
0273: if (fieldBinding.isBlankFinal()
0274: && currentScope
0275: .needBlankFinalFieldInitializationCheck(fieldBinding)
0276: && !flowInfo.isDefinitelyAssigned(fieldBinding)) {
0277: currentScope.problemReporter()
0278: .uninitializedBlankFinalField(fieldBinding,
0279: this );
0280: }
0281: }
0282: break;
0283: case Binding.LOCAL: // reading a local variable
0284: LocalVariableBinding localBinding;
0285: if (!flowInfo
0286: .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this .binding)) {
0287: currentScope.problemReporter()
0288: .uninitializedLocalVariable(localBinding, this );
0289: }
0290: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
0291: localBinding.useFlag = LocalVariableBinding.USED;
0292: } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
0293: localBinding.useFlag = LocalVariableBinding.FAKE_USED;
0294: }
0295: checkNPE(currentScope, flowContext, flowInfo, true);
0296: }
0297: if (needValue) {
0298: manageEnclosingInstanceAccessIfNecessary(currentScope,
0299: flowInfo);
0300: // only for first binding (if value needed only)
0301: }
0302: if (this .otherBindings != null) {
0303: for (int i = 0; i < otherBindingsCount; i++) {
0304: needValue = i < otherBindingsCount - 1 ? !this .otherBindings[i + 1]
0305: .isStatic()
0306: : valueRequired;
0307: if (needValue || complyTo14) {
0308: TypeBinding lastReceiverType = getGenericCast(i);
0309: if (lastReceiverType == null) {
0310: if (i == 0) {
0311: lastReceiverType = ((VariableBinding) this .binding).type;
0312: } else {
0313: lastReceiverType = this .otherBindings[i - 1].type;
0314: }
0315: }
0316: manageSyntheticAccessIfNecessary(currentScope,
0317: this .otherBindings[i], lastReceiverType,
0318: i + 1, flowInfo);
0319: }
0320: }
0321: }
0322: return flowInfo;
0323: }
0324:
0325: /**
0326: * Check and/or redirect the field access to the delegate receiver if any
0327: */
0328: public TypeBinding checkFieldAccess(BlockScope scope) {
0329: FieldBinding fieldBinding = (FieldBinding) this .binding;
0330: MethodScope methodScope = scope.methodScope();
0331: // check for forward references
0332: if (this .indexOfFirstFieldBinding == 1
0333: && methodScope.enclosingSourceType() == fieldBinding
0334: .original().declaringClass
0335: && methodScope.lastVisibleFieldID >= 0
0336: && fieldBinding.id >= methodScope.lastVisibleFieldID
0337: && (!fieldBinding.isStatic() || methodScope.isStatic)) {
0338: scope.problemReporter().forwardReference(this , 0,
0339: methodScope.enclosingSourceType());
0340: }
0341: this .bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
0342: this .bits |= Binding.FIELD;
0343: return getOtherFieldBindings(scope);
0344: }
0345:
0346: public void checkNPE(BlockScope scope, FlowContext flowContext,
0347: FlowInfo flowInfo, boolean checkString) {
0348: // cannot override localVariableBinding because this would project o.m onto o when
0349: // analysing assignments
0350: if ((this .bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
0351: LocalVariableBinding local = (LocalVariableBinding) this .binding;
0352: if (local != null
0353: && (local.type.tagBits & TagBits.IsBaseType) == 0
0354: && (checkString || local.type.id != TypeIds.T_JavaLangString)) {
0355: if ((this .bits & ASTNode.IsNonNull) == 0) {
0356: flowContext.recordUsingNullReference(scope, local,
0357: this , FlowContext.MAY_NULL, flowInfo);
0358: }
0359: flowInfo.markAsComparedEqualToNonNull(local);
0360: // from thereon it is set
0361: if (flowContext.initsOnFinally != null) {
0362: flowContext.initsOnFinally
0363: .markAsComparedEqualToNonNull(local);
0364: }
0365: }
0366: }
0367: }
0368:
0369: /**
0370: * @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)
0371: */
0372: public void computeConversion(Scope scope,
0373: TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
0374: if (runtimeTimeType == null || compileTimeType == null)
0375: return;
0376: // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
0377: FieldBinding field = null;
0378: int length = this .otherBindings == null ? 0
0379: : this .otherBindings.length;
0380: if (length == 0) {
0381: if ((this .bits & Binding.FIELD) != 0
0382: && this .binding != null
0383: && this .binding.isValidBinding()) {
0384: field = (FieldBinding) this .binding;
0385: }
0386: } else {
0387: field = this .otherBindings[length - 1];
0388: }
0389: if (field != null) {
0390: FieldBinding originalBinding = field.original();
0391: TypeBinding originalType = originalBinding.type;
0392: // extra cast needed if method return type has type variable
0393: if (originalBinding != field
0394: && originalType != field.type
0395: && runtimeTimeType.id != TypeIds.T_JavaLangObject
0396: && (originalType.tagBits & TagBits.HasTypeVariable) != 0) {
0397: TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType
0398: .isBaseType()) ? compileTimeType // unboxing: checkcast before conversion
0399: : runtimeTimeType;
0400: setGenericCast(length, originalType
0401: .genericCast(targetType));
0402: }
0403: }
0404: super
0405: .computeConversion(scope, runtimeTimeType,
0406: compileTimeType);
0407: }
0408:
0409: public void generateAssignment(BlockScope currentScope,
0410: CodeStream codeStream, Assignment assignment,
0411: boolean valueRequired) {
0412: int pc = codeStream.position;
0413: FieldBinding lastFieldBinding = generateReadSequence(
0414: currentScope, codeStream);
0415: codeStream.recordPositionsFrom(pc, this .sourceStart);
0416: assignment.expression.generateCode(currentScope, codeStream,
0417: true);
0418: fieldStore(codeStream, lastFieldBinding,
0419: this .syntheticWriteAccessor, valueRequired);
0420: // equivalent to valuesRequired[maxOtherBindings]
0421: if (valueRequired) {
0422: codeStream
0423: .generateImplicitConversion(assignment.implicitConversion);
0424: }
0425: }
0426:
0427: public void generateCode(BlockScope currentScope,
0428: CodeStream codeStream, boolean valueRequired) {
0429: int pc = codeStream.position;
0430: if (this .constant != Constant.NotAConstant) {
0431: if (valueRequired) {
0432: codeStream.generateConstant(this .constant,
0433: this .implicitConversion);
0434: }
0435: } else {
0436: FieldBinding lastFieldBinding = generateReadSequence(
0437: currentScope, codeStream);
0438: if (lastFieldBinding != null) {
0439: boolean isStatic = lastFieldBinding.isStatic();
0440: Constant fieldConstant = lastFieldBinding.constant();
0441: if (fieldConstant != Constant.NotAConstant) {
0442: if (!isStatic) {
0443: codeStream.invokeObjectGetClass();
0444: codeStream.pop();
0445: }
0446: if (valueRequired) { // inline the last field constant
0447: codeStream.generateConstant(fieldConstant,
0448: this .implicitConversion);
0449: }
0450: } else {
0451: boolean isFirst = lastFieldBinding == this .binding
0452: && (this .indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope
0453: .enclosingReceiverType())
0454: && this .otherBindings == null; // could be dup: next.next.next
0455: TypeBinding requiredGenericCast = getGenericCast(this .otherCodegenBindings == null ? 0
0456: : this .otherCodegenBindings.length);
0457: if (valueRequired
0458: || (!isFirst && currentScope
0459: .compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
0460: || ((this .implicitConversion & TypeIds.UNBOXING) != 0)
0461: || requiredGenericCast != null) {
0462: int lastFieldPc = codeStream.position;
0463: if (lastFieldBinding.declaringClass == null) { // array length
0464: codeStream.arraylength();
0465: if (valueRequired) {
0466: codeStream
0467: .generateImplicitConversion(this .implicitConversion);
0468: } else {
0469: // could occur if !valueRequired but compliance >= 1.4
0470: codeStream.pop();
0471: }
0472: } else {
0473: SyntheticMethodBinding accessor = this .syntheticReadAccessors == null ? null
0474: : this .syntheticReadAccessors[this .syntheticReadAccessors.length - 1];
0475: if (accessor == null) {
0476: if (isStatic) {
0477: codeStream
0478: .getstatic(lastFieldBinding);
0479: } else {
0480: codeStream
0481: .getfield(lastFieldBinding);
0482: }
0483: } else {
0484: codeStream.invokestatic(accessor);
0485: }
0486: if (requiredGenericCast != null)
0487: codeStream
0488: .checkcast(requiredGenericCast);
0489: if (valueRequired) {
0490: codeStream
0491: .generateImplicitConversion(this .implicitConversion);
0492: } else {
0493: boolean isUnboxing = (this .implicitConversion & TypeIds.UNBOXING) != 0;
0494: // conversion only generated if unboxing
0495: if (isUnboxing)
0496: codeStream
0497: .generateImplicitConversion(this .implicitConversion);
0498: switch (isUnboxing ? postConversionType(currentScope).id
0499: : lastFieldBinding.type.id) {
0500: case T_long:
0501: case T_double:
0502: codeStream.pop2();
0503: break;
0504: default:
0505: codeStream.pop();
0506: }
0507: }
0508: }
0509:
0510: int fieldPosition = (int) (this .sourcePositions[this .sourcePositions.length - 1] >>> 32);
0511: codeStream.recordPositionsFrom(lastFieldPc,
0512: fieldPosition);
0513: } else {
0514: if (!isStatic) {
0515: codeStream.invokeObjectGetClass(); // perform null check
0516: codeStream.pop();
0517: }
0518: }
0519: }
0520: }
0521: }
0522: codeStream.recordPositionsFrom(pc, this .sourceStart);
0523: }
0524:
0525: public void generateCompoundAssignment(BlockScope currentScope,
0526: CodeStream codeStream, Expression expression, int operator,
0527: int assignmentImplicitConversion, boolean valueRequired) {
0528:
0529: FieldBinding lastFieldBinding = generateReadSequence(
0530: currentScope, codeStream);
0531: SyntheticMethodBinding accessor = this .syntheticReadAccessors == null ? null
0532: : this .syntheticReadAccessors[this .syntheticReadAccessors.length - 1];
0533: if (lastFieldBinding.isStatic()) {
0534: if (accessor == null) {
0535: codeStream.getstatic(lastFieldBinding);
0536: } else {
0537: codeStream.invokestatic(accessor);
0538: }
0539: } else {
0540: codeStream.dup();
0541: if (accessor == null) {
0542: codeStream.getfield(lastFieldBinding);
0543: } else {
0544: codeStream.invokestatic(accessor);
0545: }
0546: }
0547: // the last field access is a write access
0548: // perform the actual compound operation
0549: int operationTypeID;
0550: switch (operationTypeID = (this .implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
0551: case T_JavaLangString:
0552: case T_JavaLangObject:
0553: case T_undefined:
0554: codeStream.generateStringConcatenationAppend(currentScope,
0555: null, expression);
0556: break;
0557: default:
0558: TypeBinding requiredGenericCast = getGenericCast(this .otherCodegenBindings == null ? 0
0559: : this .otherCodegenBindings.length);
0560: if (requiredGenericCast != null)
0561: codeStream.checkcast(requiredGenericCast);
0562: // promote the array reference to the suitable operation type
0563: codeStream
0564: .generateImplicitConversion(this .implicitConversion);
0565: // generate the increment value (will by itself be promoted to the operation value)
0566: if (expression == IntLiteral.One) { // prefix operation
0567: codeStream.generateConstant(expression.constant,
0568: this .implicitConversion);
0569: } else {
0570: expression.generateCode(currentScope, codeStream, true);
0571: }
0572: // perform the operation
0573: codeStream.sendOperator(operator, operationTypeID);
0574: // cast the value back to the array reference type
0575: codeStream
0576: .generateImplicitConversion(assignmentImplicitConversion);
0577: }
0578: // actual assignment
0579: fieldStore(codeStream, lastFieldBinding,
0580: this .syntheticWriteAccessor, valueRequired);
0581: // equivalent to valuesRequired[maxOtherBindings]
0582: }
0583:
0584: public void generatePostIncrement(BlockScope currentScope,
0585: CodeStream codeStream, CompoundAssignment postIncrement,
0586: boolean valueRequired) {
0587:
0588: FieldBinding lastFieldBinding = generateReadSequence(
0589: currentScope, codeStream);
0590: SyntheticMethodBinding accessor = this .syntheticReadAccessors == null ? null
0591: : this .syntheticReadAccessors[this .syntheticReadAccessors.length - 1];
0592: if (lastFieldBinding.isStatic()) {
0593: if (accessor == null) {
0594: codeStream.getstatic(lastFieldBinding);
0595: } else {
0596: codeStream.invokestatic(accessor);
0597: }
0598: } else {
0599: codeStream.dup();
0600: if (accessor == null) {
0601: codeStream.getfield(lastFieldBinding);
0602: } else {
0603: codeStream.invokestatic(accessor);
0604: }
0605: }
0606: // duplicate the old field value
0607: if (valueRequired) {
0608: if (lastFieldBinding.isStatic()) {
0609: if ((lastFieldBinding.type == TypeBinding.LONG)
0610: || (lastFieldBinding.type == TypeBinding.DOUBLE)) {
0611: codeStream.dup2();
0612: } else {
0613: codeStream.dup();
0614: }
0615: } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
0616: if ((lastFieldBinding.type == TypeBinding.LONG)
0617: || (lastFieldBinding.type == TypeBinding.DOUBLE)) {
0618: codeStream.dup2_x1();
0619: } else {
0620: codeStream.dup_x1();
0621: }
0622: }
0623: }
0624: TypeBinding requiredGenericCast = getGenericCast(this .otherCodegenBindings == null ? 0
0625: : this .otherCodegenBindings.length);
0626: if (requiredGenericCast != null)
0627: codeStream.checkcast(requiredGenericCast);
0628:
0629: codeStream.generateImplicitConversion(this .implicitConversion);
0630: codeStream.generateConstant(postIncrement.expression.constant,
0631: this .implicitConversion);
0632: codeStream.sendOperator(postIncrement.operator,
0633: this .implicitConversion & TypeIds.COMPILE_TYPE_MASK);
0634: codeStream
0635: .generateImplicitConversion(postIncrement.preAssignImplicitConversion);
0636: fieldStore(codeStream, lastFieldBinding,
0637: this .syntheticWriteAccessor, false);
0638: }
0639:
0640: /*
0641: * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
0642: * for a read or write access.
0643: */
0644: public FieldBinding generateReadSequence(BlockScope currentScope,
0645: CodeStream codeStream) {
0646: // determine the rank until which we now we do not need any actual value for the field access
0647: int otherBindingsCount = this .otherCodegenBindings == null ? 0
0648: : this .otherCodegenBindings.length;
0649: boolean needValue = otherBindingsCount == 0
0650: || !this .otherBindings[0].isStatic();
0651: FieldBinding lastFieldBinding = null;
0652: TypeBinding lastGenericCast = null;
0653: boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
0654:
0655: switch (this .bits & ASTNode.RestrictiveFlagMASK) {
0656: case Binding.FIELD:
0657: lastFieldBinding = (FieldBinding) this .codegenBinding;
0658: lastGenericCast = this .genericCast;
0659: // if first field is actually constant, we can inline it
0660: if (lastFieldBinding.constant() != Constant.NotAConstant) {
0661: break;
0662: }
0663: if ((needValue && !lastFieldBinding.isStatic())
0664: || lastGenericCast != null) {
0665: int pc = codeStream.position;
0666: if ((this .bits & ASTNode.DepthMASK) != 0) {
0667: ReferenceBinding targetType = currentScope
0668: .enclosingSourceType()
0669: .enclosingTypeAt(
0670: (this .bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
0671: Object[] emulationPath = currentScope
0672: .getEmulationPath(targetType,
0673: true /*only exact match*/, false/*consider enclosing arg*/);
0674: codeStream.generateOuterAccess(emulationPath, this ,
0675: targetType, currentScope);
0676: } else {
0677: generateReceiver(codeStream);
0678: }
0679: codeStream.recordPositionsFrom(pc, this .sourceStart);
0680: }
0681: break;
0682: case Binding.LOCAL: // reading the first local variable
0683: if (!needValue)
0684: break; // no value needed
0685: LocalVariableBinding localBinding = (LocalVariableBinding) this .codegenBinding;
0686: // regular local variable read
0687: Constant localConstant = localBinding.constant();
0688: if (localConstant != Constant.NotAConstant) {
0689: codeStream.generateConstant(localConstant, 0);
0690: // no implicit conversion
0691: } else {
0692: // outer local?
0693: if ((this .bits & ASTNode.DepthMASK) != 0) {
0694: // outer local can be reached either through a synthetic arg or a synthetic field
0695: VariableBinding[] path = currentScope
0696: .getEmulationPath(localBinding);
0697: codeStream.generateOuterAccess(path, this ,
0698: localBinding, currentScope);
0699: } else {
0700: codeStream.load(localBinding);
0701: }
0702: }
0703: }
0704:
0705: // all intermediate field accesses are read accesses
0706: // only the last field binding is a write access
0707: int positionsLength = this .sourcePositions.length;
0708: if (this .otherCodegenBindings != null) {
0709: for (int i = 0; i < otherBindingsCount; i++) {
0710: int pc = codeStream.position;
0711: FieldBinding nextField = this .otherCodegenBindings[i];
0712: TypeBinding nextGenericCast = this .otherGenericCasts == null ? null
0713: : this .otherGenericCasts[i];
0714: if (lastFieldBinding != null) {
0715: needValue = !nextField.isStatic();
0716: Constant fieldConstant = lastFieldBinding
0717: .constant();
0718: if (fieldConstant != Constant.NotAConstant) {
0719: if (i > 0 && !lastFieldBinding.isStatic()) {
0720: codeStream.invokeObjectGetClass(); // perform null check
0721: codeStream.pop();
0722: }
0723: if (needValue) {
0724: codeStream.generateConstant(fieldConstant,
0725: 0);
0726: }
0727: } else {
0728: if (needValue || (i > 0 && complyTo14)
0729: || lastGenericCast != null) {
0730: MethodBinding accessor = this .syntheticReadAccessors == null ? null
0731: : this .syntheticReadAccessors[i];
0732: if (accessor == null) {
0733: if (lastFieldBinding.isStatic()) {
0734: codeStream
0735: .getstatic(lastFieldBinding);
0736: } else {
0737: codeStream
0738: .getfield(lastFieldBinding);
0739: }
0740: } else {
0741: codeStream.invokestatic(accessor);
0742: }
0743: if (lastGenericCast != null)
0744: codeStream.checkcast(lastGenericCast);
0745: if (!needValue)
0746: codeStream.pop();
0747: } else {
0748: if (this .codegenBinding == lastFieldBinding) {
0749: if (lastFieldBinding.isStatic()) {
0750: // if no valueRequired, still need possible side-effects of <clinit> invocation, if field belongs to different class
0751: if (((FieldBinding) this .binding)
0752: .original().declaringClass != this .actualReceiverType
0753: .erasure()) {
0754: MethodBinding accessor = this .syntheticReadAccessors == null ? null
0755: : this .syntheticReadAccessors[i];
0756: if (accessor == null) {
0757: codeStream
0758: .getstatic(lastFieldBinding);
0759: } else {
0760: codeStream
0761: .invokestatic(accessor);
0762: }
0763: codeStream.pop();
0764: }
0765: }
0766: } else if (!lastFieldBinding.isStatic()) {
0767: codeStream.invokeObjectGetClass(); // perform null check
0768: codeStream.pop();
0769: }
0770: }
0771: if ((positionsLength - otherBindingsCount + i - 1) >= 0) {
0772: int fieldPosition = (int) (this .sourcePositions[positionsLength
0773: - otherBindingsCount + i - 1] >>> 32);
0774: codeStream.recordPositionsFrom(pc,
0775: fieldPosition);
0776: }
0777: }
0778: }
0779: lastFieldBinding = nextField;
0780: lastGenericCast = nextGenericCast;
0781: }
0782: }
0783: return lastFieldBinding;
0784: }
0785:
0786: public void generateReceiver(CodeStream codeStream) {
0787: codeStream.aload_0();
0788: }
0789:
0790: /**
0791: * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
0792: */
0793: public TypeBinding[] genericTypeArguments() {
0794: return null;
0795: }
0796:
0797: // get the matching codegenBinding
0798: protected FieldBinding getCodegenBinding(int index) {
0799: if (index == 0) {
0800: return (FieldBinding) this .codegenBinding;
0801: } else {
0802: return this .otherCodegenBindings[index - 1];
0803: }
0804: }
0805:
0806: // get the matching generic cast
0807: protected TypeBinding getGenericCast(int index) {
0808: if (index == 0) {
0809: return this .genericCast;
0810: } else {
0811: if (this .otherGenericCasts == null)
0812: return null;
0813: return this .otherGenericCasts[index - 1];
0814: }
0815: }
0816:
0817: public TypeBinding getOtherFieldBindings(BlockScope scope) {
0818: // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
0819: int length = this .tokens.length;
0820: FieldBinding field;
0821: if ((this .bits & Binding.FIELD) != 0) {
0822: field = (FieldBinding) this .binding;
0823: if (!field.isStatic()) {
0824: //must check for the static status....
0825: if (this .indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field
0826: || scope.methodScope().isStatic) { // the field is the first token of the qualified reference....
0827: scope.problemReporter()
0828: .staticFieldAccessToNonStaticVariable(this ,
0829: field);
0830: return null;
0831: }
0832: } else {
0833: // indirect static reference ?
0834: if (this .indexOfFirstFieldBinding > 1
0835: && field.declaringClass != this .actualReceiverType
0836: && field.declaringClass.canBeSeenBy(scope)) {
0837: scope.problemReporter()
0838: .indirectAccessToStaticField(this , field);
0839: }
0840: }
0841: // only last field is actually a write access if any
0842: if (isFieldUseDeprecated(field, scope,
0843: (this .bits & ASTNode.IsStrictlyAssigned) != 0
0844: && this .indexOfFirstFieldBinding == length))
0845: scope.problemReporter().deprecatedField(field, this );
0846: } else {
0847: field = null;
0848: }
0849: TypeBinding type = ((VariableBinding) this .binding).type;
0850: int index = this .indexOfFirstFieldBinding;
0851: if (index == length) { // restrictiveFlag == FIELD
0852: this .constant = ((FieldBinding) this .binding).constant();
0853: // perform capture conversion if read access
0854: return (type != null && (this .bits & ASTNode.IsStrictlyAssigned) == 0) ? type
0855: .capture(scope, this .sourceEnd)
0856: : type;
0857: }
0858: // allocation of the fieldBindings array and its respective constants
0859: int otherBindingsLength = length - index;
0860: this .otherCodegenBindings = this .otherBindings = new FieldBinding[otherBindingsLength];
0861: this .otherDepths = new int[otherBindingsLength];
0862:
0863: // fill the first constant (the one of the binding)
0864: this .constant = ((VariableBinding) this .binding).constant();
0865: // save first depth, since will be updated by visibility checks of other bindings
0866: int firstDepth = (this .bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
0867: // iteration on each field
0868: while (index < length) {
0869: char[] token = this .tokens[index];
0870: if (type == null)
0871: return null; // could not resolve type prior to this point
0872:
0873: this .bits &= ~ASTNode.DepthMASK; // flush previous depth if any
0874: FieldBinding previousField = field;
0875: field = scope.getField(type.capture(scope,
0876: (int) this .sourcePositions[index]), token, this );
0877: int place = index - this .indexOfFirstFieldBinding;
0878: this .otherBindings[place] = field;
0879: this .otherDepths[place] = (this .bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT;
0880: if (field.isValidBinding()) {
0881: // set generic cast of for previous field (if any)
0882: if (previousField != null) {
0883: TypeBinding fieldReceiverType = type;
0884: TypeBinding receiverErasure = type.erasure();
0885: if (receiverErasure instanceof ReferenceBinding) {
0886: if (receiverErasure
0887: .findSuperTypeWithSameErasure(field.declaringClass) == null) {
0888: fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound
0889: }
0890: }
0891: FieldBinding originalBinding = previousField
0892: .original();
0893: if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0
0894: && fieldReceiverType.id != TypeIds.T_JavaLangObject) {
0895: setGenericCast(index - 1, originalBinding.type
0896: .genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case
0897: }
0898: }
0899: // only last field is actually a write access if any
0900: if (isFieldUseDeprecated(field, scope,
0901: (this .bits & ASTNode.IsStrictlyAssigned) != 0
0902: && index + 1 == length)) {
0903: scope.problemReporter()
0904: .deprecatedField(field, this );
0905: }
0906: // constant propagation can only be performed as long as the previous one is a constant too.
0907: if (this .constant != Constant.NotAConstant) {
0908: this .constant = field.constant();
0909: }
0910:
0911: if (field.isStatic()) {
0912: // static field accessed through receiver? legal but unoptimal (optional warning)
0913: scope.problemReporter()
0914: .nonStaticAccessToStaticField(this , field,
0915: index);
0916: // indirect static reference ?
0917: if (field.declaringClass != type) {
0918: scope.problemReporter()
0919: .indirectAccessToStaticField(this ,
0920: field);
0921: }
0922: }
0923: type = field.type;
0924: index++;
0925: } else {
0926: this .constant = Constant.NotAConstant; //don't fill other constants slots...
0927: scope.problemReporter().invalidField(this , field,
0928: index, type);
0929: setDepth(firstDepth);
0930: return null;
0931: }
0932: }
0933: setDepth(firstDepth);
0934: type = (this .otherBindings[otherBindingsLength - 1]).type;
0935: // perform capture conversion if read access
0936: return (type != null && (this .bits & ASTNode.IsStrictlyAssigned) == 0) ? type
0937: .capture(scope, this .sourceEnd)
0938: : type;
0939: }
0940:
0941: public void manageEnclosingInstanceAccessIfNecessary(
0942: BlockScope currentScope, FlowInfo flowInfo) {
0943: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
0944: //If inlinable field, forget the access emulation, the code gen will directly target it
0945: if (((this .bits & ASTNode.DepthMASK) == 0)
0946: || (this .constant != Constant.NotAConstant)) {
0947: return;
0948: }
0949: if ((this .bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) {
0950: currentScope
0951: .emulateOuterAccess((LocalVariableBinding) this .binding);
0952: }
0953: }
0954: }
0955:
0956: /**
0957: * index is <0 to denote write access emulation
0958: */
0959: public void manageSyntheticAccessIfNecessary(
0960: BlockScope currentScope, FieldBinding fieldBinding,
0961: TypeBinding lastReceiverType, int index, FlowInfo flowInfo) {
0962: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
0963: return;
0964: // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
0965: if (fieldBinding.constant() != Constant.NotAConstant)
0966: return;
0967:
0968: // if field from parameterized type got found, use the original field at codegen time
0969: FieldBinding originalField = fieldBinding.original();
0970: if (originalField != fieldBinding) {
0971: setCodegenBinding(
0972: index < 0 ? (this .otherBindings == null ? 0
0973: : this .otherBindings.length) : index,
0974: originalField);
0975: }
0976:
0977: if (fieldBinding.isPrivate()) { // private access
0978: FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this .otherBindings == null ? 0
0979: : this .otherBindings.length)
0980: : index);
0981: if (someCodegenBinding.declaringClass != currentScope
0982: .enclosingSourceType()) {
0983: setSyntheticAccessor(
0984: fieldBinding,
0985: index,
0986: ((SourceTypeBinding) someCodegenBinding.declaringClass)
0987: .addSyntheticMethod(someCodegenBinding,
0988: index >= 0 /*read-access?*/));
0989: currentScope.problemReporter()
0990: .needToEmulateFieldAccess(someCodegenBinding,
0991: this , index >= 0 /*read-access?*/);
0992: return;
0993: }
0994: } else if (fieldBinding.isProtected()) {
0995: int depth = (index == 0 || (index < 0 && this .otherDepths == null)) ? (this .bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT
0996: : this .otherDepths[index < 0 ? this .otherDepths.length - 1
0997: : index - 1];
0998:
0999: // implicit protected access
1000: if (depth > 0
1001: && (fieldBinding.declaringClass.getPackage() != currentScope
1002: .enclosingSourceType().getPackage())) {
1003: FieldBinding someCodegenBinding = getCodegenBinding(index < 0 ? (this .otherBindings == null ? 0
1004: : this .otherBindings.length)
1005: : index);
1006: setSyntheticAccessor(fieldBinding, index,
1007: ((SourceTypeBinding) currentScope
1008: .enclosingSourceType().enclosingTypeAt(
1009: depth))
1010: .addSyntheticMethod(someCodegenBinding,
1011: index >= 0 /*read-access?*/));
1012: currentScope.problemReporter()
1013: .needToEmulateFieldAccess(someCodegenBinding,
1014: this , index >= 0 /*read-access?*/);
1015: return;
1016: }
1017: }
1018: // if the binding declaring class is not visible, need special action
1019: // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
1020: // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
1021: // and not from Object or implicit static field access.
1022: if (fieldBinding.declaringClass != lastReceiverType
1023: && !lastReceiverType.isArrayType()
1024: && fieldBinding.declaringClass != null // array.length
1025: && fieldBinding.constant() == Constant.NotAConstant) {
1026: CompilerOptions options = currentScope.compilerOptions();
1027: if ((options.targetJDK >= ClassFileConstants.JDK1_2
1028: && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(index <= 1
1029: && this .indexOfFirstFieldBinding == 1 && fieldBinding
1030: .isStatic())) && fieldBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object fields
1031: || !fieldBinding.declaringClass
1032: .canBeSeenBy(currentScope)) {
1033:
1034: setCodegenBinding(
1035: index < 0 ? (this .otherBindings == null ? 0
1036: : this .otherBindings.length) : index,
1037: currentScope
1038: .enclosingSourceType()
1039: .getUpdatedFieldBinding(
1040: getCodegenBinding(index < 0 ? (this .otherBindings == null ? 0
1041: : this .otherBindings.length)
1042: : index),
1043: (ReferenceBinding) lastReceiverType
1044: .erasure()));
1045: }
1046: }
1047: }
1048:
1049: public int nullStatus(FlowInfo flowInfo) {
1050: return FlowInfo.UNKNOWN;
1051: }
1052:
1053: public Constant optimizedBooleanConstant() {
1054: switch (this .resolvedType.id) {
1055: case T_boolean:
1056: case T_JavaLangBoolean:
1057: if (this .constant != Constant.NotAConstant)
1058: return this .constant;
1059: switch (this .bits & ASTNode.RestrictiveFlagMASK) {
1060: case Binding.FIELD: // reading a field
1061: if (this .otherBindings == null)
1062: return ((FieldBinding) this .binding).constant();
1063: // fall thru
1064: case Binding.LOCAL: // reading a local variable
1065: return this .otherBindings[this .otherBindings.length - 1]
1066: .constant();
1067: }
1068: }
1069: return Constant.NotAConstant;
1070: }
1071:
1072: /**
1073: * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
1074: */
1075: public TypeBinding postConversionType(Scope scope) {
1076: TypeBinding convertedType = this .resolvedType;
1077: TypeBinding requiredGenericCast = getGenericCast(this .otherCodegenBindings == null ? 0
1078: : this .otherCodegenBindings.length);
1079: if (requiredGenericCast != null)
1080: convertedType = requiredGenericCast;
1081: int runtimeType = (this .implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
1082: switch (runtimeType) {
1083: case T_boolean:
1084: convertedType = TypeBinding.BOOLEAN;
1085: break;
1086: case T_byte:
1087: convertedType = TypeBinding.BYTE;
1088: break;
1089: case T_short:
1090: convertedType = TypeBinding.SHORT;
1091: break;
1092: case T_char:
1093: convertedType = TypeBinding.CHAR;
1094: break;
1095: case T_int:
1096: convertedType = TypeBinding.INT;
1097: break;
1098: case T_float:
1099: convertedType = TypeBinding.FLOAT;
1100: break;
1101: case T_long:
1102: convertedType = TypeBinding.LONG;
1103: break;
1104: case T_double:
1105: convertedType = TypeBinding.DOUBLE;
1106: break;
1107: default:
1108: }
1109: if ((this .implicitConversion & TypeIds.BOXING) != 0) {
1110: convertedType = scope.environment().computeBoxingType(
1111: convertedType);
1112: }
1113: return convertedType;
1114: }
1115:
1116: public StringBuffer printExpression(int indent, StringBuffer output) {
1117: for (int i = 0; i < this .tokens.length; i++) {
1118: if (i > 0)
1119: output.append('.');
1120: output.append(this .tokens[i]);
1121: }
1122: return output;
1123: }
1124:
1125: /**
1126: * Normal field binding did not work, try to bind to a field of the delegate receiver.
1127: */
1128: public TypeBinding reportError(BlockScope scope) {
1129: if (this .binding instanceof ProblemFieldBinding) {
1130: scope.problemReporter().invalidField(this ,
1131: (FieldBinding) this .binding);
1132: } else if (this .binding instanceof ProblemReferenceBinding) {
1133: scope.problemReporter().invalidType(this ,
1134: (TypeBinding) this .binding);
1135: } else {
1136: scope.problemReporter().unresolvableReference(this ,
1137: this .binding);
1138: }
1139: return null;
1140: }
1141:
1142: public TypeBinding resolveType(BlockScope scope) {
1143: // field and/or local are done before type lookups
1144: // the only available value for the restrictiveFlag BEFORE
1145: // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
1146: this .actualReceiverType = scope.enclosingReceiverType();
1147: this .constant = Constant.NotAConstant;
1148: if ((this .codegenBinding = this .binding = scope.getBinding(
1149: this .tokens, this .bits & ASTNode.RestrictiveFlagMASK,
1150: this , true /*resolve*/)).isValidBinding()) {
1151: switch (this .bits & ASTNode.RestrictiveFlagMASK) {
1152: case Binding.VARIABLE: //============only variable===========
1153: case Binding.TYPE | Binding.VARIABLE:
1154: if (this .binding instanceof LocalVariableBinding) {
1155: if (!((LocalVariableBinding) this .binding)
1156: .isFinal()
1157: && ((this .bits & ASTNode.DepthMASK) != 0))
1158: scope
1159: .problemReporter()
1160: .cannotReferToNonFinalOuterLocal(
1161: (LocalVariableBinding) this .binding,
1162: this );
1163: this .bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1164: this .bits |= Binding.LOCAL;
1165: return this .resolvedType = getOtherFieldBindings(scope);
1166: }
1167: if (this .binding instanceof FieldBinding) {
1168: FieldBinding fieldBinding = (FieldBinding) this .binding;
1169: MethodScope methodScope = scope.methodScope();
1170: // check for forward references
1171: if (this .indexOfFirstFieldBinding == 1
1172: && methodScope.enclosingSourceType() == fieldBinding
1173: .original().declaringClass
1174: && methodScope.lastVisibleFieldID >= 0
1175: && fieldBinding.id >= methodScope.lastVisibleFieldID
1176: && (!fieldBinding.isStatic() || methodScope.isStatic)) {
1177: scope.problemReporter().forwardReference(this ,
1178: 0, methodScope.enclosingSourceType());
1179: }
1180: if (!fieldBinding.isStatic()
1181: && this .indexOfFirstFieldBinding == 1
1182: && scope
1183: .compilerOptions()
1184: .getSeverity(
1185: CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
1186: scope.problemReporter().unqualifiedFieldAccess(
1187: this , fieldBinding);
1188: }
1189: this .bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1190: this .bits |= Binding.FIELD;
1191:
1192: // // check for deprecated receiver type
1193: // // deprecation check for receiver type if not first token
1194: // if (indexOfFirstFieldBinding > 1) {
1195: // if (isTypeUseDeprecated(this.actualReceiverType, scope))
1196: // scope.problemReporter().deprecatedType(this.actualReceiverType, this);
1197: // }
1198:
1199: return this .resolvedType = getOtherFieldBindings(scope);
1200: }
1201: // thus it was a type
1202: this .bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
1203: this .bits |= Binding.TYPE;
1204: case Binding.TYPE: //=============only type ==============
1205: TypeBinding type = (TypeBinding) this .binding;
1206: // if (isTypeUseDeprecated(type, scope))
1207: // scope.problemReporter().deprecatedType(type, this);
1208: type = scope.environment().convertToRawType(type);
1209: return this .resolvedType = type;
1210: }
1211: }
1212: //========error cases===============
1213: return this .resolvedType = this .reportError(scope);
1214: }
1215:
1216: // set the matching codegenBinding and generic cast
1217: protected void setCodegenBinding(int index,
1218: FieldBinding someCodegenBinding) {
1219: if (index == 0) {
1220: this .codegenBinding = someCodegenBinding;
1221: } else {
1222: int length = this .otherBindings.length;
1223: if (this .otherCodegenBindings == this .otherBindings) {
1224: System
1225: .arraycopy(
1226: this .otherBindings,
1227: 0,
1228: this .otherCodegenBindings = new FieldBinding[length],
1229: 0, length);
1230: }
1231: this .otherCodegenBindings[index - 1] = someCodegenBinding;
1232: }
1233: }
1234:
1235: public void setFieldIndex(int index) {
1236: this .indexOfFirstFieldBinding = index;
1237: }
1238:
1239: // set the matching codegenBinding and generic cast
1240: protected void setGenericCast(int index, TypeBinding someGenericCast) {
1241: if (index == 0) {
1242: this .genericCast = someGenericCast;
1243: } else {
1244: if (this .otherGenericCasts == null) {
1245: this .otherGenericCasts = new TypeBinding[this .otherBindings.length];
1246: }
1247: this .otherGenericCasts[index - 1] = someGenericCast;
1248: }
1249: }
1250:
1251: // set the matching synthetic accessor
1252: protected void setSyntheticAccessor(FieldBinding fieldBinding,
1253: int index, SyntheticMethodBinding syntheticAccessor) {
1254: if (index < 0) { // write-access ?
1255: this .syntheticWriteAccessor = syntheticAccessor;
1256: } else {
1257: if (this .syntheticReadAccessors == null) {
1258: this .syntheticReadAccessors = new SyntheticMethodBinding[this .otherBindings == null ? 1
1259: : this .otherBindings.length + 1];
1260: }
1261: this .syntheticReadAccessors[index] = syntheticAccessor;
1262: }
1263: }
1264:
1265: public void traverse(ASTVisitor visitor, BlockScope scope) {
1266: visitor.visit(this , scope);
1267: visitor.endVisit(this , scope);
1268: }
1269:
1270: public void traverse(ASTVisitor visitor, ClassScope scope) {
1271: visitor.visit(this , scope);
1272: visitor.endVisit(this , scope);
1273: }
1274:
1275: public String unboundReferenceErrorName() {
1276: return new String(this .tokens[0]);
1277: }
1278: }
|