| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.ast; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.ASTVisitor; |
| import org.eclipse.jdt.internal.compiler.lookup.*; |
| |
| /** |
| * Syntactic representation of a reference to a generic type. |
| * Note that it might also have a dimension. |
| */ |
| public class ParameterizedSingleTypeReference extends ArrayTypeReference { |
| |
| public TypeReference[] typeArguments; |
| private boolean didResolve = false; |
| |
| public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos){ |
| super(name, dim, pos); |
| this.typeArguments = typeArguments; |
| } |
| |
| /** |
| * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int) |
| */ |
| public TypeReference copyDims(int dim) { |
| this.dimensions = dim; |
| return this; |
| } |
| |
| /** |
| * @return char[][] |
| */ |
| public char [][] getParameterizedTypeName(){ |
| StringBuffer buffer = new StringBuffer(5); |
| buffer.append(this.token).append('<'); |
| for (int i = 0, length = this.typeArguments.length; i < length; i++) { |
| if (i > 0) buffer.append(','); |
| buffer.append(CharOperation.concatWith(this.typeArguments[i].getParameterizedTypeName(), '.')); |
| } |
| buffer.append('>'); |
| int nameLength = buffer.length(); |
| char[] name = new char[nameLength]; |
| buffer.getChars(0, nameLength, name, 0); |
| int dim = this.dimensions; |
| if (dim > 0) { |
| char[] dimChars = new char[dim*2]; |
| for (int i = 0; i < dim; i++) { |
| int index = i*2; |
| dimChars[index] = '['; |
| dimChars[index+1] = ']'; |
| } |
| name = CharOperation.concat(name, dimChars); |
| } |
| return new char[][]{ name }; |
| } |
| /** |
| * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) |
| */ |
| protected TypeBinding getTypeBinding(Scope scope) { |
| return null; // not supported here - combined with resolveType(...) |
| } |
| |
| /* |
| * No need to check for reference to raw type per construction |
| */ |
| private TypeBinding internalResolveType(Scope scope, ReferenceBinding enclosingType) { |
| |
| boolean isClassScope = scope.kind == Scope.CLASS_SCOPE; |
| |
| // handle the error here |
| this.constant = NotAConstant; |
| if (this.didResolve) { // is a shared type reference which was already resolved |
| if (this.resolvedType != null && !this.resolvedType.isValidBinding()) { |
| return null; // already reported error |
| } |
| return this.resolvedType; |
| } |
| this.didResolve = true; |
| ReferenceBinding currentType = null; |
| if (enclosingType == null) { |
| this.resolvedType = scope.getType(token); |
| if (!(this.resolvedType.isValidBinding())) { |
| reportInvalidType(scope); |
| return null; |
| } |
| } else { // resolving member type (relatively to enclosingType) |
| this.resolvedType = scope.getMemberType(token, (ReferenceBinding)enclosingType.erasure()); |
| if (!this.resolvedType.isValidBinding()) { |
| scope.problemReporter().invalidEnclosingType(this, this.resolvedType, enclosingType); |
| return null; |
| } |
| if (isTypeUseDeprecated(this.resolvedType, scope)) { |
| scope.problemReporter().deprecatedType(this.resolvedType, this); |
| } |
| } |
| currentType = (ReferenceBinding) this.resolvedType; |
| if (isClassScope) |
| if (((ClassScope) scope).detectCycle(currentType, this)) |
| return null; |
| // check generic and arity |
| TypeVariableBinding[] typeVariables = currentType.typeVariables(); |
| int argLength = this.typeArguments.length; |
| TypeBinding[] argTypes = new TypeBinding[argLength]; |
| boolean argHasError = false; |
| for (int i = 0; i < argLength; i++) { |
| TypeReference typeArgument = this.typeArguments[i]; |
| TypeBinding argType = isClassScope |
| ? typeArgument.resolveTypeArgument((ClassScope) scope, currentType, i) |
| : typeArgument.resolveTypeArgument((BlockScope) scope, currentType, i); |
| if (argType == null) { |
| argHasError = true; |
| } else { |
| argTypes[i] = argType; |
| } |
| } |
| if (argHasError) return null; |
| if (typeVariables == NoTypeVariables) { // check generic |
| scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes); |
| return null; |
| } else if (argLength != typeVariables.length) { // check arity |
| scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes); |
| return null; |
| } |
| // if generic type X<T> is referred to as parameterized X<T>, then answer itself |
| checkGeneric: { |
| for (int i = 0; i < argLength; i++) |
| if (typeVariables[i] != argTypes[i]) |
| break checkGeneric; |
| return currentType; |
| } |
| ParameterizedTypeBinding parameterizedType = scope.createParameterizedType(currentType, argTypes, enclosingType); |
| // check argument type compatibility |
| for (int i = 0; i < argLength; i++) { |
| TypeBinding argType = argTypes[i]; |
| if (!typeVariables[i].boundCheck(parameterizedType, argType)) { |
| scope.problemReporter().typeMismatchError(argType, typeVariables[i], currentType, this.typeArguments[i]); |
| } |
| } |
| this.resolvedType = parameterizedType; |
| if (isTypeUseDeprecated(this.resolvedType, scope)) { |
| reportDeprecatedType(scope); |
| } |
| // array type ? |
| if (this.dimensions > 0) { |
| if (dimensions > 255) { |
| scope.problemReporter().tooManyDimensions(this); |
| } |
| scope.problemReporter().illegalArrayOfParameterizedType(parameterizedType, this); |
| this.resolvedType = scope.createArrayType(parameterizedType, dimensions); |
| } |
| return this.resolvedType; |
| } |
| |
| public StringBuffer printExpression(int indent, StringBuffer output){ |
| output.append(token); |
| output.append("<"); //$NON-NLS-1$ |
| int max = typeArguments.length - 1; |
| for (int i= 0; i < max; i++) { |
| typeArguments[i].print(0, output); |
| output.append(", ");//$NON-NLS-1$ |
| } |
| typeArguments[max].print(0, output); |
| output.append(">"); //$NON-NLS-1$ |
| for (int i= 0 ; i < dimensions ; i++) { |
| output.append("[]"); //$NON-NLS-1$ |
| } |
| return output; |
| } |
| |
| public TypeBinding resolveType(BlockScope scope) { |
| return internalResolveType(scope, null); |
| } |
| |
| public TypeBinding resolveType(ClassScope scope) { |
| return internalResolveType(scope, null); |
| } |
| |
| public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { |
| return internalResolveType(scope, enclosingType); |
| } |
| |
| public void traverse(ASTVisitor visitor, BlockScope scope) { |
| if (visitor.visit(this, scope)) { |
| for (int i = 0, max = this.typeArguments.length; i < max; i++) { |
| this.typeArguments[i].traverse(visitor, scope); |
| } |
| } |
| visitor.endVisit(this, scope); |
| } |
| |
| public void traverse(ASTVisitor visitor, ClassScope scope) { |
| if (visitor.visit(this, scope)) { |
| for (int i = 0, max = this.typeArguments.length; i < max; i++) { |
| this.typeArguments[i].traverse(visitor, scope); |
| } |
| } |
| visitor.endVisit(this, scope); |
| } |
| } |