]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/generics/InferTypeArgumentsTCModel.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / generics / InferTypeArgumentsTCModel.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 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
12package org.eclipse.jdt.internal.corext.refactoring.generics;
13
14import java.util.ArrayList;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.HashSet;
19import java.util.Iterator;
20import java.util.LinkedHashMap;
21import java.util.List;
22import java.util.Map;
23import java.util.Map.Entry;
24import java.util.Set;
25
26import org.eclipse.core.runtime.Assert;
27import org.eclipse.core.runtime.Platform;
28
29import org.eclipse.jdt.core.ICompilationUnit;
30import org.eclipse.jdt.core.dom.CastExpression;
31import org.eclipse.jdt.core.dom.Expression;
32import org.eclipse.jdt.core.dom.IMethodBinding;
33import org.eclipse.jdt.core.dom.ITypeBinding;
34import org.eclipse.jdt.core.dom.IVariableBinding;
35import org.eclipse.jdt.core.dom.Modifier;
36import org.eclipse.jdt.core.dom.Type;
37
38import org.eclipse.jdt.internal.corext.dom.Bindings;
39import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
40import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType;
41import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.GenericType;
42import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ParameterizedType;
43import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
44import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment;
45import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeVariable;
46import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayElementVariable2;
47import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayTypeVariable2;
48import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
49import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2;
50import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
51import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraint2;
52import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ImmutableTypeVariable2;
53import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.IndependentTypeVariable2;
54import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterTypeVariable2;
55import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterizedTypeVariable2;
56import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ReturnTypeVariable2;
57import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.SubTypeConstraint2;
58import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeEquivalenceSet;
59import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
60import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.VariableVariable2;
61import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
62
63
64public class InferTypeArgumentsTCModel {
65
66 protected static final boolean DEBUG= Boolean.valueOf(Platform.getDebugOption("org.eclipse.jdt.ui/debug/TypeConstraints")).booleanValue(); //$NON-NLS-1$
67
68 private static final String INDEXED_COLLECTION_ELEMENTS= "IndexedCollectionElements"; //$NON-NLS-1$
69 private static final String ARRAY_ELEMENT= "ArrayElement"; //$NON-NLS-1$
70 private static final String USED_IN= "UsedIn"; //$NON-NLS-1$
71 private static final String METHOD_RECEIVER= "MethodReceiver"; //$NON-NLS-1$
72 private static final Map<String, CollectionElementVariable2> EMPTY_COLLECTION_ELEMENT_VARIABLES_MAP= Collections.emptyMap();
73
74 protected static boolean fStoreToString= DEBUG;
75
76 /**
77 * Map from a {@link ConstraintVariable2} to itself.
78 */
79 private HashMap<ConstraintVariable2, ConstraintVariable2> fConstraintVariables;
80 /**
81 * Map from a {@link ITypeConstraint2} to itself.
82 */
83 private HashMap<ITypeConstraint2, ITypeConstraint2> fTypeConstraints;
84 private Collection<CastVariable2> fCastVariables;
85
86 private HashSet<ConstraintVariable2> fCuScopedConstraintVariables;
87
88 private TypeEnvironment fTypeEnvironment;
89
90 private static final int MAX_TTYPE_CACHE= 1024;
91 private Map<String, TType> fTTypeCache= new LinkedHashMap<String, TType>(MAX_TTYPE_CACHE, 0.75f, true) {
92 private static final long serialVersionUID= 1L;
93 @Override
94 protected boolean removeEldestEntry(Map.Entry<String, TType> eldest) {
95 return size() > MAX_TTYPE_CACHE;
96 }
97 };
98
99
100 public InferTypeArgumentsTCModel() {
101 fTypeConstraints= new HashMap<ITypeConstraint2, ITypeConstraint2>();
102 fConstraintVariables= new LinkedHashMap<ConstraintVariable2, ConstraintVariable2>(); // make iteration independent of hashCode() implementation
103 fCastVariables= new ArrayList<CastVariable2>();
104
105 fCuScopedConstraintVariables= new HashSet<ConstraintVariable2>();
106
107 fTypeEnvironment= new TypeEnvironment(true);
108 }
109
110 /**
111 * Allows for avoiding the creation of SimpleTypeConstraints based on properties of
112 * their constituent ConstraintVariables and ConstraintOperators. Can be used to e.g.
113 * avoid creation of constraints for assignments between built-in types.
114 *
115 * @param cv1
116 * @param cv2
117 * @return <code>true</code> iff the type constraint should really be created
118 */
119 protected boolean keep(ConstraintVariable2 cv1, ConstraintVariable2 cv2) {
120 if ((cv1 == null || cv2 == null))
121 return false;
122
123 if (cv1.equals(cv2)) {
124 if (cv1 == cv2)
125 return false;
126 else
127 Assert.isTrue(false);
128 }
129
130 if (cv1 instanceof CollectionElementVariable2 || cv2 instanceof CollectionElementVariable2)
131 return true;
132
133 if (cv1 instanceof IndependentTypeVariable2 || cv2 instanceof IndependentTypeVariable2)
134 return true;
135
136 if (isAGenericType(cv1.getType()))
137 return true;
138
139 if (isAGenericType(cv2.getType()))
140 return true;
141
142 return false;
143 }
144
145 /**
146 * @param cv
147 * @return a List of ITypeConstraint2s where cv is used
148 */
149 @SuppressWarnings("unchecked")
150 public List<ITypeConstraint2> getUsedIn(ConstraintVariable2 cv) {
151 Object usedIn= cv.getData(USED_IN);
152 if (usedIn == null)
153 return Collections.emptyList();
154 else if (usedIn instanceof ArrayList)
155 return Collections.unmodifiableList((ArrayList<ITypeConstraint2>) usedIn);
156 else
157 return Collections.singletonList((ITypeConstraint2) usedIn);
158 }
159
160 public void newCu() {
161 pruneUnusedCuScopedCvs();
162 fCuScopedConstraintVariables.clear();
163 fTTypeCache.clear();
164 }
165
166 private void pruneUnusedCuScopedCvs() {
167 for (Iterator<ConstraintVariable2> iter= fCuScopedConstraintVariables.iterator(); iter.hasNext();) {
168 ConstraintVariable2 cv= iter.next();
169 pruneCvIfUnused(cv);
170 }
171 }
172
173 private boolean pruneCvIfUnused(ConstraintVariable2 cv) {
174 if (getUsedIn(cv).size() != 0)
175 return false;
176
177 if (cv.getTypeEquivalenceSet() != null) {
178 if (cv.getTypeEquivalenceSet().getContributingVariables().length > 0)
179 return false;
180 }
181
182 ArrayElementVariable2 arrayElementVariable= getArrayElementVariable(cv);
183 if (arrayElementVariable != null && ! pruneCvIfUnused(arrayElementVariable))
184 return false;
185
186 Map<String, CollectionElementVariable2> elementVariables= getElementVariables(cv);
187 for (Iterator<CollectionElementVariable2> iter= elementVariables.values().iterator(); iter.hasNext();) {
188 CollectionElementVariable2 elementVariable= iter.next();
189 if (! pruneCvIfUnused(elementVariable))
190 return false;
191 }
192
193 fConstraintVariables.remove(cv);
194 return true;
195 }
196
197 public ConstraintVariable2[] getAllConstraintVariables() {
198 ConstraintVariable2[] result= new ConstraintVariable2[fConstraintVariables.size()];
199 int i= 0;
200 for (Iterator<ConstraintVariable2> iter= fConstraintVariables.keySet().iterator(); iter.hasNext(); i++)
201 result[i]= iter.next();
202 return result;
203 }
204
205 public ITypeConstraint2[] getAllTypeConstraints() {
206 Set<ITypeConstraint2> typeConstraints= fTypeConstraints.keySet();
207 return typeConstraints.toArray(new ITypeConstraint2[typeConstraints.size()]);
208 }
209
210 public CastVariable2[] getCastVariables() {
211 return fCastVariables.toArray(new CastVariable2[fCastVariables.size()]);
212 }
213
214 /**
215 * Controls calculation and storage of information for more readable toString() messages.
216 * <p><em>Warning: This method is for testing purposes only and should not be called except from unit tests.</em></p>
217 *
218 * @param store <code>true</code> iff information for toString() should be stored
219 */
220 public static void setStoreToString(boolean store) {
221 fStoreToString= store;
222 }
223
224 public void createSubtypeConstraint(ConstraintVariable2 cv1, ConstraintVariable2 cv2) {
225 if (! keep(cv1, cv2))
226 return;
227
228 ConstraintVariable2 storedCv1= storedCv(cv1);
229 ConstraintVariable2 storedCv2= storedCv(cv2);
230 ITypeConstraint2 typeConstraint= new SubTypeConstraint2(storedCv1, storedCv2);
231
232 Object storedTc= fTypeConstraints.get(typeConstraint);
233 if (storedTc == null) {
234 fTypeConstraints.put(typeConstraint, typeConstraint);
235 } else {
236 typeConstraint= (ITypeConstraint2) storedTc;
237 }
238
239 registerCvWithTc(storedCv1, typeConstraint);
240 registerCvWithTc(storedCv2, typeConstraint);
241 }
242
243 private ConstraintVariable2 storedCv(ConstraintVariable2 cv) {
244 Object stored= fConstraintVariables.get(cv);
245 if (stored == null) {
246 fConstraintVariables.put(cv, cv);
247 return cv;
248 } else {
249 return (ConstraintVariable2) stored;
250 }
251 }
252
253 private void registerCvWithTc(ConstraintVariable2 storedCv, ITypeConstraint2 typeConstraint) {
254 Object usedIn= storedCv.getData(USED_IN);
255 if (usedIn == null) {
256 storedCv.setData(USED_IN, typeConstraint);
257 } else if (usedIn instanceof ArrayList) {
258 @SuppressWarnings("unchecked")
259 ArrayList<ITypeConstraint2> usedInList= (ArrayList<ITypeConstraint2>) usedIn;
260 usedInList.add(typeConstraint);
261 } else {
262 ArrayList<ITypeConstraint2> usedInList= new ArrayList<ITypeConstraint2>(2);
263 usedInList.add((ITypeConstraint2) usedIn);
264 usedInList.add(typeConstraint);
265 storedCv.setData(USED_IN, usedInList);
266 }
267 }
268
269 public void createEqualsConstraint(ConstraintVariable2 leftElement, ConstraintVariable2 rightElement) {
270 if (leftElement == null || rightElement == null)
271 return;
272
273 TypeEquivalenceSet leftSet= leftElement.getTypeEquivalenceSet();
274 TypeEquivalenceSet rightSet= rightElement.getTypeEquivalenceSet();
275 if (leftSet == null) {
276 if (rightSet == null) {
277 TypeEquivalenceSet set= new TypeEquivalenceSet(leftElement, rightElement);
278 leftElement.setTypeEquivalenceSet(set);
279 rightElement.setTypeEquivalenceSet(set);
280 } else {
281 rightSet.add(leftElement);
282 leftElement.setTypeEquivalenceSet(rightSet);
283 }
284 } else {
285 if (rightSet == null) {
286 leftSet.add(rightElement);
287 rightElement.setTypeEquivalenceSet(leftSet);
288 } else if (leftSet == rightSet) {
289 return;
290 } else {
291 ConstraintVariable2[] cvs= rightSet.getContributingVariables();
292 leftSet.addAll(cvs);
293 for (int i= 0; i < cvs.length; i++)
294 cvs[i].setTypeEquivalenceSet(leftSet);
295 }
296 }
297 }
298
299 public TType createTType(ITypeBinding typeBinding) {
300 String key= typeBinding.getKey();
301 TType cached= fTTypeCache.get(key);
302 if (cached != null)
303 return cached;
304 TType type= fTypeEnvironment.create(typeBinding);
305 fTTypeCache.put(key, type);
306 return type;
307 }
308
309 private TType getBoxedType(ITypeBinding typeBinding, Expression expression) {
310 if (typeBinding == null)
311 return null;
312
313 if (! typeBinding.isPrimitive())
314 return createTType(typeBinding);
315
316 if (expression == null || ! expression.resolveBoxing())
317 return null;
318
319 ITypeBinding boxed= Bindings.getBoxedTypeBinding(typeBinding, expression.getAST());
320 return createTType(boxed);
321 }
322
323 public VariableVariable2 makeVariableVariable(IVariableBinding variableBinding) {
324 if (variableBinding == null)
325 return null;
326 TType type= getBoxedType(variableBinding.getType(), /*no boxing*/null);
327 if (type == null)
328 return null;
329 VariableVariable2 cv= new VariableVariable2(type, variableBinding);
330 VariableVariable2 storedCv= (VariableVariable2) storedCv(cv);
331 if (storedCv == cv) {
332 if (! variableBinding.isField() || Modifier.isPrivate(variableBinding.getModifiers()))
333 fCuScopedConstraintVariables.add(storedCv);
334 makeElementVariables(storedCv, type);
335 makeArrayElementVariable(storedCv);
336 if (fStoreToString)
337 storedCv.setData(ConstraintVariable2.TO_STRING, '[' + variableBinding.getName() + ']');
338 }
339 return storedCv;
340 }
341
342 public VariableVariable2 makeDeclaredVariableVariable(IVariableBinding variableBinding, ICompilationUnit cu) {
343 VariableVariable2 cv= makeVariableVariable(variableBinding);
344 if (cv == null)
345 return null;
346 cv.setCompilationUnit(cu);
347 return cv;
348 }
349
350 public TypeVariable2 makeTypeVariable(Type type) {
351 ICompilationUnit cu= RefactoringASTParser.getCompilationUnit(type);
352 TType ttype= getBoxedType(type.resolveBinding(), /*no boxing*/null);
353 if (ttype == null)
354 return null;
355
356 CompilationUnitRange range= new CompilationUnitRange(cu, type);
357 TypeVariable2 typeVariable= new TypeVariable2(ttype, range);
358 TypeVariable2 storedCv= (TypeVariable2) storedCv(typeVariable);
359 if (storedCv == typeVariable) {
360 fCuScopedConstraintVariables.add(storedCv);
361 if (isAGenericType(ttype))
362 makeElementVariables(storedCv, ttype);
363 makeArrayElementVariable(storedCv);
364 if (fStoreToString)
365 storedCv.setData(ConstraintVariable2.TO_STRING, type.toString());
366 }
367 return storedCv;
368 }
369
370 public IndependentTypeVariable2 makeIndependentTypeVariable(TypeVariable type) {
371 IndependentTypeVariable2 cv= new IndependentTypeVariable2(type);
372 IndependentTypeVariable2 storedCv= (IndependentTypeVariable2) storedCv(cv);
373 if (cv == storedCv) {
374 fCuScopedConstraintVariables.add(storedCv);
375// if (isAGenericType(typeBinding)) // would lead to infinite recursion!
376// makeElementVariables(storedCv, typeBinding);
377 if (fStoreToString)
378 storedCv.setData(ConstraintVariable2.TO_STRING, "IndependentType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
379 }
380 return storedCv;
381 }
382
383 public ParameterizedTypeVariable2 makeParameterizedTypeVariable(ITypeBinding typeBinding) {
384 if (typeBinding == null)
385 return null;
386 TType type= createTType(typeBinding);
387 return makeParameterizedTypeVariable(type);
388 }
389
390 private ParameterizedTypeVariable2 makeParameterizedTypeVariable(TType type) {
391 Assert.isTrue(isAGenericType(type));
392
393 ParameterizedTypeVariable2 cv= new ParameterizedTypeVariable2(type);
394 ParameterizedTypeVariable2 storedCv= (ParameterizedTypeVariable2) storedCv(cv);
395 if (cv == storedCv) {
396 fCuScopedConstraintVariables.add(storedCv);
397 makeElementVariables(storedCv, type);
398 if (fStoreToString)
399 storedCv.setData(ConstraintVariable2.TO_STRING, "ParameterizedType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
400 }
401 return storedCv;
402 }
403
404 public ArrayTypeVariable2 makeArrayTypeVariable(ITypeBinding typeBinding) {
405 if (typeBinding == null)
406 return null;
407 TType type= createTType(typeBinding);
408 return makeArrayTypeVariable((ArrayType) type);
409 }
410
411 private ArrayTypeVariable2 makeArrayTypeVariable(ArrayType type) {
412 ArrayTypeVariable2 cv= new ArrayTypeVariable2(type);
413 ArrayTypeVariable2 storedCv= (ArrayTypeVariable2) storedCv(cv);
414 if (cv == storedCv) {
415 fCuScopedConstraintVariables.add(storedCv);
416 makeArrayElementVariable(storedCv);
417 if (fStoreToString)
418 storedCv.setData(ConstraintVariable2.TO_STRING, "ArrayType(" + type.getPrettySignature() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
419 }
420 return storedCv;
421 }
422
423 public ParameterTypeVariable2 makeParameterTypeVariable(IMethodBinding methodBinding, int parameterIndex) {
424 if (methodBinding == null)
425 return null;
426 TType type= getBoxedType(methodBinding.getParameterTypes() [parameterIndex], /*no boxing*/null);
427 if (type == null)
428 return null;
429
430 ParameterTypeVariable2 cv= new ParameterTypeVariable2(type, parameterIndex, methodBinding);
431 ParameterTypeVariable2 storedCv= (ParameterTypeVariable2) storedCv(cv);
432 if (storedCv == cv) {
433 if (methodBinding.getDeclaringClass().isLocal() || Modifier.isPrivate(methodBinding.getModifiers()))
434 fCuScopedConstraintVariables.add(cv);
435 makeElementVariables(storedCv, type);
436 makeArrayElementVariable(storedCv);
437 if (fStoreToString)
438 storedCv.setData(ConstraintVariable2.TO_STRING, "[Parameter(" + parameterIndex + "," + Bindings.asString(methodBinding) + ")]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
439 }
440 return storedCv;
441 }
442
443 /**
444 * Make a ParameterTypeVariable2 from a method declaration.
445 * The constraint variable is always stored if it passes the type filter.
446 * @param methodBinding
447 * @param parameterIndex
448 * @param cu
449 * @return the ParameterTypeVariable2, or <code>null</code>
450 */
451 public ParameterTypeVariable2 makeDeclaredParameterTypeVariable(IMethodBinding methodBinding, int parameterIndex, ICompilationUnit cu) {
452 if (methodBinding == null)
453 return null;
454 ParameterTypeVariable2 cv= makeParameterTypeVariable(methodBinding, parameterIndex);
455 if (cv == null)
456 return null;
457 cv.setCompilationUnit(cu);
458 return cv;
459 }
460
461 public ReturnTypeVariable2 makeReturnTypeVariable(IMethodBinding methodBinding) {
462 if (methodBinding == null)
463 return null;
464 TType returnType= getBoxedType(methodBinding.getReturnType(), /*no boxing*/null);
465 if (returnType == null)
466 return null;
467
468 ReturnTypeVariable2 cv= new ReturnTypeVariable2(returnType, methodBinding);
469 ReturnTypeVariable2 storedCv= (ReturnTypeVariable2) storedCv(cv);
470 if (cv == storedCv) {
471 makeElementVariables(storedCv, returnType);
472 makeArrayElementVariable(storedCv);
473 if (fStoreToString)
474 storedCv.setData(ConstraintVariable2.TO_STRING, "[ReturnType(" + Bindings.asString(methodBinding) + ")]"); //$NON-NLS-1$ //$NON-NLS-2$
475 }
476 return storedCv;
477 }
478
479 public ReturnTypeVariable2 makeDeclaredReturnTypeVariable(IMethodBinding methodBinding, ICompilationUnit cu) {
480 if (methodBinding == null)
481 return null;
482 ReturnTypeVariable2 cv= makeReturnTypeVariable(methodBinding);
483 if (cv == null)
484 return null;
485
486 cv.setCompilationUnit(cu);
487 if (methodBinding.getDeclaringClass().isLocal())
488 fCuScopedConstraintVariables.add(cv);
489 return cv;
490 }
491
492 public ImmutableTypeVariable2 makeImmutableTypeVariable(ITypeBinding typeBinding, Expression expression) {
493// Assert.isTrue(! typeBinding.isGenericType()); // see JDT/Core bug 80472
494 TType type= getBoxedType(typeBinding, expression);
495 if (type == null)
496 return null;
497 return makeImmutableTypeVariable(type);
498 }
499
500 public ImmutableTypeVariable2 makeImmutableTypeVariable(TType type) {
501 ImmutableTypeVariable2 cv= new ImmutableTypeVariable2(type);
502 ImmutableTypeVariable2 storedCv= (ImmutableTypeVariable2) storedCv(cv);
503 if (cv == storedCv) {
504 makeFixedElementVariables(storedCv, type);
505 makeArrayElementVariable(storedCv);
506 }
507 return storedCv;
508 }
509
510 public static boolean isAGenericType(TType type) {
511 return type.isGenericType()
512 || type.isParameterizedType()
513 || (type.isRawType() && type.getTypeDeclaration().isGenericType());
514 }
515
516 public static boolean isAGenericType(ITypeBinding type) {
517 return type.isGenericType()
518 || type.isParameterizedType()
519 || (type.isRawType() && type.getTypeDeclaration().isGenericType());
520 }
521
522 public CastVariable2 makeCastVariable(CastExpression castExpression, ConstraintVariable2 expressionCv) {
523 ITypeBinding typeBinding= castExpression.resolveTypeBinding();
524 ICompilationUnit cu= RefactoringASTParser.getCompilationUnit(castExpression);
525 CompilationUnitRange range= new CompilationUnitRange(cu, castExpression);
526 CastVariable2 castCv= new CastVariable2(createTType(typeBinding), range, expressionCv);
527 fCastVariables.add(castCv);
528 return castCv;
529 }
530
531 public TypeEnvironment getTypeEnvironment() {
532 return fTypeEnvironment;
533 }
534
535 public CollectionElementVariable2 getElementVariable(ConstraintVariable2 constraintVariable, ITypeBinding typeVariable) {
536 Assert.isTrue(typeVariable.isTypeVariable()); // includes null check
537 HashMap<String, CollectionElementVariable2> typeVarToElementVars= (HashMap<String, CollectionElementVariable2>) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
538 if (typeVarToElementVars == null)
539 return null;
540 return typeVarToElementVars.get(typeVariable.getKey());
541 }
542
543 public Map<String, CollectionElementVariable2> getElementVariables(ConstraintVariable2 constraintVariable) {
544 Map<String, CollectionElementVariable2> elementVariables= (Map<String, CollectionElementVariable2>) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
545 if (elementVariables == null)
546 return EMPTY_COLLECTION_ELEMENT_VARIABLES_MAP;
547 else
548 return elementVariables;
549 }
550
551 public ArrayElementVariable2 getArrayElementVariable(ConstraintVariable2 constraintVariable) {
552 return (ArrayElementVariable2) constraintVariable.getData(ARRAY_ELEMENT);
553 }
554
555 private void setArrayElementVariable(ConstraintVariable2 constraintVariable, ArrayElementVariable2 arrayElementVariable) {
556 constraintVariable.setData(ARRAY_ELEMENT, arrayElementVariable);
557 }
558
559 public void makeArrayElementVariable(ConstraintVariable2 constraintVariable2) {
560 if (constraintVariable2.getType() == null || ! constraintVariable2.getType().isArrayType())
561 return;
562
563 ArrayElementVariable2 storedArrayElementVariable= getArrayElementVariable(constraintVariable2);
564 if (storedArrayElementVariable != null)
565 return;
566
567 ArrayElementVariable2 arrayElementCv= new ArrayElementVariable2(constraintVariable2);
568 arrayElementCv= (ArrayElementVariable2) storedCv(arrayElementCv);
569 setArrayElementVariable(constraintVariable2, arrayElementCv);
570
571 makeArrayElementVariable(arrayElementCv); //recursive
572 }
573
574 public void makeElementVariables(ConstraintVariable2 expressionCv, TType type) {
575 if (isAGenericType(type)) {
576 GenericType genericType= (GenericType) type.getTypeDeclaration();
577 TType[] typeParameters= genericType.getTypeParameters();
578 for (int i= 0; i < typeParameters.length; i++) {
579 TypeVariable typeVariable= (TypeVariable) typeParameters[i];
580 makeElementVariable(expressionCv, typeVariable, i);
581 if (typeVariable.getBounds().length != 0) {
582 //TODO: create subtype constraints for bounds
583 }
584 }
585 }
586 makeElementVariablesFromSupertypes(expressionCv, type.getTypeDeclaration());
587 }
588
589 private void makeElementVariablesFromSupertypes(ConstraintVariable2 expressionCv, TType type) {
590 TType superclass= type.getSuperclass();
591 if (superclass != null) {
592 makeSupertypeElementVariables(expressionCv, superclass);
593 }
594
595 TType[] interfaces= type.getInterfaces();
596 for (int i= 0; i < interfaces.length; i++) {
597 makeSupertypeElementVariables(expressionCv, interfaces[i]);
598 }
599
600 }
601
602 private void makeSupertypeElementVariables(ConstraintVariable2 expressionCv, TType supertype) {
603 if (supertype.isParameterizedType() || supertype.isRawType()) {
604 TType[] typeArguments= null;
605 if (supertype.isParameterizedType()) {
606 typeArguments= ((ParameterizedType) supertype).getTypeArguments();
607 }
608 TypeVariable[] typeParameters= ((GenericType) supertype.getTypeDeclaration()).getTypeParameters();
609 for (int i= 0; i < typeParameters.length; i++) {
610 TypeVariable typeParameter= typeParameters[i];
611 TType referenceTypeArgument;
612 if (typeArguments == null) { // raw type
613 referenceTypeArgument= typeParameter.getErasure();
614 } else {
615 referenceTypeArgument= typeArguments[i];
616 }
617 if (referenceTypeArgument.isTypeVariable()) {
618 CollectionElementVariable2 referenceTypeArgumentCv= getElementVariable(expressionCv, (TypeVariable) referenceTypeArgument);
619 if (referenceTypeArgumentCv != null) {
620 setElementVariable(expressionCv, referenceTypeArgumentCv, typeParameter);
621 continue;
622 }
623 }
624 makeElementVariable(expressionCv, typeParameter, CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX);
625 }
626 }
627 makeElementVariablesFromSupertypes(expressionCv, supertype);
628 }
629
630 public void makeFixedElementVariables(ConstraintVariable2 expressionCv, TType type) {
631 if (isAGenericType(type)) {
632 GenericType genericType= (GenericType) type.getTypeDeclaration();
633 TType[] typeParameters= genericType.getTypeParameters();
634 TType[] typeArguments= null;
635 if (type.isParameterizedType())
636 typeArguments= ((ParameterizedType) type).getTypeArguments();
637
638 for (int i= 0; i < typeParameters.length; i++) {
639 TypeVariable typeVariable= (TypeVariable) typeParameters[i];
640 CollectionElementVariable2 elementCv= makeElementVariable(expressionCv, typeVariable, i);
641 TType referenceTypeArgument;
642 if (typeArguments == null) { // raw type
643 continue; // do not consider
644 } else {
645 referenceTypeArgument= typeArguments[i];
646 }
647 createEqualsConstraint(elementCv, makeImmutableTypeVariable(referenceTypeArgument));
648// if (typeVariable.getBounds().length != 0) {
649// //TODO: create subtype constraints for bounds
650// }
651 }
652 }
653 makeFixedElementVariablesFromSupertypes(expressionCv, type.getTypeDeclaration());
654 }
655
656 private void makeFixedElementVariablesFromSupertypes(ConstraintVariable2 expressionCv, TType type) {
657 TType superclass= type.getSuperclass();
658 if (superclass != null)
659 makeFixedSupertypeElementVariables(expressionCv, superclass);
660
661 TType[] interfaces= type.getInterfaces();
662 for (int i= 0; i < interfaces.length; i++)
663 makeFixedSupertypeElementVariables(expressionCv, interfaces[i]);
664 }
665
666 private void makeFixedSupertypeElementVariables(ConstraintVariable2 expressionCv, TType supertype) {
667 if (supertype.isParameterizedType() || supertype.isRawType()) {
668 TType[] typeArguments= null;
669 if (supertype.isParameterizedType())
670 typeArguments= ((ParameterizedType) supertype).getTypeArguments();
671
672 TypeVariable[] typeParameters= ((GenericType) supertype.getTypeDeclaration()).getTypeParameters();
673 for (int i= 0; i < typeParameters.length; i++) {
674 TypeVariable typeParameter= typeParameters[i];
675 TType referenceTypeArgument;
676 if (typeArguments == null) { // raw type
677 continue; // do not consider
678 } else {
679 referenceTypeArgument= typeArguments[i];
680 }
681 if (referenceTypeArgument.isTypeVariable()) {
682 CollectionElementVariable2 referenceTypeArgumentCv= getElementVariable(expressionCv, (TypeVariable) referenceTypeArgument);
683 setElementVariable(expressionCv, referenceTypeArgumentCv, typeParameter);
684 } else {
685 CollectionElementVariable2 elementCv= makeElementVariable(expressionCv, typeParameter, CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX);
686 createEqualsConstraint(elementCv, makeImmutableTypeVariable(referenceTypeArgument));
687 }
688 }
689 }
690 makeFixedElementVariablesFromSupertypes(expressionCv, supertype);
691 }
692
693 /**
694 * Create equality constraints between generic type variables of expressionCv and referenceCv.
695 * For example, the generic interface <code>java.lang.Iterable&lt;E&gt;</code> defines a method
696 * <code>Iterator&lt;E&gt; iterator()</code>. Given
697 * <ul>
698 * <li>an expressionCv of a subtype of <code>Iterable</code>,</li>
699 * <li>a referenceCv of a subtype of <code>Iterator</code>, and</li>
700 * <li>a reference binding of the Iterable#iterator()'s return type (the parameterized type <code>Iterator&lt;E&gt;</code>),</li>
701 * </ul>
702 * this method creates an equality constraint between the type variable E in expressionCV and
703 * the type variable E in referenceCV.
704 *
705 * @param expressionCv the type constraint variable of an expression
706 * @param methodTypeVariables
707 * @param referenceCv the type constraint variable of a type reference
708 * @param reference the declared type reference
709 */
710 public void createTypeVariablesEqualityConstraints(ConstraintVariable2 expressionCv, Map<String, IndependentTypeVariable2> methodTypeVariables, ConstraintVariable2 referenceCv, TType reference) {
711 if (reference.isParameterizedType() || reference.isRawType()) {
712 TType[] referenceTypeArguments= null;
713 if (reference.isParameterizedType()) {
714 referenceTypeArguments= ((ParameterizedType) reference).getTypeArguments();
715 }
716 TType[] referenceTypeParameters= ((GenericType) reference.getTypeDeclaration()).getTypeParameters();
717 for (int i= 0; i < referenceTypeParameters.length; i++) {
718 TypeVariable referenceTypeParameter= (TypeVariable) referenceTypeParameters[i];
719 TType referenceTypeArgument;
720 if (referenceTypeArguments == null)
721 referenceTypeArgument= referenceTypeParameter.getErasure();
722 else
723 referenceTypeArgument= referenceTypeArguments[i];
724 if (referenceTypeArgument.isTypeVariable()) {
725 ConstraintVariable2 referenceTypeArgumentCv= getElementTypeCv(referenceTypeArgument, expressionCv, methodTypeVariables);
726 CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
727 createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
728 } else if (referenceTypeArgument.isWildcardType()) {
729 ConstraintVariable2 referenceTypeArgumentCv= makeImmutableTypeVariable(fTypeEnvironment.VOID); //block it for now (bug 106174)
730 CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
731 createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
732
733// WildcardType wildcardType= (WildcardType) referenceTypeArgument;
734// if (wildcardType.isUnboundWildcardType()) {
735// ConstraintVariable2 referenceTypeArgumentCv= makeImmutableTypeVariable(wildcardType);
736// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
737// createEqualsConstraint(referenceTypeArgumentCv, referenceTypeParametersCv);
738// } else if (wildcardType.isSuperWildcardType() && wildcardType.getBound().isTypeVariable()) {
739// ConstraintVariable2 referenceTypeArgumentBoundCv= getElementTypeCv(wildcardType.getBound(), expressionCv, methodTypeVariables);
740// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
741// //TODO: need *strict* subtype constraint?
742// createSubtypeConstraint(referenceTypeParametersCv, referenceTypeArgumentBoundCv);
743// }
744 // else: TODO
745
746// } else if (referenceTypeArgument.isParameterizedType()) {
747// //TODO: nested containers
748// ParameterizedType parameterizedType= (ParameterizedType) referenceTypeArgument;
749// ParameterizedTypeVariable2 parameterizedTypeCv= makeParameterizedTypeVariable(parameterizedType.getTypeDeclaration());
750// CollectionElementVariable2 referenceTypeParametersCv= getElementVariable(referenceCv, referenceTypeParameter);
751// createEqualsConstraint(parameterizedTypeCv, referenceTypeParametersCv);
752// createElementEqualsConstraints(parameterizedTypeCv, referenceTypeParametersCv);
753 } else {
754 //TODO
755 }
756 }
757
758 } else if (reference.isArrayType()) {
759 TType elementType= ((ArrayType) reference).getElementType();
760 if (elementType.isRawType())
761 elementType= elementType.getErasure();
762 ConstraintVariable2 elementTypeCv= getElementTypeCv(elementType, expressionCv, methodTypeVariables);
763 ArrayElementVariable2 arrayElementTypeCv= getArrayElementVariable(referenceCv);
764 createEqualsConstraint(elementTypeCv, arrayElementTypeCv);
765 }
766 }
767
768 private ConstraintVariable2 getElementTypeCv(TType elementType, ConstraintVariable2 expressionCv, Map<String, IndependentTypeVariable2> methodTypeVariables) {
769 if (elementType.isTypeVariable()) {
770 ConstraintVariable2 elementTypeCv= methodTypeVariables.get(elementType.getBindingKey());
771 if (elementTypeCv != null)
772 return elementTypeCv;
773 if (expressionCv != null)
774 return getElementVariable(expressionCv, (TypeVariable) elementType);
775 }
776 return null;
777 }
778
779 private CollectionElementVariable2 makeElementVariable(ConstraintVariable2 expressionCv, TypeVariable typeVariable, int declarationTypeVariableIndex) {
780 if (expressionCv == null)
781 return null;
782
783 CollectionElementVariable2 storedElementVariable= getElementVariable(expressionCv, typeVariable);
784 if (storedElementVariable != null)
785 return storedElementVariable;
786
787 CollectionElementVariable2 cv= new CollectionElementVariable2(expressionCv, typeVariable, declarationTypeVariableIndex);
788 cv= (CollectionElementVariable2) storedCv(cv);
789 setElementVariable(expressionCv, cv, typeVariable);
790 return cv;
791 }
792
793 private void setElementVariable(ConstraintVariable2 typeConstraintVariable, CollectionElementVariable2 elementVariable, TypeVariable typeVariable) {
794 HashMap<String, CollectionElementVariable2> keyToElementVar= (HashMap<String, CollectionElementVariable2>) typeConstraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
795 String key= typeVariable.getBindingKey();
796 if (keyToElementVar == null) {
797 keyToElementVar= new HashMap<String, CollectionElementVariable2>();
798 typeConstraintVariable.setData(INDEXED_COLLECTION_ELEMENTS, keyToElementVar);
799 } else {
800 Object existingElementVar= keyToElementVar.get(key);
801 if (existingElementVar != null) {
802 Assert.isTrue(existingElementVar == elementVariable);
803 }
804 }
805 keyToElementVar.put(key, elementVariable);
806 }
807
808 public CollectionElementVariable2 getElementVariable(ConstraintVariable2 constraintVariable, TypeVariable typeVariable) {
809 Assert.isTrue(typeVariable.isTypeVariable()); // includes null check
810 HashMap<String, CollectionElementVariable2> typeVarToElementVars= (HashMap<String, CollectionElementVariable2>) constraintVariable.getData(INDEXED_COLLECTION_ELEMENTS);
811 if (typeVarToElementVars == null)
812 return null;
813 return typeVarToElementVars.get(typeVariable.getBindingKey());
814 }
815
816 public void createElementEqualsConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv) {
817 internalCreateElementEqualsConstraints(cv, initializerCv, false);
818 }
819
820 public void createAssignmentElementConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv) {
821 internalCreateElementEqualsConstraints(cv, initializerCv, true);
822 }
823
824 private void internalCreateElementEqualsConstraints(ConstraintVariable2 cv, ConstraintVariable2 initializerCv, boolean isAssignment) {
825 if (cv == null || initializerCv == null)
826 return;
827
828 Map<String, CollectionElementVariable2> leftElements= getElementVariables(cv);
829 Map<String, CollectionElementVariable2> rightElements= getElementVariables(initializerCv);
830 for (Iterator<Entry<String, CollectionElementVariable2>> leftIter= leftElements.entrySet().iterator(); leftIter.hasNext();) {
831 Entry<String, CollectionElementVariable2> leftEntry= leftIter.next();
832 String leftTypeVariableKey= leftEntry.getKey();
833 CollectionElementVariable2 rightElementVariable= rightElements.get(leftTypeVariableKey);
834 if (rightElementVariable != null) {
835 CollectionElementVariable2 leftElementVariable= leftEntry.getValue();
836 createEqualsConstraint(leftElementVariable, rightElementVariable);
837 internalCreateElementEqualsConstraints(leftElementVariable, rightElementVariable, false); // recursive
838 }
839 }
840
841 ArrayElementVariable2 leftArrayElement= getArrayElementVariable(cv);
842 ArrayElementVariable2 rightArrayElement= getArrayElementVariable(initializerCv);
843 if (leftArrayElement != null && rightArrayElement != null) {
844 if (isAssignment)
845 createSubtypeConstraint(rightArrayElement, leftArrayElement);
846 else
847 createEqualsConstraint(leftArrayElement, rightArrayElement);
848 internalCreateElementEqualsConstraints(leftArrayElement, rightArrayElement, false); // recursive
849 }
850 }
851
852 /**
853 * @return the receiver of the method invocation this expressionVariable
854 * depends on, or null iff no receiver is available. If the receiver
855 * stayed raw, then the method return type cannot be substituted.
856 */
857 public ConstraintVariable2 getMethodReceiverCv(ConstraintVariable2 expressionVariable) {
858 return (ConstraintVariable2) expressionVariable.getData(METHOD_RECEIVER);
859 }
860
861 public void setMethodReceiverCV(ConstraintVariable2 expressionVariable, ConstraintVariable2 methodReceiverCV) {
862 expressionVariable.setData(METHOD_RECEIVER, methodReceiverCV);
863 }
864
865}