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.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.ASTVisitor;
014: import org.eclipse.jdt.internal.compiler.impl.Constant;
015: import org.eclipse.jdt.internal.compiler.lookup.*;
016:
017: /**
018: * Syntactic representation of a reference to a generic type.
019: * Note that it might also have a dimension.
020: */
021: public class ParameterizedQualifiedTypeReference extends
022: ArrayQualifiedTypeReference {
023:
024: public TypeReference[][] typeArguments;
025:
026: /**
027: * @param tokens
028: * @param dim
029: * @param positions
030: */
031: public ParameterizedQualifiedTypeReference(char[][] tokens,
032: TypeReference[][] typeArguments, int dim, long[] positions) {
033:
034: super (tokens, dim, positions);
035: this .typeArguments = typeArguments;
036: }
037:
038: public void checkBounds(Scope scope) {
039: if (this .resolvedType == null)
040: return;
041:
042: checkBounds((ReferenceBinding) this .resolvedType
043: .leafComponentType(), scope,
044: this .typeArguments.length - 1);
045: }
046:
047: public void checkBounds(ReferenceBinding type, Scope scope,
048: int index) {
049: // recurse on enclosing type if any, and assuming explictly part of the reference (index>0)
050: if (index > 0 && type.enclosingType() != null) {
051: checkBounds(type.enclosingType(), scope, index - 1);
052: }
053: if (type.isParameterizedType()) {
054: ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
055: ReferenceBinding currentType = parameterizedType
056: .genericType();
057: TypeVariableBinding[] typeVariables = currentType
058: .typeVariables();
059: TypeBinding[] argTypes = parameterizedType.arguments;
060: if (argTypes != null && typeVariables != null) { // argTypes may be null in error cases
061: parameterizedType.boundCheck(scope,
062: this .typeArguments[index]);
063: }
064: }
065: }
066:
067: public TypeReference copyDims(int dim) {
068: return new ParameterizedQualifiedTypeReference(this .tokens,
069: this .typeArguments, dim, this .sourcePositions);
070: }
071:
072: /**
073: * @return char[][]
074: */
075: public char[][] getParameterizedTypeName() {
076: int length = this .tokens.length;
077: char[][] qParamName = new char[length][];
078: for (int i = 0; i < length; i++) {
079: TypeReference[] arguments = this .typeArguments[i];
080: if (arguments == null) {
081: qParamName[i] = this .tokens[i];
082: } else {
083: StringBuffer buffer = new StringBuffer(5);
084: buffer.append(this .tokens[i]);
085: buffer.append('<');
086: for (int j = 0, argLength = arguments.length; j < argLength; j++) {
087: if (j > 0)
088: buffer.append(',');
089: buffer.append(CharOperation.concatWith(arguments[j]
090: .getParameterizedTypeName(), '.'));
091: }
092: buffer.append('>');
093: int nameLength = buffer.length();
094: qParamName[i] = new char[nameLength];
095: buffer.getChars(0, nameLength, qParamName[i], 0);
096: }
097: }
098: int dim = this .dimensions;
099: if (dim > 0) {
100: char[] dimChars = new char[dim * 2];
101: for (int i = 0; i < dim; i++) {
102: int index = i * 2;
103: dimChars[index] = '[';
104: dimChars[index + 1] = ']';
105: }
106: qParamName[length - 1] = CharOperation.concat(
107: qParamName[length - 1], dimChars);
108: }
109: return qParamName;
110: }
111:
112: /* (non-Javadoc)
113: * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
114: */
115: protected TypeBinding getTypeBinding(Scope scope) {
116: return null; // not supported here - combined with resolveType(...)
117: }
118:
119: /*
120: * No need to check for reference to raw type per construction
121: */
122: private TypeBinding internalResolveType(Scope scope,
123: boolean checkBounds) {
124:
125: // handle the error here
126: this .constant = Constant.NotAConstant;
127: if ((this .bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved
128: if (this .resolvedType != null
129: && !this .resolvedType.isValidBinding())
130: return null; // already reported error
131: return this .resolvedType;
132: }
133: this .bits |= ASTNode.DidResolve;
134: boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
135: Binding binding = scope.getPackage(this .tokens);
136: if (binding != null && !binding.isValidBinding()) {
137: this .resolvedType = (ReferenceBinding) binding;
138: reportInvalidType(scope);
139: // be resilient, still attempt resolving arguments
140: for (int i = 0, max = this .tokens.length; i < max; i++) {
141: TypeReference[] args = this .typeArguments[i];
142: if (args != null) {
143: int argLength = args.length;
144: for (int j = 0; j < argLength; j++) {
145: TypeReference typeArgument = args[j];
146: if (isClassScope) {
147: typeArgument
148: .resolveType((ClassScope) scope);
149: } else {
150: typeArgument.resolveType(
151: (BlockScope) scope, checkBounds);
152: }
153: }
154: }
155: }
156: return null;
157: }
158:
159: PackageBinding packageBinding = binding == null ? null
160: : (PackageBinding) binding;
161: boolean typeIsConsistent = true;
162: ReferenceBinding qualifiedType = null;
163: for (int i = packageBinding == null ? 0
164: : packageBinding.compoundName.length, max = this .tokens.length; i < max; i++) {
165: findNextTypeBinding(i, scope, packageBinding);
166: if (!(this .resolvedType.isValidBinding())) {
167: reportInvalidType(scope);
168: // be resilient, still attempt resolving arguments
169: for (int j = i; j < max; j++) {
170: TypeReference[] args = this .typeArguments[j];
171: if (args != null) {
172: int argLength = args.length;
173: for (int k = 0; k < argLength; k++) {
174: TypeReference typeArgument = args[k];
175: if (isClassScope) {
176: typeArgument
177: .resolveType((ClassScope) scope);
178: } else {
179: typeArgument
180: .resolveType((BlockScope) scope);
181: }
182: }
183: }
184: }
185: return null;
186: }
187: ReferenceBinding currentType = (ReferenceBinding) this .resolvedType;
188: if (qualifiedType == null) {
189: qualifiedType = currentType.enclosingType(); // if member type
190: if (qualifiedType != null
191: && (qualifiedType.isGenericType() || qualifiedType
192: .isParameterizedType())) {
193: qualifiedType = currentType.isStatic() ? (ReferenceBinding) scope
194: .environment().convertToRawType(
195: qualifiedType)
196: : scope.environment()
197: .convertToParameterizedType(
198: qualifiedType);
199: }
200: }
201: if (typeIsConsistent
202: && currentType.isStatic()
203: && qualifiedType != null
204: && (qualifiedType.isParameterizedType() || qualifiedType
205: .isGenericType())) {
206: scope
207: .problemReporter()
208: .staticMemberOfParameterizedType(
209: this ,
210: scope
211: .environment()
212: .createParameterizedType(
213: (ReferenceBinding) currentType
214: .erasure(),
215: null, qualifiedType));
216: typeIsConsistent = false;
217: }
218: // check generic and arity
219: TypeReference[] args = this .typeArguments[i];
220: if (args != null) {
221: TypeReference keep = null;
222: if (isClassScope) {
223: keep = ((ClassScope) scope).super TypeReference;
224: ((ClassScope) scope).super TypeReference = null;
225: }
226: int argLength = args.length;
227: TypeBinding[] argTypes = new TypeBinding[argLength];
228: boolean argHasError = false;
229: for (int j = 0; j < argLength; j++) {
230: TypeReference arg = args[j];
231: TypeBinding argType = isClassScope ? arg
232: .resolveTypeArgument((ClassScope) scope,
233: currentType, j) : arg
234: .resolveTypeArgument((BlockScope) scope,
235: currentType, j);
236: if (argType == null) {
237: argHasError = true;
238: } else {
239: argTypes[j] = argType;
240: }
241: }
242: if (argHasError) {
243: return null;
244: }
245: if (isClassScope) {
246: ((ClassScope) scope).super TypeReference = keep;
247: if (((ClassScope) scope).detectHierarchyCycle(
248: currentType, this ))
249: return null;
250: }
251:
252: TypeVariableBinding[] typeVariables = currentType
253: .typeVariables();
254: if (typeVariables == Binding.NO_TYPE_VARIABLES) { // check generic
255: scope.problemReporter()
256: .nonGenericTypeCannotBeParameterized(i,
257: this , currentType, argTypes);
258: return null;
259: } else if (argLength != typeVariables.length) { // check arity
260: scope.problemReporter()
261: .incorrectArityForParameterizedType(this ,
262: currentType, argTypes);
263: return null;
264: }
265: // check parameterizing non-static member type of raw type
266: if (typeIsConsistent && !currentType.isStatic()) {
267: ReferenceBinding actualEnclosing = currentType
268: .enclosingType();
269: if (actualEnclosing != null
270: && actualEnclosing.isRawType()) {
271: scope
272: .problemReporter()
273: .rawMemberTypeCannotBeParameterized(
274: this ,
275: scope
276: .environment()
277: .createRawType(
278: (ReferenceBinding) currentType
279: .erasure(),
280: actualEnclosing),
281: argTypes);
282: typeIsConsistent = false;
283: }
284: }
285: ParameterizedTypeBinding parameterizedType = scope
286: .environment().createParameterizedType(
287: (ReferenceBinding) currentType
288: .erasure(), argTypes,
289: qualifiedType);
290: // check argument type compatibility
291: if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
292: parameterizedType.boundCheck(scope, args);
293: qualifiedType = parameterizedType;
294: } else {
295: if (isClassScope)
296: if (((ClassScope) scope).detectHierarchyCycle(
297: currentType, this ))
298: return null;
299: ReferenceBinding currentErasure = (ReferenceBinding) currentType
300: .erasure();
301: if (currentErasure.isGenericType()) {
302: if (typeIsConsistent && qualifiedType != null
303: && qualifiedType.isParameterizedType()) {
304: scope
305: .problemReporter()
306: .parameterizedMemberTypeMissingArguments(
307: this ,
308: scope
309: .environment()
310: .createParameterizedType(
311: currentErasure,
312: null,
313: qualifiedType));
314: typeIsConsistent = false;
315: }
316: qualifiedType = scope.environment().createRawType(
317: currentErasure, qualifiedType); // raw type
318: } else {
319: qualifiedType = (qualifiedType != null && qualifiedType
320: .isParameterizedType()) ? scope
321: .environment()
322: .createParameterizedType(currentErasure,
323: null, qualifiedType) : currentType;
324: }
325: }
326: if (isTypeUseDeprecated(qualifiedType, scope))
327: reportDeprecatedType(qualifiedType, scope);
328: this .resolvedType = qualifiedType;
329: }
330: // this.resolvedType = qualifiedType;
331: // array type ?
332: if (this .dimensions > 0) {
333: if (dimensions > 255)
334: scope.problemReporter().tooManyDimensions(this );
335: this .resolvedType = scope.createArrayType(
336: this .resolvedType, dimensions);
337: }
338: return this .resolvedType;
339: }
340:
341: public StringBuffer printExpression(int indent, StringBuffer output) {
342: int length = tokens.length;
343: for (int i = 0; i < length - 1; i++) {
344: output.append(tokens[i]);
345: TypeReference[] typeArgument = typeArguments[i];
346: if (typeArgument != null) {
347: output.append('<');
348: int max = typeArgument.length - 1;
349: for (int j = 0; j < max; j++) {
350: typeArgument[j].print(0, output);
351: output.append(", ");//$NON-NLS-1$
352: }
353: typeArgument[max].print(0, output);
354: output.append('>');
355: }
356: output.append('.');
357: }
358: output.append(tokens[length - 1]);
359: TypeReference[] typeArgument = typeArguments[length - 1];
360: if (typeArgument != null) {
361: output.append('<');
362: int max = typeArgument.length - 1;
363: for (int j = 0; j < max; j++) {
364: typeArgument[j].print(0, output);
365: output.append(", ");//$NON-NLS-1$
366: }
367: typeArgument[max].print(0, output);
368: output.append('>');
369: }
370: if ((this .bits & IsVarArgs) != 0) {
371: for (int i = 0; i < dimensions - 1; i++) {
372: output.append("[]"); //$NON-NLS-1$
373: }
374: output.append("..."); //$NON-NLS-1$
375: } else {
376: for (int i = 0; i < dimensions; i++) {
377: output.append("[]"); //$NON-NLS-1$
378: }
379: }
380: return output;
381: }
382:
383: public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
384: return internalResolveType(scope, checkBounds);
385: }
386:
387: public TypeBinding resolveType(ClassScope scope) {
388: return internalResolveType(scope, false);
389: }
390:
391: public void traverse(ASTVisitor visitor, BlockScope scope) {
392: if (visitor.visit(this , scope)) {
393: for (int i = 0, max = this .typeArguments.length; i < max; i++) {
394: if (this .typeArguments[i] != null) {
395: for (int j = 0, max2 = this .typeArguments[i].length; j < max2; j++) {
396: this .typeArguments[i][j].traverse(visitor,
397: scope);
398: }
399: }
400: }
401: }
402: visitor.endVisit(this , scope);
403: }
404:
405: public void traverse(ASTVisitor visitor, ClassScope scope) {
406: if (visitor.visit(this , scope)) {
407: for (int i = 0, max = this .typeArguments.length; i < max; i++) {
408: if (this .typeArguments[i] != null) {
409: for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
410: this.typeArguments[i][j].traverse(visitor,
411: scope);
412: }
413: }
414: }
415: }
416: visitor.endVisit(this, scope);
417: }
418:
419: }
|