KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > generics > InferTypeArgumentsConstraintCreator


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.corext.refactoring.generics;
13
14 import java.util.Collections JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import org.eclipse.core.runtime.Assert;
21
22 import org.eclipse.jdt.core.ICompilationUnit;
23 import org.eclipse.jdt.core.dom.ASTNode;
24 import org.eclipse.jdt.core.dom.ArrayAccess;
25 import org.eclipse.jdt.core.dom.ArrayCreation;
26 import org.eclipse.jdt.core.dom.ArrayType;
27 import org.eclipse.jdt.core.dom.Assignment;
28 import org.eclipse.jdt.core.dom.BooleanLiteral;
29 import org.eclipse.jdt.core.dom.CastExpression;
30 import org.eclipse.jdt.core.dom.CatchClause;
31 import org.eclipse.jdt.core.dom.CharacterLiteral;
32 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
33 import org.eclipse.jdt.core.dom.CompilationUnit;
34 import org.eclipse.jdt.core.dom.ConditionalExpression;
35 import org.eclipse.jdt.core.dom.Expression;
36 import org.eclipse.jdt.core.dom.FieldAccess;
37 import org.eclipse.jdt.core.dom.FieldDeclaration;
38 import org.eclipse.jdt.core.dom.IBinding;
39 import org.eclipse.jdt.core.dom.IMethodBinding;
40 import org.eclipse.jdt.core.dom.ITypeBinding;
41 import org.eclipse.jdt.core.dom.IVariableBinding;
42 import org.eclipse.jdt.core.dom.Javadoc;
43 import org.eclipse.jdt.core.dom.MethodDeclaration;
44 import org.eclipse.jdt.core.dom.MethodInvocation;
45 import org.eclipse.jdt.core.dom.NumberLiteral;
46 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
47 import org.eclipse.jdt.core.dom.QualifiedName;
48 import org.eclipse.jdt.core.dom.ReturnStatement;
49 import org.eclipse.jdt.core.dom.SimpleName;
50 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
51 import org.eclipse.jdt.core.dom.StringLiteral;
52 import org.eclipse.jdt.core.dom.ThisExpression;
53 import org.eclipse.jdt.core.dom.Type;
54 import org.eclipse.jdt.core.dom.TypeLiteral;
55 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
56 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
57 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
58
59 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
60 import org.eclipse.jdt.internal.corext.dom.Bindings;
61 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
62 import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
63 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.GenericType;
64 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ParameterizedType;
65 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
66 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeVariable;
67 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.WildcardType;
68 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayElementVariable2;
69 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2;
70 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
71 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ImmutableTypeVariable2;
72 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.IndependentTypeVariable2;
73 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterTypeVariable2;
74 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterizedTypeVariable2;
75 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ReturnTypeVariable2;
76 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TTypes;
77 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
78 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.VariableVariable2;
79 import org.eclipse.jdt.internal.corext.util.JdtFlags;
80
81 public class InferTypeArgumentsConstraintCreator extends HierarchicalASTVisitor {
82
83     /**
84      * Property in <code>ASTNode</code>s that holds the node's <code>ConstraintVariable</code>.
85      */

86     private static final String JavaDoc CV_PROP= "org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CONSTRAINT_VARIABLE"; //$NON-NLS-1$
87

88     private InferTypeArgumentsTCModel fTCModel;
89     private ICompilationUnit fCU;
90
91     private final boolean fAssumeCloneReturnsSameType;
92     
93
94     public InferTypeArgumentsConstraintCreator(InferTypeArgumentsTCModel model, boolean assumeCloneReturnsSameType) {
95         fTCModel= model;
96         fAssumeCloneReturnsSameType= assumeCloneReturnsSameType;
97     }
98     
99     public boolean visit(CompilationUnit node) {
100         fTCModel.newCu(); //TODO: make sure that accumulators are reset after last CU!
101
fCU= (ICompilationUnit) node.getJavaElement();
102         return super.visit(node);
103     }
104     
105     public boolean visit(Javadoc node) {
106         return false;
107     }
108     
109     public boolean visit(Type node) {
110         return false; //TODO
111
}
112     
113     /*
114      * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.Type)
115      */

116     public void endVisit(Type node) {
117         if (node.isParameterizedType()) {
118             // retain already parameterized types
119
ImmutableTypeVariable2 typeVariable= fTCModel.makeImmutableTypeVariable(node.resolveBinding(), /*no boxing*/null);
120             setConstraintVariable(node, typeVariable);
121         } else {
122             TypeVariable2 typeVariable= fTCModel.makeTypeVariable(node);
123             setConstraintVariable(node, typeVariable);
124         }
125     }
126     
127     public void endVisit(SimpleName node) {
128         if (node.resolveBoxing()) {
129             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
130             setConstraintVariable(node, boxed);
131             return;
132         }
133         IBinding binding= node.resolveBinding();
134         if (binding instanceof IVariableBinding) {
135             //TODO: code is similar to handling of method return value
136
IVariableBinding variableBinding= (IVariableBinding) binding;
137             ITypeBinding declaredVariableType= variableBinding.getVariableDeclaration().getType();
138             if (declaredVariableType.isTypeVariable()) {
139                 Expression receiver= getSimpleNameReceiver(node);
140                 if (receiver != null) {
141                     ConstraintVariable2 receiverCv= getConstraintVariable(receiver);
142                     Assert.isNotNull(receiverCv); // the type variable must come from the receiver!
143

144                     ConstraintVariable2 elementCv= fTCModel.getElementVariable(receiverCv, declaredVariableType);
145                     // [retVal] =^= Elem[receiver]:
146
setConstraintVariable(node, elementCv);
147                     return;
148                 }
149                 
150             } else if (declaredVariableType.isParameterizedType()){
151                 Expression receiver= getSimpleNameReceiver(node);
152                 if (receiver != null) {
153                     ConstraintVariable2 receiverCv= getConstraintVariable(receiver);
154                     if (receiverCv != null) {
155 // ITypeBinding genericVariableType= declaredVariableType.getTypeDeclaration();
156
ConstraintVariable2 returnTypeCv= fTCModel.makeParameterizedTypeVariable(declaredVariableType);
157                         setConstraintVariable(node, returnTypeCv);
158                         // Elem[retVal] =^= Elem[receiver]
159
TType declaredVariableTType= fTCModel.createTType(declaredVariableType);
160                         fTCModel.createTypeVariablesEqualityConstraints(receiverCv, Collections.EMPTY_MAP, returnTypeCv, declaredVariableTType);
161                         return;
162                     }
163                 }
164                 
165             } else {
166                 //TODO: array...
167
//logUnexpectedNode(node, null);
168
}
169             
170             // default:
171
VariableVariable2 cv= fTCModel.makeVariableVariable(variableBinding);
172             setConstraintVariable(node, cv);
173         }
174         // TODO else?
175
}
176
177     private Expression getSimpleNameReceiver(SimpleName node) {
178         Expression receiver;
179         if (node.getParent() instanceof QualifiedName && node.getLocationInParent() == QualifiedName.NAME_PROPERTY) {
180             receiver= ((QualifiedName) node.getParent()).getQualifier();
181         } else if (node.getParent() instanceof FieldAccess && node.getLocationInParent() == FieldAccess.NAME_PROPERTY) {
182             receiver= ((FieldAccess) node.getParent()).getExpression();
183         } else {
184             //TODO other cases? (ThisExpression, SuperAccessExpression, ...)
185
receiver= null;
186         }
187         if (receiver instanceof ThisExpression)
188             return null;
189         else
190             return receiver;
191     }
192     
193     public void endVisit(FieldAccess node) {
194         if (node.resolveBoxing()) {
195             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
196             setConstraintVariable(node, boxed);
197             return;
198         }
199         ConstraintVariable2 nameCv= getConstraintVariable(node.getName());
200         setConstraintVariable(node, nameCv);
201     }
202     
203     public void endVisit(QualifiedName node) {
204         if (node.resolveBoxing()) {
205             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
206             setConstraintVariable(node, boxed);
207             return;
208         }
209         ConstraintVariable2 cv= getConstraintVariable(node.getName());
210         setConstraintVariable(node, cv);
211     }
212     
213     public void endVisit(ArrayAccess node) {
214         if (node.resolveBoxing()) {
215             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
216             setConstraintVariable(node, boxed);
217             return;
218         }
219         
220         ConstraintVariable2 arrayCv= getConstraintVariable(node.getArray());
221         if (arrayCv == null)
222             return;
223         
224         ArrayElementVariable2 arrayElementCv= fTCModel.getArrayElementVariable(arrayCv);
225         setConstraintVariable(node, arrayElementCv);
226     }
227     
228     public void endVisit(Assignment node) {
229         Expression lhs= node.getLeftHandSide();
230         Expression rhs= node.getRightHandSide();
231         
232         ConstraintVariable2 left= getConstraintVariable(lhs);
233         ConstraintVariable2 right= getConstraintVariable(rhs);
234         if (node.resolveBoxing()) {
235             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
236             setConstraintVariable(node, boxed);
237         } else {
238             setConstraintVariable(node, left); // type of assignement is type of 'left'
239
}
240         if (left == null || right == null)
241             return;
242         
243         Assignment.Operator op= node.getOperator();
244         if (op == Assignment.Operator.PLUS_ASSIGN && (lhs.resolveTypeBinding() == node.getAST().resolveWellKnownType("java.lang.String"))) { //$NON-NLS-1$
245
//Special handling for automatic String conversion: do nothing; the RHS can be anything.
246
} else {
247             fTCModel.createElementEqualsConstraints(left, right);
248             fTCModel.createSubtypeConstraint(right, left); // left= right; --> [right] <= [left]
249
}
250         //TODO: other implicit conversions: numeric promotion, autoboxing?
251
}
252     
253     public void endVisit(CastExpression node) {
254 // if (! (expressionCv instanceof CollectionElementVariable2))
255
// return; //TODO: returns too early when dealing with nested collections.
256

257         Type type= node.getType();
258         ITypeBinding typeBinding= type.resolveBinding();
259         if (typeBinding.isPrimitive()) {
260             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(typeBinding, node);
261             setConstraintVariable(node, boxed);
262             return; // avoid removing numeric conversions
263
}
264         
265         ConstraintVariable2 typeCv= getConstraintVariable(type);
266         if (typeCv == null)
267             return;
268         
269         //TODO: can this be loosened when we remove casts?
270
setConstraintVariable(node, typeCv);
271         
272         Expression expression= node.getExpression();
273         ConstraintVariable2 expressionCv= getConstraintVariable(expression);
274         
275         //Avoid removing casts that have not been made obsolete by this refactoring:
276
if (expressionCv == null)
277             return;
278         if (expressionCv instanceof ImmutableTypeVariable2)
279             return;
280         if (! (expressionCv instanceof TypeVariable2 || expressionCv instanceof IndependentTypeVariable2 || expressionCv instanceof CollectionElementVariable2)
281                 && fTCModel.getElementVariables(expressionCv).size() == 0 && fTCModel.getArrayElementVariable(expressionCv) == null)
282             return;
283         
284         fTCModel.createAssignmentElementConstraints(typeCv, expressionCv);
285         
286         if (expression instanceof MethodInvocation) {
287             MethodInvocation invoc= (MethodInvocation) expression;
288             if (! isSpecialCloneInvocation(invoc.resolveMethodBinding(), invoc.getExpression())) {
289                 fTCModel.makeCastVariable(node, expressionCv);
290             }
291         } else {
292             fTCModel.makeCastVariable(node, expressionCv);
293         }
294         
295         boolean eitherIsIntf= typeBinding.isInterface() || expression.resolveTypeBinding().isInterface();
296         if (eitherIsIntf)
297             return;
298         
299         //TODO: preserve up- and down-castedness!
300

301     }
302     
303     public void endVisit(ParenthesizedExpression node) {
304         if (node.resolveBoxing()) {
305             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
306             setConstraintVariable(node, boxed);
307             return;
308         }
309         ConstraintVariable2 expressionCv= getConstraintVariable(node.getExpression());
310         setConstraintVariable(node, expressionCv);
311     }
312     
313     public void endVisit(ConditionalExpression node) {
314         // for now, no support for passing generic types through conditional expressions
315
ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(node.resolveTypeBinding(), node);
316         setConstraintVariable(node, boxed);
317     }
318     
319     public boolean visit(CatchClause node) {
320         SingleVariableDeclaration exception= node.getException();
321         IVariableBinding variableBinding= exception.resolveBinding();
322         VariableVariable2 cv= fTCModel.makeDeclaredVariableVariable(variableBinding, fCU);
323         setConstraintVariable(exception, cv);
324         return true;
325     }
326     
327     public void endVisit(StringLiteral node) {
328         ITypeBinding typeBinding= node.resolveTypeBinding();
329         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, /*no boxing*/null);
330         setConstraintVariable(node, cv);
331     }
332     
333     public void endVisit(NumberLiteral node) {
334         ITypeBinding typeBinding= node.resolveTypeBinding();
335         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, node);
336         setConstraintVariable(node, cv);
337     }
338     
339     public void endVisit(BooleanLiteral node) {
340         ITypeBinding typeBinding= node.resolveTypeBinding();
341         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, node);
342         setConstraintVariable(node, cv);
343     }
344     
345     public void endVisit(CharacterLiteral node) {
346         ITypeBinding typeBinding= node.resolveTypeBinding();
347         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, node);
348         setConstraintVariable(node, cv);
349     }
350     
351     public void endVisit(ThisExpression node) {
352         ITypeBinding typeBinding= node.resolveTypeBinding();
353         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, /*no boxing*/null);
354         setConstraintVariable(node, cv);
355     }
356
357     public void endVisit(TypeLiteral node) {
358         ITypeBinding typeBinding= node.resolveTypeBinding();
359         ImmutableTypeVariable2 cv= fTCModel.makeImmutableTypeVariable(typeBinding, /*no boxing*/null);
360         setConstraintVariable(node, cv);
361     }
362     
363     public void endVisit(MethodDeclaration node) {
364         IMethodBinding methodBinding= node.resolveBinding();
365     
366         if (methodBinding == null)
367             return; //TODO: emit error?
368

369         int parameterCount= node.parameters().size();
370         ConstraintVariable2[] parameterTypeCvs= new ConstraintVariable2[parameterCount];
371         for (int i= 0; i < parameterCount; i++) {
372             SingleVariableDeclaration paramDecl= (SingleVariableDeclaration) node.parameters().get(i);
373             //parameterTypeVariable currently not used, but need to register in order to store source range
374
ConstraintVariable2 parameterTypeCv= fTCModel.makeDeclaredParameterTypeVariable(methodBinding, i, fCU);
375             parameterTypeCvs[i]= parameterTypeCv;
376             if (parameterTypeCv == null)
377                 continue;
378             
379             //creating equals constraint between parameterTypeVariable's elements and the Type's elements
380
ConstraintVariable2 typeCv= getConstraintVariable(paramDecl.getType());
381             fTCModel.createElementEqualsConstraints(parameterTypeCv, typeCv);
382             
383             //TODO: should avoid having a VariableVariable as well as a ParameterVariable for a parameter
384
ConstraintVariable2 nameCv= getConstraintVariable(paramDecl.getName());
385             fTCModel.createElementEqualsConstraints(parameterTypeCv, nameCv);
386         }
387         
388         ConstraintVariable2 returnTypeCv= null;
389         if (! methodBinding.isConstructor()) {
390             //TODO: should only create return type variable if type is generic?
391
ConstraintVariable2 returnTypeBindingCv= fTCModel.makeDeclaredReturnTypeVariable(methodBinding, fCU);
392             if (returnTypeBindingCv != null) {
393                 returnTypeCv= getConstraintVariable(node.getReturnType2());
394                 fTCModel.createElementEqualsConstraints(returnTypeBindingCv, returnTypeCv);
395             }
396         }
397         if (MethodChecks.isVirtual(methodBinding)) {
398             //TODO: RippleMethod constraints for corner cases: see testCuRippleMethods3, bug 41989
399
addConstraintsForOverriding(methodBinding, returnTypeCv, parameterTypeCvs);
400         }
401     }
402     
403     private void addConstraintsForOverriding(IMethodBinding methodBinding, ConstraintVariable2 returnTypeCv, ConstraintVariable2[] parameterTypeCvs) {
404         boolean hasParameterElementCvs= false;
405         for (int i= 0; i < parameterTypeCvs.length; i++)
406             if (parameterTypeCvs[i] != null)
407                 hasParameterElementCvs= true;
408         
409         if (returnTypeCv == null && ! hasParameterElementCvs)
410             return;
411         
412         ITypeBinding[] allSuperTypes= Bindings.getAllSuperTypes(methodBinding.getDeclaringClass());
413         for (int i= 0; i < allSuperTypes.length; i++) {
414             ITypeBinding superType= allSuperTypes[i];
415             IMethodBinding superMethod= Bindings.findOverriddenMethodInType(superType, methodBinding);
416             if (superMethod == null)
417                 continue;
418             
419             for (int p= 0; p < parameterTypeCvs.length; p++) {
420                 if (parameterTypeCvs[p] == null)
421                     continue;
422                 ParameterTypeVariable2 parameterTypeCv= fTCModel.makeParameterTypeVariable(superMethod, p);
423                 fTCModel.createElementEqualsConstraints(parameterTypeCv, parameterTypeCvs[p]);
424             }
425             
426             if (returnTypeCv != null) {
427                 ReturnTypeVariable2 superMethodReturnTypeCv= fTCModel.makeReturnTypeVariable(superMethod);
428                 fTCModel.createElementEqualsConstraints(superMethodReturnTypeCv, returnTypeCv);
429             }
430         }
431     }
432     
433     public void endVisit(MethodInvocation node) {
434         IMethodBinding methodBinding= node.resolveMethodBinding();
435         if (methodBinding == null)
436             return;
437         
438         Expression receiver;
439         if (JdtFlags.isStatic(methodBinding))
440             receiver= null;
441         else
442             receiver= node.getExpression();
443         
444         //TODO: Expression can be null when visiting a non-special method in a subclass of a container type.
445

446         if (isSpecialCloneInvocation(methodBinding, receiver)) {
447             ConstraintVariable2 expressionCv= getConstraintVariable(receiver);
448             // [retVal] =^= [receiver]:
449
setConstraintVariable(node, expressionCv);
450             
451         } else if ("getClass".equals(methodBinding.getName()) && methodBinding.getParameterTypes().length == 0) { //$NON-NLS-1$
452
//special case: see JLS3 4.3.2
453
ITypeBinding returnType= node.resolveTypeBinding();
454             ITypeBinding returnTypeDeclaration= returnType.getTypeDeclaration();
455             ParameterizedTypeVariable2 expressionCv= fTCModel.makeParameterizedTypeVariable(returnTypeDeclaration);
456             setConstraintVariable(node, expressionCv);
457             ConstraintVariable2 classTypeVariable= fTCModel.getElementVariable(expressionCv, returnTypeDeclaration.getTypeParameters()[0]);
458             
459             //type of expression 'e.getClass()' is 'Class<? extends X>' where X is the static type of e
460
ITypeBinding capture= returnType.getTypeArguments()[0];
461             ITypeBinding wildcard= capture.getWildcard();
462             ImmutableTypeVariable2 wildcardType= fTCModel.makeImmutableTypeVariable(wildcard, /*no boxing*/null);
463             fTCModel.createSubtypeConstraint(classTypeVariable, wildcardType);
464             
465 // ITypeBinding bound= wildcard.getBound();
466
// ImmutableTypeVariable2 boundType= fTCModel.makeImmutableTypeVariable(bound, node.getAST());
467
// fTCModel.createSubtypeConstraint(classTypeVariable, boundType);
468

469         } else {
470             Map JavaDoc/*<String, IndependentTypeVariable2>*/ methodTypeVariables= createMethodTypeArguments(methodBinding);
471             
472             doVisitMethodInvocationReturnType(node, methodBinding, receiver, methodTypeVariables);
473             doVisitMethodInvocationArguments(methodBinding, node.arguments(), receiver, methodTypeVariables, /*no created type*/null);
474         }
475         
476     }
477
478     /**
479      * @return a map from type variable key to type variable constraint variable
480      */

481     private Map JavaDoc/*<String, IndependentTypeVariable2>*/ createMethodTypeArguments(IMethodBinding methodBinding) {
482         ITypeBinding[] methodTypeParameters= methodBinding.getMethodDeclaration().getTypeParameters();
483         Map JavaDoc methodTypeVariables;
484         if (methodTypeParameters.length == 0) {
485             methodTypeVariables= Collections.EMPTY_MAP;
486         } else {
487             methodTypeVariables= new HashMap JavaDoc();
488             for (int i= 0; i < methodTypeParameters.length; i++) {
489                 ITypeBinding methodTypeParameter= methodTypeParameters[i];
490                 //TODO: typeVariable does not need a type binding - only used in equality constraints
491
TypeVariable typeVariable= (TypeVariable) fTCModel.createTType(methodTypeParameter);
492                 IndependentTypeVariable2 typeVariableCv= fTCModel.makeIndependentTypeVariable(typeVariable);
493                 methodTypeVariables.put(methodTypeParameter.getKey(), typeVariableCv);
494             }
495         }
496         return methodTypeVariables;
497     }
498     
499     private void doVisitMethodInvocationReturnType(MethodInvocation node, IMethodBinding methodBinding, Expression receiver, Map JavaDoc/*<String, IndependentTypeVariable2>*/ methodTypeVariables) {
500         ITypeBinding declaredReturnType= methodBinding.getMethodDeclaration().getReturnType();
501         
502         if (declaredReturnType.isPrimitive()) {
503             ImmutableTypeVariable2 boxed= fTCModel.makeImmutableTypeVariable(declaredReturnType, node);
504             setConstraintVariable(node, boxed);
505             
506         } else if (declaredReturnType.isTypeVariable()) {
507             ConstraintVariable2 methodTypeVariableCv= (ConstraintVariable2) methodTypeVariables.get(declaredReturnType.getKey());
508             if (methodTypeVariableCv != null) {
509                 // e.g. in Collections: <T ..> T min(Collection<? extends T> coll):
510
setConstraintVariable(node, methodTypeVariableCv); //TODO: should be [retVal] <= Elem[arg] in this case?
511

512     // TODO:
513
// } else if (methodBinding.getErasure().getTypeParameters().length == 1 &&
514
// (genericReturnType.isTypeVariable() || genericReturnType.isWildcardType()) &&
515
// methodBinding.getParameterTypes().length == 1 &&
516
// methodBinding.getParameterTypes()[0].getErasure().isGenericType()) {
517
// // e.g. in Collections: <T ..> T min(Collection<? extends T> coll):
518
// TypeConstraintVariable2 argCv= (TypeConstraintVariable2) getConstraintVariable((Expression) node.arguments().get(0));
519
// ConstraintVariable2 elementCv= fTCModel.makeElementVariable(argCv);
520
// // [retVal] =^= Elem[arg]:
521
// setConstraintVariable(node, elementCv); //TODO: should be [retVal] <= Elem[arg]
522

523             } else {
524                 //TODO: nested generic classes and methods?
525

526                 if (receiver == null) //TODO: deal with methods inside generic types
527
return;
528                 // e.g. in List<E>: E get(int index):
529
ConstraintVariable2 expressionCv= getConstraintVariable(receiver);
530                 ConstraintVariable2 elementCv= fTCModel.getElementVariable(expressionCv, declaredReturnType);
531                 // [retVal] =^= Elem[receiver]:
532
setConstraintVariable(node, elementCv);
533             }
534         
535         } else if (declaredReturnType.isParameterizedType()) {
536             ConstraintVariable2 returnTypeCv= fTCModel.makeParameterizedTypeVariable(declaredReturnType.getTypeDeclaration());
537             setConstraintVariable(node, returnTypeCv);
538             //e.g. List<E>: Iterator<E> iterator()
539
ConstraintVariable2 receiverCv= null;
540             if (receiver != null) //TODO: deal with methods inside generic types
541
receiverCv= getConstraintVariable(receiver);
542             // Elem[retVal] =^= Elem[receiver]
543
TType declaredReturnTType= fTCModel.createTType(declaredReturnType);
544             fTCModel.createTypeVariablesEqualityConstraints(receiverCv, methodTypeVariables, returnTypeCv, declaredReturnTType);
545         
546         } else if (declaredReturnType.isArray()) {
547             ConstraintVariable2 returnTypeCv= fTCModel.makeArrayTypeVariable(declaredReturnType);
548             setConstraintVariable(node, returnTypeCv);
549             //e.g. List<E>: <T> T[] toArray(T[] a)
550
ConstraintVariable2 receiverCv= null;
551             if (receiver != null) { //TODO: deal with methods inside generic types
552
receiverCv= getConstraintVariable(receiver);
553
554                 //TODO: is this necessary elsewhere?
555
fTCModel.setMethodReceiverCV(returnTypeCv, receiverCv);
556             }
557             // Elem[retVal] =^= Elem[receiver]
558
TType declaredReturnTType= fTCModel.createTType(declaredReturnType);
559             fTCModel.createTypeVariablesEqualityConstraints(receiverCv, methodTypeVariables, returnTypeCv, declaredReturnTType);
560                     
561         } else {
562             ReturnTypeVariable2 returnTypeCv= fTCModel.makeReturnTypeVariable(methodBinding);
563             setConstraintVariable(node, returnTypeCv);
564         }
565     }
566
567     private boolean isSpecialCloneInvocation(IMethodBinding methodBinding, Expression receiver) {
568         return fAssumeCloneReturnsSameType
569                 && "clone".equals(methodBinding.getName()) //$NON-NLS-1$
570
&& methodBinding.getParameterTypes().length == 0
571                 && receiver != null
572                 && receiver.resolveTypeBinding() != methodBinding.getMethodDeclaration().getReturnType();
573     }
574
575     private void doVisitMethodInvocationArguments(IMethodBinding methodBinding, List JavaDoc arguments, Expression receiver, Map JavaDoc methodTypeVariables, Type createdType) {
576         //TODO: connect generic method type parameters, e.g. <T> void take(T t, List<T> ts)
577
ITypeBinding[] declaredParameterTypes= methodBinding.getMethodDeclaration().getParameterTypes();
578         int lastParamIdx= declaredParameterTypes.length - 1;
579         for (int i= 0; i < arguments.size(); i++) {
580             Expression arg= (Expression) arguments.get(i);
581             ConstraintVariable2 argCv= getConstraintVariable(arg);
582             if (argCv == null)
583                 continue;
584             
585             TType declaredParameterType;
586             int iParam;
587             if (! methodBinding.isVarargs() || i < lastParamIdx) {
588                 iParam= i;
589                 declaredParameterType= fTCModel.createTType(declaredParameterTypes[iParam]);
590             } else { // isVararg() && i >= lastParamIdx
591
iParam= lastParamIdx;
592                 declaredParameterType= fTCModel.createTType(declaredParameterTypes[iParam]);
593                 if (i == lastParamIdx && canAssignToVararg(
594                         fTCModel.createTType(arg.resolveTypeBinding()),
595                         (org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType) declaredParameterType)) {
596                     //OK: argument will not be packed into an array
597
} else {
598                     declaredParameterType= ((org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType) declaredParameterType).getComponentType();
599                 }
600             }
601             
602             if (declaredParameterType.isTypeVariable()) {
603                 
604                 ConstraintVariable2 methodTypeVariableCv= (ConstraintVariable2) methodTypeVariables.get(declaredParameterType.getBindingKey());
605                 if (methodTypeVariableCv != null) {
606                     // e.g. t in "<T> void take(T t, List<T> ts)"
607
fTCModel.createSubtypeConstraint(argCv, methodTypeVariableCv);
608                     
609                 } else {
610                     if (createdType != null) {
611                         //e.g. Tuple<T1, T2>: constructor Tuple(T1 t1, T2 t2)
612
ConstraintVariable2 createdTypeCv= getConstraintVariable(createdType);
613                         ConstraintVariable2 elementCv= fTCModel.getElementVariable(createdTypeCv, (TypeVariable) declaredParameterType);
614                         // [arg] <= Elem[createdType]:
615
fTCModel.createSubtypeConstraint(argCv, elementCv);
616                     }
617                     if (receiver != null) {
618                         //e.g. "Collection<E>: boolean add(E o)"
619
ConstraintVariable2 expressionCv= getConstraintVariable(receiver);
620                         ConstraintVariable2 elementCv= fTCModel.getElementVariable(expressionCv, (TypeVariable) declaredParameterType);
621     
622                         // //TypeVariableConstraintVariable2 typeVariableCv= fTCModel.makeTypeVariableVariable(declaredParameterType);
623
// ConstraintVariable2 elementCv= fTCModel.makeElementVariable(expressionCv, typeVariableCv);
624
//TODO: Somebody must connect typeVariableCv to corresponding typeVariableCVs of supertypes.
625
//- Do only once for binaries.
626
//- Do when passing for sources.
627
//- Keep a flag in CV whether done?
628
//- Do in one pass over all TypeVarCvs at the end?
629

630                         // [arg] <= Elem[receiver]:
631
fTCModel.createSubtypeConstraint(argCv, elementCv);
632                     } else {
633                         //TODO: ???
634
}
635                 }
636             } else if (declaredParameterType.isParameterizedType()) {
637                 TType[] typeArguments= ((ParameterizedType) declaredParameterType).getTypeArguments();
638                 TypeVariable[] typeParameters= ((GenericType) declaredParameterType.getTypeDeclaration()).getTypeParameters();
639                 for (int ta= 0; ta < typeArguments.length; ta++) {
640                     TType typeArgument= typeArguments[ta];
641                     CollectionElementVariable2 argElementCv= fTCModel.getElementVariable(argCv, typeParameters[ta]);
642                     if (typeArgument.isWildcardType()) {
643                         // Elem[arg] <= Elem[receiver]
644
WildcardType wildcardTypeArgument= (WildcardType) typeArgument;
645                         TType bound= wildcardTypeArgument.getBound();
646                         if (bound != null && bound.isTypeVariable()) {
647                             ConstraintVariable2 methodTypeVariableCv= (ConstraintVariable2) methodTypeVariables.get(bound.getBindingKey());
648                             if (methodTypeVariableCv != null) {
649                                 //e.g. in Collections: <T ..> T min(Collection<? extends T> coll):
650
createWildcardConstraint(wildcardTypeArgument, argElementCv, methodTypeVariableCv);
651                             } else {
652                                 if (createdType != null) {
653                                     ConstraintVariable2 createdTypeCv= getConstraintVariable(createdType);
654                                     CollectionElementVariable2 elementCv= fTCModel.getElementVariable(createdTypeCv, typeParameters[ta]);
655                                     createWildcardConstraint(wildcardTypeArgument, argElementCv, elementCv);
656                                 }
657                                 if (receiver != null) {
658                                     //e.g. Collection<E>: boolean addAll(Collection<? extends E> c)
659
ConstraintVariable2 expressionCv= getConstraintVariable(receiver);
660                                     CollectionElementVariable2 elementCv= fTCModel.getElementVariable(expressionCv, typeParameters[ta]);
661                                     createWildcardConstraint(wildcardTypeArgument, argElementCv, elementCv);
662                                 } else {
663                                     //TODO: ???
664
}
665                             }
666                         
667                         } else {
668                             //TODO
669
}
670                         
671                     } else if (typeArgument.isTypeVariable()) {
672                         ConstraintVariable2 methodTypeVariableCv= (ConstraintVariable2) methodTypeVariables.get(typeArgument.getBindingKey());
673                         if (methodTypeVariableCv != null) {
674                             //e.g. in Collections: <T> List<T> synchronizedList(List<T> list)
675
fTCModel.createEqualsConstraint(argElementCv, methodTypeVariableCv);
676                         } else {
677                             if (createdType != null) {
678                                 ConstraintVariable2 createdTypeCv= getConstraintVariable(createdType);
679                                 ConstraintVariable2 elementCv= fTCModel.getElementVariable(createdTypeCv, (TypeVariable) typeArgument);
680                                 fTCModel.createEqualsConstraint(argElementCv, elementCv);
681                             }
682                             if (receiver != null) {
683                                 ConstraintVariable2 expressionCv= getConstraintVariable(receiver);
684                                 ConstraintVariable2 elementCv= fTCModel.getElementVariable(expressionCv, (TypeVariable) typeArgument);
685                                 fTCModel.createEqualsConstraint(argElementCv, elementCv);
686                             } else {
687                                 //TODO: ???
688
}
689                         }
690                         
691                     } else {
692                         ImmutableTypeVariable2 typeArgumentCv= fTCModel.makeImmutableTypeVariable(typeArgument);
693                         fTCModel.createEqualsConstraint(argElementCv, typeArgumentCv);
694                     }
695                 }
696                 
697             } else if (declaredParameterType.isArrayType()) {
698                 //TODO: check methodBinding.isVarargs() !
699
TType declaredElementType= ((org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType) declaredParameterType).getElementType();
700                 if (declaredElementType.isTypeVariable()) {
701                     ConstraintVariable2 methodTypeVariableCv= (ConstraintVariable2) methodTypeVariables.get(declaredElementType.getBindingKey());
702                     if (methodTypeVariableCv != null) {
703                         ArrayElementVariable2 argElementCv= fTCModel.getArrayElementVariable(argCv);
704                         //e.g. in Arrays: <T> List<T> asList(T... a): //<T> List<T> asList(T[] a)
705
fTCModel.createEqualsConstraint(argElementCv, methodTypeVariableCv);
706                     } else {
707                         //TODO: receiver, createdType
708
}
709                 } else {
710                     //TODO
711
}
712
713             } else { //TODO: not else, but always? Other kinds of type references?
714
if (! InferTypeArgumentsTCModel.isAGenericType(declaredParameterType))
715                     continue;
716                 ParameterTypeVariable2 parameterTypeCv= fTCModel.makeParameterTypeVariable(methodBinding, iParam);
717                 // Elem[param] =^= Elem[arg]
718
fTCModel.createElementEqualsConstraints(parameterTypeCv, argCv);
719             }
720         }
721     }
722
723     private boolean canAssignToVararg(TType rhs, org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType lhs) {
724         return TTypes.canAssignTo(rhs.getErasure(), lhs.getErasure());
725     }
726
727     private void createWildcardConstraint(WildcardType typeArgument, CollectionElementVariable2 argElementCv, ConstraintVariable2 paramElementCv) {
728         if (typeArgument.isExtendsWildcardType())
729             fTCModel.createSubtypeConstraint(argElementCv, paramElementCv);
730         else
731             fTCModel.createSubtypeConstraint(paramElementCv, argElementCv);
732     }
733
734     public void endVisit(ClassInstanceCreation node) {
735         Expression receiver= node.getExpression();
736         Type createdType= node.getType();
737         
738         ConstraintVariable2 typeCv;
739         if (node.getAnonymousClassDeclaration() == null) {
740             typeCv= getConstraintVariable(createdType);
741         } else {
742             typeCv= fTCModel.makeImmutableTypeVariable(createdType.resolveBinding(), null);
743             setConstraintVariable(createdType, typeCv);
744         }
745         setConstraintVariable(node, typeCv);
746         
747         IMethodBinding methodBinding= node.resolveConstructorBinding();
748         Map JavaDoc methodTypeVariables= createMethodTypeArguments(methodBinding);
749         List JavaDoc arguments= node.arguments();
750         doVisitMethodInvocationArguments(methodBinding, arguments, receiver, methodTypeVariables, createdType);
751     }
752     
753     public void endVisit(ArrayCreation node) {
754         ArrayType arrayType= node.getType();
755         TypeVariable2 arrayTypeCv= (TypeVariable2) getConstraintVariable(arrayType);
756         if (arrayTypeCv == null)
757             return;
758         setConstraintVariable(node, arrayTypeCv);
759         //TODO: constraints for array initializer?
760
}
761     
762     public void endVisit(ReturnStatement node) {
763         Expression expression= node.getExpression();
764         if (expression == null)
765             return;
766         ConstraintVariable2 expressionCv= getConstraintVariable(expression);
767         if (expressionCv == null)
768             return;
769         
770         MethodDeclaration methodDeclaration= (MethodDeclaration) ASTNodes.getParent(node, ASTNode.METHOD_DECLARATION);
771         if (methodDeclaration == null)
772             return;
773         IMethodBinding methodBinding= methodDeclaration.resolveBinding();
774         if (methodBinding == null)
775             return;
776         ReturnTypeVariable2 returnTypeCv= fTCModel.makeReturnTypeVariable(methodBinding);
777         if (returnTypeCv == null)
778             return;
779         
780         fTCModel.createElementEqualsConstraints(returnTypeCv, expressionCv);
781     }
782     
783     public void endVisit(VariableDeclarationExpression node) {
784         // Constrain the types of the child VariableDeclarationFragments to be equal to one
785
// another, since the initializers in a 'for' statement can only have one type.
786
// Pairwise constraints between adjacent variables is enough.
787
Type type= node.getType();
788         ConstraintVariable2 typeCv= getConstraintVariable(type);
789         if (typeCv == null)
790             return;
791         
792         setConstraintVariable(node, typeCv);
793         
794         List JavaDoc fragments= node.fragments();
795         for (Iterator JavaDoc iter= fragments.iterator(); iter.hasNext();) {
796             VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next();
797             ConstraintVariable2 fragmentCv= getConstraintVariable(fragment);
798             fTCModel.createElementEqualsConstraints(typeCv, fragmentCv);
799         }
800     }
801     
802     public void endVisit(VariableDeclarationStatement node) {
803         // TODO: in principle, no need to tie the VariableDeclarationFragments together.
804
// The VariableDeclarationExpression can be split up when fragments get different types.
805
// Warning: still need to connect fragments with type!
806
endVisitFieldVariableDeclaration(node.getType(), node.fragments());
807     }
808
809     public void endVisit(FieldDeclaration node) {
810         // TODO: in principle, no need to tie the VariableDeclarationFragments together.
811
// The FieldDeclaration can be split up when fragments get different types.
812
// Warning: still need to connect fragments with type!
813
endVisitFieldVariableDeclaration(node.getType(), node.fragments());
814     }
815     
816     private void endVisitFieldVariableDeclaration(Type type, List JavaDoc variableDeclarationFragments) {
817         ConstraintVariable2 typeCv= getConstraintVariable(type);
818         if (typeCv == null)
819             return;
820         
821         for (Iterator JavaDoc iter= variableDeclarationFragments.iterator(); iter.hasNext();) {
822             VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next();
823             ConstraintVariable2 fragmentCv= getConstraintVariable(fragment);
824             fTCModel.createElementEqualsConstraints(typeCv, fragmentCv);
825         }
826     }
827
828     public void endVisit(SingleVariableDeclaration node) {
829         // used for formal method parameters and catch clauses
830
//TODO: extra dimensions?
831

832 // ConstraintVariable2 typeCv= getConstraintVariable(node.getType()); //TODO: who needs this?
833

834 // ConstraintVariable2 nameCv;
835
// switch (node.getParent().getNodeType()) {
836
// case ASTNode.METHOD_DECLARATION :
837
// MethodDeclaration parent= (MethodDeclaration) node.getParent();
838
// int index= parent.parameters().indexOf(node);
839
// nameCv= fTCFactory.makeParameterTypeVariable(parent.resolveBinding(), index, node.getType());
840
// //store source range even if variable not used in constraint here. TODO: move to visit(MethodDeclaration)?
841
// break;
842
// case ASTNode.CATCH_CLAUSE :
843
// nameCv= fTCFactory.makeVariableVariable(node.resolveBinding());
844
//
845
// break;
846
// default:
847
// unexpectedNode(node.getParent());
848
// }
849
// setConstraintVariable(node, nameCv);
850

851         //TODO: Move this into visit(SimpleName) or leave it here?
852
// ExpressionVariable2 name= fTCFactory.makeExpressionVariable(node.getName());
853
// TypeVariable2 type= fTCFactory.makeTypeVariable(node.getType());
854
// ITypeConstraint2[] nameEqualsType= fTCFactory.createEqualsConstraint(name, type);
855
// addConstraints(nameEqualsType);
856

857         //TODO: When can a SingleVariableDeclaration have an initializer? Never up to Java 1.5?
858
Expression initializer= node.getInitializer();
859         if (initializer == null)
860             return;
861         
862 // ConstraintVariable2 initializerCv= getConstraintVariable(initializer);
863
// ConstraintVariable2 nameCv= getConstraintVariable(node);
864
//TODO: check: property has been set in visit(CatchClause), visit(MethodDeclaration), visit(EnhancedForStatament)
865
//fTCFactory.createSubtypeConstraint(initializerCv, nameCv); //TODO: not for augment raw container clients
866
}
867     
868     public void endVisit(VariableDeclarationFragment node) {
869         VariableVariable2 cv= fTCModel.makeDeclaredVariableVariable(node.resolveBinding(), fCU);
870         if (cv == null)
871             return;
872         
873         setConstraintVariable(node, cv);
874         
875         //TODO: prune unused CV for local variables (but not fields)
876

877         Expression initializer= node.getInitializer();
878         if (initializer == null)
879             return;
880         
881         ConstraintVariable2 initializerCv= getConstraintVariable(initializer);
882         if (initializerCv == null)
883             return;
884         
885         fTCModel.createElementEqualsConstraints(cv, initializerCv);
886         
887         // name= initializer --> [initializer] <= [name]
888
// if (initializerCv instanceof CollectionElementVariable2)
889
// fTCModel.createSubtypeConstraint(initializerCv, cv);
890
}
891     
892     //--------- private helpers ----------------//
893

894     public InferTypeArgumentsTCModel getTCModel() {
895         return fTCModel;
896     }
897     
898     /**
899      * @param node the ASTNode
900      * @return the {@link ConstraintVariable2} associated with the node, or <code>null</code>
901      */

902     protected static ConstraintVariable2 getConstraintVariable(ASTNode node) {
903         return (ConstraintVariable2) node.getProperty(CV_PROP);
904     }
905     
906     /**
907      * @param node the ASTNode
908      * @param constraintVariable the {@link ConstraintVariable2} to be associated with node
909      */

910     protected static void setConstraintVariable(ASTNode node, ConstraintVariable2 constraintVariable) {
911         node.setProperty(CV_PROP, constraintVariable);
912     }
913     
914 // private void logUnexpectedNode(ASTNode node, String msg) {
915
// String message= msg == null ? "" : msg + ":\n"; //$NON-NLS-1$//$NON-NLS-2$
916
// if (node == null) {
917
// message+= "ASTNode was not expected to be null"; //$NON-NLS-1$
918
// } else {
919
// message+= "Found unexpected node (type: " + node.getNodeType() + "):\n" + node.toString(); //$NON-NLS-1$ //$NON-NLS-2$
920
// }
921
// JavaPlugin.log(new Exception(message).fillInStackTrace());
922
// }
923

924 }
925
Popular Tags