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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package org.eclipse.jdt.internal.corext.refactoring.generics;
15 import java.util.ArrayList;
16 import java.util.Comparator;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.LinkedList;
20 import java.util.List;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.OperationCanceledException;
25 import org.eclipse.core.runtime.SubProgressMonitor;
27 import org.eclipse.jdt.core.JavaModelException;
29 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.HierarchyType;
30 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
31 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.SingletonTypeSet;
32 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet;
33 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSetEnvironment;
34 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayElementVariable2;
35 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ArrayTypeVariable2;
36 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
37 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
38 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraint2;
39 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.IndependentTypeVariable2;
40 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeEquivalenceSet;
43 public class InferTypeArgumentsConstraintsSolver {
45 public static class TTypeComparator implements Comparator<TType> {
46 public int compare(TType o1, TType o2) {
47 return o1.getPrettySignature().compareTo(o2.getPrettySignature());
49 public static TTypeComparator INSTANCE= new TTypeComparator();
52 private final static String CHOSEN_TYPE= "chosenType"; //$NON-NLS-1$
54 final InferTypeArgumentsTCModel fTCModel;
55 public TypeSetEnvironment fTypeSetEnvironment;
58 * The work-list used by the type constraint solver to hold the set of
59 * nodes in the constraint graph that remain to be (re-)processed. Entries
60 * are <code>ConstraintVariable2</code>s.
62 public LinkedList<ConstraintVariable2> fWorkList;
64 public InferTypeArgumentsUpdate fUpdate;
67 public InferTypeArgumentsConstraintsSolver(InferTypeArgumentsTCModel typeConstraintFactory) {
68 fTCModel= typeConstraintFactory;
69 fWorkList= new LinkedList<ConstraintVariable2>();
72 public InferTypeArgumentsUpdate solveConstraints(IProgressMonitor pm) {
73 pm.beginTask("", 2); //$NON-NLS-1$
74 return fTCModel.generated_5627551663167226042(this, pm);
77 void initializeTypeEstimates(ConstraintVariable2[] allConstraintVariables) {
78 for (int i= 0; i < allConstraintVariables.length; i++) {
79 ConstraintVariable2 cv= allConstraintVariables[i];
80 //TODO: not necessary for types that are not used in a TypeConstraint but only as type in CollectionElementVariable
81 //TODO: handle nested element variables; see ParametricStructureComputer.createAndInitVars()
82 TypeEquivalenceSet set= cv.getTypeEquivalenceSet();
84 set= new TypeEquivalenceSet(cv);
85 set.generated_1744245873183469336(cv, this);
87 TypeSet typeEstimate= (TypeSet) cv.getTypeEstimate();
88 if (typeEstimate == null) {
89 ConstraintVariable2[] cvs= set.getContributingVariables();
90 typeEstimate= fTypeSetEnvironment.getUniverseTypeSet();
91 for (int j= 0; j < cvs.length; j++) //TODO: optimize: just try to find an immutable CV; if not found, use Universe
92 typeEstimate= typeEstimate.intersectedWith(createInitialEstimate(cvs[j]));
93 set.setTypeEstimate(typeEstimate);
99 public TypeSet createInitialEstimate(ConstraintVariable2 cv) {
100 // TODO: check assumption: only immutable CVs have a type
101 // ParametricStructure parametricStructure= fElemStructureEnv.elemStructure(cv);
102 // if (parametricStructure != null && parametricStructure != ParametricStructureComputer.ParametricStructure.NONE) {
103 // return SubTypesOfSingleton.create(parametricStructure.getBase());
106 TType type= cv.getType();
108 return fTypeSetEnvironment.getUniverseTypeSet();
110 } else if (cv instanceof IndependentTypeVariable2) {
111 return fTypeSetEnvironment.getUniverseTypeSet();
112 //TODO: solve problem with recursive bounds
113 // TypeVariable tv= (TypeVariable) type;
114 // TType[] bounds= tv.getBounds();
115 // TypeSet result= SubTypesOfSingleton.create(bounds[0].getErasure());
116 // for (int i= 1; i < bounds.length; i++) {
117 // result= result.intersectedWith(SubTypesOfSingleton.create(bounds[i].getErasure()));
121 } else if (cv instanceof ArrayTypeVariable2) {
122 return fTypeSetEnvironment.getUniverseTypeSet();
123 } else if (cv instanceof ArrayElementVariable2) {
124 if (cv.getType() != null && cv.getType().isTypeVariable()) {
125 return fTypeSetEnvironment.getUniverseTypeSet();
127 return new SingletonTypeSet(type, fTypeSetEnvironment);
131 return fTypeSetEnvironment.generated_2609078052071831070(type);
134 void runSolver(SubProgressMonitor pm) {
135 pm.beginTask("", fWorkList.size() * 3); //$NON-NLS-1$
136 while (! fWorkList.isEmpty()) {
137 // Get a variable whose type estimate has changed
138 ConstraintVariable2 cv= fWorkList.removeFirst();
139 List<ITypeConstraint2> usedIn= fTCModel.getUsedIn(cv);
140 processConstraints(usedIn);
143 throw new OperationCanceledException();
149 * Given a list of <code>ITypeConstraint2</code>s that all refer to a
150 * given <code>ConstraintVariable2</code> (whose type bound has presumably
151 * just changed), process each <code>ITypeConstraint</code>, propagating
152 * the type bound across the constraint as needed.
154 * @param usedIn the <code>List</code> of <code>ITypeConstraint2</code>s
157 private void processConstraints(List<ITypeConstraint2> usedIn) {
158 Iterator<ITypeConstraint2> iter= usedIn.iterator();
159 while (iter.hasNext()) {
160 ITypeConstraint2 tc= iter.next();
162 maintainSimpleConstraint(tc);
163 //TODO: prune tcs which cannot cause further changes
164 // Maybe these should be pruned after a special first loop over all ConstraintVariables,
165 // Since this can only happen once for every CV in the work list.
166 // if (isConstantConstraint(stc))
167 // fTypeConstraintFactory.removeUsedIn(stc, changedCv);
171 private void maintainSimpleConstraint(ITypeConstraint2 stc) {
172 ConstraintVariable2 left= stc.getLeft();
173 ConstraintVariable2 right= stc.getRight();
175 TypeEquivalenceSet leftSet= left.getTypeEquivalenceSet();
176 leftSet.generated_8886690084417838134(right, this);
179 void chooseTypes(ConstraintVariable2[] allConstraintVariables, SubProgressMonitor pm) {
180 pm.beginTask("", allConstraintVariables.length); //$NON-NLS-1$
181 for (int i= 0; i < allConstraintVariables.length; i++) {
182 ConstraintVariable2 cv= allConstraintVariables[i];
184 TypeEquivalenceSet set= cv.getTypeEquivalenceSet();
186 continue; //TODO: should not happen iff all unused constraint variables got pruned
187 //TODO: should calculate only once per EquivalenceRepresentative; can throw away estimate TypeSet afterwards
188 TType type= cv.generated_2463815950094098277(pm, this);
193 public TType chooseSingleType(TypeSet typeEstimate) {
194 return typeEstimate.generated_8224593875850740143(this);
197 private static final int MAX_CACHE= 1024;
198 public Map<TType, Boolean> fInterfaceTaggingCache= new LinkedHashMap<TType, Boolean>(MAX_CACHE, 0.75f, true) {
199 private static final long serialVersionUID= 1L;
201 protected boolean removeEldestEntry(Map.Entry<TType, Boolean> eldest) {
202 return size() > MAX_CACHE;
206 public ArrayList<TType> getNonTaggingInterfaces(ArrayList<TType> interfaceCandidates) {
207 ArrayList<TType> unresolvedTypes= new ArrayList<TType>();
208 ArrayList<TType> nonTagging= new ArrayList<TType>();
210 for (int i= 0; i < interfaceCandidates.size(); i++) {
211 TType interf= interfaceCandidates.get(i);
212 Object isTagging= fInterfaceTaggingCache.get(interf);
213 if (isTagging == null)
214 unresolvedTypes.add(interf);
215 else if (isTagging == Boolean.FALSE)
216 nonTagging.add(interf);
219 if (unresolvedTypes.size() != 0) {
220 TType[] interfaces= unresolvedTypes.toArray(new TType[unresolvedTypes.size()]);
221 for (int i= 0; i < interfaces.length; i++) {
222 TType interf= interfaces[i];
223 interf.generated_906562671490961319(nonTagging, this);
230 public static boolean isTaggingInterface(TType interf) {
231 if (interf instanceof HierarchyType) {
233 return ((HierarchyType) interf).getJavaElementType().getMethods().length == 0;
234 } catch (JavaModelException e) {
241 void findCastsToRemove(CastVariable2[] castVariables) {
242 fUpdate.generated_4229093701003042937(this, castVariables);
245 public static TType getChosenType(ConstraintVariable2 cv) {
246 TType type= (TType) cv.getData(CHOSEN_TYPE);
249 TypeEquivalenceSet set= cv.getTypeEquivalenceSet();
250 if (set == null) { //TODO: should not have to set this here. Clean up when caching chosen type
252 // // no representative == no restriction
253 // set= new TypeEquivalenceSet(cv);
254 // set.setTypeEstimate(TypeUniverseSet.create());
255 // cv.setTypeEquivalenceSet(set);
257 return cv.getTypeEstimate().chooseSingleType();
260 public static void setChosenType(ConstraintVariable2 cv, TType type) {
261 cv.setData(CHOSEN_TYPE, type);