import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ParameterizedQualifiedTypeReference.java
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          */
31         public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) {
32             
33                 super(tokens, dim, positions);
34                 this.typeArguments = typeArguments;
35         }
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         }
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         }
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          */
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      */
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      */
114         private TypeBinding internalResolveType(Scope scope, boolean checkBounds) {
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 (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());
146                                 }
147                         }                               
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;
151                         }                       
152                         // check generic and arity
153                     TypeReference[] args = this.typeArguments[i];
154                     if (args != null) {
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) {
164                                                 argHasError = true;
165                                         } else {
166                                                 argTypes[j] = argType;
167                                         }                           
168                                 }
169                                 if (argHasError) return null;
170 // TODO (philippe)      if ((this.bits & ASTNode.IsSuperType) != 0)
171                                 if (isClassScope)
172                                         if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
173                                                 return null;
174
175                             TypeVariableBinding[] typeVariables = currentType.typeVariables();
176                                 if (typeVariables == NoTypeVariables) { // check generic
177                                         scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes);
178                                         return null;
179                                 } else if (argLength != typeVariables.length) { // check arity
180                                         scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
181                                         return null;
182                                 }
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;                               
188                                 }
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;
196                     } else {
197 // TODO (philippe)      if ((this.bits & ASTNode.IsSuperType) != 0)
198                                 if (isClassScope)
199                                         if (((ClassScope) scope).detectHierarchyCycle(currentType, this, null))
200                                                 return 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;
205                                         }
206                                     qualifiedType = scope.environment().createRawType(currentType, qualifiedType); // raw type
207                                 } else {
208                                         qualifiedType = (qualifiedType != null && qualifiedType.isParameterizedType())
209                                                                                                         ? scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType)
210                                                                                                         : currentType;
211                                 }
212                         }
213                 }
214                 this.resolvedType = qualifiedType;
215                 if (isTypeUseDeprecated(this.resolvedType, scope))
216                         reportDeprecatedType(scope);
217                 // array type ?
218                 if (this.dimensions > 0) {
219                         if (dimensions > 255)
220                                 scope.problemReporter().tooManyDimensions(this);
221                         this.resolvedType = scope.createArrayType(this.resolvedType, dimensions);
222                 }
223                 return this.resolvedType;
224         }
225         
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$
237                                 }
238                                 typeArgument[max].print(0, output);
239                                 output.append('>');
240                         }
241                         output.append('.');
242                 }
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$
251                         }
252                         typeArgument[max].print(0, output);
253                         output.append('>');
254                 }
255                 if ((this.bits & IsVarArgs) != 0) {
256                         for (int i= 0 ; i < dimensions - 1; i++) {
257                                 output.append("[]"); //$NON-NLS-1$
258                         }
259                         output.append("..."); //$NON-NLS-1$
260                 } else {
261                         for (int i= 0 ; i < dimensions; i++) {
262                                 output.append("[]"); //$NON-NLS-1$
263                         }
264                 }
265                 return output;
266         }       
267         
268         public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
269             return internalResolveType(scope, checkBounds);
270         }       
271         public TypeBinding resolveType(ClassScope scope) {
272             return internalResolveType(scope, false);
273         }
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);
280                                         }
281                                 }
282                         }
283                 }
284                 visitor.endVisit(this, scope);
285         }
286         
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);
293                                         }
294                                 }
295                         }
296                 }
297                 visitor.endVisit(this, scope);
298         }
299
300 }