blob: f75198bb7a2e65bd4f9c91b62d2aa4104eb36bce [file] [log] [blame]
/*******************************************************************************
* 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.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.FunctionDeclaration;
import org.eclipse.wst.jsdt.core.dom.FunctionInvocation;
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.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.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;
}
}