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.Constant;
014: import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
015: import org.eclipse.jdt.internal.compiler.lookup.Binding;
016: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
017: import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
018: import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
019: import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
020: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
021:
022: /**
023: * MemberValuePair node
024: */
025: public class MemberValuePair extends ASTNode {
026:
027: public char[] name;
028: public Expression value;
029: public MethodBinding binding;
030: /**
031: * The representation of this pair in the type system.
032: */
033: public ElementValuePair compilerElementPair = null;
034:
035: public MemberValuePair(char[] token, int sourceStart,
036: int sourceEnd, Expression value) {
037: this .name = token;
038: this .sourceStart = sourceStart;
039: this .sourceEnd = sourceEnd;
040: this .value = value;
041: if (value instanceof ArrayInitializer) {
042: value.bits |= IsAnnotationDefaultValue;
043: }
044: }
045:
046: /* (non-Javadoc)
047: * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#print(int, java.lang.StringBuffer)
048: */
049: public StringBuffer print(int indent, StringBuffer output) {
050: output.append(name).append(" = "); //$NON-NLS-1$
051: value.print(0, output);
052: return output;
053: }
054:
055: public void resolveTypeExpecting(BlockScope scope,
056: TypeBinding requiredType) {
057:
058: if (this .value == null) {
059: this .compilerElementPair = new ElementValuePair(this .name,
060: this .value, this .binding);
061: return;
062: }
063: if (requiredType == null) {
064: // fault tolerance: keep resolving
065: if (this .value instanceof ArrayInitializer) {
066: this .value.resolveTypeExpecting(scope, null);
067: } else {
068: this .value.resolveType(scope);
069: }
070: this .compilerElementPair = new ElementValuePair(this .name,
071: this .value, this .binding);
072: return;
073: }
074:
075: this .value.setExpectedType(requiredType); // needed in case of generic method invocation
076: TypeBinding valueType;
077: if (this .value instanceof ArrayInitializer) {
078: ArrayInitializer initializer = (ArrayInitializer) this .value;
079: valueType = initializer.resolveTypeExpecting(scope,
080: this .binding.returnType);
081: } else if (this .value instanceof ArrayAllocationExpression) {
082: scope.problemReporter()
083: .annotationValueMustBeArrayInitializer(
084: this .binding.declaringClass, this .name,
085: this .value);
086: this .value.resolveType(scope);
087: valueType = null; // no need to pursue
088: } else {
089: valueType = this .value.resolveType(scope);
090: }
091: this .compilerElementPair = new ElementValuePair(this .name,
092: this .value, this .binding);
093: if (valueType == null)
094: return;
095:
096: TypeBinding leafType = requiredType.leafComponentType();
097: if (!((this .value.isConstantValueOfTypeAssignableToType(
098: valueType, requiredType) || (requiredType.isBaseType() && BaseTypeBinding
099: .isWidening(requiredType.id, valueType.id))) || valueType
100: .isCompatibleWith(requiredType))) {
101:
102: if (!(requiredType.isArrayType()
103: && requiredType.dimensions() == 1
104: && (this .value
105: .isConstantValueOfTypeAssignableToType(
106: valueType, leafType) || (leafType
107: .isBaseType() && BaseTypeBinding
108: .isWidening(leafType.id, valueType.id))) || valueType
109: .isCompatibleWith(leafType))) {
110:
111: if (leafType.isAnnotationType()
112: && !valueType.isAnnotationType()) {
113: scope.problemReporter()
114: .annotationValueMustBeAnnotation(
115: this .binding.declaringClass,
116: this .name, this .value, leafType);
117: } else {
118: scope.problemReporter().typeMismatchError(
119: valueType, requiredType, this .value);
120: }
121: return; // may allow to proceed to find more errors at once
122: }
123: } else {
124: scope.compilationUnitScope().recordTypeConversion(
125: requiredType.leafComponentType(),
126: valueType.leafComponentType());
127: this .value
128: .computeConversion(scope, requiredType, valueType);
129: }
130:
131: // annotation methods can only return base types, String, Class, enum type, annotation types and arrays of these
132: checkAnnotationMethodType: {
133: switch (leafType.erasure().id) {
134: case T_byte:
135: case T_short:
136: case T_char:
137: case T_int:
138: case T_long:
139: case T_float:
140: case T_double:
141: case T_boolean:
142: case T_JavaLangString:
143: if (this .value instanceof ArrayInitializer) {
144: ArrayInitializer initializer = (ArrayInitializer) this .value;
145: final Expression[] expressions = initializer.expressions;
146: if (expressions != null) {
147: for (int i = 0, max = expressions.length; i < max; i++) {
148: Expression expression = expressions[i];
149: if (expression.resolvedType == null)
150: continue; // fault-tolerance
151: if (expression.constant == Constant.NotAConstant) {
152: scope
153: .problemReporter()
154: .annotationValueMustBeConstant(
155: this .binding.declaringClass,
156: this .name,
157: expressions[i], false);
158: }
159: }
160: }
161: } else if (this .value.constant == Constant.NotAConstant) {
162: if (valueType.isArrayType()) {
163: scope.problemReporter()
164: .annotationValueMustBeArrayInitializer(
165: this .binding.declaringClass,
166: this .name, this .value);
167: } else {
168: scope.problemReporter()
169: .annotationValueMustBeConstant(
170: this .binding.declaringClass,
171: this .name, this .value, false);
172: }
173: }
174: break checkAnnotationMethodType;
175: case T_JavaLangClass:
176: if (this .value instanceof ArrayInitializer) {
177: ArrayInitializer initializer = (ArrayInitializer) this .value;
178: final Expression[] expressions = initializer.expressions;
179: if (expressions != null) {
180: for (int i = 0, max = expressions.length; i < max; i++) {
181: Expression currentExpression = expressions[i];
182: if (!(currentExpression instanceof ClassLiteralAccess)) {
183: scope
184: .problemReporter()
185: .annotationValueMustBeClassLiteral(
186: this .binding.declaringClass,
187: this .name,
188: currentExpression);
189: }
190: }
191: }
192: } else if (!(this .value instanceof ClassLiteralAccess)) {
193: scope.problemReporter()
194: .annotationValueMustBeClassLiteral(
195: this .binding.declaringClass,
196: this .name, this .value);
197: }
198: break checkAnnotationMethodType;
199: }
200: if (leafType.isEnum()) {
201: if (this .value instanceof NullLiteral) {
202: scope.problemReporter()
203: .annotationValueMustBeConstant(
204: this .binding.declaringClass,
205: this .name, this .value, true);
206: } else if (this .value instanceof ArrayInitializer) {
207: ArrayInitializer initializer = (ArrayInitializer) this .value;
208: final Expression[] expressions = initializer.expressions;
209: if (expressions != null) {
210: for (int i = 0, max = expressions.length; i < max; i++) {
211: Expression currentExpression = expressions[i];
212: if (currentExpression instanceof NullLiteral) {
213: scope
214: .problemReporter()
215: .annotationValueMustBeConstant(
216: this .binding.declaringClass,
217: this .name,
218: currentExpression, true);
219: } else if (currentExpression instanceof NameReference) {
220: NameReference nameReference = (NameReference) currentExpression;
221: final Binding nameReferenceBinding = nameReference.binding;
222: if (nameReferenceBinding.kind() == Binding.FIELD) {
223: FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding;
224: if (!fieldBinding.declaringClass
225: .isEnum()) {
226: scope
227: .problemReporter()
228: .annotationValueMustBeConstant(
229: this .binding.declaringClass,
230: this .name,
231: currentExpression,
232: true);
233: }
234: }
235: }
236: }
237: }
238: } else if (this .value instanceof NameReference) {
239: NameReference nameReference = (NameReference) this .value;
240: final Binding nameReferenceBinding = nameReference.binding;
241: if (nameReferenceBinding.kind() == Binding.FIELD) {
242: FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding;
243: if (!fieldBinding.declaringClass.isEnum()) {
244: if (!fieldBinding.type.isArrayType()) {
245: scope
246: .problemReporter()
247: .annotationValueMustBeConstant(
248: this .binding.declaringClass,
249: this .name, this .value,
250: true);
251: } else {
252: scope
253: .problemReporter()
254: .annotationValueMustBeArrayInitializer(
255: this .binding.declaringClass,
256: this .name, this .value);
257: }
258: }
259: }
260: }
261: break checkAnnotationMethodType;
262: }
263: if (leafType.isAnnotationType()) {
264: if (!valueType.leafComponentType().isAnnotationType()) { // check annotation type and also reject null literal
265: scope.problemReporter()
266: .annotationValueMustBeAnnotation(
267: this .binding.declaringClass,
268: this .name, this .value, leafType);
269: } else if (this .value instanceof ArrayInitializer) {
270: ArrayInitializer initializer = (ArrayInitializer) this .value;
271: final Expression[] expressions = initializer.expressions;
272: if (expressions != null) {
273: for (int i = 0, max = expressions.length; i < max; i++) {
274: Expression currentExpression = expressions[i];
275: if (currentExpression instanceof NullLiteral
276: || !(currentExpression instanceof Annotation)) {
277: scope
278: .problemReporter()
279: .annotationValueMustBeAnnotation(
280: this .binding.declaringClass,
281: this .name,
282: currentExpression,
283: leafType);
284: }
285: }
286: }
287: } else if (!(this .value instanceof Annotation)) {
288: scope.problemReporter()
289: .annotationValueMustBeAnnotation(
290: this .binding.declaringClass,
291: this .name, this .value, leafType);
292: }
293: break checkAnnotationMethodType;
294: }
295: }
296: }
297:
298: public void traverse(ASTVisitor visitor, BlockScope scope) {
299: if (visitor.visit(this, scope)) {
300: if (this.value != null) {
301: this.value.traverse(visitor, scope);
302: }
303: }
304: visitor.endVisit(this, scope);
305: }
306: }
|