]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/core refactoring/org/eclipse/jdt/internal/corext/refactoring/typeconstraints/FullConstraintCreator.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core refactoring / org / eclipse / jdt / internal / corext / refactoring / typeconstraints / FullConstraintCreator.java
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 package org.eclipse.jdt.internal.corext.refactoring.typeconstraints;
12
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.LinkedHashSet;
19 import java.util.List;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.Assert;
23
24 import org.eclipse.jdt.core.dom.ArrayCreation;
25 import org.eclipse.jdt.core.dom.ArrayInitializer;
26 import org.eclipse.jdt.core.dom.Assignment;
27 import org.eclipse.jdt.core.dom.CastExpression;
28 import org.eclipse.jdt.core.dom.CatchClause;
29 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
30 import org.eclipse.jdt.core.dom.ConditionalExpression;
31 import org.eclipse.jdt.core.dom.ConstructorInvocation;
32 import org.eclipse.jdt.core.dom.Expression;
33 import org.eclipse.jdt.core.dom.FieldAccess;
34 import org.eclipse.jdt.core.dom.FieldDeclaration;
35 import org.eclipse.jdt.core.dom.IBinding;
36 import org.eclipse.jdt.core.dom.IMethodBinding;
37 import org.eclipse.jdt.core.dom.ITypeBinding;
38 import org.eclipse.jdt.core.dom.IVariableBinding;
39 import org.eclipse.jdt.core.dom.InstanceofExpression;
40 import org.eclipse.jdt.core.dom.MethodDeclaration;
41 import org.eclipse.jdt.core.dom.MethodInvocation;
42 import org.eclipse.jdt.core.dom.Name;
43 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
44 import org.eclipse.jdt.core.dom.QualifiedName;
45 import org.eclipse.jdt.core.dom.ReturnStatement;
46 import org.eclipse.jdt.core.dom.SimpleName;
47 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
48 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
49 import org.eclipse.jdt.core.dom.SuperFieldAccess;
50 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
51 import org.eclipse.jdt.core.dom.ThisExpression;
52 import org.eclipse.jdt.core.dom.Type;
53 import org.eclipse.jdt.core.dom.VariableDeclaration;
54 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
55 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
56 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
57
58 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
59 import org.eclipse.jdt.internal.corext.dom.Bindings;
60 import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
61
62
63 /**
64  * Default implementation of the creator. Creates all or nearly all constraints for program constructs.
65  * Subclasses can provide additional checks to avoid creating constraints that are not useful for their purposes.
66  */
67 public class FullConstraintCreator extends ConstraintCreator{
68
69         final IConstraintVariableFactory fConstraintVariableFactory;
70         final ITypeConstraintFactory fTypeConstraintFactory;
71         private IContext fContext;
72
73         public FullConstraintCreator(){
74                 this(new ConstraintVariableFactory(), new TypeConstraintFactory());
75         }
76
77         public FullConstraintCreator(IConstraintVariableFactory cFactory,
78                                                                  ITypeConstraintFactory tFactory) {
79                 Assert.isTrue(cFactory != null);
80                 fConstraintVariableFactory= cFactory;
81                 fTypeConstraintFactory= tFactory;
82                 fContext= new NullContext();
83         }
84
85         public IContext getContext() {
86                 return fContext;
87         }
88
89         public void setContext(IContext context) {
90                 fContext= context;
91         }
92
93         public ITypeConstraintFactory getConstraintFactory(){
94                 return fTypeConstraintFactory;
95         }
96
97         public IConstraintVariableFactory getConstraintVariableFactory(){
98                 return fConstraintVariableFactory;
99         }
100
101         /* (non-Javadoc)
102          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayInitializer)
103          */
104         @Override
105         public ITypeConstraint[] create(ArrayInitializer arrayInitializer){
106                 ITypeBinding arrayBinding= arrayInitializer.resolveTypeBinding();
107                 Assert.isTrue(arrayBinding.isArray());
108                 List<Expression> expressions= arrayInitializer.expressions();
109                 List<ITypeConstraint> constraints= new ArrayList<ITypeConstraint>();
110                 Type type= getTypeParent(arrayInitializer);
111                 ConstraintVariable typeVariable= fConstraintVariableFactory.makeTypeVariable(type);
112                 for (int i= 0; i < expressions.size(); i++) {
113                         Expression each= expressions.get(i);
114                         ITypeConstraint[] c= fTypeConstraintFactory.createSubtypeConstraint(
115                                         fConstraintVariableFactory.makeExpressionOrTypeVariable(each, getContext()),
116                                         typeVariable);
117                         constraints.addAll(Arrays.asList(c));
118                 }
119                 return constraints.toArray(new ITypeConstraint[constraints.size()]);
120         }
121
122         /* (non-Javadoc)
123          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Assignment)
124          */
125         @Override
126         public ITypeConstraint[] create(Assignment assignment){
127                 return fTypeConstraintFactory.createSubtypeConstraint(
128                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(assignment.getRightHandSide(), getContext()),
129                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(assignment.getLeftHandSide(), getContext()));
130         }
131
132         /* (non-Javadoc)
133          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CastExpression)
134          */
135         @Override
136         public ITypeConstraint[] create(CastExpression castExpression){
137                 Expression expression= castExpression.getExpression();
138                 Type type= castExpression.getType();
139                 ITypeConstraint[] definesConstraint= fTypeConstraintFactory.createDefinesConstraint(fConstraintVariableFactory.makeExpressionOrTypeVariable(castExpression, getContext()),
140                                                                                                         fConstraintVariableFactory.makeTypeVariable(castExpression.getType()));
141                 if (isClassBinding(expression.resolveTypeBinding()) && isClassBinding(type.resolveBinding())){
142                         ConstraintVariable expressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(expression, getContext());
143                         ConstraintVariable castExpressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(castExpression, getContext());
144                         ITypeConstraint[] c2 = createOrOrSubtypeConstraint(expressionVariable, castExpressionVariable);
145                         if (definesConstraint.length == 0){
146                                 return c2;
147                         } else {
148                                 ITypeConstraint c1 = definesConstraint[0];
149                                 Collection<ITypeConstraint> constraints= new ArrayList<ITypeConstraint>();
150                                 constraints.add(c1);
151                                 constraints.addAll(Arrays.asList(c2));
152                                 return constraints.toArray(new ITypeConstraint[constraints.size()]);
153                         }
154                 } else
155                         return definesConstraint;
156         }
157
158         @Override
159         public ITypeConstraint[] create(CatchClause node) {
160                 SingleVariableDeclaration exception= node.getException();
161                 ConstraintVariable nameVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(exception.getName(), getContext());
162
163                 ArrayList<ITypeConstraint> result= nameVariable.generated_7973021047960075765(node, exception, this);
164                 return result.toArray(new ITypeConstraint[result.size()]);
165         }
166
167         /* (non-Javadoc)
168          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation)
169          */
170         @Override
171         public ITypeConstraint[] create(ClassInstanceCreation instanceCreation){
172                 List<Expression> arguments= instanceCreation.arguments();
173                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
174                 IMethodBinding methodBinding= instanceCreation.resolveConstructorBinding();
175                 result.addAll(Arrays.asList(getArgumentConstraints(arguments, methodBinding)));
176                 if (instanceCreation.getAnonymousClassDeclaration() == null){
177                         ConstraintVariable constructorVar= fConstraintVariableFactory.makeExpressionOrTypeVariable(instanceCreation, getContext());
178                         ConstraintVariable typeVar= fConstraintVariableFactory.makeRawBindingVariable(instanceCreation.resolveTypeBinding());
179                         result.addAll(Arrays.asList(fTypeConstraintFactory.createDefinesConstraint(constructorVar, typeVar)));
180                 }
181                 return result.toArray(new ITypeConstraint[result.size()]);
182         }
183
184         /* (non-Javadoc)
185          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation)
186          */
187         @Override
188         public ITypeConstraint[] create(ConstructorInvocation invocation){
189                 List<Expression> arguments= invocation.arguments();
190                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
191                 IMethodBinding methodBinding= invocation.resolveConstructorBinding();
192                 result.addAll(Arrays.asList(getArgumentConstraints(arguments, methodBinding)));
193                 return result.toArray(new ITypeConstraint[result.size()]);
194         }
195
196         /* (non-Javadoc)
197          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccess)
198          */
199         @Override
200         public ITypeConstraint[] create(FieldAccess access){
201                 Expression expression= access.getExpression();
202                 SimpleName name= access.getName();
203                 IBinding binding= name.resolveBinding();
204                 if (! (binding instanceof IVariableBinding))
205                         return new ITypeConstraint[0];
206                 IVariableBinding vb= (IVariableBinding)binding;
207                 return createConstraintsForAccessToField(vb, expression, access);
208         }
209
210         /* (non-Javadoc)
211          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
212          */
213         @Override
214         public ITypeConstraint[] create(FieldDeclaration fd){
215                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
216                 result.addAll(Arrays.asList(getConstraintsFromFragmentList(fd.fragments(), fd.getType())));
217                 result.addAll(getConstraintsForHiding(fd));
218                 result.addAll(getConstraintsForFieldDeclaringTypes(fd));
219                 return result.toArray(new ITypeConstraint[result.size()]);
220         }
221
222         /* (non-Javadoc)
223          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InstanceofExpression)
224          */
225         @Override
226         public ITypeConstraint[] create(InstanceofExpression instanceofExpression){
227                 Expression expression= instanceofExpression.getLeftOperand();
228                 Type type= instanceofExpression.getRightOperand();
229                 if (isClassBinding(expression.resolveTypeBinding()) && isClassBinding(type.resolveBinding())) {
230                         ConstraintVariable expressionVar= fConstraintVariableFactory.makeExpressionOrTypeVariable(expression, getContext());
231                         ConstraintVariable typeVariable= fConstraintVariableFactory.makeTypeVariable(type);
232                         return createOrOrSubtypeConstraint(expressionVar, typeVariable);
233                 } else
234                         return new ITypeConstraint[0];
235         }
236
237         /* (non-Javadoc)
238          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConditionalExpression)
239          */
240         @Override
241         public ITypeConstraint[] create(ConditionalExpression node) {
242                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
243                 Expression thenExpression= node.getThenExpression();
244                 Expression elseExpression= node.getElseExpression();
245                 ConstraintVariable whole= fConstraintVariableFactory.makeExpressionOrTypeVariable(node, getContext());
246                 whole.generated_9019518919539633630(result, thenExpression, elseExpression, this);
247                 return result.toArray(new ITypeConstraint[result.size()]);
248         }
249
250         /* (non-Javadoc)
251          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
252          */
253         @Override
254         public ITypeConstraint[] create(MethodDeclaration declaration){
255                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
256                 IMethodBinding methodBinding= declaration.resolveBinding();
257                 if (methodBinding == null)
258                         return new ITypeConstraint[0];
259                 ITypeConstraint[] constraints = fTypeConstraintFactory.createDefinesConstraint(
260                                 fConstraintVariableFactory.makeDeclaringTypeVariable(methodBinding),
261                                 fConstraintVariableFactory.makeRawBindingVariable(methodBinding.getDeclaringClass()));
262                 result.addAll(Arrays.asList(constraints));
263                 if (! methodBinding.isConstructor() && ! methodBinding.getReturnType().isPrimitive()){
264                         ConstraintVariable returnTypeBindingVariable= fConstraintVariableFactory.makeReturnTypeVariable(methodBinding);
265                         ConstraintVariable returnTypeVariable= fConstraintVariableFactory.makeTypeVariable(declaration.getReturnType2());
266                         ITypeConstraint[] defines= fTypeConstraintFactory.createDefinesConstraint(
267                                         returnTypeBindingVariable, returnTypeVariable);
268                         result.addAll(Arrays.asList(defines));
269                 }
270                 for (int i= 0, n= declaration.parameters().size(); i < n; i++) {
271                         SingleVariableDeclaration paramDecl= (SingleVariableDeclaration)declaration.parameters().get(i);
272                         ConstraintVariable parameterTypeVariable= fConstraintVariableFactory.makeParameterTypeVariable(methodBinding, i);
273                         ConstraintVariable parameterNameVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(paramDecl.getName(), getContext());
274                         ITypeConstraint[] constraint= fTypeConstraintFactory.createDefinesConstraint(
275                                         parameterTypeVariable, parameterNameVariable);
276                         result.addAll(Arrays.asList(constraint));
277                 }
278                 if (MethodChecks.isVirtual(methodBinding)){
279                         Collection<ITypeConstraint> constraintsForOverriding = getConstraintsForOverriding(methodBinding);
280                         result.addAll(constraintsForOverriding);
281                 }
282                 return result.toArray(new ITypeConstraint[result.size()]);
283         }
284
285         /* (non-Javadoc)
286          * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ParenthesizedExpression)
287          */
288         @Override
289         public ITypeConstraint[] create(ParenthesizedExpression node) {
290                 ConstraintVariable v1= fConstraintVariableFactory.makeExpressionOrTypeVariable(node, getContext());
291                 ConstraintVariable v2= fConstraintVariableFactory.makeExpressionOrTypeVariable(node.getExpression(), getContext());
292                 ITypeConstraint[] equal= fTypeConstraintFactory.createEqualsConstraint(v1, v2);
293                 return equal;
294         }
295
296         /* (non-Javadoc)
297          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
298          */
299         @Override
300         public ITypeConstraint[] create(MethodInvocation invocation){
301                 List<Expression> arguments= invocation.arguments();
302                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
303                 IMethodBinding methodBinding= invocation.resolveMethodBinding();
304                 if (methodBinding == null)
305                         return new ITypeConstraint[0];
306                 ITypeConstraint[] returnTypeConstraint= getReturnTypeConstraint(invocation, methodBinding);
307                 result.addAll(Arrays.asList(returnTypeConstraint));
308                 result.addAll(Arrays.asList(getArgumentConstraints(arguments, methodBinding)));
309                 if (invocation.getExpression() != null){
310                         if(MethodChecks.isVirtual(methodBinding)){
311                                 IMethodBinding[] rootDefs= getRootDefs(methodBinding);
312                                 Assert.isTrue(rootDefs.length > 0);
313                                 ConstraintVariable expressionVar= fConstraintVariableFactory.makeExpressionOrTypeVariable(invocation.getExpression(), getContext());
314                                 expressionVar.generated_4724111901275699150(result, rootDefs, this);
315                         } else {
316                                 ConstraintVariable typeVar= fConstraintVariableFactory.makeDeclaringTypeVariable(methodBinding);
317                                 ConstraintVariable expressionVar= fConstraintVariableFactory.makeExpressionOrTypeVariable(invocation.getExpression(), getContext());
318                                 result.addAll(Arrays.asList(fTypeConstraintFactory.createSubtypeConstraint(expressionVar, typeVar)));
319                         }
320                 }
321                 return result.toArray(new ITypeConstraint[result.size()]);
322         }
323
324         /* (non-Javadoc)
325          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedName)
326          */
327         @Override
328         public ITypeConstraint[] create(QualifiedName qualifiedName){
329                 SimpleName name= qualifiedName.getName();
330                 Name qualifier= qualifiedName.getQualifier();
331                 IBinding nameBinding= name.resolveBinding();
332                 if (nameBinding instanceof IVariableBinding){
333                         IVariableBinding vb= (IVariableBinding)nameBinding;
334                         if (vb.isField())
335                                 return createConstraintsForAccessToField(vb, qualifier, qualifiedName);
336                 } //TODO other bindings
337                 return new ITypeConstraint[0];
338         }
339
340         /* (non-Javadoc)
341          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ReturnStatement)
342          */
343         @Override
344         public ITypeConstraint[] create(ReturnStatement returnStatement){
345                 if (returnStatement.getExpression() == null)
346                         return new ITypeConstraint[0];
347
348                 ConstraintVariable returnTypeVariable= fConstraintVariableFactory.makeReturnTypeVariable(returnStatement);
349                 return fTypeConstraintFactory.createSubtypeConstraint(
350                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(returnStatement.getExpression(), getContext()),
351                                 returnTypeVariable);
352         }
353
354         /* (non-Javadoc)
355          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration)
356          */
357         @Override
358         public ITypeConstraint[] create(SingleVariableDeclaration svd){
359                 ITypeConstraint[] defines= fTypeConstraintFactory.createDefinesConstraint(
360                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(svd.getName(), getContext()),
361                                 fConstraintVariableFactory.makeTypeVariable(svd.getType()));
362                 if (svd.getInitializer() == null)
363                         return defines;
364                 ITypeConstraint[] constraints = fTypeConstraintFactory.createSubtypeConstraint(
365                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(svd.getInitializer(), getContext()),
366                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(svd.getName(), getContext()));
367                 if (defines.length == 0 && constraints.length == 0){
368                         return new ITypeConstraint[0];
369                 } else if (defines.length == 0){
370                         return constraints;
371                 } else if (constraints.length == 0){
372                         return defines;
373                 } else {
374                         List<ITypeConstraint> all= new ArrayList<ITypeConstraint>();
375                         all.addAll(Arrays.asList(defines));
376                         all.addAll(Arrays.asList(constraints));
377                         return (ITypeConstraint[])all.toArray();
378                 }
379         }
380
381         /* (non-Javadoc)
382          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation)
383          */
384         @Override
385         public ITypeConstraint[] create(SuperConstructorInvocation invocation){
386                 List<Expression> arguments= invocation.arguments();
387                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
388                 IMethodBinding methodBinding= invocation.resolveConstructorBinding();
389                 result.addAll(Arrays.asList(getArgumentConstraints(arguments, methodBinding)));
390                 return result.toArray(new ITypeConstraint[result.size()]);
391         }
392
393         /* (non-Javadoc)
394          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperFieldAccess)
395          */
396         @Override
397         public ITypeConstraint[] create(SuperFieldAccess access){
398                 SimpleName name= access.getName();
399                 IBinding binding= name.resolveBinding();
400                 if (! (binding instanceof IVariableBinding))
401                         return new ITypeConstraint[0];
402                 IVariableBinding vb= (IVariableBinding)binding;
403                 return createConstraintsForAccessToField(vb, null, access);
404         }
405
406         /* (non-Javadoc)
407          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperMethodInvocation)
408          */
409         @Override
410         public ITypeConstraint[] create(SuperMethodInvocation invocation){
411                 List<Expression> arguments= invocation.arguments();
412                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
413                 IMethodBinding methodBinding= invocation.resolveMethodBinding();
414                 ITypeConstraint[] returnTypeConstraint= getReturnTypeConstraint(invocation, methodBinding);
415                 result.addAll(Arrays.asList(returnTypeConstraint));
416                 result.addAll(Arrays.asList(getArgumentConstraints(arguments, methodBinding)));
417                 return result.toArray(new ITypeConstraint[result.size()]);
418         }
419
420         /* (non-Javadoc)
421          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression)
422          */
423         @Override
424         public ITypeConstraint[] create(ThisExpression expression){
425                 ConstraintVariable thisExpression= fConstraintVariableFactory.makeExpressionOrTypeVariable(expression, getContext());
426                 ConstraintVariable declaringType= fConstraintVariableFactory.makeRawBindingVariable(expression.resolveTypeBinding());//TODO fix this - can't use Decl(M) because 'this' can live outside of methods
427                 return fTypeConstraintFactory.createDefinesConstraint(thisExpression, declaringType);
428         }
429
430         /* (non-Javadoc)
431          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationExpression)
432          */
433         @Override
434         public ITypeConstraint[] create(VariableDeclarationExpression vde){
435                 return getConstraintsFromFragmentList(vde.fragments(), vde.getType());
436         }
437
438         /* (non-Javadoc)
439          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment)
440          */
441         @Override
442         public ITypeConstraint[] create(VariableDeclarationFragment vdf){
443                 if (vdf.getInitializer() == null)
444                         return new ITypeConstraint[0];
445                 return fTypeConstraintFactory.createSubtypeConstraint(
446                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(vdf.getInitializer(), getContext()),
447                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(vdf.getName(), getContext()));
448         }
449
450         /* (non-Javadoc)
451          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement)
452          */
453         @Override
454         public ITypeConstraint[] create(VariableDeclarationStatement vds){
455                 return getConstraintsFromFragmentList(vds.fragments(), vds.getType());
456         }
457
458
459         //--------- private helpers ----------------//
460
461         private Collection<ITypeConstraint> getConstraintsForFieldDeclaringTypes(FieldDeclaration fd) {
462                 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>(fd.fragments().size());
463                 for (Iterator<VariableDeclarationFragment> iter= fd.fragments().iterator(); iter.hasNext();) {
464                         VariableDeclarationFragment varDecl= iter.next();
465                         IVariableBinding binding= varDecl.resolveBinding();
466                         Assert.isTrue(binding.isField());
467                         result.addAll(Arrays.asList(fTypeConstraintFactory.createDefinesConstraint(
468                                         fConstraintVariableFactory.makeDeclaringTypeVariable(binding),
469                                         fConstraintVariableFactory.makeRawBindingVariable(binding.getDeclaringClass()))));
470                 }
471                 return result;
472         }
473
474         private Collection<ITypeConstraint> getConstraintsForHiding(FieldDeclaration fd) {
475                 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
476                 for (Iterator<VariableDeclarationFragment> iter= fd.fragments().iterator(); iter.hasNext();) {
477                         result.addAll(getConstraintsForHiding(iter.next()));
478                 }
479                 return result;
480         }
481
482         private Collection<ITypeConstraint> getConstraintsForHiding(VariableDeclarationFragment fragment) {
483                 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
484                 IVariableBinding fieldBinding= fragment.resolveBinding();
485                 Assert.isTrue(fieldBinding.isField());
486                 Set<ITypeBinding> declaringTypes= getDeclaringSuperTypes(fieldBinding);
487                 ConstraintVariable hiddingFieldVar= fConstraintVariableFactory.makeDeclaringTypeVariable(fieldBinding);
488                 for (Iterator<ITypeBinding> iter= declaringTypes.iterator(); iter.hasNext();) {
489                         ITypeBinding declaringSuperType= iter.next();
490                         IVariableBinding hiddenField= findField(fieldBinding, declaringSuperType);
491                         Assert.isTrue(hiddenField.isField());
492                         ConstraintVariable hiddenFieldVar= fConstraintVariableFactory.makeDeclaringTypeVariable(hiddenField);
493                         result.addAll(Arrays.asList(fTypeConstraintFactory.createStrictSubtypeConstraint(hiddingFieldVar, hiddenFieldVar)));
494                 }
495                 return result;
496         }
497
498         private ITypeConstraint[] getConstraintsFromFragmentList(List<VariableDeclarationFragment> list, Type type) {
499                 int size= list.size();
500                 ConstraintVariable typeVariable= fConstraintVariableFactory.makeTypeVariable(type);
501                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>((size * (size - 1))/2);
502                 for (int i= 0; i < size; i++) {
503                         VariableDeclarationFragment fragment1= list.get(i);
504                         SimpleName fragment1Name= fragment1.getName();
505                         result.addAll(Arrays.asList(fTypeConstraintFactory.createDefinesConstraint(
506                                         fConstraintVariableFactory.makeExpressionOrTypeVariable(fragment1Name, getContext()),
507                                         typeVariable)));
508                         for (int j= i + 1; j < size; j++) {
509                                 VariableDeclarationFragment fragment2= list.get(j);
510                                 result.addAll(Arrays.asList(fTypeConstraintFactory.createEqualsConstraint(
511                                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(fragment1Name, getContext()),
512                                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(fragment2.getName(), getContext()))));
513                         }
514                 }
515                 return result.toArray(new ITypeConstraint[result.size()]);
516         }
517
518         private Collection<ITypeConstraint> getConstraintsForOverriding(IMethodBinding overridingMethod) {
519                 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
520                 Set<ITypeBinding> declaringSupertypes= getDeclaringSuperTypes(overridingMethod);
521                 for (Iterator<ITypeBinding> iter= declaringSupertypes.iterator(); iter.hasNext();) {
522                         ITypeBinding superType= iter.next();
523                         IMethodBinding overriddenMethod= findMethod(overridingMethod, superType);
524                         Assert.isNotNull(overriddenMethod);//because we asked for declaring types
525                         if (Bindings.equals(overridingMethod, overriddenMethod))
526                                 continue;
527                         ITypeConstraint[] returnTypeConstraint= fTypeConstraintFactory.createEqualsConstraint(
528                                         fConstraintVariableFactory.makeReturnTypeVariable(overriddenMethod),
529                                         fConstraintVariableFactory.makeReturnTypeVariable(overridingMethod));
530                         result.addAll(Arrays.asList(returnTypeConstraint));
531                         Assert.isTrue(overriddenMethod.getParameterTypes().length == overridingMethod.getParameterTypes().length);
532                         for (int i= 0, n= overriddenMethod.getParameterTypes().length; i < n; i++) {
533                                 ITypeConstraint[] parameterTypeConstraint= fTypeConstraintFactory.createEqualsConstraint(
534                                                 fConstraintVariableFactory.makeParameterTypeVariable(overriddenMethod, i),
535                                                 fConstraintVariableFactory.makeParameterTypeVariable(overridingMethod, i));
536                                 result.addAll(Arrays.asList(parameterTypeConstraint));
537                         }
538                         ITypeConstraint[] declaringTypeConstraint= fTypeConstraintFactory.createStrictSubtypeConstraint(
539                                         fConstraintVariableFactory.makeDeclaringTypeVariable(overridingMethod),
540                                         fConstraintVariableFactory.makeDeclaringTypeVariable(overriddenMethod));
541                         result.addAll(Arrays.asList(declaringTypeConstraint));
542                 }
543                 return result;
544         }
545
546         private ITypeConstraint[] getReturnTypeConstraint(Expression invocation, IMethodBinding methodBinding){
547                 if (methodBinding == null || methodBinding.isConstructor() || methodBinding.getReturnType().isPrimitive())
548                         return new ITypeConstraint[0];
549                 ConstraintVariable returnTypeVariable= fConstraintVariableFactory.makeReturnTypeVariable(methodBinding);
550                 ConstraintVariable invocationVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(invocation, getContext());
551                 return fTypeConstraintFactory.createDefinesConstraint(invocationVariable, returnTypeVariable);
552         }
553
554         private ITypeConstraint[] getArgumentConstraints(List<Expression> arguments, IMethodBinding methodBinding) {
555                 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
556                 
557                 if (methodBinding == null)
558                         return new ITypeConstraint[0];
559
560                 if (methodBinding.isVarargs()) {
561                         ITypeBinding[] parameterTypes= methodBinding.getParameterTypes();
562                         final int nParams= parameterTypes.length;
563                         final int nArgs= arguments.size();
564                         Assert.isTrue(nArgs >= nParams - 1); // there may be zero args for the vararg parameter
565                         Assert.isTrue(nParams >= 1); // at least one parameter for a vararg method
566
567                         int i= 0;
568                         // add the normal argument constraints up to the last one
569                         for (; i < nParams - 1; i++) {
570                                 Expression argument= arguments.get(i);
571                                 ConstraintVariable expressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(argument, getContext());
572                                 ConstraintVariable parameterTypeVariable= fConstraintVariableFactory.makeParameterTypeVariable(methodBinding, i);
573                                 ITypeConstraint[] argConstraint= fTypeConstraintFactory.createSubtypeConstraint(expressionVariable, parameterTypeVariable);
574                                 result.addAll(Arrays.asList(argConstraint));
575                         }
576
577                         // create argument constraints for all arguments wrapped into the vararg parameter
578                         boolean directArray= false;
579
580                         // a) there is exactly one remaining argument -> be careful as it may be a direct array param
581
582 // This is currently not used by Generalize Type Declaration as it does not support array types:
583 //                      if (i == nArgs - 1) {
584 //                              Expression argument= (Expression) arguments.get(i);
585 //                              if (TypeRules.canAssign(parameterTypes[nParams - 1], argument.resolveTypeBinding())) {
586 //                                      ConstraintVariable parameterTypeVariable= fConstraintVariableFactory.makeParameterTypeVariable(methodBinding, nParams - 1);
587 //                                      ConstraintVariable expressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(argument, getContext());
588 //                                      ITypeConstraint[] argConstraint= fTypeConstraintFactory.createSubtypeConstraint(expressionVariable, parameterTypeVariable);
589 //                                      result.addAll(Arrays.asList(argConstraint));
590 //                                      directArray= true;
591 //                                      //XXX there should be a constraint that logically ORs the direct array and element type constraints
592 //                              }
593 //                      }
594
595                         // b) there are zero ore more than one arguments remaining
596                         if (!directArray && i < nArgs) {
597                                 // get the component type of the vararg-array
598                                 ITypeBinding binding= methodBinding.getParameterTypes()[nParams - 1];
599                                 ITypeBinding componentBinding= binding.getComponentType();
600                                 Assert.isNotNull(componentBinding);
601                                 ConstraintVariable parameterTypeVariable= fConstraintVariableFactory.makeRawBindingVariable(componentBinding);
602                                 for (; i < nArgs; i++) {
603                                         Expression argument= arguments.get(i);
604                                         ConstraintVariable expressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(argument, getContext());
605                                         ITypeConstraint[] argConstraint= fTypeConstraintFactory.createSubtypeConstraint(expressionVariable, parameterTypeVariable);
606                                         result.addAll(Arrays.asList(argConstraint));
607                                 }
608                         }
609
610                 } else {
611                         for (int i= 0, n= arguments.size(); i < n; i++) {
612                                 Expression argument= arguments.get(i);
613                                 ConstraintVariable expressionVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(argument, getContext());
614                                 ConstraintVariable parameterTypeVariable= fConstraintVariableFactory.makeParameterTypeVariable(methodBinding, i);
615                                 ITypeConstraint[] argConstraint= fTypeConstraintFactory.createSubtypeConstraint(expressionVariable, parameterTypeVariable);
616                                 result.addAll(Arrays.asList(argConstraint));
617                         }
618                 }
619
620                 return result.toArray(new ITypeConstraint[result.size()]);
621         }
622
623         private static Type getTypeParent(ArrayInitializer arrayInitializer) {
624                 if (arrayInitializer.getParent() instanceof ArrayCreation){
625                         return ((ArrayCreation)arrayInitializer.getParent()).getType().getElementType();
626                 } else if (arrayInitializer.getParent() instanceof ArrayInitializer){
627                         return getTypeParent((ArrayInitializer) arrayInitializer.getParent());
628                 } else if (arrayInitializer.getParent() instanceof VariableDeclaration){
629                         VariableDeclaration parent= (VariableDeclaration)arrayInitializer.getParent();
630
631                         if (parent.getParent() instanceof VariableDeclarationStatement){
632                                 Type type= ((VariableDeclarationStatement)parent.getParent()).getType();
633                                 return ASTNodes.getElementType(type);
634                         } else if (parent.getParent() instanceof VariableDeclarationExpression){
635                                 Type type= ((VariableDeclarationExpression)parent.getParent()).getType();
636                                 return ASTNodes.getElementType(type);
637                         } else if (parent.getParent() instanceof FieldDeclaration){
638                                 Type type= ((FieldDeclaration)parent.getParent()).getType();
639                                 return ASTNodes.getElementType(type);
640                         }
641                 }
642                 Assert.isTrue(false);//array initializers are allowed in only 2 places
643                 return null;
644         }
645
646         private ITypeConstraint[] createOrOrSubtypeConstraint(ConstraintVariable var1, ConstraintVariable var2){
647                 return var2.generated_4084425156541321420(var1, this);
648         }
649
650         private ITypeConstraint[] createConstraintsForAccessToField(IVariableBinding fieldBinding, Expression qualifier, Expression accessExpression){
651                 Assert.isTrue(fieldBinding.isField());
652                 ITypeConstraint[] defines= fTypeConstraintFactory.createDefinesConstraint(
653                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(accessExpression, getContext()),
654                                 fConstraintVariableFactory.makeRawBindingVariable(fieldBinding.getType()));
655                 if (qualifier == null)
656                         return defines;
657                 ITypeConstraint[] subType= fTypeConstraintFactory.createSubtypeConstraint(
658                                 fConstraintVariableFactory.makeExpressionOrTypeVariable(qualifier, getContext()),
659                                 fConstraintVariableFactory.makeDeclaringTypeVariable(fieldBinding));
660
661                 if (defines.length == 0){
662                         return subType;
663                 } else if (subType.length == 0){
664                         return defines;
665                 } else {
666                         return new ITypeConstraint[]{defines[0], subType[0]};
667                 }
668         }
669
670         private static IVariableBinding findField(IVariableBinding fieldBinding, ITypeBinding type) {
671                 if (fieldBinding.getDeclaringClass().equals(type))
672                         return fieldBinding;
673                 return Bindings.findFieldInType(type, fieldBinding.getName());
674         }
675
676         /*
677          * return Set of ITypeBindings
678          */
679         private static Set<ITypeBinding> getDeclaringSuperTypes(IVariableBinding fieldBinding) {
680                 ITypeBinding[] allSuperTypes= Bindings.getAllSuperTypes(fieldBinding.getDeclaringClass());
681                 Set<ITypeBinding> result= new HashSet<ITypeBinding>();
682                 for (int i= 0; i < allSuperTypes.length; i++) {
683                         ITypeBinding type= allSuperTypes[i];
684                         if (findField(fieldBinding, type) != null)
685                                 result.add(type);
686                 }
687                 return result;
688         }
689
690         //--- RootDef ----//
691         protected static IMethodBinding[] getRootDefs(IMethodBinding methodBinding) {
692                 Set<ITypeBinding> declaringSuperTypes= getDeclaringSuperTypes(methodBinding);
693                 Set<IMethodBinding> result= new LinkedHashSet<IMethodBinding>();
694                 for (Iterator<ITypeBinding> iter= declaringSuperTypes.iterator(); iter.hasNext();) {
695                         ITypeBinding type= iter.next();
696                         if (! containsASuperType(type, declaringSuperTypes))
697                                 result.add(findMethod(methodBinding, type));
698                 }
699
700                 if (result.size() == 0){
701                         result.add(methodBinding);
702                 }
703                 return result.toArray(new IMethodBinding[result.size()]);
704         }
705
706         /*
707          * @param declaringSuperTypes Set of ITypeBindings
708          * @return <code>true</code> iff <code>declaringSuperTypes</code> contains a type
709          *              which is a strict supertype of <code>type</code>
710          */
711         private static boolean containsASuperType(ITypeBinding type, Set<ITypeBinding> declaringSuperTypes) {
712                 for (Iterator<ITypeBinding> iter= declaringSuperTypes.iterator(); iter.hasNext();) {
713                         ITypeBinding maybeSuperType= iter.next();
714                         if (! Bindings.equals(maybeSuperType, type) && Bindings.isSuperType(maybeSuperType, type))
715                                 return true;
716                 }
717                 return false;
718         }
719
720         /*
721          * return Set of ITypeBindings
722          */
723         protected static Set<ITypeBinding> getDeclaringSuperTypes(IMethodBinding methodBinding) {
724                 ITypeBinding superClass = methodBinding.getDeclaringClass();
725                 Set<ITypeBinding> allSuperTypes= new LinkedHashSet<ITypeBinding>();
726                 allSuperTypes.addAll(Arrays.asList(Bindings.getAllSuperTypes(superClass)));
727                 if (allSuperTypes.isEmpty())
728                         allSuperTypes.add(methodBinding.getDeclaringClass()); //TODO: Why only iff empty? The declaring class is not a supertype ...
729                 Set<ITypeBinding> result= new HashSet<ITypeBinding>();
730                 for (Iterator<ITypeBinding> iter= allSuperTypes.iterator(); iter.hasNext();) {
731                         ITypeBinding type= iter.next();
732                         if (findMethod(methodBinding, type) != null)
733                                 result.add(type);
734                 }
735                 return result;
736         }
737
738         protected static IMethodBinding findMethod(IMethodBinding methodBinding, ITypeBinding type) {
739                 if (methodBinding.getDeclaringClass().equals(type))
740                         return methodBinding;
741                 return Bindings.findOverriddenMethodInType(type, methodBinding);
742         }
743
744         private static boolean isClassBinding(ITypeBinding typeBinding){
745                 return typeBinding != null && typeBinding.isClass();
746         }
747
748 }