1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.lookup.*;
18 * Syntactic representation of a reference to a generic type.
19 * Note that it might also have a dimension.
21 public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeReference {
23 public TypeReference[][] typeArguments;
24 private boolean didResolve = false;
31 public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) {
33 super(tokens, dim, positions);
34 this.typeArguments = typeArguments;
36 public void checkBounds(Scope scope) {
37 if (this.resolvedType == null) return;
40 (ReferenceBinding) this.resolvedType.leafComponentType(),
42 this.typeArguments.length - 1);
44 public void checkBounds(ReferenceBinding type, Scope scope, int index) {
45 if (type.enclosingType() != null)
46 checkBounds(type.enclosingType(), scope, index - 1);
48 if (type.isParameterizedType()) {
49 ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
50 ReferenceBinding currentType = parameterizedType.type;
51 TypeVariableBinding[] typeVariables = currentType.typeVariables();
52 TypeBinding[] argTypes = parameterizedType.arguments;
53 if (argTypes != null && typeVariables != null) { // argTypes may be null in error cases
54 for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
55 if (!typeVariables[i].boundCheck(parameterizedType, argTypes[i]))
56 scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[index][i]);
60 public TypeReference copyDims(int dim){
61 //return a type reference copy of me with some dimensions
62 //warning : the new type ref has a null binding
63 this.dimensions = dim;
70 public char [][] getParameterizedTypeName(){
71 int length = this.tokens.length;
72 char[][] qParamName = new char[length][];
73 for (int i = 0; i < length; i++) {
74 TypeReference[] arguments = this.typeArguments[i];
75 if (arguments == null) {
76 qParamName[i] = this.tokens[i];
78 StringBuffer buffer = new StringBuffer(5);
79 buffer.append(this.tokens[i]);
81 for (int j = 0, argLength =arguments.length; j < argLength; j++) {
82 if (j > 0) buffer.append(',');
83 buffer.append(CharOperation.concatWith(arguments[j].getParameterizedTypeName(), '.'));
86 int nameLength = buffer.length();
87 qParamName[i] = new char[nameLength];
88 buffer.getChars(0, nameLength, qParamName[i], 0);
91 int dim = this.dimensions;
93 char[] dimChars = new char[dim*2];
94 for (int i = 0; i < dim; i++) {
96 dimChars[index] = '[';
97 dimChars[index+1] = ']';
99 qParamName[length-1] = CharOperation.concat(qParamName[length-1], dimChars);
105 * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
107 protected TypeBinding getTypeBinding(Scope scope) {
108 return null; // not supported here - combined with resolveType(...)
112 * No need to check for reference to raw type per construction
114 private TypeBinding internalResolveType(Scope scope, boolean checkBounds) {
116 // handle the error here
117 this.constant = NotAConstant;
118 if (this.didResolve) { // is a shared type reference which was already resolved
119 if (this.resolvedType != null && !this.resolvedType.isValidBinding())
120 return null; // already reported error
121 return this.resolvedType;
123 this.didResolve = true;
124 Binding binding = scope.getPackage(this.tokens);
125 if (binding != null && !binding.isValidBinding()) {
126 this.resolvedType = (ReferenceBinding) binding;
127 reportInvalidType(scope);
131 PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding;
132 boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
133 boolean typeIsConsistent = true;
134 ReferenceBinding qualifiedType = null;
135 for (int i = packageBinding == null ? 0 : packageBinding.compoundName.length, max = this.tokens.length; i < max; i++) {
136 findNextTypeBinding(i, scope, packageBinding);
137 if (!(this.resolvedType.isValidBinding())) {
138 reportInvalidType(scope);
141 ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
142 if (qualifiedType == null) {
143 qualifiedType = currentType.enclosingType(); // if member type
144 if (qualifiedType != null && currentType.isStatic() && (qualifiedType.isGenericType() || qualifiedType.isParameterizedType())) {
145 qualifiedType = scope.environment().createRawType((ReferenceBinding)qualifiedType.erasure(), qualifiedType.enclosingType());
148 if (typeIsConsistent && currentType.isStatic() && qualifiedType != null && (qualifiedType.isParameterizedType() || qualifiedType.isGenericType())) {
149 scope.problemReporter().staticMemberOfParameterizedType(this, scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
150 typeIsConsistent = false;
152 // check generic and arity
153 TypeReference[] args = this.typeArguments[i];
155 int argLength = args.length;
156 TypeBinding[] argTypes = new TypeBinding[argLength];
157 boolean argHasError = false;
158 for (int j = 0; j < argLength; j++) {
159 TypeReference arg = args[j];
160 TypeBinding argType = isClassScope
161 ? arg.resolveTypeArgument((ClassScope) scope, currentType, j)
162 : arg.resolveTypeArgument((BlockScope) scope, currentType, j);
163 if (argType == null) {
166 argTypes[j] = argType;
169 if (argHasError) return null;
170 // TODO (philippe) if ((this.bits & ASTNode.IsSuperType) != 0)
172 if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
175 TypeVariableBinding[] typeVariables = currentType.typeVariables();
176 if (typeVariables == NoTypeVariables) { // check generic
177 scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes);
179 } else if (argLength != typeVariables.length) { // check arity
180 scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
183 // check parameterizing non-static member type of raw type
184 if (typeIsConsistent && !currentType.isStatic() && qualifiedType != null && qualifiedType.isRawType()) {
185 scope.problemReporter().rawMemberTypeCannotBeParameterized(
186 this, scope.environment().createRawType((ReferenceBinding)currentType.erasure(), qualifiedType), argTypes);
187 typeIsConsistent = false;
189 ParameterizedTypeBinding parameterizedType = scope.createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, qualifiedType);
190 // check argument type compatibility
191 if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
192 for (int j = 0; j < argLength; j++)
193 if (!typeVariables[j].boundCheck(parameterizedType, argTypes[j]))
194 scope.problemReporter().typeMismatchError(argTypes[j], typeVariables[j], currentType, args[j]);
195 qualifiedType = parameterizedType;
197 // TODO (philippe) if ((this.bits & ASTNode.IsSuperType) != 0)
199 if (((ClassScope) scope).detectHierarchyCycle(currentType, this, null))
201 if (currentType.isGenericType()) {
202 if (typeIsConsistent && qualifiedType != null && qualifiedType.isParameterizedType()) {
203 scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
204 typeIsConsistent = false;
206 qualifiedType = scope.environment().createRawType(currentType, qualifiedType); // raw type
208 qualifiedType = (qualifiedType != null && qualifiedType.isParameterizedType())
209 ? scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType)
214 this.resolvedType = qualifiedType;
215 if (isTypeUseDeprecated(this.resolvedType, scope))
216 reportDeprecatedType(scope);
218 if (this.dimensions > 0) {
219 if (dimensions > 255)
220 scope.problemReporter().tooManyDimensions(this);
221 this.resolvedType = scope.createArrayType(this.resolvedType, dimensions);
223 return this.resolvedType;
226 public StringBuffer printExpression(int indent, StringBuffer output) {
227 int length = tokens.length;
228 for (int i = 0; i < length - 1; i++) {
229 output.append(tokens[i]);
230 TypeReference[] typeArgument = typeArguments[i];
231 if (typeArgument != null) {
232 output.append('<');//$NON-NLS-1$
233 int max = typeArgument.length - 1;
234 for (int j = 0; j < max; j++) {
235 typeArgument[j].print(0, output);
236 output.append(", ");//$NON-NLS-1$
238 typeArgument[max].print(0, output);
243 output.append(tokens[length - 1]);
244 TypeReference[] typeArgument = typeArguments[length - 1];
245 if (typeArgument != null) {
246 output.append('<');//$NON-NLS-1$
247 int max = typeArgument.length - 1;
248 for (int j = 0; j < max; j++) {
249 typeArgument[j].print(0, output);
250 output.append(", ");//$NON-NLS-1$
252 typeArgument[max].print(0, output);
255 if ((this.bits & IsVarArgs) != 0) {
256 for (int i= 0 ; i < dimensions - 1; i++) {
257 output.append("[]"); //$NON-NLS-1$
259 output.append("..."); //$NON-NLS-1$
261 for (int i= 0 ; i < dimensions; i++) {
262 output.append("[]"); //$NON-NLS-1$
268 public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
269 return internalResolveType(scope, checkBounds);
271 public TypeBinding resolveType(ClassScope scope) {
272 return internalResolveType(scope, false);
274 public void traverse(ASTVisitor visitor, BlockScope scope) {
275 if (visitor.visit(this, scope)) {
276 for (int i = 0, max = this.typeArguments.length; i < max; i++) {
277 if (this.typeArguments[i] != null) {
278 for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
279 this.typeArguments[i][j].traverse(visitor, scope);
284 visitor.endVisit(this, scope);
287 public void traverse(ASTVisitor visitor, ClassScope scope) {
288 if (visitor.visit(this, scope)) {
289 for (int i = 0, max = this.typeArguments.length; i < max; i++) {
290 if (this.typeArguments[i] != null) {
291 for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
292 this.typeArguments[i][j].traverse(visitor, scope);
297 visitor.endVisit(this, scope);