001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.impl.*;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.lookup.*;
017:
018: public class ArrayReference extends Reference {
019:
020: public Expression receiver;
021: public Expression position;
022:
023: public ArrayReference(Expression rec, Expression pos) {
024: this .receiver = rec;
025: this .position = pos;
026: sourceStart = rec.sourceStart;
027: }
028:
029: public FlowInfo analyseAssignment(BlockScope currentScope,
030: FlowContext flowContext, FlowInfo flowInfo,
031: Assignment assignment, boolean compoundAssignment) {
032: // TODO (maxime) optimization: unconditionalInits is applied to all existing calls
033: if (assignment.expression == null) {
034: return analyseCode(currentScope, flowContext, flowInfo);
035: }
036: return assignment.expression.analyseCode(currentScope,
037: flowContext, analyseCode(currentScope, flowContext,
038: flowInfo).unconditionalInits());
039: }
040:
041: public FlowInfo analyseCode(BlockScope currentScope,
042: FlowContext flowContext, FlowInfo flowInfo) {
043: receiver.checkNPE(currentScope, flowContext, flowInfo);
044: flowInfo = receiver.analyseCode(currentScope, flowContext,
045: flowInfo);
046: return position
047: .analyseCode(currentScope, flowContext, flowInfo);
048: }
049:
050: public void generateAssignment(BlockScope currentScope,
051: CodeStream codeStream, Assignment assignment,
052: boolean valueRequired) {
053:
054: int pc = codeStream.position;
055: receiver.generateCode(currentScope, codeStream, true);
056: if (receiver instanceof CastExpression // ((type[])null)[0]
057: && ((CastExpression) receiver)
058: .innermostCastedExpression().resolvedType == TypeBinding.NULL) {
059: codeStream.checkcast(receiver.resolvedType);
060: }
061: codeStream.recordPositionsFrom(pc, this .sourceStart);
062: position.generateCode(currentScope, codeStream, true);
063: assignment.expression.generateCode(currentScope, codeStream,
064: true);
065: codeStream.arrayAtPut(this .resolvedType.id, valueRequired);
066: if (valueRequired) {
067: codeStream
068: .generateImplicitConversion(assignment.implicitConversion);
069: }
070: }
071:
072: /**
073: * Code generation for a array reference
074: */
075: public void generateCode(BlockScope currentScope,
076: CodeStream codeStream, boolean valueRequired) {
077:
078: int pc = codeStream.position;
079: receiver.generateCode(currentScope, codeStream, true);
080: if (receiver instanceof CastExpression // ((type[])null)[0]
081: && ((CastExpression) receiver)
082: .innermostCastedExpression().resolvedType == TypeBinding.NULL) {
083: codeStream.checkcast(receiver.resolvedType);
084: }
085: position.generateCode(currentScope, codeStream, true);
086: codeStream.arrayAt(this .resolvedType.id);
087: // Generating code for the potential runtime type checking
088: if (valueRequired) {
089: codeStream.generateImplicitConversion(implicitConversion);
090: } else {
091: boolean isUnboxing = (implicitConversion & TypeIds.UNBOXING) != 0;
092: // conversion only generated if unboxing
093: if (isUnboxing)
094: codeStream
095: .generateImplicitConversion(implicitConversion);
096: switch (isUnboxing ? postConversionType(currentScope).id
097: : this .resolvedType.id) {
098: case T_long:
099: case T_double:
100: codeStream.pop2();
101: break;
102: default:
103: codeStream.pop();
104: }
105: }
106: codeStream.recordPositionsFrom(pc, this .sourceStart);
107: }
108:
109: public void generateCompoundAssignment(BlockScope currentScope,
110: CodeStream codeStream, Expression expression, int operator,
111: int assignmentImplicitConversion, boolean valueRequired) {
112:
113: receiver.generateCode(currentScope, codeStream, true);
114: if (receiver instanceof CastExpression // ((type[])null)[0]
115: && ((CastExpression) receiver)
116: .innermostCastedExpression().resolvedType == TypeBinding.NULL) {
117: codeStream.checkcast(receiver.resolvedType);
118: }
119: position.generateCode(currentScope, codeStream, true);
120: codeStream.dup2();
121: codeStream.arrayAt(this .resolvedType.id);
122: int operationTypeID;
123: switch (operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
124: case T_JavaLangString:
125: case T_JavaLangObject:
126: case T_undefined:
127: codeStream.generateStringConcatenationAppend(currentScope,
128: null, expression);
129: break;
130: default:
131: // promote the array reference to the suitable operation type
132: codeStream.generateImplicitConversion(implicitConversion);
133: // generate the increment value (will by itself be promoted to the operation value)
134: if (expression == IntLiteral.One) { // prefix operation
135: codeStream.generateConstant(expression.constant,
136: implicitConversion);
137: } else {
138: expression.generateCode(currentScope, codeStream, true);
139: }
140: // perform the operation
141: codeStream.sendOperator(operator, operationTypeID);
142: // cast the value back to the array reference type
143: codeStream
144: .generateImplicitConversion(assignmentImplicitConversion);
145: }
146: codeStream.arrayAtPut(this .resolvedType.id, valueRequired);
147: }
148:
149: public void generatePostIncrement(BlockScope currentScope,
150: CodeStream codeStream, CompoundAssignment postIncrement,
151: boolean valueRequired) {
152:
153: receiver.generateCode(currentScope, codeStream, true);
154: if (receiver instanceof CastExpression // ((type[])null)[0]
155: && ((CastExpression) receiver)
156: .innermostCastedExpression().resolvedType == TypeBinding.NULL) {
157: codeStream.checkcast(receiver.resolvedType);
158: }
159: position.generateCode(currentScope, codeStream, true);
160: codeStream.dup2();
161: codeStream.arrayAt(this .resolvedType.id);
162: if (valueRequired) {
163: if ((this .resolvedType == TypeBinding.LONG)
164: || (this .resolvedType == TypeBinding.DOUBLE)) {
165: codeStream.dup2_x2();
166: } else {
167: codeStream.dup_x2();
168: }
169: }
170: codeStream.generateImplicitConversion(implicitConversion);
171: codeStream.generateConstant(postIncrement.expression.constant,
172: implicitConversion);
173: codeStream.sendOperator(postIncrement.operator,
174: this .implicitConversion & COMPILE_TYPE_MASK);
175: codeStream
176: .generateImplicitConversion(postIncrement.preAssignImplicitConversion);
177: codeStream.arrayAtPut(this .resolvedType.id, false);
178: }
179:
180: public int nullStatus(FlowInfo flowInfo) {
181: return FlowInfo.UNKNOWN;
182: }
183:
184: public StringBuffer printExpression(int indent, StringBuffer output) {
185:
186: receiver.printExpression(0, output).append('[');
187: return position.printExpression(0, output).append(']');
188: }
189:
190: public TypeBinding resolveType(BlockScope scope) {
191:
192: constant = Constant.NotAConstant;
193: if (receiver instanceof CastExpression // no cast check for ((type[])null)[0]
194: && ((CastExpression) receiver)
195: .innermostCastedExpression() instanceof NullLiteral) {
196: this .receiver.bits |= DisableUnnecessaryCastCheck; // will check later on
197: }
198: TypeBinding arrayType = receiver.resolveType(scope);
199: if (arrayType != null) {
200: receiver.computeConversion(scope, arrayType, arrayType);
201: if (arrayType.isArrayType()) {
202: TypeBinding elementType = ((ArrayBinding) arrayType)
203: .elementsType();
204: this .resolvedType = ((this .bits & IsStrictlyAssigned) == 0) ? elementType
205: .capture(scope, this .sourceEnd)
206: : elementType;
207: } else {
208: scope.problemReporter().referenceMustBeArrayTypeAt(
209: arrayType, this );
210: }
211: }
212: TypeBinding positionType = position.resolveTypeExpecting(scope,
213: TypeBinding.INT);
214: if (positionType != null) {
215: position.computeConversion(scope, TypeBinding.INT,
216: positionType);
217: }
218: return this .resolvedType;
219: }
220:
221: public void traverse(ASTVisitor visitor, BlockScope scope) {
222:
223: if (visitor.visit(this, scope)) {
224: receiver.traverse(visitor, scope);
225: position.traverse(visitor, scope);
226: }
227: visitor.endVisit(this, scope);
228: }
229: }
|