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.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.impl.Constant;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class ArrayInitializer extends Expression {
020:
021: public Expression[] expressions;
022: public ArrayBinding binding; //the type of the { , , , }
023:
024: /**
025: * ArrayInitializer constructor comment.
026: */
027: public ArrayInitializer() {
028:
029: super ();
030: }
031:
032: public FlowInfo analyseCode(BlockScope currentScope,
033: FlowContext flowContext, FlowInfo flowInfo) {
034:
035: if (expressions != null) {
036: for (int i = 0, max = expressions.length; i < max; i++) {
037: flowInfo = expressions[i].analyseCode(currentScope,
038: flowContext, flowInfo).unconditionalInits();
039: }
040: }
041: return flowInfo;
042: }
043:
044: /**
045: * Code generation for a array initializer
046: */
047: public void generateCode(BlockScope currentScope,
048: CodeStream codeStream, boolean valueRequired) {
049:
050: // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers
051: int pc = codeStream.position;
052: int expressionLength = (expressions == null) ? 0
053: : expressions.length;
054: codeStream.generateInlinedValue(expressionLength);
055: codeStream.newArray(binding);
056: if (expressions != null) {
057: // binding is an ArrayType, so I can just deal with the dimension
058: int elementsTypeID = binding.dimensions > 1 ? -1
059: : binding.leafComponentType.id;
060: for (int i = 0; i < expressionLength; i++) {
061: Expression expr;
062: if ((expr = expressions[i]).constant != Constant.NotAConstant) {
063: switch (elementsTypeID) { // filter out initializations to default values
064: case T_int:
065: case T_short:
066: case T_byte:
067: case T_char:
068: case T_long:
069: if (expr.constant.longValue() != 0) {
070: codeStream.dup();
071: codeStream.generateInlinedValue(i);
072: expr.generateCode(currentScope, codeStream,
073: true);
074: codeStream
075: .arrayAtPut(elementsTypeID, false);
076: }
077: break;
078: case T_float:
079: case T_double:
080: double constantValue = expr.constant
081: .doubleValue();
082: if (constantValue == -0.0 || constantValue != 0) {
083: codeStream.dup();
084: codeStream.generateInlinedValue(i);
085: expr.generateCode(currentScope, codeStream,
086: true);
087: codeStream
088: .arrayAtPut(elementsTypeID, false);
089: }
090: break;
091: case T_boolean:
092: if (expr.constant.booleanValue() != false) {
093: codeStream.dup();
094: codeStream.generateInlinedValue(i);
095: expr.generateCode(currentScope, codeStream,
096: true);
097: codeStream
098: .arrayAtPut(elementsTypeID, false);
099: }
100: break;
101: default:
102: if (!(expr instanceof NullLiteral)) {
103: codeStream.dup();
104: codeStream.generateInlinedValue(i);
105: expr.generateCode(currentScope, codeStream,
106: true);
107: codeStream
108: .arrayAtPut(elementsTypeID, false);
109: }
110: }
111: } else if (!(expr instanceof NullLiteral)) {
112: codeStream.dup();
113: codeStream.generateInlinedValue(i);
114: expr.generateCode(currentScope, codeStream, true);
115: codeStream.arrayAtPut(elementsTypeID, false);
116: }
117: }
118: }
119: if (valueRequired) {
120: codeStream
121: .generateImplicitConversion(this .implicitConversion);
122: } else {
123: codeStream.pop();
124: }
125: codeStream.recordPositionsFrom(pc, this .sourceStart);
126: }
127:
128: public StringBuffer printExpression(int indent, StringBuffer output) {
129:
130: output.append('{');
131: if (expressions != null) {
132: int j = 20;
133: for (int i = 0; i < expressions.length; i++) {
134: if (i > 0)
135: output.append(", "); //$NON-NLS-1$
136: expressions[i].printExpression(0, output);
137: j--;
138: if (j == 0) {
139: output.append('\n');
140: printIndent(indent + 1, output);
141: j = 20;
142: }
143: }
144: }
145: return output.append('}');
146: }
147:
148: public TypeBinding resolveTypeExpecting(BlockScope scope,
149: TypeBinding expectedType) {
150: // Array initializers can only occur on the right hand side of an assignment
151: // expression, therefore the expected type contains the valid information
152: // concerning the type that must be enforced by the elements of the array initializer.
153:
154: // this method is recursive... (the test on isArrayType is the stop case)
155:
156: this .constant = Constant.NotAConstant;
157:
158: if (expectedType instanceof ArrayBinding) {
159: // allow new List<?>[5]
160: if ((this .bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7
161: // allow new List<?>[5] - only check for generic array when no initializer, since also checked inside initializer resolution
162: TypeBinding leafComponentType = expectedType
163: .leafComponentType();
164: if (!leafComponentType.isReifiable()) {
165: scope.problemReporter().illegalGenericArray(
166: leafComponentType, this );
167: }
168: }
169: this .resolvedType = this .binding = (ArrayBinding) expectedType;
170: if (this .expressions == null)
171: return this .binding;
172: TypeBinding elementType = this .binding.elementsType();
173: for (int i = 0, length = this .expressions.length; i < length; i++) {
174: Expression expression = this .expressions[i];
175: expression.setExpectedType(elementType);
176: TypeBinding expressionType = expression instanceof ArrayInitializer ? expression
177: .resolveTypeExpecting(scope, elementType)
178: : expression.resolveType(scope);
179: if (expressionType == null)
180: continue;
181:
182: // Compile-time conversion required?
183: if (elementType != expressionType) // must call before computeConversion() and typeMismatchError()
184: scope.compilationUnitScope().recordTypeConversion(
185: elementType, expressionType);
186:
187: if ((expression.isConstantValueOfTypeAssignableToType(
188: expressionType, elementType) || (elementType
189: .isBaseType() && BaseTypeBinding.isWidening(
190: elementType.id, expressionType.id)))
191: || expressionType.isCompatibleWith(elementType)) {
192: expression.computeConversion(scope, elementType,
193: expressionType);
194: } else if (scope.isBoxingCompatibleWith(expressionType,
195: elementType)
196: || (expressionType.isBaseType() // narrowing then boxing ?
197: && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
198: && !elementType.isBaseType() && expression
199: .isConstantValueOfTypeAssignableToType(
200: expressionType, scope
201: .environment()
202: .computeBoxingType(
203: elementType)))) {
204: expression.computeConversion(scope, elementType,
205: expressionType);
206: } else {
207: scope.problemReporter().typeMismatchError(
208: expressionType, elementType, expression);
209: }
210: }
211: return this .binding;
212: }
213:
214: // infer initializer type for error reporting based on first element
215: TypeBinding leafElementType = null;
216: int dim = 1;
217: if (this .expressions == null) {
218: leafElementType = scope.getJavaLangObject();
219: } else {
220: Expression expression = this .expressions[0];
221: while (expression != null
222: && expression instanceof ArrayInitializer) {
223: dim++;
224: Expression[] subExprs = ((ArrayInitializer) expression).expressions;
225: if (subExprs == null) {
226: leafElementType = scope.getJavaLangObject();
227: expression = null;
228: break;
229: }
230: expression = ((ArrayInitializer) expression).expressions[0];
231: }
232: if (expression != null) {
233: leafElementType = expression.resolveType(scope);
234: }
235: // fault-tolerance - resolve other expressions as well
236: for (int i = 1, length = this .expressions.length; i < length; i++) {
237: expression = this .expressions[i];
238: if (expression != null) {
239: expression.resolveType(scope);
240: }
241: }
242: }
243: if (leafElementType != null) {
244: this .resolvedType = scope.createArrayType(leafElementType,
245: dim);
246: if (expectedType != null)
247: scope.problemReporter().typeMismatchError(
248: this .resolvedType, expectedType, this );
249: }
250: return null;
251: }
252:
253: public void traverse(ASTVisitor visitor, BlockScope scope) {
254:
255: if (visitor.visit(this , scope)) {
256: if (this .expressions != null) {
257: int expressionsLength = this .expressions.length;
258: for (int i = 0; i < expressionsLength; i++)
259: this.expressions[i].traverse(visitor, scope);
260: }
261: }
262: visitor.endVisit(this, scope);
263: }
264: }
|