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 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.typeconstraints;
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;
22 import org.eclipse.core.runtime.Assert;
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;
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;
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.
67 public class FullConstraintCreator extends ConstraintCreator{
69 final IConstraintVariableFactory fConstraintVariableFactory;
70 final ITypeConstraintFactory fTypeConstraintFactory;
71 private IContext fContext;
73 public FullConstraintCreator(){
74 this(new ConstraintVariableFactory(), new TypeConstraintFactory());
77 public FullConstraintCreator(IConstraintVariableFactory cFactory,
78 ITypeConstraintFactory tFactory) {
79 Assert.isTrue(cFactory != null);
80 fConstraintVariableFactory= cFactory;
81 fTypeConstraintFactory= tFactory;
82 fContext= new NullContext();
85 public IContext getContext() {
89 public void setContext(IContext context) {
93 public ITypeConstraintFactory getConstraintFactory(){
94 return fTypeConstraintFactory;
97 public IConstraintVariableFactory getConstraintVariableFactory(){
98 return fConstraintVariableFactory;
102 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayInitializer)
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()),
117 constraints.addAll(Arrays.asList(c));
119 return constraints.toArray(new ITypeConstraint[constraints.size()]);
123 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Assignment)
126 public ITypeConstraint[] create(Assignment assignment){
127 return fTypeConstraintFactory.createSubtypeConstraint(
128 fConstraintVariableFactory.makeExpressionOrTypeVariable(assignment.getRightHandSide(), getContext()),
129 fConstraintVariableFactory.makeExpressionOrTypeVariable(assignment.getLeftHandSide(), getContext()));
133 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CastExpression)
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){
148 ITypeConstraint c1 = definesConstraint[0];
149 Collection<ITypeConstraint> constraints= new ArrayList<ITypeConstraint>();
151 constraints.addAll(Arrays.asList(c2));
152 return constraints.toArray(new ITypeConstraint[constraints.size()]);
155 return definesConstraint;
159 public ITypeConstraint[] create(CatchClause node) {
160 SingleVariableDeclaration exception= node.getException();
161 ConstraintVariable nameVariable= fConstraintVariableFactory.makeExpressionOrTypeVariable(exception.getName(), getContext());
163 ArrayList<ITypeConstraint> result= nameVariable.generated_7973021047960075765(node, exception, this);
164 return result.toArray(new ITypeConstraint[result.size()]);
168 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation)
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)));
181 return result.toArray(new ITypeConstraint[result.size()]);
185 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation)
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()]);
197 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccess)
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);
211 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
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()]);
223 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InstanceofExpression)
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);
234 return new ITypeConstraint[0];
238 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConditionalExpression)
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()]);
251 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
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));
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));
278 if (MethodChecks.isVirtual(methodBinding)){
279 Collection<ITypeConstraint> constraintsForOverriding = getConstraintsForOverriding(methodBinding);
280 result.addAll(constraintsForOverriding);
282 return result.toArray(new ITypeConstraint[result.size()]);
286 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ParenthesizedExpression)
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);
297 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
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);
316 ConstraintVariable typeVar= fConstraintVariableFactory.makeDeclaringTypeVariable(methodBinding);
317 ConstraintVariable expressionVar= fConstraintVariableFactory.makeExpressionOrTypeVariable(invocation.getExpression(), getContext());
318 result.addAll(Arrays.asList(fTypeConstraintFactory.createSubtypeConstraint(expressionVar, typeVar)));
321 return result.toArray(new ITypeConstraint[result.size()]);
325 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedName)
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;
335 return createConstraintsForAccessToField(vb, qualifier, qualifiedName);
336 } //TODO other bindings
337 return new ITypeConstraint[0];
341 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ReturnStatement)
344 public ITypeConstraint[] create(ReturnStatement returnStatement){
345 if (returnStatement.getExpression() == null)
346 return new ITypeConstraint[0];
348 ConstraintVariable returnTypeVariable= fConstraintVariableFactory.makeReturnTypeVariable(returnStatement);
349 return fTypeConstraintFactory.createSubtypeConstraint(
350 fConstraintVariableFactory.makeExpressionOrTypeVariable(returnStatement.getExpression(), getContext()),
355 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration)
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)
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){
371 } else if (constraints.length == 0){
374 List<ITypeConstraint> all= new ArrayList<ITypeConstraint>();
375 all.addAll(Arrays.asList(defines));
376 all.addAll(Arrays.asList(constraints));
377 return (ITypeConstraint[])all.toArray();
382 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation)
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()]);
394 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperFieldAccess)
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);
407 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperMethodInvocation)
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()]);
421 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression)
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);
431 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationExpression)
434 public ITypeConstraint[] create(VariableDeclarationExpression vde){
435 return getConstraintsFromFragmentList(vde.fragments(), vde.getType());
439 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment)
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()));
451 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement)
454 public ITypeConstraint[] create(VariableDeclarationStatement vds){
455 return getConstraintsFromFragmentList(vds.fragments(), vds.getType());
459 //--------- private helpers ----------------//
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()))));
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()));
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)));
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()),
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()))));
515 return result.toArray(new ITypeConstraint[result.size()]);
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))
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));
538 ITypeConstraint[] declaringTypeConstraint= fTypeConstraintFactory.createStrictSubtypeConstraint(
539 fConstraintVariableFactory.makeDeclaringTypeVariable(overridingMethod),
540 fConstraintVariableFactory.makeDeclaringTypeVariable(overriddenMethod));
541 result.addAll(Arrays.asList(declaringTypeConstraint));
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);
554 private ITypeConstraint[] getArgumentConstraints(List<Expression> arguments, IMethodBinding methodBinding) {
555 List<ITypeConstraint> result= new ArrayList<ITypeConstraint>(arguments.size());
557 if (methodBinding == null)
558 return new ITypeConstraint[0];
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
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));
577 // create argument constraints for all arguments wrapped into the vararg parameter
578 boolean directArray= false;
580 // a) there is exactly one remaining argument -> be careful as it may be a direct array param
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
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));
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));
620 return result.toArray(new ITypeConstraint[result.size()]);
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();
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);
642 Assert.isTrue(false);//array initializers are allowed in only 2 places
646 private ITypeConstraint[] createOrOrSubtypeConstraint(ConstraintVariable var1, ConstraintVariable var2){
647 return var2.generated_4084425156541321420(var1, this);
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)
657 ITypeConstraint[] subType= fTypeConstraintFactory.createSubtypeConstraint(
658 fConstraintVariableFactory.makeExpressionOrTypeVariable(qualifier, getContext()),
659 fConstraintVariableFactory.makeDeclaringTypeVariable(fieldBinding));
661 if (defines.length == 0){
663 } else if (subType.length == 0){
666 return new ITypeConstraint[]{defines[0], subType[0]};
670 private static IVariableBinding findField(IVariableBinding fieldBinding, ITypeBinding type) {
671 if (fieldBinding.getDeclaringClass().equals(type))
673 return Bindings.findFieldInType(type, fieldBinding.getName());
677 * return Set of ITypeBindings
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)
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));
700 if (result.size() == 0){
701 result.add(methodBinding);
703 return result.toArray(new IMethodBinding[result.size()]);
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>
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))
721 * return Set of ITypeBindings
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)
738 protected static IMethodBinding findMethod(IMethodBinding methodBinding, ITypeBinding type) {
739 if (methodBinding.getDeclaringClass().equals(type))
740 return methodBinding;
741 return Bindings.findOverriddenMethodInType(type, methodBinding);
744 private static boolean isClassBinding(ITypeBinding typeBinding){
745 return typeBinding != null && typeBinding.isClass();