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 ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeReference { 22 23 public TypeReference[][] typeArguments; 24 private boolean didResolve = false; 25 26 /** 27 * @param tokens 28 * @param dim 29 * @param positions 30 */ ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions)31 public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) { 32 33 super(tokens, dim, positions); 34 this.typeArguments = typeArguments; 35 } checkBounds(Scope scope)36 public void checkBounds(Scope scope) { 37 if (this.resolvedType == null) return; 38 39 checkBounds( 40 (ReferenceBinding) this.resolvedType.leafComponentType(), 41 scope, 42 this.typeArguments.length - 1); 43 } checkBounds(ReferenceBinding type, Scope scope, int index)44 public void checkBounds(ReferenceBinding type, Scope scope, int index) { 45 if (type.enclosingType() != null) 46 checkBounds(type.enclosingType(), scope, index - 1); 47 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]); 57 } 58 } 59 } copyDims(int dim)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; 64 return this; 65 } 66 67 /** 68 * @return char[][] 69 */ getParameterizedTypeName()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]; 77 } else { 78 StringBuffer buffer = new StringBuffer(5); 79 buffer.append(this.tokens[i]); 80 buffer.append('<'); 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(), '.')); 84 } 85 buffer.append('>'); 86 int nameLength = buffer.length(); 87 qParamName[i] = new char[nameLength]; 88 buffer.getChars(0, nameLength, qParamName[i], 0); 89 } 90 } 91 int dim = this.dimensions; 92 if (dim > 0) { 93 char[] dimChars = new char[dim*2]; 94 for (int i = 0; i < dim; i++) { 95 int index = i*2; 96 dimChars[index] = '['; 97 dimChars[index+1] = ']'; 98 } 99 qParamName[length-1] = CharOperation.concat(qParamName[length-1], dimChars); 100 } 101 return qParamName; 102 } 103 104 /* (non-Javadoc) 105 * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) 106 */ getTypeBinding(Scope scope)107 protected TypeBinding getTypeBinding(Scope scope) { 108 return null; // not supported here - combined with resolveType(...) 109 } 110 111 /* 112 * No need to check for reference to raw type per construction 113 */ internalResolveType(Scope scope)114 private TypeBinding internalResolveType(Scope scope) { 115 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; 122 } 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); 128 return null; 129 } 130 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); 139 return null; 140 } 141 ReferenceBinding currentType = (ReferenceBinding) this.resolvedType; 142 if (typeIsConsistent && currentType.isStatic() && qualifiedType != null && (qualifiedType.isParameterizedType() || qualifiedType.isGenericType())) { 143 scope.problemReporter().staticMemberOfParameterizedType(this, scope.createParameterizedType(currentType, null, qualifiedType)); 144 typeIsConsistent = false; 145 } 146 // check generic and arity 147 TypeReference[] args = this.typeArguments[i]; 148 if (args != null) { 149 int argLength = args.length; 150 TypeBinding[] argTypes = new TypeBinding[argLength]; 151 boolean argHasError = false; 152 for (int j = 0; j < argLength; j++) { 153 TypeReference arg = args[j]; 154 TypeBinding argType = isClassScope 155 ? arg.resolveTypeArgument((ClassScope) scope, currentType, j) 156 : arg.resolveTypeArgument((BlockScope) scope, currentType, j); 157 if (argType == null) { 158 argHasError = true; 159 } else { 160 argTypes[j] = argType; 161 } 162 } 163 if (argHasError) return null; 164 // TODO (philippe) if ((this.bits & ASTNode.IsSuperType) != 0) 165 if (isClassScope) 166 if (((ClassScope) scope).detectCycle(currentType, this, argTypes)) 167 return null; 168 169 TypeVariableBinding[] typeVariables = currentType.typeVariables(); 170 if (typeVariables == NoTypeVariables) { // check generic 171 scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes); 172 return null; 173 } else if (argLength != typeVariables.length) { // check arity 174 scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes); 175 return null; 176 } 177 // check parameterizing non-static member type of raw type 178 if (typeIsConsistent && !currentType.isStatic() && qualifiedType != null && qualifiedType.isRawType()) { 179 scope.problemReporter().rawMemberTypeCannotBeParameterized( 180 this, scope.environment().createRawType(currentType, qualifiedType), argTypes); 181 typeIsConsistent = false; 182 } 183 ParameterizedTypeBinding parameterizedType = scope.createParameterizedType(currentType, argTypes, qualifiedType); 184 // check argument type compatibility now if not a class scope 185 if (!isClassScope) // otherwise will do it in Scope.connectTypeVariables() 186 for (int j = 0; j < argLength; j++) 187 if (!typeVariables[j].boundCheck(parameterizedType, argTypes[j])) 188 scope.problemReporter().typeMismatchError(argTypes[j], typeVariables[j], currentType, args[j]); 189 qualifiedType = parameterizedType; 190 } else { 191 // TODO (philippe) if ((this.bits & ASTNode.IsSuperType) != 0) 192 if (isClassScope) 193 if (((ClassScope) scope).detectCycle(currentType, this, null)) 194 return null; 195 if (currentType.isGenericType()) { 196 if (typeIsConsistent && qualifiedType != null && qualifiedType.isParameterizedType()) { 197 scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.createParameterizedType(currentType, null, qualifiedType)); 198 typeIsConsistent = false; 199 } 200 qualifiedType = scope.environment().createRawType(currentType, qualifiedType); // raw type 201 } else { 202 qualifiedType = (qualifiedType != null && qualifiedType.isParameterizedType()) 203 ? scope.createParameterizedType(currentType, null, qualifiedType) 204 : currentType; 205 } 206 } 207 } 208 this.resolvedType = qualifiedType; 209 if (isTypeUseDeprecated(this.resolvedType, scope)) 210 reportDeprecatedType(scope); 211 // array type ? 212 if (this.dimensions > 0) { 213 if (dimensions > 255) 214 scope.problemReporter().tooManyDimensions(this); 215 this.resolvedType = scope.createArrayType(this.resolvedType, dimensions); 216 } 217 return this.resolvedType; 218 } 219 printExpression(int indent, StringBuffer output)220 public StringBuffer printExpression(int indent, StringBuffer output) { 221 int length = tokens.length; 222 for (int i = 0; i < length - 1; i++) { 223 output.append(tokens[i]); 224 TypeReference[] typeArgument = typeArguments[i]; 225 if (typeArgument != null) { 226 output.append('<');//$NON-NLS-1$ 227 int max = typeArgument.length - 1; 228 for (int j = 0; j < max; j++) { 229 typeArgument[j].print(0, output); 230 output.append(", ");//$NON-NLS-1$ 231 } 232 typeArgument[max].print(0, output); 233 output.append('>'); 234 } 235 output.append('.'); 236 } 237 output.append(tokens[length - 1]); 238 TypeReference[] typeArgument = typeArguments[length - 1]; 239 if (typeArgument != null) { 240 output.append('<');//$NON-NLS-1$ 241 int max = typeArgument.length - 1; 242 for (int j = 0; j < max; j++) { 243 typeArgument[j].print(0, output); 244 output.append(", ");//$NON-NLS-1$ 245 } 246 typeArgument[max].print(0, output); 247 output.append('>'); 248 } 249 for (int i= 0 ; i < dimensions ; i++) { 250 output.append("[]"); //$NON-NLS-1$ 251 } 252 return output; 253 } 254 resolveType(BlockScope scope)255 public TypeBinding resolveType(BlockScope scope) { 256 return internalResolveType(scope); 257 } resolveType(ClassScope scope)258 public TypeBinding resolveType(ClassScope scope) { 259 return internalResolveType(scope); 260 } traverse(ASTVisitor visitor, BlockScope scope)261 public void traverse(ASTVisitor visitor, BlockScope scope) { 262 if (visitor.visit(this, scope)) { 263 for (int i = 0, max = this.typeArguments.length; i < max; i++) { 264 if (this.typeArguments[i] != null) { 265 for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) { 266 this.typeArguments[i][j].traverse(visitor, scope); 267 } 268 } 269 } 270 } 271 visitor.endVisit(this, scope); 272 } 273 traverse(ASTVisitor visitor, ClassScope scope)274 public void traverse(ASTVisitor visitor, ClassScope 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); 280 } 281 } 282 } 283 } 284 visitor.endVisit(this, scope); 285 } 286 287 } 288