| /******************************************************************************* |
| * Copyright (c) 2000, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Stack; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.wst.jsdt.core.dom.ASTNode; |
| import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.AnnotationTypeDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.AnonymousClassDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.ArrayAccess; |
| import org.eclipse.wst.jsdt.core.dom.ArrayCreation; |
| import org.eclipse.wst.jsdt.core.dom.ArrayInitializer; |
| import org.eclipse.wst.jsdt.core.dom.ArrayType; |
| import org.eclipse.wst.jsdt.core.dom.Assignment; |
| import org.eclipse.wst.jsdt.core.dom.CastExpression; |
| import org.eclipse.wst.jsdt.core.dom.CatchClause; |
| import org.eclipse.wst.jsdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.wst.jsdt.core.dom.Comment; |
| import org.eclipse.wst.jsdt.core.dom.ConditionalExpression; |
| import org.eclipse.wst.jsdt.core.dom.ConstructorInvocation; |
| import org.eclipse.wst.jsdt.core.dom.Expression; |
| import org.eclipse.wst.jsdt.core.dom.FieldAccess; |
| import org.eclipse.wst.jsdt.core.dom.FieldDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.IBinding; |
| import org.eclipse.wst.jsdt.core.dom.IFunctionBinding; |
| import org.eclipse.wst.jsdt.core.dom.ITypeBinding; |
| import org.eclipse.wst.jsdt.core.dom.IVariableBinding; |
| import org.eclipse.wst.jsdt.core.dom.ImportDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.InstanceofExpression; |
| import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.FunctionInvocation; |
| import org.eclipse.wst.jsdt.core.dom.Name; |
| import org.eclipse.wst.jsdt.core.dom.NullLiteral; |
| import org.eclipse.wst.jsdt.core.dom.PackageDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.ParenthesizedExpression; |
| import org.eclipse.wst.jsdt.core.dom.QualifiedName; |
| import org.eclipse.wst.jsdt.core.dom.ReturnStatement; |
| import org.eclipse.wst.jsdt.core.dom.SimpleName; |
| import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.SuperConstructorInvocation; |
| import org.eclipse.wst.jsdt.core.dom.SuperFieldAccess; |
| import org.eclipse.wst.jsdt.core.dom.SuperMethodInvocation; |
| import org.eclipse.wst.jsdt.core.dom.ThisExpression; |
| import org.eclipse.wst.jsdt.core.dom.Type; |
| import org.eclipse.wst.jsdt.core.dom.TypeLiteral; |
| import org.eclipse.wst.jsdt.core.dom.UndefinedLiteral; |
| import org.eclipse.wst.jsdt.core.dom.VariableDeclarationExpression; |
| import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.wst.jsdt.core.dom.VariableDeclarationStatement; |
| import org.eclipse.wst.jsdt.internal.corext.SourceRange; |
| import org.eclipse.wst.jsdt.internal.corext.dom.Bindings; |
| import org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor; |
| import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange; |
| import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2; |
| import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringASTParser; |
| |
| /** |
| * Type constraints creator to determine the necessary constraints to replace type occurrences by a given super type. |
| * |
| * @since 3.1 |
| */ |
| public final class SuperTypeConstraintsCreator extends HierarchicalASTVisitor { |
| |
| /** The constraint variable property */ |
| private static final String PROPERTY_CONSTRAINT_VARIABLE= "cv"; //$NON-NLS-1$ |
| |
| /** |
| * Returns the original methods of the method hierarchy of the specified method. |
| * |
| * @param binding the method binding |
| * @param type the current type |
| * @param originals the original methods which have already been found (element type: <code>IFunctionBinding</code>) |
| * @param implementations <code>true</code> to favor implementation methods, <code>false</code> otherwise |
| */ |
| private static void getOriginalMethods(final IFunctionBinding binding, final ITypeBinding type, final Collection originals, final boolean implementations) { |
| final ITypeBinding ancestor= type.getSuperclass(); |
| if (!implementations) { |
| final ITypeBinding[] types= type.getInterfaces(); |
| for (int index= 0; index < types.length; index++) |
| getOriginalMethods(binding, types[index], originals, implementations); |
| if (ancestor != null) |
| getOriginalMethods(binding, ancestor, originals, implementations); |
| } |
| if (implementations && ancestor != null) |
| getOriginalMethods(binding, ancestor, originals, implementations); |
| final IFunctionBinding[] methods= type.getDeclaredMethods(); |
| IFunctionBinding method= null; |
| for (int index= 0; index < methods.length; index++) { |
| method= methods[index]; |
| if (!binding.getKey().equals(method.getKey())) { |
| boolean match= false; |
| IFunctionBinding current= null; |
| for (final Iterator iterator= originals.iterator(); iterator.hasNext();) { |
| current= (IFunctionBinding) iterator.next(); |
| if (Bindings.areOverriddenMethods(method, current)) |
| match= true; |
| } |
| if (!match && Bindings.areOverriddenMethods(binding, method)) |
| originals.add(method); |
| } |
| } |
| } |
| |
| /** The current method declarations being processed (element type: <code>FunctionDeclaration</code>) */ |
| private final Stack fCurrentMethods= new Stack(); |
| |
| /** Should instanceof expressions be rewritten? */ |
| private final boolean fInstanceOf; |
| |
| /** The type constraint model to solve */ |
| private final SuperTypeConstraintsModel fModel; |
| |
| /** |
| * Creates a new super type constraints creator. |
| * |
| * @param model the model to create the type constraints for |
| * @param instanceofs <code>true</code> to rewrite instanceof expressions, <code>false</code> otherwise |
| */ |
| public SuperTypeConstraintsCreator(final SuperTypeConstraintsModel model, final boolean instanceofs) { |
| Assert.isNotNull(model); |
| |
| fModel= model; |
| fInstanceOf= instanceofs; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ArrayAccess) |
| */ |
| public final void endVisit(final ArrayAccess node) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, node.getArray().getProperty(PROPERTY_CONSTRAINT_VARIABLE)); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ArrayCreation) |
| */ |
| public final void endVisit(final ArrayCreation node) { |
| final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| final ArrayInitializer initializer= node.getInitializer(); |
| if (initializer != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) initializer.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ArrayInitializer) |
| */ |
| public final void endVisit(final ArrayInitializer node) { |
| final ITypeBinding binding= node.resolveTypeBinding(); |
| if (binding != null && binding.isArray()) { |
| final ConstraintVariable2 ancestor= fModel.createIndependentTypeVariable(binding.getElementType()); |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| Expression expression= null; |
| ConstraintVariable2 descendant= null; |
| final List expressions= node.expressions(); |
| for (int index= 0; index < expressions.size(); index++) { |
| expression= (Expression) expressions.get(index); |
| descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ArrayType) |
| */ |
| public final void endVisit(final ArrayType node) { |
| ArrayType array= null; |
| Type component= node.getComponentType(); |
| while (component instanceof ArrayType) { |
| array= (ArrayType) component; |
| component= array.getComponentType(); |
| } |
| final ConstraintVariable2 variable= fModel.createTypeVariable(component); |
| if (variable != null) { |
| component.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.Assignment) |
| */ |
| public final void endVisit(final Assignment node) { |
| final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getLeftHandSide().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| final ConstraintVariable2 descendant= (ConstraintVariable2) node.getRightHandSide().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| if (ancestor != null && descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.CastExpression) |
| */ |
| public final void endVisit(final CastExpression node) { |
| final ConstraintVariable2 first= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (first != null) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, first); |
| final ConstraintVariable2 second= (ConstraintVariable2) node.getExpression().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (second != null) |
| fModel.createCastVariable(node, second); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.CatchClause) |
| */ |
| public final void endVisit(final CatchClause node) { |
| final SingleVariableDeclaration declaration= node.getException(); |
| if (declaration != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) declaration.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) { |
| final ITypeBinding binding= node.getAST().resolveWellKnownType("java.lang.Throwable"); //$NON-NLS-1$ |
| if (binding != null) { |
| final ConstraintVariable2 ancestor= fModel.createImmutableTypeVariable(binding); |
| if (ancestor != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ClassInstanceCreation) |
| */ |
| public final void endVisit(final ClassInstanceCreation node) { |
| final IFunctionBinding binding= node.resolveConstructorBinding(); |
| if (binding != null) { |
| endVisit(node.arguments(), binding); |
| ConstraintVariable2 variable= null; |
| final AnonymousClassDeclaration declaration= node.getAnonymousClassDeclaration(); |
| if (declaration != null) { |
| final ITypeBinding type= declaration.resolveBinding(); |
| if (type != null) |
| variable= fModel.createImmutableTypeVariable(type); |
| } else { |
| final ITypeBinding type= node.resolveTypeBinding(); |
| if (type != null) |
| variable= fModel.createImmutableTypeVariable(type); |
| } |
| if (variable != null) |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ConditionalExpression) |
| */ |
| public final void endVisit(final ConditionalExpression node) { |
| ConstraintVariable2 thenVariable= null; |
| ConstraintVariable2 elseVariable= null; |
| final Expression thenExpression= node.getThenExpression(); |
| if (thenExpression != null) |
| thenVariable= (ConstraintVariable2) thenExpression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| final Expression elseExpression= node.getElseExpression(); |
| if (elseExpression != null) |
| elseVariable= (ConstraintVariable2) elseExpression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| ITypeBinding binding= node.resolveTypeBinding(); |
| if (binding != null) { |
| if (binding.isArray()) |
| binding= binding.getElementType(); |
| final ConstraintVariable2 ancestor= fModel.createIndependentTypeVariable(binding); |
| if (ancestor != null) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| if (thenVariable != null) |
| fModel.createSubtypeConstraint(thenVariable, ancestor); |
| if (elseVariable != null) |
| fModel.createSubtypeConstraint(elseVariable, ancestor); |
| if (thenVariable != null && elseVariable != null) |
| fModel.createConditionalTypeConstraint(ancestor, thenVariable, elseVariable); |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ConstructorInvocation) |
| */ |
| public final void endVisit(final ConstructorInvocation node) { |
| final IFunctionBinding binding= node.resolveConstructorBinding(); |
| if (binding != null) |
| endVisit(node.arguments(), binding); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.FieldAccess) |
| */ |
| public final void endVisit(final FieldAccess node) { |
| final IVariableBinding binding= node.resolveFieldBinding(); |
| if (binding != null) |
| endVisit(binding, node.getExpression(), node); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.FieldDeclaration) |
| */ |
| public final void endVisit(final FieldDeclaration node) { |
| endVisit(node.fragments(), node.getType(), node); |
| } |
| |
| /** |
| * End of visit the specified method declaration. |
| * |
| * @param binding the method binding |
| */ |
| private void endVisit(final IFunctionBinding binding) { |
| IFunctionBinding method= null; |
| ConstraintVariable2 ancestor= null; |
| final ConstraintVariable2 descendant= fModel.createReturnTypeVariable(binding); |
| if (descendant != null) { |
| final Collection originals= getOriginalMethods(binding); |
| for (final Iterator iterator= originals.iterator(); iterator.hasNext();) { |
| method= (IFunctionBinding) iterator.next(); |
| if (!method.getKey().equals(binding.getKey())) { |
| ancestor= fModel.createReturnTypeVariable(method); |
| if (ancestor != null) |
| fModel.createCovariantTypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| |
| /** |
| * End of visit the specified method invocation. |
| * |
| * @param binding the method binding |
| * @param descendant the constraint variable of the invocation expression |
| */ |
| private void endVisit(final IFunctionBinding binding, final ConstraintVariable2 descendant) { |
| ITypeBinding declaring= null; |
| IFunctionBinding method= null; |
| final Collection originals= getOriginalMethods(binding); |
| for (final Iterator iterator= originals.iterator(); iterator.hasNext();) { |
| method= (IFunctionBinding) iterator.next(); |
| declaring= method.getDeclaringClass(); |
| if (declaring != null) { |
| final ConstraintVariable2 ancestor= fModel.createDeclaringTypeVariable(declaring); |
| if (ancestor != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| |
| /** |
| * End of visit the thrown exception |
| * |
| * @param binding the type binding of the thrown exception |
| * @param node the exception name node |
| */ |
| private void endVisit(final ITypeBinding binding, final Name node) { |
| final ConstraintVariable2 variable= fModel.createExceptionVariable(node); |
| if (variable != null) |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| } |
| |
| /** |
| * End of visit the field access. |
| * |
| * @param binding the variable binding |
| * @param qualifier the qualifier expression, or <code>null</code> |
| * @param access the access expression |
| */ |
| private void endVisit(final IVariableBinding binding, final Expression qualifier, final Expression access) { |
| access.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createVariableVariable(binding)); |
| if (qualifier != null) { |
| final ITypeBinding type= binding.getDeclaringClass(); |
| if (type != null) { |
| // array.length does not have a declaring class |
| final ConstraintVariable2 ancestor= fModel.createDeclaringTypeVariable(type); |
| if (ancestor != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) qualifier.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| |
| /** |
| * End of visit the method argument list. |
| * |
| * @param arguments the arguments (element type: <code>Expression</code>) |
| * @param binding the method binding |
| */ |
| private void endVisit(final List arguments, final IFunctionBinding binding) { |
| Expression expression= null; |
| ConstraintVariable2 ancestor= null; |
| ConstraintVariable2 descendant= null; |
| for (int index= 0; index < arguments.size(); index++) { |
| expression= (Expression) arguments.get(index); |
| descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| ancestor= fModel.createMethodParameterVariable(binding, index); |
| if (ancestor != null && descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| |
| /** |
| * End of visit the variable declaration fragment list. |
| * |
| * @param fragments the fragments (element type: <code>VariableDeclarationFragment</code>) |
| * @param type the type of the fragments |
| * @param parent the parent of the fragment list |
| */ |
| private void endVisit(final List fragments, final Type type, final ASTNode parent) { |
| final ConstraintVariable2 ancestor= (ConstraintVariable2) type.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (ancestor != null) { |
| IVariableBinding binding= null; |
| ConstraintVariable2 descendant= null; |
| VariableDeclarationFragment fragment= null; |
| for (int index= 0; index < fragments.size(); index++) { |
| fragment= (VariableDeclarationFragment) fragments.get(index); |
| descendant= (ConstraintVariable2) fragment.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| binding= fragment.resolveBinding(); |
| if (binding != null) { |
| descendant= fModel.createVariableVariable(binding); |
| if (descendant != null) |
| fModel.createEqualityConstraint(ancestor, descendant); |
| } |
| } |
| parent.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.FunctionDeclaration) |
| */ |
| public final void endVisit(final FunctionDeclaration node) { |
| fCurrentMethods.pop(); |
| final IFunctionBinding binding= node.resolveBinding(); |
| if (binding != null) { |
| if (!binding.isConstructor()) { |
| final Type type= node.getReturnType2(); |
| if (type != null) { |
| final ConstraintVariable2 first= fModel.createReturnTypeVariable(binding); |
| final ConstraintVariable2 second= (ConstraintVariable2) type.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (first != null) { |
| if (second != null) |
| fModel.createEqualityConstraint(first, second); |
| endVisit(binding); |
| } |
| } |
| } |
| ConstraintVariable2 ancestor= null; |
| ConstraintVariable2 descendant= null; |
| IVariableBinding variable= null; |
| final List parameters= node.parameters(); |
| if (!parameters.isEmpty()) { |
| final Collection originals= getOriginalMethods(binding); |
| SingleVariableDeclaration declaration= null; |
| for (int index= 0; index < parameters.size(); index++) { |
| declaration= (SingleVariableDeclaration) parameters.get(index); |
| ancestor= fModel.createMethodParameterVariable(binding, index); |
| if (ancestor != null) { |
| descendant= (ConstraintVariable2) declaration.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createEqualityConstraint(descendant, ancestor); |
| variable= declaration.resolveBinding(); |
| if (variable != null) { |
| descendant= fModel.createVariableVariable(variable); |
| if (descendant != null) |
| fModel.createEqualityConstraint(ancestor, descendant); |
| } |
| IFunctionBinding method= null; |
| for (final Iterator iterator= originals.iterator(); iterator.hasNext();) { |
| method= (IFunctionBinding) iterator.next(); |
| if (!method.getKey().equals(binding.getKey())) { |
| descendant= fModel.createMethodParameterVariable(method, index); |
| if (descendant != null) |
| fModel.createEqualityConstraint(ancestor, descendant); |
| } |
| } |
| } |
| } |
| } |
| final List exceptions= node.thrownExceptions(); |
| if (!exceptions.isEmpty()) { |
| final ITypeBinding throwable= node.getAST().resolveWellKnownType("java.lang.Throwable"); //$NON-NLS-1$ |
| if (throwable != null) { |
| ancestor= fModel.createImmutableTypeVariable(throwable); |
| if (ancestor != null) { |
| Name exception= null; |
| for (int index= 0; index < exceptions.size(); index++) { |
| exception= (Name) exceptions.get(index); |
| descendant= (ConstraintVariable2) exception.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.FunctionInvocation) |
| */ |
| public final void endVisit(final FunctionInvocation node) { |
| final IFunctionBinding binding= node.resolveMethodBinding(); |
| if (binding != null) { |
| endVisit(node, binding); |
| endVisit(node.arguments(), binding); |
| final Expression expression= node.getExpression(); |
| if (expression != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| endVisit(binding, descendant); |
| } |
| } |
| } |
| |
| /** |
| * End of visit the return type of a method invocation. |
| * |
| * @param invocation the method invocation |
| * @param binding the method binding |
| */ |
| private void endVisit(final FunctionInvocation invocation, final IFunctionBinding binding) { |
| if (!binding.isConstructor()) { |
| final ConstraintVariable2 variable= fModel.createReturnTypeVariable(binding); |
| if (variable != null) |
| invocation.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.NullLiteral) |
| */ |
| public final void endVisit(final NullLiteral node) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createImmutableTypeVariable(node.resolveTypeBinding())); |
| } |
| public final void endVisit(final UndefinedLiteral node) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createImmutableTypeVariable(node.resolveTypeBinding())); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ParenthesizedExpression) |
| */ |
| public final void endVisit(final ParenthesizedExpression node) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, node.getExpression().getProperty(PROPERTY_CONSTRAINT_VARIABLE)); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.QualifiedName) |
| */ |
| public final void endVisit(final QualifiedName node) { |
| final ASTNode parent= node.getParent(); |
| final Name qualifier= node.getQualifier(); |
| IBinding binding= qualifier.resolveBinding(); |
| if (binding instanceof ITypeBinding) { |
| final ConstraintVariable2 variable= fModel.createTypeVariable((ITypeBinding) binding, new CompilationUnitRange(RefactoringASTParser.getCompilationUnit(node), new SourceRange(qualifier.getStartPosition(), qualifier.getLength()))); |
| if (variable != null) |
| qualifier.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); |
| } |
| binding= node.getName().resolveBinding(); |
| if (binding instanceof IVariableBinding && !(parent instanceof ImportDeclaration)) |
| endVisit((IVariableBinding) binding, qualifier, node); |
| else if (binding instanceof ITypeBinding && parent instanceof FunctionDeclaration) |
| endVisit((ITypeBinding) binding, node); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ReturnStatement) |
| */ |
| public final void endVisit(final ReturnStatement node) { |
| final Expression expression= node.getExpression(); |
| if (expression != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) { |
| final FunctionDeclaration declaration= (FunctionDeclaration) fCurrentMethods.peek(); |
| if (declaration != null) { |
| final IFunctionBinding binding= declaration.resolveBinding(); |
| if (binding != null) { |
| final ConstraintVariable2 ancestor= fModel.createReturnTypeVariable(binding); |
| if (ancestor != null) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.SimpleName) |
| */ |
| public final void endVisit(final SimpleName node) { |
| final ASTNode parent= node.getParent(); |
| if (!(parent instanceof ImportDeclaration) && !(parent instanceof PackageDeclaration) && !(parent instanceof AbstractTypeDeclaration)) { |
| final IBinding binding= node.resolveBinding(); |
| if (binding instanceof IVariableBinding && !(parent instanceof FunctionDeclaration)) |
| endVisit((IVariableBinding) binding, null, node); |
| else if (binding instanceof ITypeBinding && parent instanceof FunctionDeclaration) |
| endVisit((ITypeBinding) binding, node); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration) |
| */ |
| public final void endVisit(final SingleVariableDeclaration node) { |
| final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (ancestor != null) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| final Expression expression= node.getInitializer(); |
| if (expression != null) { |
| final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); |
| if (descendant != null) |
| fModel.createSubtypeConstraint(descendant, ancestor); |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.SuperConstructorInvocation) |
| */ |
| public final void endVisit(final SuperConstructorInvocation node) { |
| final IFunctionBinding binding= node.resolveConstructorBinding(); |
| if (binding != null) |
| endVisit(node.arguments(), binding); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.SuperFieldAccess) |
| */ |
| public final void endVisit(final SuperFieldAccess node) { |
| final Name name= node.getName(); |
| final IBinding binding= name.resolveBinding(); |
| if (binding instanceof IVariableBinding) |
| endVisit((IVariableBinding) binding, null, node); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.SuperMethodInvocation) |
| */ |
| public final void endVisit(final SuperMethodInvocation node) { |
| final IFunctionBinding superBinding= node.resolveMethodBinding(); |
| if (superBinding != null) { |
| endVisit(node.arguments(), superBinding); |
| final FunctionDeclaration declaration= (FunctionDeclaration) fCurrentMethods.peek(); |
| if (declaration != null) { |
| final IFunctionBinding subBinding= declaration.resolveBinding(); |
| if (subBinding != null) { |
| final ConstraintVariable2 ancestor= fModel.createReturnTypeVariable(superBinding); |
| if (ancestor != null) { |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); |
| final ConstraintVariable2 descendant= fModel.createReturnTypeVariable(subBinding); |
| if (descendant != null) |
| fModel.createEqualityConstraint(descendant, ancestor); |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.ThisExpression) |
| */ |
| public final void endVisit(final ThisExpression node) { |
| final ITypeBinding binding= node.resolveTypeBinding(); |
| if (binding != null) |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createDeclaringTypeVariable(binding)); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.Type) |
| */ |
| public final void endVisit(final Type node) { |
| final ASTNode parent= node.getParent(); |
| if (!(parent instanceof AbstractTypeDeclaration) && !(parent instanceof ClassInstanceCreation) && !(parent instanceof TypeLiteral) && (!(parent instanceof InstanceofExpression) || fInstanceOf)) |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createTypeVariable(node)); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.VariableDeclarationExpression) |
| */ |
| public final void endVisit(final VariableDeclarationExpression node) { |
| endVisit(node.fragments(), node.getType(), node); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment) |
| */ |
| public final void endVisit(final VariableDeclarationFragment node) { |
| final Expression initializer= node.getInitializer(); |
| if (initializer != null) |
| node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, initializer.getProperty(PROPERTY_CONSTRAINT_VARIABLE)); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.wst.jsdt.core.dom.VariableDeclarationStatement) |
| */ |
| public final void endVisit(final VariableDeclarationStatement node) { |
| endVisit(node.fragments(), node.getType(), node); |
| } |
| |
| /** |
| * Returns the original methods of the method hierarchy of the specified method. |
| * |
| * @param binding the method binding |
| * @return the original methods (element type: <code>IFunctionBinding</code>) |
| */ |
| private Collection getOriginalMethods(final IFunctionBinding binding) { |
| final Collection originals= new ArrayList(); |
| final ITypeBinding type= binding.getDeclaringClass(); |
| getOriginalMethods(binding, type, originals, false); |
| getOriginalMethods(binding, type, originals, true); |
| if (originals.isEmpty()) |
| originals.add(binding); |
| return originals; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.AnnotationTypeDeclaration) |
| */ |
| public final boolean visit(final AnnotationTypeDeclaration node) { |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.Comment) |
| */ |
| public final boolean visit(final Comment node) { |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.ImportDeclaration) |
| */ |
| public final boolean visit(final ImportDeclaration node) { |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.FunctionDeclaration) |
| */ |
| public final boolean visit(final FunctionDeclaration node) { |
| fCurrentMethods.push(node); |
| return super.visit(node); |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.PackageDeclaration) |
| */ |
| public final boolean visit(final PackageDeclaration node) { |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.ThisExpression) |
| */ |
| public final boolean visit(final ThisExpression node) { |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.wst.jsdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.Type) |
| */ |
| public final boolean visit(final Type node) { |
| return false; |
| } |
| } |