001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.typeconstraints;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Collection;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.LinkedHashSet;
018: import java.util.List;
019: import java.util.Set;
020:
021: import org.eclipse.core.runtime.Assert;
022:
023: import org.eclipse.jdt.core.dom.ArrayCreation;
024: import org.eclipse.jdt.core.dom.ArrayInitializer;
025: import org.eclipse.jdt.core.dom.Assignment;
026: import org.eclipse.jdt.core.dom.CastExpression;
027: import org.eclipse.jdt.core.dom.CatchClause;
028: import org.eclipse.jdt.core.dom.ClassInstanceCreation;
029: import org.eclipse.jdt.core.dom.ConditionalExpression;
030: import org.eclipse.jdt.core.dom.ConstructorInvocation;
031: import org.eclipse.jdt.core.dom.Expression;
032: import org.eclipse.jdt.core.dom.FieldAccess;
033: import org.eclipse.jdt.core.dom.FieldDeclaration;
034: import org.eclipse.jdt.core.dom.IBinding;
035: import org.eclipse.jdt.core.dom.IMethodBinding;
036: import org.eclipse.jdt.core.dom.ITypeBinding;
037: import org.eclipse.jdt.core.dom.IVariableBinding;
038: import org.eclipse.jdt.core.dom.InstanceofExpression;
039: import org.eclipse.jdt.core.dom.MethodDeclaration;
040: import org.eclipse.jdt.core.dom.MethodInvocation;
041: import org.eclipse.jdt.core.dom.Name;
042: import org.eclipse.jdt.core.dom.ParenthesizedExpression;
043: import org.eclipse.jdt.core.dom.QualifiedName;
044: import org.eclipse.jdt.core.dom.ReturnStatement;
045: import org.eclipse.jdt.core.dom.SimpleName;
046: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
047: import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
048: import org.eclipse.jdt.core.dom.SuperFieldAccess;
049: import org.eclipse.jdt.core.dom.SuperMethodInvocation;
050: import org.eclipse.jdt.core.dom.ThisExpression;
051: import org.eclipse.jdt.core.dom.Type;
052: import org.eclipse.jdt.core.dom.VariableDeclaration;
053: import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
054: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
055: import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
056:
057: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
058: import org.eclipse.jdt.internal.corext.dom.Bindings;
059: import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
060:
061: /**
062: * Default implementation of the creator. Creates all or nearly all constraints for program constructs.
063: * Subclasses can provide additional checks to avoid creating constraints that are not useful for their purposes.
064: */
065: public class FullConstraintCreator extends ConstraintCreator {
066:
067: private final IConstraintVariableFactory fConstraintVariableFactory;
068: private final ITypeConstraintFactory fTypeConstraintFactory;
069: private IContext fContext;
070:
071: public FullConstraintCreator() {
072: this (new ConstraintVariableFactory(),
073: new TypeConstraintFactory());
074: }
075:
076: public FullConstraintCreator(IConstraintVariableFactory cFactory,
077: ITypeConstraintFactory tFactory) {
078: Assert.isTrue(cFactory != null);
079: fConstraintVariableFactory = cFactory;
080: fTypeConstraintFactory = tFactory;
081: fContext = new NullContext();
082: }
083:
084: public IContext getContext() {
085: return fContext;
086: }
087:
088: public void setContext(IContext context) {
089: fContext = context;
090: }
091:
092: public ITypeConstraintFactory getConstraintFactory() {
093: return fTypeConstraintFactory;
094: }
095:
096: public IConstraintVariableFactory getConstraintVariableFactory() {
097: return fConstraintVariableFactory;
098: }
099:
100: /* (non-Javadoc)
101: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayInitializer)
102: */
103: public ITypeConstraint[] create(ArrayInitializer arrayInitializer) {
104: ITypeBinding arrayBinding = arrayInitializer
105: .resolveTypeBinding();
106: Assert.isTrue(arrayBinding.isArray());
107: List expressions = arrayInitializer.expressions();
108: List/*<ITypeConstraint>*/constraints = new ArrayList();
109: Type type = getTypeParent(arrayInitializer);
110: ConstraintVariable typeVariable = fConstraintVariableFactory
111: .makeTypeVariable(type);
112: for (int i = 0; i < expressions.size(); i++) {
113: Expression each = (Expression) expressions.get(i);
114: ITypeConstraint[] c = fTypeConstraintFactory
115: .createSubtypeConstraint(fConstraintVariableFactory
116: .makeExpressionOrTypeVariable(each,
117: getContext()), typeVariable);
118: constraints.addAll(Arrays.asList(c));
119: }
120: return (ITypeConstraint[]) constraints
121: .toArray(new ITypeConstraint[constraints.size()]);
122: }
123:
124: /* (non-Javadoc)
125: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Assignment)
126: */
127: public ITypeConstraint[] create(Assignment assignment) {
128: return fTypeConstraintFactory.createSubtypeConstraint(
129: fConstraintVariableFactory
130: .makeExpressionOrTypeVariable(assignment
131: .getRightHandSide(), getContext()),
132: fConstraintVariableFactory
133: .makeExpressionOrTypeVariable(assignment
134: .getLeftHandSide(), getContext()));
135: }
136:
137: /* (non-Javadoc)
138: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CastExpression)
139: */
140: public ITypeConstraint[] create(CastExpression castExpression) {
141: Expression expression = castExpression.getExpression();
142: Type type = castExpression.getType();
143: ITypeConstraint[] definesConstraint = fTypeConstraintFactory
144: .createDefinesConstraint(fConstraintVariableFactory
145: .makeExpressionOrTypeVariable(castExpression,
146: getContext()),
147: fConstraintVariableFactory
148: .makeTypeVariable(castExpression
149: .getType()));
150: if (isClassBinding(expression.resolveTypeBinding())
151: && isClassBinding(type.resolveBinding())) {
152: ConstraintVariable expressionVariable = fConstraintVariableFactory
153: .makeExpressionOrTypeVariable(expression,
154: getContext());
155: ConstraintVariable castExpressionVariable = fConstraintVariableFactory
156: .makeExpressionOrTypeVariable(castExpression,
157: getContext());
158: ITypeConstraint[] c2 = createOrOrSubtypeConstraint(
159: expressionVariable, castExpressionVariable);
160: if (definesConstraint.length == 0) {
161: return c2;
162: } else {
163: ITypeConstraint c1 = definesConstraint[0];
164: Collection/*<ITypeConstraint>*/constraints = new ArrayList();
165: constraints.add(c1);
166: constraints.addAll(Arrays.asList(c2));
167: return (ITypeConstraint[]) constraints
168: .toArray(new ITypeConstraint[constraints.size()]);
169: }
170: } else
171: return definesConstraint;
172: }
173:
174: public ITypeConstraint[] create(CatchClause node) {
175: SingleVariableDeclaration exception = node.getException();
176: ConstraintVariable nameVariable = fConstraintVariableFactory
177: .makeExpressionOrTypeVariable(exception.getName(),
178: getContext());
179:
180: ITypeConstraint[] defines = fTypeConstraintFactory
181: .createDefinesConstraint(nameVariable,
182: fConstraintVariableFactory
183: .makeTypeVariable(exception.getType()));
184:
185: ITypeBinding throwable = node.getAST().resolveWellKnownType(
186: "java.lang.Throwable"); //$NON-NLS-1$
187: ITypeConstraint[] catchBound = fTypeConstraintFactory
188: .createSubtypeConstraint(nameVariable,
189: fConstraintVariableFactory
190: .makeRawBindingVariable(throwable));
191:
192: ArrayList result = new ArrayList();
193: result.addAll(Arrays.asList(defines));
194: result.addAll(Arrays.asList(catchBound));
195: return (ITypeConstraint[]) result
196: .toArray(new ITypeConstraint[result.size()]);
197: }
198:
199: /* (non-Javadoc)
200: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation)
201: */
202: public ITypeConstraint[] create(
203: ClassInstanceCreation instanceCreation) {
204: List arguments = instanceCreation.arguments();
205: List result = new ArrayList(arguments.size());
206: IMethodBinding methodBinding = instanceCreation
207: .resolveConstructorBinding();
208: result.addAll(Arrays.asList(getArgumentConstraints(arguments,
209: methodBinding)));
210: if (instanceCreation.getAnonymousClassDeclaration() == null) {
211: ConstraintVariable constructorVar = fConstraintVariableFactory
212: .makeExpressionOrTypeVariable(instanceCreation,
213: getContext());
214: ConstraintVariable typeVar = fConstraintVariableFactory
215: .makeRawBindingVariable(instanceCreation
216: .resolveTypeBinding());
217: result.addAll(Arrays.asList(fTypeConstraintFactory
218: .createDefinesConstraint(constructorVar, typeVar)));
219: }
220: return (ITypeConstraint[]) result
221: .toArray(new ITypeConstraint[result.size()]);
222: }
223:
224: /* (non-Javadoc)
225: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation)
226: */
227: public ITypeConstraint[] create(ConstructorInvocation invocation) {
228: List arguments = invocation.arguments();
229: List result = new ArrayList(arguments.size());
230: IMethodBinding methodBinding = invocation
231: .resolveConstructorBinding();
232: result.addAll(Arrays.asList(getArgumentConstraints(arguments,
233: methodBinding)));
234: return (ITypeConstraint[]) result
235: .toArray(new ITypeConstraint[result.size()]);
236: }
237:
238: /* (non-Javadoc)
239: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccess)
240: */
241: public ITypeConstraint[] create(FieldAccess access) {
242: Expression expression = access.getExpression();
243: SimpleName name = access.getName();
244: IBinding binding = name.resolveBinding();
245: if (!(binding instanceof IVariableBinding))
246: return new ITypeConstraint[0];
247: IVariableBinding vb = (IVariableBinding) binding;
248: return createConstraintsForAccessToField(vb, expression, access);
249: }
250:
251: /* (non-Javadoc)
252: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
253: */
254: public ITypeConstraint[] create(FieldDeclaration fd) {
255: List result = new ArrayList();
256: result.addAll(Arrays.asList(getConstraintsFromFragmentList(fd
257: .fragments(), fd.getType())));
258: result.addAll(getConstraintsForHiding(fd));
259: result.addAll(getConstraintsForFieldDeclaringTypes(fd));
260: return (ITypeConstraint[]) result
261: .toArray(new ITypeConstraint[result.size()]);
262: }
263:
264: /* (non-Javadoc)
265: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InstanceofExpression)
266: */
267: public ITypeConstraint[] create(
268: InstanceofExpression instanceof Expression) {
269: Expression expression = instanceof Expression.getLeftOperand();
270: Type type = instanceof Expression.getRightOperand();
271: if (isClassBinding(expression.resolveTypeBinding())
272: && isClassBinding(type.resolveBinding())) {
273: ConstraintVariable expressionVar = fConstraintVariableFactory
274: .makeExpressionOrTypeVariable(expression,
275: getContext());
276: ConstraintVariable typeVariable = fConstraintVariableFactory
277: .makeTypeVariable(type);
278: return createOrOrSubtypeConstraint(expressionVar,
279: typeVariable);
280: } else
281: return new ITypeConstraint[0];
282: }
283:
284: /* (non-Javadoc)
285: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConditionalExpression)
286: */
287: public ITypeConstraint[] create(ConditionalExpression node) {
288: List result = new ArrayList();
289: Expression thenExpression = node.getThenExpression();
290: Expression elseExpression = node.getElseExpression();
291: ConstraintVariable whole = fConstraintVariableFactory
292: .makeExpressionOrTypeVariable(node, getContext());
293: ConstraintVariable ev1 = fConstraintVariableFactory
294: .makeExpressionOrTypeVariable(thenExpression,
295: getContext());
296: ConstraintVariable ev2 = fConstraintVariableFactory
297: .makeExpressionOrTypeVariable(elseExpression,
298: getContext());
299: ITypeConstraint[] constraints1 = fTypeConstraintFactory
300: .createEqualsConstraint(ev1, ev2);
301: ITypeConstraint[] constraints2 = fTypeConstraintFactory
302: .createSubtypeConstraint(ev1, whole);
303: ITypeConstraint[] constraints3 = fTypeConstraintFactory
304: .createSubtypeConstraint(ev2, whole);
305: result.addAll(Arrays.asList(constraints1));
306: result.addAll(Arrays.asList(constraints2));
307: result.addAll(Arrays.asList(constraints3));
308: return (ITypeConstraint[]) result
309: .toArray(new ITypeConstraint[result.size()]);
310: }
311:
312: /* (non-Javadoc)
313: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
314: */
315: public ITypeConstraint[] create(MethodDeclaration declaration) {
316: List result = new ArrayList();
317: IMethodBinding methodBinding = declaration.resolveBinding();
318: if (methodBinding == null)
319: return new ITypeConstraint[0];
320: ITypeConstraint[] constraints = fTypeConstraintFactory
321: .createDefinesConstraint(fConstraintVariableFactory
322: .makeDeclaringTypeVariable(methodBinding),
323: fConstraintVariableFactory
324: .makeRawBindingVariable(methodBinding
325: .getDeclaringClass()));
326: result.addAll(Arrays.asList(constraints));
327: if (!methodBinding.isConstructor()
328: && !methodBinding.getReturnType().isPrimitive()) {
329: ConstraintVariable returnTypeBindingVariable = fConstraintVariableFactory
330: .makeReturnTypeVariable(methodBinding);
331: ConstraintVariable returnTypeVariable = fConstraintVariableFactory
332: .makeTypeVariable(declaration.getReturnType2());
333: ITypeConstraint[] defines = fTypeConstraintFactory
334: .createDefinesConstraint(returnTypeBindingVariable,
335: returnTypeVariable);
336: result.addAll(Arrays.asList(defines));
337: }
338: for (int i = 0, n = declaration.parameters().size(); i < n; i++) {
339: SingleVariableDeclaration paramDecl = (SingleVariableDeclaration) declaration
340: .parameters().get(i);
341: ConstraintVariable parameterTypeVariable = fConstraintVariableFactory
342: .makeParameterTypeVariable(methodBinding, i);
343: ConstraintVariable parameterNameVariable = fConstraintVariableFactory
344: .makeExpressionOrTypeVariable(paramDecl.getName(),
345: getContext());
346: ITypeConstraint[] constraint = fTypeConstraintFactory
347: .createDefinesConstraint(parameterTypeVariable,
348: parameterNameVariable);
349: result.addAll(Arrays.asList(constraint));
350: }
351: if (MethodChecks.isVirtual(methodBinding)) {
352: Collection constraintsForOverriding = getConstraintsForOverriding(methodBinding);
353: result.addAll(constraintsForOverriding);
354: }
355: return (ITypeConstraint[]) result
356: .toArray(new ITypeConstraint[result.size()]);
357: }
358:
359: /* (non-Javadoc)
360: * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ParenthesizedExpression)
361: */
362: public ITypeConstraint[] create(ParenthesizedExpression node) {
363: ConstraintVariable v1 = fConstraintVariableFactory
364: .makeExpressionOrTypeVariable(node, getContext());
365: ConstraintVariable v2 = fConstraintVariableFactory
366: .makeExpressionOrTypeVariable(node.getExpression(),
367: getContext());
368: ITypeConstraint[] equal = fTypeConstraintFactory
369: .createEqualsConstraint(v1, v2);
370: return equal;
371: }
372:
373: /* (non-Javadoc)
374: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
375: */
376: public ITypeConstraint[] create(MethodInvocation invocation) {
377: List arguments = invocation.arguments();
378: List result = new ArrayList(arguments.size());
379: IMethodBinding methodBinding = invocation
380: .resolveMethodBinding();
381: if (methodBinding == null)
382: return new ITypeConstraint[0];
383: ITypeConstraint[] returnTypeConstraint = getReturnTypeConstraint(
384: invocation, methodBinding);
385: result.addAll(Arrays.asList(returnTypeConstraint));
386: result.addAll(Arrays.asList(getArgumentConstraints(arguments,
387: methodBinding)));
388: if (invocation.getExpression() != null) {
389: if (MethodChecks.isVirtual(methodBinding)) {
390: IMethodBinding[] rootDefs = getRootDefs(methodBinding);
391: Assert.isTrue(rootDefs.length > 0);
392: ConstraintVariable expressionVar = fConstraintVariableFactory
393: .makeExpressionOrTypeVariable(invocation
394: .getExpression(), getContext());
395: if (rootDefs.length == 1) {
396: result
397: .addAll(Arrays
398: .asList(fTypeConstraintFactory
399: .createSubtypeConstraint(
400: expressionVar,
401: fConstraintVariableFactory
402: .makeDeclaringTypeVariable(rootDefs[0]))));
403: } else {
404: Collection/*<ITypeConstraint>*/constraints = new ArrayList();
405: for (int i = 0; i < rootDefs.length; i++) {
406: ConstraintVariable rootDefTypeVar = fConstraintVariableFactory
407: .makeDeclaringTypeVariable(rootDefs[i]);
408: ITypeConstraint[] tc = fTypeConstraintFactory
409: .createSubtypeConstraint(expressionVar,
410: rootDefTypeVar);
411: constraints.addAll(Arrays.asList(tc));
412: }
413: ITypeConstraint[] constraintsArray = (ITypeConstraint[]) constraints
414: .toArray(new ITypeConstraint[constraints
415: .size()]);
416: if (constraintsArray.length > 0) {
417: result
418: .add(fTypeConstraintFactory
419: .createCompositeOrTypeConstraint(constraintsArray));
420: }
421: }
422: } else {
423: ConstraintVariable typeVar = fConstraintVariableFactory
424: .makeDeclaringTypeVariable(methodBinding);
425: ConstraintVariable expressionVar = fConstraintVariableFactory
426: .makeExpressionOrTypeVariable(invocation
427: .getExpression(), getContext());
428: result.addAll(Arrays
429: .asList(fTypeConstraintFactory
430: .createSubtypeConstraint(expressionVar,
431: typeVar)));
432: }
433: }
434: return (ITypeConstraint[]) result
435: .toArray(new ITypeConstraint[result.size()]);
436: }
437:
438: /* (non-Javadoc)
439: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedName)
440: */
441: public ITypeConstraint[] create(QualifiedName qualifiedName) {
442: SimpleName name = qualifiedName.getName();
443: Name qualifier = qualifiedName.getQualifier();
444: IBinding nameBinding = name.resolveBinding();
445: if (nameBinding instanceof IVariableBinding) {
446: IVariableBinding vb = (IVariableBinding) nameBinding;
447: if (vb.isField())
448: return createConstraintsForAccessToField(vb, qualifier,
449: qualifiedName);
450: } //TODO other bindings
451: return new ITypeConstraint[0];
452: }
453:
454: /* (non-Javadoc)
455: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ReturnStatement)
456: */
457: public ITypeConstraint[] create(ReturnStatement returnStatement) {
458: if (returnStatement.getExpression() == null)
459: return new ITypeConstraint[0];
460:
461: ConstraintVariable returnTypeVariable = fConstraintVariableFactory
462: .makeReturnTypeVariable(returnStatement);
463: return fTypeConstraintFactory.createSubtypeConstraint(
464: fConstraintVariableFactory
465: .makeExpressionOrTypeVariable(returnStatement
466: .getExpression(), getContext()),
467: returnTypeVariable);
468: }
469:
470: /* (non-Javadoc)
471: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration)
472: */
473: public ITypeConstraint[] create(SingleVariableDeclaration svd) {
474: ITypeConstraint[] defines = fTypeConstraintFactory
475: .createDefinesConstraint(fConstraintVariableFactory
476: .makeExpressionOrTypeVariable(svd.getName(),
477: getContext()),
478: fConstraintVariableFactory.makeTypeVariable(svd
479: .getType()));
480: if (svd.getInitializer() == null)
481: return defines;
482: ITypeConstraint[] constraints = fTypeConstraintFactory
483: .createSubtypeConstraint(fConstraintVariableFactory
484: .makeExpressionOrTypeVariable(svd
485: .getInitializer(), getContext()),
486: fConstraintVariableFactory
487: .makeExpressionOrTypeVariable(svd
488: .getName(), getContext()));
489: if (defines.length == 0 && constraints.length == 0) {
490: return new ITypeConstraint[0];
491: } else if (defines.length == 0) {
492: return constraints;
493: } else if (constraints.length == 0) {
494: return defines;
495: } else {
496: List all = new ArrayList();
497: all.addAll(Arrays.asList(defines));
498: all.addAll(Arrays.asList(constraints));
499: return (ITypeConstraint[]) all.toArray();
500: }
501: }
502:
503: /* (non-Javadoc)
504: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation)
505: */
506: public ITypeConstraint[] create(
507: SuperConstructorInvocation invocation) {
508: List arguments = invocation.arguments();
509: List result = new ArrayList(arguments.size());
510: IMethodBinding methodBinding = invocation
511: .resolveConstructorBinding();
512: result.addAll(Arrays.asList(getArgumentConstraints(arguments,
513: methodBinding)));
514: return (ITypeConstraint[]) result
515: .toArray(new ITypeConstraint[result.size()]);
516: }
517:
518: /* (non-Javadoc)
519: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperFieldAccess)
520: */
521: public ITypeConstraint[] create(SuperFieldAccess access) {
522: SimpleName name = access.getName();
523: IBinding binding = name.resolveBinding();
524: if (!(binding instanceof IVariableBinding))
525: return new ITypeConstraint[0];
526: IVariableBinding vb = (IVariableBinding) binding;
527: return createConstraintsForAccessToField(vb, null, access);
528: }
529:
530: /* (non-Javadoc)
531: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperMethodInvocation)
532: */
533: public ITypeConstraint[] create(SuperMethodInvocation invocation) {
534: List arguments = invocation.arguments();
535: List result = new ArrayList(arguments.size());
536: IMethodBinding methodBinding = invocation
537: .resolveMethodBinding();
538: ITypeConstraint[] returnTypeConstraint = getReturnTypeConstraint(
539: invocation, methodBinding);
540: result.addAll(Arrays.asList(returnTypeConstraint));
541: result.addAll(Arrays.asList(getArgumentConstraints(arguments,
542: methodBinding)));
543: return (ITypeConstraint[]) result
544: .toArray(new ITypeConstraint[result.size()]);
545: }
546:
547: /* (non-Javadoc)
548: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression)
549: */
550: public ITypeConstraint[] create(ThisExpression expression) {
551: ConstraintVariable this Expression = fConstraintVariableFactory
552: .makeExpressionOrTypeVariable(expression, getContext());
553: ConstraintVariable declaringType = fConstraintVariableFactory
554: .makeRawBindingVariable(expression.resolveTypeBinding());//TODO fix this - can't use Decl(M) because 'this' can live outside of methods
555: return fTypeConstraintFactory.createDefinesConstraint(
556: this Expression, declaringType);
557: }
558:
559: /* (non-Javadoc)
560: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationExpression)
561: */
562: public ITypeConstraint[] create(VariableDeclarationExpression vde) {
563: return getConstraintsFromFragmentList(vde.fragments(), vde
564: .getType());
565: }
566:
567: /* (non-Javadoc)
568: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment)
569: */
570: public ITypeConstraint[] create(VariableDeclarationFragment vdf) {
571: if (vdf.getInitializer() == null)
572: return new ITypeConstraint[0];
573: return fTypeConstraintFactory.createSubtypeConstraint(
574: fConstraintVariableFactory
575: .makeExpressionOrTypeVariable(vdf
576: .getInitializer(), getContext()),
577: fConstraintVariableFactory
578: .makeExpressionOrTypeVariable(vdf.getName(),
579: getContext()));
580: }
581:
582: /* (non-Javadoc)
583: * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement)
584: */
585: public ITypeConstraint[] create(VariableDeclarationStatement vds) {
586: return getConstraintsFromFragmentList(vds.fragments(), vds
587: .getType());
588: }
589:
590: //--------- private helpers ----------------//
591:
592: private Collection getConstraintsForFieldDeclaringTypes(
593: FieldDeclaration fd) {
594: Collection result = new ArrayList(fd.fragments().size());
595: for (Iterator iter = fd.fragments().iterator(); iter.hasNext();) {
596: VariableDeclarationFragment varDecl = (VariableDeclarationFragment) iter
597: .next();
598: IVariableBinding binding = varDecl.resolveBinding();
599: Assert.isTrue(binding.isField());
600: result.addAll(Arrays.asList(fTypeConstraintFactory
601: .createDefinesConstraint(fConstraintVariableFactory
602: .makeDeclaringTypeVariable(binding),
603: fConstraintVariableFactory
604: .makeRawBindingVariable(binding
605: .getDeclaringClass()))));
606: }
607: return result;
608: }
609:
610: private Collection getConstraintsForHiding(FieldDeclaration fd) {
611: Collection result = new ArrayList();
612: for (Iterator iter = fd.fragments().iterator(); iter.hasNext();) {
613: result
614: .addAll(getConstraintsForHiding((VariableDeclarationFragment) iter
615: .next()));
616: }
617: return result;
618: }
619:
620: private Collection getConstraintsForHiding(
621: VariableDeclarationFragment fragment) {
622: Collection result = new ArrayList();
623: IVariableBinding fieldBinding = fragment.resolveBinding();
624: Assert.isTrue(fieldBinding.isField());
625: Set declaringTypes = getDeclaringSuperTypes(fieldBinding);
626: ConstraintVariable hiddingFieldVar = fConstraintVariableFactory
627: .makeDeclaringTypeVariable(fieldBinding);
628: for (Iterator iter = declaringTypes.iterator(); iter.hasNext();) {
629: ITypeBinding declaringSuperType = (ITypeBinding) iter
630: .next();
631: IVariableBinding hiddenField = findField(fieldBinding,
632: declaringSuperType);
633: Assert.isTrue(hiddenField.isField());
634: ConstraintVariable hiddenFieldVar = fConstraintVariableFactory
635: .makeDeclaringTypeVariable(hiddenField);
636: result.addAll(Arrays.asList(fTypeConstraintFactory
637: .createStrictSubtypeConstraint(hiddingFieldVar,
638: hiddenFieldVar)));
639: }
640: return result;
641: }
642:
643: private ITypeConstraint[] getConstraintsFromFragmentList(
644: List fragments, Type type) {
645: int size = fragments.size();
646: ConstraintVariable typeVariable = fConstraintVariableFactory
647: .makeTypeVariable(type);
648: List result = new ArrayList((size * (size - 1)) / 2);
649: for (int i = 0; i < size; i++) {
650: VariableDeclarationFragment fragment1 = (VariableDeclarationFragment) fragments
651: .get(i);
652: SimpleName fragment1Name = fragment1.getName();
653: result.addAll(Arrays.asList(fTypeConstraintFactory
654: .createDefinesConstraint(fConstraintVariableFactory
655: .makeExpressionOrTypeVariable(
656: fragment1Name, getContext()),
657: typeVariable)));
658: for (int j = i + 1; j < size; j++) {
659: VariableDeclarationFragment fragment2 = (VariableDeclarationFragment) fragments
660: .get(j);
661: result.addAll(Arrays.asList(fTypeConstraintFactory
662: .createEqualsConstraint(
663: fConstraintVariableFactory
664: .makeExpressionOrTypeVariable(
665: fragment1Name,
666: getContext()),
667: fConstraintVariableFactory
668: .makeExpressionOrTypeVariable(
669: fragment2.getName(),
670: getContext()))));
671: }
672: }
673: return (ITypeConstraint[]) result
674: .toArray(new ITypeConstraint[result.size()]);
675: }
676:
677: private Collection getConstraintsForOverriding(
678: IMethodBinding overriddingMethod) {
679: Collection result = new ArrayList();
680: Set declaringSupertypes = getDeclaringSuperTypes(overriddingMethod);
681: for (Iterator iter = declaringSupertypes.iterator(); iter
682: .hasNext();) {
683: ITypeBinding super Type = (ITypeBinding) iter.next();
684: IMethodBinding overriddenMethod = findMethod(
685: overriddingMethod, super Type);
686: Assert.isNotNull(overriddenMethod);//because we asked for declaring types
687: if (Bindings.equals(overriddingMethod, overriddenMethod))
688: continue;
689: ITypeConstraint[] returnTypeConstraint = fTypeConstraintFactory
690: .createEqualsConstraint(
691: fConstraintVariableFactory
692: .makeReturnTypeVariable(overriddenMethod),
693: fConstraintVariableFactory
694: .makeReturnTypeVariable(overriddingMethod));
695: result.addAll(Arrays.asList(returnTypeConstraint));
696: Assert
697: .isTrue(overriddenMethod.getParameterTypes().length == overriddingMethod
698: .getParameterTypes().length);
699: for (int i = 0, n = overriddenMethod.getParameterTypes().length; i < n; i++) {
700: ITypeConstraint[] parameterTypeConstraint = fTypeConstraintFactory
701: .createEqualsConstraint(
702: fConstraintVariableFactory
703: .makeParameterTypeVariable(
704: overriddenMethod, i),
705: fConstraintVariableFactory
706: .makeParameterTypeVariable(
707: overriddingMethod, i));
708: result.addAll(Arrays.asList(parameterTypeConstraint));
709: }
710: ITypeConstraint[] declaringTypeConstraint = fTypeConstraintFactory
711: .createStrictSubtypeConstraint(
712: fConstraintVariableFactory
713: .makeDeclaringTypeVariable(overriddingMethod),
714: fConstraintVariableFactory
715: .makeDeclaringTypeVariable(overriddenMethod));
716: result.addAll(Arrays.asList(declaringTypeConstraint));
717: }
718: return result;
719: }
720:
721: private ITypeConstraint[] getReturnTypeConstraint(
722: Expression invocation, IMethodBinding methodBinding) {
723: if (methodBinding == null || methodBinding.isConstructor()
724: || methodBinding.getReturnType().isPrimitive())
725: return new ITypeConstraint[0];
726: ConstraintVariable returnTypeVariable = fConstraintVariableFactory
727: .makeReturnTypeVariable(methodBinding);
728: ConstraintVariable invocationVariable = fConstraintVariableFactory
729: .makeExpressionOrTypeVariable(invocation, getContext());
730: return fTypeConstraintFactory.createDefinesConstraint(
731: invocationVariable, returnTypeVariable);
732: }
733:
734: private ITypeConstraint[] getArgumentConstraints(List arguments,
735: IMethodBinding methodBinding) {
736: List result = new ArrayList(arguments.size());
737: for (int i = 0, n = arguments.size(); i < n; i++) {
738: Expression argument = (Expression) arguments.get(i);
739: ConstraintVariable expressionVariable = fConstraintVariableFactory
740: .makeExpressionOrTypeVariable(argument,
741: getContext());
742: ConstraintVariable parameterTypeVariable = fConstraintVariableFactory
743: .makeParameterTypeVariable(methodBinding, i);
744: ITypeConstraint[] argConstraint = fTypeConstraintFactory
745: .createSubtypeConstraint(expressionVariable,
746: parameterTypeVariable);
747: result.addAll(Arrays.asList(argConstraint));
748: }
749: return (ITypeConstraint[]) result
750: .toArray(new ITypeConstraint[result.size()]);
751: }
752:
753: private static Type getTypeParent(ArrayInitializer arrayInitializer) {
754: if (arrayInitializer.getParent() instanceof ArrayCreation) {
755: return ((ArrayCreation) arrayInitializer.getParent())
756: .getType().getElementType();
757: } else if (arrayInitializer.getParent() instanceof ArrayInitializer) {
758: return getTypeParent((ArrayInitializer) arrayInitializer
759: .getParent());
760: } else if (arrayInitializer.getParent() instanceof VariableDeclaration) {
761: VariableDeclaration parent = (VariableDeclaration) arrayInitializer
762: .getParent();
763:
764: if (parent.getParent() instanceof VariableDeclarationStatement) {
765: Type type = ((VariableDeclarationStatement) parent
766: .getParent()).getType();
767: return ASTNodes.getElementType(type);
768: } else if (parent.getParent() instanceof VariableDeclarationExpression) {
769: Type type = ((VariableDeclarationExpression) parent
770: .getParent()).getType();
771: return ASTNodes.getElementType(type);
772: } else if (parent.getParent() instanceof FieldDeclaration) {
773: Type type = ((FieldDeclaration) parent.getParent())
774: .getType();
775: return ASTNodes.getElementType(type);
776: }
777: }
778: Assert.isTrue(false);//array initializers are allowed in only 2 places
779: return null;
780: }
781:
782: private ITypeConstraint[] createOrOrSubtypeConstraint(
783: ConstraintVariable var1, ConstraintVariable var2) {
784: ITypeConstraint[] c1 = fTypeConstraintFactory
785: .createSubtypeConstraint(var1, var2);
786: ITypeConstraint[] c2 = fTypeConstraintFactory
787: .createSubtypeConstraint(var2, var1);
788: if (c1.length == 0 && c2.length == 0) {
789: return new ITypeConstraint[0];
790: }
791: return new ITypeConstraint[] { fTypeConstraintFactory
792: .createCompositeOrTypeConstraint(new ITypeConstraint[] {
793: c1[0], c2[0] }) };
794: }
795:
796: private ITypeConstraint[] createConstraintsForAccessToField(
797: IVariableBinding fieldBinding, Expression qualifier,
798: Expression accessExpression) {
799: Assert.isTrue(fieldBinding.isField());
800: ITypeConstraint[] defines = fTypeConstraintFactory
801: .createDefinesConstraint(fConstraintVariableFactory
802: .makeExpressionOrTypeVariable(accessExpression,
803: getContext()),
804: fConstraintVariableFactory
805: .makeRawBindingVariable(fieldBinding
806: .getType()));
807: if (qualifier == null)
808: return defines;
809: ITypeConstraint[] subType = fTypeConstraintFactory
810: .createSubtypeConstraint(
811: fConstraintVariableFactory
812: .makeExpressionOrTypeVariable(
813: qualifier, getContext()),
814: fConstraintVariableFactory
815: .makeDeclaringTypeVariable(fieldBinding));
816:
817: if (defines.length == 0) {
818: return subType;
819: } else if (subType.length == 0) {
820: return defines;
821: } else {
822: return new ITypeConstraint[] { defines[0], subType[0] };
823: }
824: }
825:
826: private static IVariableBinding findField(
827: IVariableBinding fieldBinding, ITypeBinding type) {
828: if (fieldBinding.getDeclaringClass().equals(type))
829: return fieldBinding;
830: return Bindings.findFieldInType(type, fieldBinding.getName());
831: }
832:
833: /*
834: * return Set of ITypeBindings
835: */
836: private static Set getDeclaringSuperTypes(
837: IVariableBinding fieldBinding) {
838: ITypeBinding[] allSuperTypes = Bindings
839: .getAllSuperTypes(fieldBinding.getDeclaringClass());
840: Set result = new HashSet();
841: for (int i = 0; i < allSuperTypes.length; i++) {
842: ITypeBinding type = allSuperTypes[i];
843: if (findField(fieldBinding, type) != null)
844: result.add(type);
845: }
846: return result;
847: }
848:
849: //--- RootDef ----//
850: protected static IMethodBinding[] getRootDefs(
851: IMethodBinding methodBinding) {
852: Set/*<ITypeBinding>*/declaringSuperTypes = getDeclaringSuperTypes(methodBinding);
853: Set/*<IMethodBinding>*/result = new LinkedHashSet();
854: for (Iterator iter = declaringSuperTypes.iterator(); iter
855: .hasNext();) {
856: ITypeBinding type = (ITypeBinding) iter.next();
857: if (!containsASuperType(type, declaringSuperTypes))
858: result.add(findMethod(methodBinding, type));
859: }
860:
861: if (result.size() == 0) {
862: result.add(methodBinding);
863: }
864: return (IMethodBinding[]) result
865: .toArray(new IMethodBinding[result.size()]);
866: }
867:
868: /*
869: * @param declaringSuperTypes Set of ITypeBindings
870: * @return <code>true</code> iff <code>declaringSuperTypes</code> contains a type
871: * which is a strict supertype of <code>type</code>
872: */
873: private static boolean containsASuperType(ITypeBinding type,
874: Set declaringSuperTypes) {
875: for (Iterator iter = declaringSuperTypes.iterator(); iter
876: .hasNext();) {
877: ITypeBinding maybeSuperType = (ITypeBinding) iter.next();
878: if (!Bindings.equals(maybeSuperType, type)
879: && Bindings.isSuperType(maybeSuperType, type))
880: return true;
881: }
882: return false;
883: }
884:
885: /*
886: * return Set of ITypeBindings
887: */
888: protected static Set getDeclaringSuperTypes(
889: IMethodBinding methodBinding) {
890: ITypeBinding super Class = methodBinding.getDeclaringClass();
891: Set allSuperTypes = new LinkedHashSet();
892: allSuperTypes.addAll(Arrays.asList(Bindings
893: .getAllSuperTypes(super Class)));
894: if (allSuperTypes.isEmpty())
895: allSuperTypes.add(methodBinding.getDeclaringClass()); //TODO: Why only iff empty? The declaring class is not a supertype ...
896: Set result = new HashSet();
897: for (Iterator iter = allSuperTypes.iterator(); iter.hasNext();) {
898: ITypeBinding type = (ITypeBinding) iter.next();
899: if (findMethod(methodBinding, type) != null)
900: result.add(type);
901: }
902: return result;
903: }
904:
905: protected static IMethodBinding findMethod(
906: IMethodBinding methodBinding, ITypeBinding type) {
907: if (methodBinding.getDeclaringClass().equals(type))
908: return methodBinding;
909: return Bindings.findOverriddenMethodInType(type, methodBinding);
910: }
911:
912: private static boolean isClassBinding(ITypeBinding typeBinding) {
913: return typeBinding != null && typeBinding.isClass();
914: }
915:
916: }
|