KickJava   Java API By Example, From Geeks To Geeks.

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


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.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.HashSet JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.LinkedHashMap JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.eclipse.core.runtime.Assert;
26 import org.eclipse.core.runtime.Platform;
27
28 import org.eclipse.jdt.core.ICompilationUnit;
29 import org.eclipse.jdt.core.dom.CastExpression;
30 import org.eclipse.jdt.core.dom.Expression;
31 import org.eclipse.jdt.core.dom.IMethodBinding;
32 import org.eclipse.jdt.core.dom.ITypeBinding;
33 import org.eclipse.jdt.core.dom.IVariableBinding;
34 import org.eclipse.jdt.core.dom.Modifier;
35 import org.eclipse.jdt.core.dom.Type;
36
37 import org.eclipse.jdt.internal.corext.dom.Bindings;
38 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
39 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType;
40 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.GenericType;
41 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ParameterizedType;
42 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
43 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment;
44 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeVariable;
45 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayElementVariable2;
46 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayTypeVariable2;
47 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
48 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2;
49 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
50 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraint2;
51 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ImmutableTypeVariable2;
52 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.IndependentTypeVariable2;
53 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterTypeVariable2;
54 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterizedTypeVariable2;
55 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ReturnTypeVariable2;
56 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.SubTypeConstraint2;
57 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeEquivalenceSet;
58 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
59 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.VariableVariable2;
60 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
61
62
63 public class InferTypeArgumentsTCModel {
64     
65     protected static final boolean DEBUG= Boolean.valueOf(Platform.getDebugOption("org.eclipse.jdt.ui/debug/TypeConstraints")).booleanValue(); //$NON-NLS-1$
66

67     private static final String JavaDoc INDEXED_COLLECTION_ELEMENTS= "IndexedCollectionElements"; //$NON-NLS-1$
68
private static final String JavaDoc ARRAY_ELEMENT= "ArrayElement"; //$NON-NLS-1$
69
private static final String JavaDoc USED_IN= "UsedIn"; //$NON-NLS-1$
70
private static final String JavaDoc METHOD_RECEIVER= "MethodReceiver"; //$NON-NLS-1$
71
private static final Map JavaDoc EMPTY_COLLECTION_ELEMENT_VARIABLES_MAP= Collections.EMPTY_MAP;
72     
73     protected static boolean fStoreToString= DEBUG;
74     
75     /**
76      * Map from a {@link ConstraintVariable2} to itself.
77      */

78     private HashMap JavaDoc/*<ConstraintVariable2, ConstraintVariable2>*/ fConstraintVariables;
79     /**
80      * Map from a {@link ITypeConstraint2} to itself.
81      */

82     private HashMap JavaDoc/*<ITypeConstraint2, ITypeConstraint2>*/ fTypeConstraints;
83     private Collection JavaDoc/*CastVariable2*/ fCastVariables;
84     
85     private HashSet JavaDoc fCuScopedConstraintVariables;
86     
87     private TypeEnvironment fTypeEnvironment;
88     
89     private static final int MAX_TTYPE_CACHE= 1024;
90     private Map JavaDoc/*<String, TType>*/ fTTypeCache= new LinkedHashMap JavaDoc(MAX_TTYPE_CACHE, 0.75f, true) {
91         private static final long serialVersionUID= 1L;
92         protected boolean removeEldestEntry(Map.Entry JavaDoc eldest) {
93             return size() > MAX_TTYPE_CACHE;
94         }
95     };
96     
97     
98     public InferTypeArgumentsTCModel() {
99         fTypeConstraints= new HashMap JavaDoc();
100         fConstraintVariables= new LinkedHashMap JavaDoc(); // make iteration independent of hashCode() implementation
101
fCastVariables= new ArrayList JavaDoc();
102         
103         fCuScopedConstraintVariables= new HashSet JavaDoc();
104         
105         fTypeEnvironment= new TypeEnvironment(true);
106     }
107     
108     /**
109      * Allows for avoiding the creation of SimpleTypeConstraints based on properties of
110      * their constituent ConstraintVariables and ConstraintOperators. Can be used to e.g.
111      * avoid creation of constraints for assignments between built-in types.
112      *
113      * @param cv1
114      * @param cv2
115      * @return <code>true</code> iff the type constraint should really be created
116      */

117     protected boolean keep(ConstraintVariable2 cv1, ConstraintVariable2 cv2) {
118         if ((cv1 == null || cv2 == null))
119             return false;
120         
121         if (cv1.equals(cv2)) {
122             if (cv1 == cv2)
123                 return false;
124             else
125                 Assert.isTrue(false);
126         }
127         
128         if (cv1 instanceof CollectionElementVariable2 || cv2 instanceof CollectionElementVariable2)
129             return true;
130         
131         if (cv1 instanceof IndependentTypeVariable2 || cv2 instanceof IndependentTypeVariable2)
132             return true;
133
134         if (isAGenericType(cv1.getType()))
135             return true;
136
137         if (isAGenericType(cv2.getType()))
138             return true;
139         
140         return false;
141     }
142     
143     /**
144      * @param cv
145      * @return a List of ITypeConstraint2s where cv is used
146      */

147     public List JavaDoc/*<ITypeConstraint2>*/ getUsedIn(ConstraintVariable2 cv) {
148         Object JavaDoc usedIn= cv.getData(USED_IN);
149         if (usedIn == null)
150             return Collections.EMPTY_LIST;
151         else if (usedIn instanceof ArrayList JavaDoc)
152             return Collections.unmodifiableList((ArrayList JavaDoc) usedIn);
153         else
154             return Collections.singletonList(usedIn);
155     }
156     
157     public void newCu() {
158         pruneUnusedCuScopedCvs();
159         fCuScopedConstraintVariables.clear();
160         fTTypeCache.clear();
161     }
162     
163     private void pruneUnusedCuScopedCvs() {
164         for (Iterator JavaDoc iter= fCuScopedConstraintVariables.iterator(); iter.hasNext();) {
165             ConstraintVariable2 cv= (ConstraintVariable2) iter.next();
166             pruneCvIfUnused(cv);
167         }
168     }
169
170     private boolean pruneCvIfUnused(ConstraintVariable2 cv) {
171         if (getUsedIn(cv).size() != 0)
172             return false;
173         
174         if (cv.getTypeEquivalenceSet() != null) {
175             if (cv.getTypeEquivalenceSet().getContributingVariables().length > 0)
176                 return false;
177         }
178         
179         ArrayElementVariable2 arrayElementVariable= getArrayElementVariable(cv);
180         if (arrayElementVariable != null && ! pruneCvIfUnused(arrayElementVariable))
181             return false;
182         
183         Map JavaDoc elementVariables= getElementVariables(cv);
184         for (Iterator JavaDoc iter= elementVariables.values().iterator(); iter.hasNext();) {
185             CollectionElementVariable2 elementVariable= (CollectionElementVariable2) iter.next();
186             if (! pruneCvIfUnused(elementVariable))
187                 return false;
188         }
189         
190         fConstraintVariables.remove(cv);
191         return true;
192     }
193
194     public ConstraintVariable2[] getAllConstraintVariables() {
195         ConstraintVariable2[] result= new ConstraintVariable2[fConstraintVariables.size()];
196         int i= 0;
197         for (Iterator JavaDoc iter= fConstraintVariables.keySet().iterator(); iter.hasNext(); i++)
198             result[i]= (ConstraintVariable2) iter.next();
199         return result;
200     }
201     
202     public ITypeConstraint2[] getAllTypeConstraints() {
203         Set JavaDoc typeConstraints= fTypeConstraints.keySet();
204         return (ITypeConstraint2[]) typeConstraints.toArray(new ITypeConstraint2[typeConstraints.size()]);
205     }
206     
207     public CastVariable2[] getCastVariables() {
208         return (CastVariable2[]) fCastVariables.toArray(new CastVariable2[fCastVariables.size()]);
209     }
210     
211     /**
212      * Controls calculation and storage of information for more readable toString() messages.
213      * <p><em>Warning: This method is for testing purposes only and should not be called except from unit tests.</em></p>
214      *
215      * @param store <code>true</code> iff information for toString() should be stored
216      */

217     public static void setStoreToString(boolean store) {
218         fStoreToString= store;
219     }
220     
221     public void createSubtypeConstraint(ConstraintVariable2 cv1, ConstraintVariable2 cv2) {
222         if (! keep(cv1, cv2))
223             return;
224         
225         ConstraintVariable2 storedCv1= storedCv(cv1);
226         ConstraintVariable2 storedCv2= storedCv(cv2);
227         ITypeConstraint2 typeConstraint= new SubTypeConstraint2(storedCv1, storedCv2);
228         
229         Object JavaDoc storedTc= fTypeConstraints.get(typeConstraint);
230         if (storedTc == null) {
231             fTypeConstraints.put(typeConstraint, typeConstraint);
232         } else {
233             typeConstraint= (ITypeConstraint2) storedTc;
234         }
235         
236         registerCvWithTc(storedCv1, typeConstraint);
237         registerCvWithTc(storedCv2, typeConstraint);
238     }
239
240     private ConstraintVariable2 storedCv(ConstraintVariable2 cv) {
241         Object JavaDoc stored= fConstraintVariables.get(cv);
242         if (stored == null) {
243             fConstraintVariables.put(cv, cv);
244             return cv;
245         } else {
246             return (ConstraintVariable2) stored;
247         }
248     }
249     
250     private void registerCvWithTc(ConstraintVariable2 storedCv, ITypeConstraint2 typeConstraint) {
251         Object JavaDoc usedIn= storedCv.getData(USED_IN);
252         if (usedIn == null) {
253             storedCv.setData(USED_IN, typeConstraint);
254         } else if (usedIn instanceof ArrayList JavaDoc) {
255             ArrayList JavaDoc usedInList= (ArrayList JavaDoc) usedIn;
256             usedInList.add(typeConstraint);
257         } else {
258             ArrayList JavaDoc usedInList= new ArrayList JavaDoc(2);
259             usedInList.add(usedIn);
260             usedInList.add(typeConstraint);
261             storedCv.setData(USED_IN, usedInList);
262         }
263     }
264     
265     public void createEqualsConstraint(ConstraintVariable2 leftElement, ConstraintVariable2 rightElement) {
266         if (leftElement == null || rightElement == null)
267             return;
268         
269         TypeEquivalenceSet leftSet= leftElement.getTypeEquivalenceSet();
270         TypeEquivalenceSet rightSet= rightElement.getTypeEquivalenceSet();
271         if (leftSet == null) {
272             if (rightSet == null) {
273                 TypeEquivalenceSet set= new TypeEquivalenceSet(leftElement, rightElement);
274                 leftElement.setTypeEquivalenceSet(set);
275                 rightElement.setTypeEquivalenceSet(set);
276             } else {
277                 rightSet.add(leftElement);
278                 leftElement.setTypeEquivalenceSet(rightSet);
279             }
280         } else {
281             if (rightSet == null) {
282                 leftSet.add(rightElement);
283                 rightElement.setTypeEquivalenceSet(leftSet);
284             } else if (leftSet == rightSet) {
285                 return;
286             } else {
287                 ConstraintVariable2[] cvs= rightSet.getContributingVariables();
288                 leftSet.addAll(cvs);
289                 for (int i= 0; i < cvs.length; i++)
290                     cvs[i].setTypeEquivalenceSet(leftSet);
291             }
292         }
293     }
294     
295     public TType createTType(ITypeBinding typeBinding) {
296         String JavaDoc key= typeBinding.getKey();
297         TType cached= (TType) fTTypeCache.get(key);
298         if (cached != null)
299             return cached;
300         TType type= fTypeEnvironment.create(typeBinding);
301         fTTypeCache.put(key, type);
302         return type;
303     }
304     
305     private TType getBoxedType(ITypeBinding typeBinding, Expression expression) {
306         if (typeBinding == null)
307             return null;
308         
309         if (! typeBinding.isPrimitive())
310             return createTType(typeBinding);
311         
312         if (expression == null || ! expression.resolveBoxing())
313             return null;
314         
315         String JavaDoc primitiveName= typeBinding.getName();
316         ITypeBinding boxed= expression.getAST().resolveWellKnownType(getBoxedTypeName(primitiveName));
317         return createTType(boxed);
318     }
319
320     private String JavaDoc getBoxedTypeName(String JavaDoc primitiveName) {
321         if ("long".equals(primitiveName)) //$NON-NLS-1$
322
return "java.lang.Long"; //$NON-NLS-1$
323

324         else if ("int".equals(primitiveName)) //$NON-NLS-1$
325
return "java.lang.Integer"; //$NON-NLS-1$
326

327         else if ("short".equals(primitiveName)) //$NON-NLS-1$
328
return "java.lang.Short"; //$NON-NLS-1$
329

330         else if ("char".equals(primitiveName)) //$NON-NLS-1$
331
return "java.lang.Character"; //$NON-NLS-1$
332

333         else if ("byte".equals(primitiveName)) //$NON-NLS-1$
334
return "java.lang.Byte"; //$NON-NLS-1$
335

336         else if ("boolean".equals(primitiveName)) //$NON-NLS-1$
337
return "java.lang.Boolean"; //$NON-NLS-1$
338

339         else if ("float".equals(primitiveName)) //$NON-NLS-1$
340
return "java.lang.Float"; //$NON-NLS-1$
341

342         else if ("double".equals(primitiveName)) //$NON-NLS-1$
343
return "java.lang.Double"; //$NON-NLS-1$
344

345         else
346             return null;
347     }
348     
349     public VariableVariable2 makeVariableVariable(IVariableBinding variableBinding) {
350         if (variableBinding == null)
351             return null;
352         TType type= getBoxedType(variableBinding.getType(), /*no boxing*/null);
353         if (type == null)
354             return null;
355         VariableVariable2 cv= new VariableVariable2(type, variableBinding);
356         VariableVariable2 storedCv= (VariableVariable2) storedCv(cv);
357         if (storedCv == cv) {
358             if (! variableBinding.isField() || Modifier.isPrivate(variableBinding.getModifiers()))
359                 fCuScopedConstraintVariables.add(storedCv);
360             makeElementVariables(storedCv, type);
361             makeArrayElementVariable(storedCv);
362             if (fStoreToString)
363                 storedCv.setData(ConstraintVariable2.TO_STRING, '[' + variableBinding.getName() + ']');
364         }
365         return storedCv;
366     }
367
368     public VariableVariable2 makeDeclaredVariableVariable(IVariableBinding variableBinding, ICompilationUnit cu) {
369         VariableVariable2 cv= makeVariableVariable(variableBinding);
370         if (cv == null)
371             return null;
372         cv.setCompilationUnit(cu);
373         return cv;
374     }
375     
376     public TypeVariable2 makeTypeVariable(Type type) {
377         ICompilationUnit cu= RefactoringASTParser.getCompilationUnit(type);
378         TType ttype= getBoxedType(type.resolveBinding(), /*no boxing*/null);
379         if (ttype == null)
380             return null;
381         
382         CompilationUnitRange range= new CompilationUnitRange(cu, type);
383         TypeVariable2 typeVariable= new TypeVariable2(ttype, range);
384         TypeVariable2 storedCv= (TypeVariable2) storedCv(typeVariable);
385         if (storedCv == typeVariable) {
386             fCuScopedConstraintVariables.add(storedCv);
387             if (isAGenericType(ttype))
388                 makeElementVariables(storedCv, ttype);
389             makeArrayElementVariable(storedCv);
390             if (fStoreToString)
391                 storedCv.setData(ConstraintVariable2.TO_STRING, type.toString());
392         }
393         return storedCv;
394     }
395
396     public IndependentTypeVariable2 makeIndependentTypeVariable(TypeVariable type) {
397         IndependentTypeVariable2 cv= new IndependentTypeVariable2(type);
398         IndependentTypeVariable2 storedCv= (IndependentTypeVariable2) storedCv(cv);
399         if (cv == storedCv) {
400             fCuScopedConstraintVariables.add(storedCv);
401 // if (isAGenericType(typeBinding)) // would lead to infinite recursion!
402
// makeElementVariables(storedCv, typeBinding);
403
if (fStoreToString)
404                 storedCv.setData(ConstraintVariable2.TO_STRING, "IndependentType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
405
}
406         return storedCv;
407     }
408         
409     public ParameterizedTypeVariable2 makeParameterizedTypeVariable(ITypeBinding typeBinding) {
410         if (typeBinding == null)
411             return null;
412         TType type= createTType(typeBinding);
413         return makeParameterizedTypeVariable(type);
414     }
415
416     private ParameterizedTypeVariable2 makeParameterizedTypeVariable(TType type) {
417         Assert.isTrue(isAGenericType(type));
418         
419         ParameterizedTypeVariable2 cv= new ParameterizedTypeVariable2(type);
420         ParameterizedTypeVariable2 storedCv= (ParameterizedTypeVariable2) storedCv(cv);
421         if (cv == storedCv) {
422             fCuScopedConstraintVariables.add(storedCv);
423             makeElementVariables(storedCv, type);
424             if (fStoreToString)
425                 storedCv.setData(ConstraintVariable2.TO_STRING, "ParameterizedType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
426
}
427         return storedCv;
428     }
429
430     public ArrayTypeVariable2 makeArrayTypeVariable(ITypeBinding typeBinding) {
431         if (typeBinding == null)
432             return null;
433         TType type= createTType(typeBinding);
434         return makeArrayTypeVariable((ArrayType) type);
435     }
436     
437     private ArrayTypeVariable2 makeArrayTypeVariable(ArrayType type) {
438         ArrayTypeVariable2 cv= new ArrayTypeVariable2(type);
439         ArrayTypeVariable2 storedCv= (ArrayTypeVariable2) storedCv(cv);
440         if (cv == storedCv) {
441             fCuScopedConstraintVariables.add(storedCv);
442             makeArrayElementVariable(storedCv);
443             if (fStoreToString)
444                 storedCv.setData(ConstraintVariable2.TO_STRING, "ArrayType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
445
}
446         return storedCv;
447     }
448     
449     public ParameterTypeVariable2 makeParameterTypeVariable(IMethodBinding methodBinding, int parameterIndex) {
450         if (methodBinding == null)
451             return null;
452         TType type= getBoxedType(methodBinding.getParameterTypes() [parameterIndex], /*no boxing*/null);
453         if (type == null)
454             return null;
455         
456         ParameterTypeVariable2 cv= new ParameterTypeVariable2(type, parameterIndex, methodBinding);
457         ParameterTypeVariable2 storedCv= (ParameterTypeVariable2) storedCv(cv);
458         if (storedCv == cv) {
459             if (methodBinding.getDeclaringClass().isLocal() || Modifier.isPrivate(methodBinding.getModifiers()))
460                 fCuScopedConstraintVariables.add(cv);
461             makeElementVariables(storedCv, type);
462             makeArrayElementVariable(storedCv);
463             if (fStoreToString)
464                 storedCv.setData(ConstraintVariable2.TO_STRING, "[Parameter(" + parameterIndex + "," + Bindings.asString(methodBinding) + ")]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
465
}
466         return storedCv;
467     }
468     
469     /**
470      * Make a ParameterTypeVariable2 from a method declaration.
471      * The constraint variable is always stored if it passes the type filter.
472      * @param methodBinding
473      * @param parameterIndex
474      * @param cu
475      * @return the ParameterTypeVariable2, or <code>null</code>
476      */

477     public ParameterTypeVariable2 makeDeclaredParameterTypeVariable(IMethodBinding methodBinding, int parameterIndex, ICompilationUnit cu) {
478         if (methodBinding == null)
479             return null;
480         ParameterTypeVariable2 cv= makeParameterTypeVariable(methodBinding, parameterIndex);
481         if (cv == null)
482             return null;
483         cv.setCompilationUnit(cu);
484         return cv;
485     }
486
487     public ReturnTypeVariable2 makeReturnTypeVariable(IMethodBinding methodBinding) {
488         if (methodBinding == null)
489             return null;
490         TType returnType= getBoxedType(methodBinding.getReturnType(), /*no boxing*/null);
491         if (returnType == null)
492             return null;
493         
494         ReturnTypeVariable2 cv= new ReturnTypeVariable2(returnType, methodBinding);
495         ReturnTypeVariable2 storedCv= (ReturnTypeVariable2) storedCv(cv);
496         if (cv == storedCv) {
497             makeElementVariables(storedCv, returnType);
498             makeArrayElementVariable(storedCv);
499             if (fStoreToString)
500                 storedCv.setData(ConstraintVariable2.TO_STRING, "[ReturnType(" + Bindings.asString(methodBinding) + ")]"); //$NON-NLS-1$ //$NON-NLS-2$
501
}
502         return storedCv;
503     }
504
505     public ReturnTypeVariable2 makeDeclaredReturnTypeVariable(IMethodBinding methodBinding, ICompilationUnit cu) {
506         if (methodBinding == null)
507             return null;
508         ReturnTypeVariable2 cv= makeReturnTypeVariable(methodBinding);
509         if (cv == null)
510             return null;
511         
512         cv.setCompilationUnit(cu);
513         if (methodBinding.getDeclaringClass().isLocal())
514             fCuScopedConstraintVariables.add(cv);
515         return cv;
516     }
517     
518     public ImmutableTypeVariable2 makeImmutableTypeVariable(ITypeBinding typeBinding, Expression expression) {
519 // Assert.isTrue(! typeBinding.isGenericType()); // see JDT/Core bug 80472
520
TType type= getBoxedType(typeBinding, expression);
521         if (type == null)
522             return null;
523         return makeImmutableTypeVariable(type);
524     }
525
526     public ImmutableTypeVariable2 makeImmutableTypeVariable(TType type) {
527         ImmutableTypeVariable2 cv= new ImmutableTypeVariable2(type);
528         ImmutableTypeVariable2 storedCv= (ImmutableTypeVariable2) storedCv(cv);
529         if (cv == storedCv) {
530             makeFixedElementVariables(storedCv, type);
531             makeArrayElementVariable(storedCv);
532         }
533         return storedCv;
534     }
535     
536     public static boolean isAGenericType(TType type) {
537         return type.isGenericType()
538                 || type.isParameterizedType()
539                 || (type.isRawType() && type.getTypeDeclaration().isGenericType());
540     }
541
542     public static boolean isAGenericType(ITypeBinding type) {
543         return type.isGenericType()
544                 || type.isParameterizedType()
545                 || (type.isRawType() && type.getTypeDeclaration().isGenericType());
546     }
547
548     public CastVariable2 makeCastVariable(CastExpression castExpression, ConstraintVariable2 expressionCv) {
549         ITypeBinding typeBinding= castExpression.resolveTypeBinding();
550         ICompilationUnit cu= RefactoringASTParser.getCompilationUnit(castExpression);
551         CompilationUnitRange range= new CompilationUnitRange(cu, castExpression);
552         CastVariable2 castCv= new CastVariable2(createTType(typeBinding), range, expressionCv);
553         fCastVariables.add(castCv);
554         return castCv;
555     }
556     
557     public TypeEnvironment getTypeEnvironment() {
558         return fTypeEnvironment;
559     }
560     
561     public CollectionElementVariable2 getElementVariable(ConstraintVariable2 constraintVariable, ITypeBinding typeVariable) {
562         Assert.isTrue(typeVariable.isTypeVariable()); // includes null check
563
HashMap JavaDoc typeVarToElementVars= (HashMap JavaDoc) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
564         if (typeVarToElementVars == null)
565             return null;
566         return (CollectionElementVariable2) typeVarToElementVars.get(typeVariable.getKey());
567     }
568
569     public Map JavaDoc/*<String typeVariableKey, CollectionElementVariable2>*/ getElementVariables(ConstraintVariable2 constraintVariable) {
570         Map JavaDoc elementVariables= (Map JavaDoc) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
571         if (elementVariables == null)
572             return EMPTY_COLLECTION_ELEMENT_VARIABLES_MAP;
573         else
574             return elementVariables;
575     }
576     
577     public ArrayElementVariable2 getArrayElementVariable(ConstraintVariable2 constraintVariable) {
578         return (ArrayElementVariable2) constraintVariable.getData(ARRAY_ELEMENT);
579     }
580     
581     private void setArrayElementVariable(ConstraintVariable2 constraintVariable, ArrayElementVariable2 arrayElementVariable) {
582         constraintVariable.setData(ARRAY_ELEMENT, arrayElementVariable);
583     }
584     
585     public void makeArrayElementVariable(ConstraintVariable2 constraintVariable2) {
586         if (constraintVariable2.getType() == null || ! constraintVariable2.getType().isArrayType())
587             return;
588         
589         ArrayElementVariable2 storedArrayElementVariable= getArrayElementVariable(constraintVariable2);
590         if (storedArrayElementVariable != null)
591             return;
592         
593         ArrayElementVariable2 arrayElementCv= new ArrayElementVariable2(constraintVariable2);
594         arrayElementCv= (ArrayElementVariable2) storedCv(arrayElementCv);
595         setArrayElementVariable(constraintVariable2, arrayElementCv);
596         
597         makeArrayElementVariable(arrayElementCv); //recursive
598
}
599         
600     public void makeElementVariables(ConstraintVariable2 expressionCv, TType type) {
601         if (isAGenericType(type)) {
602             GenericType genericType= (GenericType) type.getTypeDeclaration();
603             TType[] typeParameters= genericType.getTypeParameters();
604             for (int i= 0; i < typeParameters.length; i++) {
605                 TypeVariable typeVariable= (TypeVariable) typeParameters[i];
606                 makeElementVariable(expressionCv, typeVariable, i);
607                 if (typeVariable.getBounds().length != 0) {
608                     //TODO: create subtype constraints for bounds
609
}
610             }
611         }
612         makeElementVariablesFromSupertypes(expressionCv, type.getTypeDeclaration());
613     }
614     
615     private void makeElementVariablesFromSupertypes(ConstraintVariable2 expressionCv, TType type) {
616         TType superclass= type.getSuperclass();
617         if (superclass != null) {
618             makeSupertypeElementVariables(expressionCv, superclass);
619         }
620         
621         TType[] interfaces= type.getInterfaces();
622         for (int i= 0; i < interfaces.length; i++) {
623             makeSupertypeElementVariables(expressionCv, interfaces[i]);
624         }
625         
626     }
627     
628     private void makeSupertypeElementVariables(ConstraintVariable2 expressionCv, TType supertype) {
629         if (supertype.isParameterizedType() || supertype.isRawType()) {
630             TType[] typeArguments= null;
631             if (supertype.isParameterizedType()) {
632                 typeArguments= ((ParameterizedType) supertype).getTypeArguments();
633             }
634             TypeVariable[] typeParameters= ((GenericType) supertype.getTypeDeclaration()).getTypeParameters();
635             for (int i= 0; i < typeParameters.length; i++) {
636                 TypeVariable typeParameter= typeParameters[i];
637                 TType referenceTypeArgument;
638                 if (typeArguments == null) { // raw type
639
referenceTypeArgument= typeParameter.getErasure();
640                 } else {
641                     referenceTypeArgument= typeArguments[i];
642                 }
643                 if (referenceTypeArgument.isTypeVariable()) {
644                     CollectionElementVariable2 referenceTypeArgumentCv= getElementVariable(expressionCv, (TypeVariable) referenceTypeArgument);
645                     setElementVariable(expressionCv, referenceTypeArgumentCv, typeParameter);
646                 } else {
647                     makeElementVariable(expressionCv, typeParameter, CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX);
648                 }
649             }
650         }
651         makeElementVariablesFromSupertypes(expressionCv, supertype);
652     }
653
654     public void makeFixedElementVariables(ConstraintVariable2 expressionCv, TType type) {
655         if (isAGenericType(type)) {
656             GenericType genericType= (GenericType) type.getTypeDeclaration();
657             TType[] typeParameters= genericType.getTypeParameters();
658             TType[] typeArguments= null;
659             if (type.isParameterizedType())
660                 typeArguments= ((ParameterizedType) type).getTypeArguments();
661             
662             for (int i= 0; i < typeParameters.length; i++) {
663                 TypeVariable typeVariable= (TypeVariable) typeParameters[i];
664                 CollectionElementVariable2 elementCv= makeElementVariable(expressionCv, typeVariable, i);
665                 TType referenceTypeArgument;
666                 if (typeArguments == null) { // raw type
667
continue; // do not consider
668
} else {
669                     referenceTypeArgument= typeArguments[i];
670                 }
671                 createEqualsConstraint(elementCv, makeImmutableTypeVariable(referenceTypeArgument));
672 // if (typeVariable.getBounds().length != 0) {
673
// //TODO: create subtype constraints for bounds
674
// }
675
}
676         }
677         makeFixedElementVariablesFromSupertypes(expressionCv, type.getTypeDeclaration());
678     }
679     
680     private void makeFixedElementVariablesFromSupertypes(ConstraintVariable2 expressionCv, TType type) {
681         TType superclass= type.getSuperclass();
682         if (superclass != null)
683             makeFixedSupertypeElementVariables(expressionCv, superclass);
684         
685         TType[] interfaces= type.getInterfaces();
686         for (int i= 0; i < interfaces.length; i++)
687             makeFixedSupertypeElementVariables(expressionCv, interfaces[i]);
688     }
689     
690     private void makeFixedSupertypeElementVariables(ConstraintVariable2 expressionCv, TType supertype) {
691         if (supertype.isParameterizedType() || supertype.isRawType()) {
692             TType[] typeArguments= null;
693             if (supertype.isParameterizedType())
694                 typeArguments= ((ParameterizedType) supertype).getTypeArguments();
695             
696             TypeVariable[] typeParameters= ((GenericType) supertype.getTypeDeclaration()).getTypeParameters();
697             for (int i= 0; i < typeParameters.length; i++) {
698                 TypeVariable typeParameter= typeParameters[i];
699                 TType referenceTypeArgument;
700                 if (typeArguments == null) { // raw type
701
continue; // do not consider
702
} else {
703                     referenceTypeArgument= typeArguments[i];
704                 }
705                 if (referenceTypeArgument.isTypeVariable()) {
706                     CollectionElementVariable2 referenceTypeArgumentCv= getElementVariable(expressionCv, (TypeVariable) referenceTypeArgument);
707                     setElementVariable(expressionCv, referenceTypeArgumentCv, typeParameter);
708                 } else {
709                     CollectionElementVariable2 elementCv= makeElementVariable(expressionCv, typeParameter, CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX);
710                     createEqualsConstraint(elementCv, makeImmutableTypeVariable(referenceTypeArgument));
711                 }
712             }
713         }
714         makeFixedElementVariablesFromSupertypes(expressionCv, supertype);
715     }
716
717     /**
718      * Create equality constraints between generic type variables of expressionCv and referenceCv.
719      * For example, the generic interface <code>java.lang.Iterable&lt;E&gt;</code> defines a method
720      * <code>Iterator&lt;E&gt; iterator()</code>. Given
721      * <ul>
722      * <li>an expressionCv of a subtype of <code>Iterable</code>,</li>
723      * <li>a referenceCv of a subtype of <code>Iterator</code>, and</li>
724      * <li>a reference binding of the Iterable#iterator()'s return type (the parameterized type <code>Iterator&lt;E&gt;</code>),</li>
725      * </ul>
726      * this method creates an equality constraint between the type variable E in expressionCV and
727      * the type variable E in referenceCV.
728      *
729      * @param expressionCv the type constraint variable of an expression
730      * @param methodTypeVariables
731      * @param referenceCv the type constraint variable of a type reference
732      * @param reference the declared type reference
733      */

734     public void createTypeVariablesEqualityConstraints(ConstraintVariable2 expressionCv, Map JavaDoc/*<String, IndependentTypeVariable2>*/ methodTypeVariables, ConstraintVariable2 referenceCv, TType reference) {
735         if (reference.isParameterizedType() || reference.isRawType()) {
736             TType[] referenceTypeArguments= null;
737             if (reference.isParameterizedType()) {
738                 referenceTypeArguments= ((ParameterizedType) reference).getTypeArguments();
739             }
740             TType[] referenceTypeParameters= ((GenericType) reference.getTypeDeclaration()).getTypeParameters();
741             for (int i= 0; i < referenceTypeParameters.length; i++) {
742                 TypeVariable referenceTypeParameter= (TypeVariable) referenceTypeParameters[i];
743                 TType referenceTypeArgument;
744                 if (referenceTypeArguments == null)
745                     referenceTypeArgument= referenceTypeParameter.getErasure();
746                 else
747                     referenceTypeArgument= referenceTypeArguments[i];
748                 if (referenceTypeArgument.isTypeVariable()) {
749                     ConstraintVariable2 referenceTypeArgumentCv= getElementTypeCv(referenceTypeArgument, expressionCv, methodTypeVariables);
750                     CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
751                     createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
752                 } else if (referenceTypeArgument.isWildcardType()) {
753                     ConstraintVariable2 referenceTypeArgumentCv= makeImmutableTypeVariable(fTypeEnvironment.VOID); //block it for now (bug 106174)
754
CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
755                     createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
756                     
757 // WildcardType wildcardType= (WildcardType) referenceTypeArgument;
758
// if (wildcardType.isUnboundWildcardType()) {
759
// ConstraintVariable2 referenceTypeArgumentCv= makeImmutableTypeVariable(wildcardType);
760
// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
761
// createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
762
// } else if (wildcardType.isSuperWildcardType() && wildcardType.getBound().isTypeVariable()) {
763
// ConstraintVariable2 referenceTypeArgumentBoundCv= getElementTypeCv(wildcardType.getBound(), expressionCv, methodTypeVariables);
764
// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
765
// //TODO: need *strict* subtype constraint?
766
// createSubtypeConstraint(referenceTypeParametersCv, referenceTypeArgumentBoundCv);
767
// }
768
// else: TODO
769

770 // } else if (referenceTypeArgument.isParameterizedType()) {
771
// //TODO: nested containers
772
// ParameterizedType parameterizedType= (ParameterizedType) referenceTypeArgument;
773
// ParameterizedTypeVariable2 parameterizedTypeCv= makeParameterizedTypeVariable(parameterizedType.getTypeDeclaration());
774
// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
775
// createEqualsConstraint(parameterizedTypeCv, referenceTypeParametersCv);
776
// createElementEqualsConstraints(parameterizedTypeCv, referenceTypeParametersCv);
777
} else {
778                     //TODO
779
}
780             }
781             
782         } else if (reference.isArrayType()) {
783             TType elementType= ((ArrayType) reference).getElementType();
784             if (elementType.isRawType())
785                 elementType= elementType.getErasure();
786             ConstraintVariable2 elementTypeCv= getElementTypeCv(elementType, expressionCv, methodTypeVariables);
787             ArrayElementVariable2 arrayElementTypeCv= getArrayElementVariable(referenceCv);
788             createEqualsConstraint(elementTypeCv, arrayElementTypeCv);
789         }
790     }
791
792     private ConstraintVariable2 getElementTypeCv(TType elementType, ConstraintVariable2 expressionCv, Map JavaDoc methodTypeVariables) {
793         if (elementType.isTypeVariable()) {
794             ConstraintVariable2 elementTypeCv= (ConstraintVariable2) methodTypeVariables.get(elementType.getBindingKey());
795             if (elementTypeCv != null)
796                 return elementTypeCv;
797             if (expressionCv != null)
798                 return getElementVariable(expressionCv, (TypeVariable) elementType);
799         }
800         return null;
801     }
802     
803     private CollectionElementVariable2 makeElementVariable(ConstraintVariable2 expressionCv, TypeVariable typeVariable, int declarationTypeVariableIndex) {
804         if (expressionCv == null)
805             return null;
806         
807         CollectionElementVariable2 storedElementVariable= getElementVariable(expressionCv, typeVariable);
808         if (storedElementVariable != null)
809             return storedElementVariable;
810         
811         CollectionElementVariable2 cv= new CollectionElementVariable2(expressionCv, typeVariable, declarationTypeVariableIndex);
812         cv= (CollectionElementVariable2) storedCv(cv);
813         setElementVariable(expressionCv, cv, typeVariable);
814         return cv;
815     }
816     
817     private void setElementVariable(ConstraintVariable2 typeConstraintVariable, CollectionElementVariable2 elementVariable, TypeVariable typeVariable) {
818         HashMap JavaDoc keyToElementVar= (HashMap JavaDoc) typeConstraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
819         String JavaDoc key= typeVariable.getBindingKey();
820         if (keyToElementVar == null) {
821             keyToElementVar= new HashMap JavaDoc();
822             typeConstraintVariable.setData(INDEXED_COLLECTION_ELEMENTS, keyToElementVar);
823         } else {
824             Object JavaDoc existingElementVar= keyToElementVar.get(key);
825             if (existingElementVar != null) {
826                 Assert.isTrue(existingElementVar == elementVariable);
827             }
828         }
829         keyToElementVar.put(key, elementVariable);
830     }
831     
832     public CollectionElementVariable2 getElementVariable(ConstraintVariable2 constraintVariable, TypeVariable typeVariable) {
833         Assert.isTrue(typeVariable.isTypeVariable()); // includes null check
834
HashMap JavaDoc typeVarToElementVars= (HashMap JavaDoc) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
835         if (typeVarToElementVars == null)
836             return null;
837         return (CollectionElementVariable2) typeVarToElementVars.get(typeVariable.getBindingKey());
838     }
839
840     public void createElementEqualsConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv) {
841         internalCreateElementEqualsConstraints(cv, initializerCv, false);
842     }
843
844     public void createAssignmentElementConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv) {
845         internalCreateElementEqualsConstraints(cv, initializerCv, true);
846     }
847     
848     private void internalCreateElementEqualsConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv, boolean isAssignment) {
849         if (cv == null || initializerCv == null)
850             return;
851         
852         Map JavaDoc leftElements= getElementVariables(cv);
853         Map JavaDoc rightElements= getElementVariables(initializerCv);
854         for (Iterator JavaDoc leftIter= leftElements.entrySet().iterator(); leftIter.hasNext();) {
855             Map.Entry JavaDoc leftEntry= (Map.Entry JavaDoc) leftIter.next();
856             String JavaDoc leftTypeVariableKey= (String JavaDoc) leftEntry.getKey();
857             CollectionElementVariable2 rightElementVariable= (CollectionElementVariable2) rightElements.get(leftTypeVariableKey);
858             if (rightElementVariable != null) {
859                 CollectionElementVariable2 leftElementVariable= (CollectionElementVariable2) leftEntry.getValue();
860                 createEqualsConstraint(leftElementVariable, rightElementVariable);
861                 internalCreateElementEqualsConstraints(leftElementVariable, rightElementVariable, false); // recursive
862
}
863         }
864         
865         ArrayElementVariable2 leftArrayElement= getArrayElementVariable(cv);
866         ArrayElementVariable2 rightArrayElement= getArrayElementVariable(initializerCv);
867         if (leftArrayElement != null && rightArrayElement != null) {
868             if (isAssignment)
869                 createSubtypeConstraint(rightArrayElement, leftArrayElement);
870             else
871                 createEqualsConstraint(leftArrayElement, rightArrayElement);
872             internalCreateElementEqualsConstraints(leftArrayElement, rightArrayElement, false); // recursive
873
}
874     }
875
876     /**
877      * @return the receiver of the method invocation this expressionVariable
878      * depends on, or null iff no receiver is available. If the receiver
879      * stayed raw, then the method return type cannot be substituted.
880      */

881     public ConstraintVariable2 getMethodReceiverCv(ConstraintVariable2 expressionVariable) {
882         return (ConstraintVariable2) expressionVariable.getData(METHOD_RECEIVER);
883     }
884     
885     public void setMethodReceiverCV(ConstraintVariable2 expressionVariable, ConstraintVariable2 methodReceiverCV) {
886         expressionVariable.setData(METHOD_RECEIVER, methodReceiverCV);
887     }
888     
889 }
890
Popular Tags