001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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 ArrayAllocationExpression extends Expression {
019:
020: public TypeReference type;
021:
022: //dimensions.length gives the number of dimensions, but the
023: // last ones may be nulled as in new int[4][5][][]
024: public Expression[] dimensions;
025: public ArrayInitializer initializer;
026:
027: public FlowInfo analyseCode(BlockScope currentScope,
028: FlowContext flowContext, FlowInfo flowInfo) {
029: for (int i = 0, max = this .dimensions.length; i < max; i++) {
030: Expression dim;
031: if ((dim = this .dimensions[i]) != null) {
032: flowInfo = dim.analyseCode(currentScope, flowContext,
033: flowInfo);
034: }
035: }
036: if (this .initializer != null) {
037: return this .initializer.analyseCode(currentScope,
038: flowContext, flowInfo);
039: }
040: return flowInfo;
041: }
042:
043: /**
044: * Code generation for a array allocation expression
045: */
046: public void generateCode(BlockScope currentScope,
047: CodeStream codeStream, boolean valueRequired) {
048:
049: int pc = codeStream.position;
050:
051: if (this .initializer != null) {
052: this .initializer.generateCode(currentScope, codeStream,
053: valueRequired);
054: return;
055: }
056:
057: int explicitDimCount = 0;
058: for (int i = 0, max = this .dimensions.length; i < max; i++) {
059: Expression dimExpression;
060: if ((dimExpression = this .dimensions[i]) == null)
061: break; // implicit dim, no further explict after this point
062: dimExpression.generateCode(currentScope, codeStream, true);
063: explicitDimCount++;
064: }
065:
066: // array allocation
067: if (explicitDimCount == 1) {
068: // Mono-dimensional array
069: codeStream.newArray((ArrayBinding) this .resolvedType);
070: } else {
071: // Multi-dimensional array
072: codeStream.multianewarray(this .resolvedType,
073: explicitDimCount);
074: }
075: if (valueRequired) {
076: codeStream
077: .generateImplicitConversion(this .implicitConversion);
078: } else {
079: codeStream.pop();
080: }
081: codeStream.recordPositionsFrom(pc, this .sourceStart);
082: }
083:
084: public StringBuffer printExpression(int indent, StringBuffer output) {
085: output.append("new "); //$NON-NLS-1$
086: this .type.print(0, output);
087: for (int i = 0; i < this .dimensions.length; i++) {
088: if (this .dimensions[i] == null)
089: output.append("[]"); //$NON-NLS-1$
090: else {
091: output.append('[');
092: this .dimensions[i].printExpression(0, output);
093: output.append(']');
094: }
095: }
096: if (this .initializer != null)
097: this .initializer.printExpression(0, output);
098: return output;
099: }
100:
101: public TypeBinding resolveType(BlockScope scope) {
102: // Build an array type reference using the current dimensions
103: // The parser does not check for the fact that dimension may be null
104: // only at the -end- like new int [4][][]. The parser allows new int[][4][]
105: // so this must be checked here......(this comes from a reduction to LL1 grammar)
106:
107: TypeBinding referenceType = this .type
108: .resolveType(scope, true /* check bounds*/);
109:
110: // will check for null after dimensions are checked
111: this .constant = Constant.NotAConstant;
112: if (referenceType == TypeBinding.VOID) {
113: scope.problemReporter().cannotAllocateVoidArray(this );
114: referenceType = null;
115: }
116:
117: // check the validity of the dimension syntax (and test for all null dimensions)
118: int explicitDimIndex = -1;
119: loop: for (int i = this .dimensions.length; --i >= 0;) {
120: if (this .dimensions[i] != null) {
121: if (explicitDimIndex < 0)
122: explicitDimIndex = i;
123: } else if (explicitDimIndex > 0) {
124: // should not have an empty dimension before an non-empty one
125: scope.problemReporter()
126: .incorrectLocationForNonEmptyDimension(this ,
127: explicitDimIndex);
128: break loop;
129: }
130: }
131:
132: // explicitDimIndex < 0 says if all dimensions are nulled
133: // when an initializer is given, no dimension must be specified
134: if (this .initializer == null) {
135: if (explicitDimIndex < 0) {
136: scope.problemReporter()
137: .mustDefineDimensionsOrInitializer(this );
138: }
139: // allow new List<?>[5] - only check for generic array when no initializer, since also checked inside initializer resolution
140: if (referenceType != null && !referenceType.isReifiable()) {
141: scope.problemReporter().illegalGenericArray(
142: referenceType, this );
143: }
144: } else if (explicitDimIndex >= 0) {
145: scope.problemReporter()
146: .cannotDefineDimensionsAndInitializer(this );
147: }
148:
149: // dimensions resolution
150: for (int i = 0; i <= explicitDimIndex; i++) {
151: Expression dimExpression;
152: if ((dimExpression = this .dimensions[i]) != null) {
153: TypeBinding dimensionType = dimExpression
154: .resolveTypeExpecting(scope, TypeBinding.INT);
155: if (dimensionType != null) {
156: this .dimensions[i].computeConversion(scope,
157: TypeBinding.INT, dimensionType);
158: }
159: }
160: }
161:
162: // building the array binding
163: if (referenceType != null) {
164: if (this .dimensions.length > 255) {
165: scope.problemReporter().tooManyDimensions(this );
166: }
167: this .resolvedType = scope.createArrayType(referenceType,
168: this .dimensions.length);
169:
170: // check the initializer
171: if (this .initializer != null) {
172: if ((this .initializer.resolveTypeExpecting(scope,
173: this .resolvedType)) != null)
174: this .initializer.binding = (ArrayBinding) this .resolvedType;
175: }
176: }
177: return this .resolvedType;
178: }
179:
180: public void traverse(ASTVisitor visitor, BlockScope scope) {
181: if (visitor.visit(this , scope)) {
182: int dimensionsLength = this .dimensions.length;
183: this .type.traverse(visitor, scope);
184: for (int i = 0; i < dimensionsLength; i++) {
185: if (this.dimensions[i] != null)
186: this.dimensions[i].traverse(visitor, scope);
187: }
188: if (this.initializer != null)
189: this.initializer.traverse(visitor, scope);
190: }
191: visitor.endVisit(this, scope);
192: }
193: }
|