KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > structure > constraints > SuperTypeConstraintsModel


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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 package org.eclipse.jdt.internal.corext.refactoring.structure.constraints;
12
13 import java.util.AbstractSet JavaDoc;
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.Map JavaDoc;
22 import java.util.Set JavaDoc;
23
24 import org.eclipse.jdt.core.dom.CastExpression;
25 import org.eclipse.jdt.core.dom.IMethodBinding;
26 import org.eclipse.jdt.core.dom.ITypeBinding;
27 import org.eclipse.jdt.core.dom.IVariableBinding;
28 import org.eclipse.jdt.core.dom.Name;
29 import org.eclipse.jdt.core.dom.Type;
30
31 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
32 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
33 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment;
34 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
35 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
36 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraint2;
37 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ImmutableTypeVariable2;
38 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.IndependentTypeVariable2;
39 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ParameterTypeVariable2;
40 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ReturnTypeVariable2;
41 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.SubTypeConstraint2;
42 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeEquivalenceSet;
43 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
44 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.VariableVariable2;
45 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
46
47 /**
48  * Type constraints model to hold all type constraints to replace type occurrences by a given supertype.
49  *
50  * @since 3.1
51  */

52 public final class SuperTypeConstraintsModel {
53
54     /** Customized implementation of a hash set */
55     private static class HashedSet extends AbstractSet JavaDoc implements Set JavaDoc {
56
57         /** The backing hash map */
58         private final Map JavaDoc fImplementation= new HashMap JavaDoc();
59
60         /*
61          * @see java.util.AbstractCollection#add(java.lang.Object)
62          */

63         public final boolean add(final Object JavaDoc object) {
64             return fImplementation.put(object, object) == null;
65         }
66
67         /**
68          * Attempts to add the specified object to this set.
69          *
70          * @param object the object to add
71          * @return An already existing object considered equal to the specified one, or the newly added object
72          */

73         public final Object JavaDoc addExisting(final Object JavaDoc object) {
74             final Object JavaDoc result= fImplementation.get(object);
75             if (result != null)
76                 return result;
77             fImplementation.put(object, object);
78             return object;
79         }
80
81         /*
82          * @see java.util.AbstractCollection#clear()
83          */

84         public final void clear() {
85             fImplementation.clear();
86         }
87
88         /*
89          * @see java.util.AbstractCollection#contains(java.lang.Object)
90          */

91         public final boolean contains(final Object JavaDoc object) {
92             return fImplementation.containsKey(object);
93         }
94
95         /*
96          * @see java.util.AbstractCollection#isEmpty()
97          */

98         public final boolean isEmpty() {
99             return fImplementation.isEmpty();
100         }
101
102         /*
103          * @see java.util.AbstractCollection#iterator()
104          */

105         public final Iterator JavaDoc iterator() {
106             return fImplementation.keySet().iterator();
107         }
108
109         /*
110          * @see java.util.AbstractCollection#remove(java.lang.Object)
111          */

112         public final boolean remove(final Object JavaDoc object) {
113             return fImplementation.remove(object) == object;
114         }
115
116         /*
117          * @see java.util.AbstractCollection#size()
118          */

119         public final int size() {
120             return fImplementation.size();
121         }
122     }
123
124     /** The usage data */
125     private static final String JavaDoc DATA_USAGE= "us"; //$NON-NLS-1$
126

127     /** Maximal number of TTypes */
128     private static final int MAX_CACHE= 64;
129
130     /**
131      * Returns the usage of the specified constraint variable.
132      *
133      * @param variable the constraint variable
134      * @return the usage of the constraint variable (element type: <code>ITypeConstraint2</code>)
135      */

136     public static Collection JavaDoc getVariableUsage(final ConstraintVariable2 variable) {
137         final Object JavaDoc data= variable.getData(DATA_USAGE);
138         if (data == null)
139             return Collections.EMPTY_LIST;
140         else if (data instanceof Collection JavaDoc)
141             return Collections.unmodifiableCollection((Collection JavaDoc) data);
142         else
143             return Collections.singletonList(data);
144     }
145
146     /**
147      * Is the type represented by the specified binding a constrained type?
148      *
149      * @param binding the binding to check, or <code>null</code>
150      * @return <code>true</code> if it is constrained, <code>false</code> otherwise
151      */

152     public static boolean isConstrainedType(final ITypeBinding binding) {
153         return binding != null && !binding.isSynthetic() && !binding.isPrimitive();
154     }
155
156     /**
157      * Sets the usage of the specified constraint variable.
158      *
159      * @param variable the constraint variable
160      * @param constraint the type constraint
161      */

162     public static void setVariableUsage(final ConstraintVariable2 variable, ITypeConstraint2 constraint) {
163         final Object JavaDoc data= variable.getData(DATA_USAGE);
164         if (data == null)
165             variable.setData(DATA_USAGE, constraint);
166         else if (data instanceof Collection JavaDoc)
167             ((Collection JavaDoc) data).add(constraint);
168         else {
169             final Collection JavaDoc usage= new ArrayList JavaDoc(2);
170             usage.add(data);
171             usage.add(constraint);
172             variable.setData(DATA_USAGE, usage);
173         }
174     }
175
176     /** The cast variables (element type: <code>CastVariable2</code>) */
177     private final Collection JavaDoc fCastVariables= new ArrayList JavaDoc();
178
179     /** The compliance level */
180     private int fCompliance= 3;
181
182     /** The set of constraint variables (element type: <code>ConstraintVariable2</code>) */
183     private final HashedSet fConstraintVariables= new HashedSet();
184
185     /** The covariant type constraints (element type: <code>CovariantTypeConstraint</code>) */
186     private final Collection JavaDoc fCovariantTypeConstraints= new ArrayList JavaDoc();
187
188     /** The type environment to use */
189     private TypeEnvironment fEnvironment;
190
191     /** The subtype to replace */
192     private final TType fSubType;
193
194     /** The supertype as replacement */
195     private final TType fSuperType;
196
197     /** The TType cache (element type: <code>&lt;String, ITypeBinding&gt;</code>) */
198     private Map JavaDoc fTTypeCache= new LinkedHashMap JavaDoc(MAX_CACHE, 0.75f, true) {
199
200         private static final long serialVersionUID= 1L;
201
202         protected final boolean removeEldestEntry(Map.Entry JavaDoc entry) {
203             return size() > MAX_CACHE;
204         }
205     };
206
207     /** The set of type constraints (element type: <code>ITypeConstraint2</code>) */
208     private final Set JavaDoc fTypeConstraints= new HashSet JavaDoc();
209
210     /**
211      * Creates a new super type constraints model.
212      *
213      * @param subType the subtype to replace
214      * @param superType the supertype replacement
215      */

216     public SuperTypeConstraintsModel(final TypeEnvironment environment, TType subType, TType superType) {
217         fEnvironment= environment;
218         fSubType= subType;
219         fSuperType= superType;
220     }
221
222     /**
223      * Gets called when the creation of the model begins.
224      */

225     public final void beginCreation() {
226         // Do nothing right now
227
}
228
229     /**
230      * Creates a cast variable.
231      *
232      * @param expression the cast expression
233      * @param variable the associated constraint variable
234      * @return the created cast variable
235      */

236     public final ConstraintVariable2 createCastVariable(final CastExpression expression, final ConstraintVariable2 variable) {
237         ITypeBinding binding= expression.resolveTypeBinding();
238         if (binding.isArray())
239             binding= binding.getElementType();
240         if (isConstrainedType(binding)) {
241             final CastVariable2 result= new CastVariable2(createTType(binding), new CompilationUnitRange(RefactoringASTParser.getCompilationUnit(expression), expression), variable);
242             fCastVariables.add(result);
243             return result;
244         }
245         return null;
246     }
247
248     /**
249      * Creates a conditional type constraint.
250      *
251      * @param expressionVariable the expression type constraint variable
252      * @param thenVariable the then type constraint variable
253      * @param elseVariable the else type constraint variable
254      */

255     public final void createConditionalTypeConstraint(final ConstraintVariable2 expressionVariable, final ConstraintVariable2 thenVariable, final ConstraintVariable2 elseVariable) {
256         final ITypeConstraint2 constraint= new ConditionalTypeConstraint(expressionVariable, thenVariable, elseVariable);
257         if (!fTypeConstraints.contains(constraint)) {
258             fTypeConstraints.add(constraint);
259             setVariableUsage(expressionVariable, constraint);
260             setVariableUsage(thenVariable, constraint);
261             setVariableUsage(elseVariable, constraint);
262         }
263     }
264
265     /**
266      * Creates a subtype constraint.
267      *
268      * @param descendant the descendant type constraint variable
269      * @param ancestor the ancestor type constraint variable
270      */

271     public final void createCovariantTypeConstraint(final ConstraintVariable2 descendant, final ConstraintVariable2 ancestor) {
272         final ITypeConstraint2 constraint= new CovariantTypeConstraint(descendant, ancestor);
273         if (!fTypeConstraints.contains(constraint)) {
274             fTypeConstraints.add(constraint);
275             fCovariantTypeConstraints.add(constraint);
276             setVariableUsage(descendant, constraint);
277             setVariableUsage(ancestor, constraint);
278         }
279     }
280
281     /**
282      * Creates a declaring type variable.
283      * <p>
284      * A declaring type variable stands for a type where something has been declared.
285      * </p>
286      *
287      * @param type the type binding
288      * @return the created declaring type variable
289      */

290     public final ConstraintVariable2 createDeclaringTypeVariable(ITypeBinding type) {
291         if (type.isArray())
292             type= type.getElementType();
293         type= type.getTypeDeclaration();
294         return (ConstraintVariable2) fConstraintVariables.addExisting(new ImmutableTypeVariable2(createTType(type)));
295     }
296
297     /**
298      * Creates an equality constraint.
299      *
300      * @param left the left typeconstraint variable
301      * @param right the right typeconstraint variable
302      */

303     public final void createEqualityConstraint(final ConstraintVariable2 left, final ConstraintVariable2 right) {
304         if (left != null && right != null) {
305             final TypeEquivalenceSet first= left.getTypeEquivalenceSet();
306             final TypeEquivalenceSet second= right.getTypeEquivalenceSet();
307             if (first == null) {
308                 if (second == null) {
309                     final TypeEquivalenceSet set= new TypeEquivalenceSet(left, right);
310                     left.setTypeEquivalenceSet(set);
311                     right.setTypeEquivalenceSet(set);
312                 } else {
313                     second.add(left);
314                     left.setTypeEquivalenceSet(second);
315                 }
316             } else {
317                 if (second == null) {
318                     first.add(right);
319                     right.setTypeEquivalenceSet(first);
320                 } else if (first == second)
321                     return;
322                 else {
323                     final ConstraintVariable2[] variables= second.getContributingVariables();
324                     first.addAll(variables);
325                     for (int index= 0; index < variables.length; index++)
326                         variables[index].setTypeEquivalenceSet(first);
327                 }
328             }
329         }
330     }
331
332     /**
333      * Creates an exception variable.
334      *
335      * @param name the name of the thrown exception
336      * @return the created exception variable
337      */

338     public final ConstraintVariable2 createExceptionVariable(final Name name) {
339         final ITypeBinding binding= name.resolveTypeBinding();
340         if (isConstrainedType(binding))
341             return (ConstraintVariable2) fConstraintVariables.addExisting(new TypeVariable2(createTType(binding), new CompilationUnitRange(RefactoringASTParser.getCompilationUnit(name), name)));
342         return null;
343     }
344
345     /**
346      * Creates an immutable type variable.
347      *
348      * @param type the type binding
349      * @return the created plain type variable
350      */

351     public final ConstraintVariable2 createImmutableTypeVariable(ITypeBinding type) {
352         if (type.isArray())
353             type= type.getElementType();
354         if (isConstrainedType(type))
355             return (ConstraintVariable2) fConstraintVariables.addExisting(new ImmutableTypeVariable2(createTType(type)));
356         return null;
357     }
358
359     /**
360      * Creates an independent type variable.
361      * <p>
362      * An independant type variable stands for an arbitrary type.
363      * </p>
364      *
365      * @param type the type binding
366      * @return the created independant type variable
367      */

368     public final ConstraintVariable2 createIndependentTypeVariable(ITypeBinding type) {
369         if (type.isArray())
370             type= type.getElementType();
371         if (isConstrainedType(type))
372             return (ConstraintVariable2) fConstraintVariables.addExisting(new IndependentTypeVariable2(createTType(type)));
373         return null;
374     }
375
376     /**
377      * Creates a new method parameter variable.
378      *
379      * @param method the method binding
380      * @param index the index of the parameter
381      * @return the created method parameter variable
382      */

383     public final ConstraintVariable2 createMethodParameterVariable(final IMethodBinding method, final int index) {
384         final ITypeBinding[] parameters= method.getParameterTypes();
385         ITypeBinding binding= parameters[Math.min(index, parameters.length - 1)];
386         if (binding.isArray())
387             binding= binding.getElementType();
388         if (isConstrainedType(binding)) {
389             ConstraintVariable2 variable= null;
390             final TType type= createTType(binding);
391             if (method.getDeclaringClass().isFromSource())
392                 variable= new ParameterTypeVariable2(type, index, method.getMethodDeclaration());
393             else
394                 variable= new ImmutableTypeVariable2(type);
395             return (ConstraintVariable2) fConstraintVariables.addExisting(variable);
396         }
397         return null;
398     }
399
400     /**
401      * Creates a new return type variable.
402      *
403      * @param method the method binding
404      * @return the created return type variable
405      */

406     public final ConstraintVariable2 createReturnTypeVariable(final IMethodBinding method) {
407         if (!method.isConstructor()) {
408             ITypeBinding binding= method.getReturnType();
409             if (binding != null && binding.isArray())
410                 binding= binding.getElementType();
411             if (binding != null && isConstrainedType(binding)) {
412                 ConstraintVariable2 variable= null;
413                 final TType type= createTType(binding);
414                 if (method.getDeclaringClass().isFromSource())
415                     variable= new ReturnTypeVariable2(type, method);
416                 else
417                     variable= new ImmutableTypeVariable2(type);
418                 return (ConstraintVariable2) fConstraintVariables.addExisting(variable);
419             }
420         }
421         return null;
422     }
423
424     /**
425      * Creates a subtype constraint.
426      *
427      * @param descendant the descendant type constraint variable
428      * @param ancestor the ancestor type constraint variable
429      */

430     public final void createSubtypeConstraint(final ConstraintVariable2 descendant, final ConstraintVariable2 ancestor) {
431         final ITypeConstraint2 constraint= new SubTypeConstraint2(descendant, ancestor);
432         if (!fTypeConstraints.contains(constraint)) {
433             fTypeConstraints.add(constraint);
434             setVariableUsage(descendant, constraint);
435             setVariableUsage(ancestor, constraint);
436         }
437     }
438
439     /**
440      * Creates a new TType for the corresponding binding.
441      *
442      * @param binding The type binding
443      * @return The corresponding TType
444      */

445     public final TType createTType(final ITypeBinding binding) {
446         final String JavaDoc key= binding.getKey();
447         final TType cached= (TType) fTTypeCache.get(key);
448         if (cached != null)
449             return cached;
450         final TType type= fEnvironment.create(binding);
451         fTTypeCache.put(key, type);
452         return type;
453     }
454
455     /**
456      * Creates a type variable.
457      *
458      * @param type the type binding
459      * @param range the compilation unit range
460      * @return the created type variable
461      */

462     public final ConstraintVariable2 createTypeVariable(ITypeBinding type, final CompilationUnitRange range) {
463         if (type.isArray())
464             type= type.getElementType();
465         if (isConstrainedType(type))
466             return (ConstraintVariable2) fConstraintVariables.addExisting(new TypeVariable2(createTType(type), range));
467         return null;
468     }
469
470     /**
471      * Creates a type variable.
472      *
473      * @param type the type
474      * @return the created type variable
475      */

476     public final ConstraintVariable2 createTypeVariable(final Type type) {
477         ITypeBinding binding= type.resolveBinding();
478         if (binding != null) {
479             if (binding.isArray())
480                 binding= binding.getElementType();
481             if (isConstrainedType(binding))
482                 return (ConstraintVariable2) fConstraintVariables.addExisting(new TypeVariable2(createTType(binding), new CompilationUnitRange(RefactoringASTParser.getCompilationUnit(type), type)));
483         }
484         return null;
485     }
486
487     /**
488      * Creates a variable type variable.
489      *
490      * @param binding the variable binding
491      * @return the created variable variable
492      */

493     public final ConstraintVariable2 createVariableVariable(final IVariableBinding binding) {
494         ITypeBinding type= binding.getType();
495         if (type.isArray())
496             type= type.getElementType();
497         if (isConstrainedType(type)) {
498             ConstraintVariable2 variable= null;
499             final IVariableBinding declaration= binding.getVariableDeclaration();
500             if (declaration.isField()) {
501                 final ITypeBinding declaring= declaration.getDeclaringClass();
502                 if (!declaring.isFromSource())
503                     variable= new ImmutableTypeVariable2(createTType(type));
504             } else {
505                 final IMethodBinding declaring= declaration.getDeclaringMethod();
506                 if (declaring != null && !declaring.getDeclaringClass().isFromSource())
507                     variable= new ImmutableTypeVariable2(createTType(type));
508             }
509             if (variable == null)
510                 variable= new VariableVariable2(createTType(type), declaration);
511             return (ConstraintVariable2) fConstraintVariables.addExisting(variable);
512         }
513         return null;
514     }
515
516     /**
517      * Gets called when the creation of the model ends.
518      */

519     public final void endCreation() {
520         fEnvironment= null;
521         fTTypeCache= null;
522     }
523
524     /**
525      * Returns the cast variables of this model.
526      *
527      * @return the cast variables (element type: <code>CastVariable2</code>)
528      */

529     public final Collection JavaDoc getCastVariables() {
530         return Collections.unmodifiableCollection(fCastVariables);
531     }
532
533     /**
534      * Returns the compliance level to use.
535      *
536      * @return the compliance level
537      */

538     public final int getCompliance() {
539         return fCompliance;
540     }
541
542     /**
543      * Returns the constraint variables of this model.
544      *
545      * @return the constraint variables (element type: <code>ConstraintVariable2</code>)
546      */

547     public final Collection JavaDoc getConstraintVariables() {
548         return Collections.unmodifiableCollection(fConstraintVariables);
549     }
550
551     /**
552      * Returns the subtype to be replaced.
553      *
554      * @return the subtype to be replaced
555      */

556     public final TType getSubType() {
557         return fSubType;
558     }
559
560     /**
561      * Returns the supertype as replacement.
562      *
563      * @return the supertype as replacement
564      */

565     public final TType getSuperType() {
566         return fSuperType;
567     }
568
569     /**
570      * Returns the type constraints of this model.
571      *
572      * @return the type constraints (element type: <code>ITypeConstraint2</code>)
573      */

574     public final Collection JavaDoc getTypeConstraints() {
575         return Collections.unmodifiableCollection(fTypeConstraints);
576     }
577
578     /**
579      * Sets the compliance level to use.
580      *
581      * @param level the compliance level to use. The argument must be one of the <code>AST.JLSx</code> constants.
582      */

583     public final void setCompliance(final int level) {
584         fCompliance= level;
585     }
586 }
Popular Tags