blob: 9b2fcd454e424c88efe088829dc5cad91d16ab0c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.internal.core.util;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.dltk.core.Flags;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ITypeHierarchy;
import org.eclipse.dltk.core.ModelException;
public class MethodOverrideTester {
private final IType fFocusType;
private final ITypeHierarchy fHierarchy;
public MethodOverrideTester(IType focusType, ITypeHierarchy hierarchy) {
fFocusType = focusType;
fHierarchy = hierarchy;
}
public IType getFocusType() {
return fFocusType;
}
public ITypeHierarchy getTypeHierarchy() {
return fHierarchy;
}
/**
* Finds the method that declares the given method. A declaring method is
* the 'original' method declaration that does not override nor implement a
* method. <code>null</code> is returned it the given method does not
* override a method. When searching, super class are examined before
* implemented interfaces.
*
* @param testVisibility
* If true the result is tested on visibility. Null is returned
* if the method is not visible.
* @throws ModelException
*/
public IMethod findDeclaringMethod(IMethod overriding,
boolean testVisibility) throws ModelException {
IMethod result = null;
IMethod overridden = findOverriddenMethod(overriding, testVisibility);
while (overridden != null) {
result = overridden;
overridden = findOverriddenMethod(result, testVisibility);
}
return result;
}
/**
* Finds the method that is overridden by the given method. First the super
* class is examined and then the implemented interfaces.
*
* @param testVisibility
* If true the result is tested on visibility. Null is returned
* if the method is not visible.
* @throws ModelException
*/
public IMethod findOverriddenMethod(IMethod overriding,
boolean testVisibility) throws ModelException {
int flags = overriding.getFlags();
if (Flags.isPrivate(flags) || Flags.isStatic(flags)
|| overriding.isConstructor()) {
return null;
}
IType type = overriding.getDeclaringType();
IType[] superClass = fHierarchy.getSuperclass(type);
if (superClass != null) {
for (int q = 0; q < superClass.length; ++q) {
IMethod res = findOverriddenMethodInHierarchy(superClass[q],
overriding);
if (res != null && !Flags.isPrivate(res.getFlags())) {
return res;
}
}
}
return null;
}
/**
* Finds the directly overridden method in a type and its super types. First
* the super class is examined and then the implemented interfaces. With
* generics it is possible that 2 methods in the same type are overidden at
* the same time. In that case, the first overridden method found is
* returned.
*
* @param type
* The type to find methods in
* @param overriding
* The overriding method
* @return The first overridden method or <code>null</code> if no method is
* overridden
* @throws ModelException
*/
public IMethod findOverriddenMethodInHierarchy(IType type,
IMethod overriding) throws ModelException {
return innerFindOverriddenMethodInHierarchy(type, overriding,
new HashSet<IType>());
}
private IMethod innerFindOverriddenMethodInHierarchy(IType type,
IMethod overriding, Set<IType> processedTypes)
throws ModelException {
if (!processedTypes.add(type)) {
return null;
}
IMethod method = findOverriddenMethodInType(type, overriding);
if (method != null) {
return method;
}
IType[] superClass = fHierarchy.getSuperclass(type);
if (superClass != null) {
for (int q = 0; q < superClass.length; ++q) {
IMethod res = innerFindOverriddenMethodInHierarchy(
superClass[q], overriding, processedTypes);
if (res != null) {
return res;
}
}
}
return method;
}
/**
* Finds an overridden method in a type. WWith generics it is possible that
* 2 methods in the same type are overidden at the same time. In that case
* the first overridden method found is returned.
*
* @param overriddenType
* The type to find methods in
* @param overriding
* The overriding method
* @return The first overridden method or <code>null</code> if no method is
* overridden
* @throws ModelException
*/
public IMethod findOverriddenMethodInType(IType overriddenType,
IMethod overriding) throws ModelException {
IMethod[] overriddenMethods = overriddenType.getMethods();
for (int i = 0; i < overriddenMethods.length; i++) {
if (isSubsignature(overriding, overriddenMethods[i])) {
return overriddenMethods[i];
}
}
return null;
}
/**
* Finds an overriding method in a type.
*
* @param overridingType
* The type to find methods in
* @param overridden
* The overridden method
* @return The overriding method or <code>null</code> if no method is
* overriding.
* @throws ModelException
*/
public IMethod findOverridingMethodInType(IType overridingType,
IMethod overridden) throws ModelException {
IMethod[] overridingMethods = overridingType.getMethods();
for (int i = 0; i < overridingMethods.length; i++) {
if (isSubsignature(overridingMethods[i], overridden)) {
return overridingMethods[i];
}
}
return null;
}
/**
* Tests if a method is a subsignature of another method.
*
* @param overriding
* overriding method (m1)
* @param overridden
* overridden method (m2)
* @return <code>true</code> iff the method <code>m1</code> is a
* subsignature of the method <code>m2</code>. This is one of the
* requirements for m1 to override m2. Note that subsignature is
* <em>not</em> symmetric!
* @throws ModelException
*/
public boolean isSubsignature(IMethod overriding, IMethod overridden)
throws ModelException {
if (!overridden.getElementName().equals(overriding.getElementName())) {
return false;
}
return true;
}
}