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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12 
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.lookup.*;
16 
17 /**
18  * Syntactic representation of a reference to a generic type.
19  * Note that it might also have a dimension.
20  */
21 public class ParameterizedSingleTypeReference extends ArrayTypeReference {
22 
23 	public TypeReference[] typeArguments;
24 	private boolean didResolve = false;
25 
ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos)26 	public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos){
27 		super(name, dim, pos);
28 		this.typeArguments = typeArguments;
29 	}
checkBounds(Scope scope)30 	public void checkBounds(Scope scope) {
31 		if (this.resolvedType == null) return;
32 
33 		if (this.resolvedType.leafComponentType() instanceof ParameterizedTypeBinding) {
34 			ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) this.resolvedType.leafComponentType();
35 			ReferenceBinding currentType = parameterizedType.type;
36 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
37 			TypeBinding[] argTypes = parameterizedType.arguments;
38 			if (argTypes != null && typeVariables != null) { // may be null in error cases
39 				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
40 					if (!typeVariables[i].boundCheck(parameterizedType, argTypes[i]))
41 						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
42 			}
43 		}
44 	}
45 	/**
46 	 * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int)
47 	 */
copyDims(int dim)48 	public TypeReference copyDims(int dim) {
49 		this.dimensions = dim;
50 		return this;
51 	}
52 
53 	/**
54 	 * @return char[][]
55 	 */
getParameterizedTypeName()56 	public char [][] getParameterizedTypeName(){
57 		StringBuffer buffer = new StringBuffer(5);
58 		buffer.append(this.token).append('<');
59 		for (int i = 0, length = this.typeArguments.length; i < length; i++) {
60 			if (i > 0) buffer.append(',');
61 			buffer.append(CharOperation.concatWith(this.typeArguments[i].getParameterizedTypeName(), '.'));
62 		}
63 		buffer.append('>');
64 		int nameLength = buffer.length();
65 		char[] name = new char[nameLength];
66 		buffer.getChars(0, nameLength, name, 0);
67 		int dim = this.dimensions;
68 		if (dim > 0) {
69 			char[] dimChars = new char[dim*2];
70 			for (int i = 0; i < dim; i++) {
71 				int index = i*2;
72 				dimChars[index] = '[';
73 				dimChars[index+1] = ']';
74 			}
75 			name = CharOperation.concat(name, dimChars);
76 		}
77 		return new char[][]{ name };
78 	}
79 	/**
80      * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
81      */
getTypeBinding(Scope scope)82     protected TypeBinding getTypeBinding(Scope scope) {
83         return null; // not supported here - combined with resolveType(...)
84     }
85 
86     /*
87      * No need to check for reference to raw type per construction
88      */
internalResolveType(Scope scope, ReferenceBinding enclosingType)89 	private TypeBinding internalResolveType(Scope scope, ReferenceBinding enclosingType) {
90 
91 		// handle the error here
92 		this.constant = NotAConstant;
93 		if (this.didResolve) { // is a shared type reference which was already resolved
94 			if (this.resolvedType != null && !this.resolvedType.isValidBinding())
95 				return null; // already reported error
96 			return this.resolvedType;
97 		}
98 	    this.didResolve = true;
99 		if (enclosingType == null) {
100 			this.resolvedType = scope.getType(token);
101 			if (!(this.resolvedType.isValidBinding())) {
102 				reportInvalidType(scope);
103 				return null;
104 			}
105 		} else { // resolving member type (relatively to enclosingType)
106 			this.resolvedType = scope.getMemberType(token, (ReferenceBinding)enclosingType.erasure());
107 			if (!this.resolvedType.isValidBinding()) {
108 				scope.problemReporter().invalidEnclosingType(this, this.resolvedType, enclosingType);
109 				return null;
110 			}
111 			if (isTypeUseDeprecated(this.resolvedType, scope))
112 				scope.problemReporter().deprecatedType(this.resolvedType, this);
113 		}
114 
115 		// check generic and arity
116 	    boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
117 		ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
118 		int argLength = this.typeArguments.length;
119 		TypeBinding[] argTypes = new TypeBinding[argLength];
120 		boolean argHasError = false;
121 		for (int i = 0; i < argLength; i++) {
122 		    TypeReference typeArgument = this.typeArguments[i];
123 		    TypeBinding argType = isClassScope
124 				? typeArgument.resolveTypeArgument((ClassScope) scope, currentType, i)
125 				: typeArgument.resolveTypeArgument((BlockScope) scope, currentType, i);
126 		     if (argType == null) {
127 		         argHasError = true;
128 		     } else {
129 			    argTypes[i] = argType;
130 		     }
131 		}
132 		if (argHasError) return null;
133 // TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
134 		if (isClassScope)
135 			if (((ClassScope) scope).detectCycle(currentType, this, argTypes))
136 				return null;
137 
138 		TypeVariableBinding[] typeVariables = currentType.typeVariables();
139 		if (typeVariables == NoTypeVariables) { // check generic
140 			scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes);
141 			return null;
142 		} else if (argLength != typeVariables.length) { // check arity
143 			scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
144 			return null;
145 		}
146 		// if generic type X<T> is referred to as parameterized X<T>, then answer itself
147 		checkGeneric: {
148 		    for (int i = 0; i < argLength; i++)
149 				if (typeVariables[i] != argTypes[i])
150 				    break checkGeneric;
151 			return currentType;
152 		}
153 		ParameterizedTypeBinding parameterizedType = scope.createParameterizedType(currentType, argTypes, enclosingType);
154 		// check argument type compatibility now if not a class scope
155 		if (!isClassScope) // otherwise will do it in Scope.connectTypeVariables()
156 			for (int i = 0; i < argLength; i++)
157 			    if (!typeVariables[i].boundCheck(parameterizedType, argTypes[i]))
158 					scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
159 
160 		this.resolvedType = parameterizedType;
161 		if (isTypeUseDeprecated(this.resolvedType, scope))
162 			reportDeprecatedType(scope);
163 		// array type ?
164 		if (this.dimensions > 0) {
165 			if (dimensions > 255)
166 				scope.problemReporter().tooManyDimensions(this);
167 			this.resolvedType = scope.createArrayType(parameterizedType, dimensions);
168 		}
169 		return this.resolvedType;
170 	}
171 
printExpression(int indent, StringBuffer output)172 	public StringBuffer printExpression(int indent, StringBuffer output){
173 		output.append(token);
174 		output.append("<"); //$NON-NLS-1$
175 		int max = typeArguments.length - 1;
176 		for (int i= 0; i < max; i++) {
177 			typeArguments[i].print(0, output);
178 			output.append(", ");//$NON-NLS-1$
179 		}
180 		typeArguments[max].print(0, output);
181 		output.append(">"); //$NON-NLS-1$
182 		for (int i= 0 ; i < dimensions ; i++) {
183 			output.append("[]"); //$NON-NLS-1$
184 		}
185 		return output;
186 	}
187 
resolveType(BlockScope scope)188 	public TypeBinding resolveType(BlockScope scope) {
189 	    return internalResolveType(scope, null);
190 	}
191 
resolveType(ClassScope scope)192 	public TypeBinding resolveType(ClassScope scope) {
193 	    return internalResolveType(scope, null);
194 	}
195 
resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType)196 	public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) {
197 	    return internalResolveType(scope, enclosingType);
198 	}
199 
traverse(ASTVisitor visitor, BlockScope scope)200 	public void traverse(ASTVisitor visitor, BlockScope scope) {
201 		if (visitor.visit(this, scope)) {
202 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
203 				this.typeArguments[i].traverse(visitor, scope);
204 			}
205 		}
206 		visitor.endVisit(this, scope);
207 	}
208 
traverse(ASTVisitor visitor, ClassScope scope)209 	public void traverse(ASTVisitor visitor, ClassScope scope) {
210 		if (visitor.visit(this, scope)) {
211 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
212 				this.typeArguments[i].traverse(visitor, scope);
213 			}
214 		}
215 		visitor.endVisit(this, scope);
216 	}
217 }
218