1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Utility methods to work with virtual methods, bug 248846.

This commit is contained in:
Markus Schorn 2008-10-09 14:06:00 +00:00
parent 04fa1f9ff5
commit 37c141ceab
3 changed files with 343 additions and 162 deletions

View file

@ -112,6 +112,7 @@ import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPPointerType;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@ -6046,4 +6047,77 @@ public class AST2CPPTests extends AST2BaseTest {
ICPPFunction func2= helper.assertNonProblem("func(y[0])", 4, ICPPFunction.class); ICPPFunction func2= helper.assertNonProblem("func(y[0])", 4, ICPPFunction.class);
assertNotSame(func1, func2); assertNotSame(func1, func2);
} }
// class NonVirt {
// void m();//0
// };
// class C1 : NonVirt {
// virtual void m();//1
// };
// class C2 : C1 {
// void m();//2
// };
// class C3 : C2 {
// void m(int);
// };
// class C4 : C3 {
// void m();//4
// };
// class C5 : C1 {
// void m();//5
// };
public void testOverridden_248846() throws Exception {
BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true);
ICPPMethod m0= helper.assertNonProblem("m();//0", 1, ICPPMethod.class);
ICPPMethod m1= helper.assertNonProblem("m();//1", 1, ICPPMethod.class);
ICPPMethod m2= helper.assertNonProblem("m();//2", 1, ICPPMethod.class);
ICPPMethod m3= helper.assertNonProblem("m(int);", 1, ICPPMethod.class);
ICPPMethod m4= helper.assertNonProblem("m();//4", 1, ICPPMethod.class);
ICPPMethod m5= helper.assertNonProblem("m();//5", 1, ICPPMethod.class);
assertFalse(ClassTypeHelper.isVirtual(m0));
assertFalse(ClassTypeHelper.isVirtual(m3));
assertTrue(ClassTypeHelper.isVirtual(m1));
assertTrue(ClassTypeHelper.isVirtual(m2));
assertTrue(ClassTypeHelper.isVirtual(m4));
assertTrue(ClassTypeHelper.isVirtual(m5));
assertFalse(ClassTypeHelper.isOverrider(m0, m0));
assertFalse(ClassTypeHelper.isOverrider(m1, m0));
assertFalse(ClassTypeHelper.isOverrider(m2, m0));
assertFalse(ClassTypeHelper.isOverrider(m3, m0));
assertFalse(ClassTypeHelper.isOverrider(m4, m0));
assertFalse(ClassTypeHelper.isOverrider(m5, m0));
assertFalse(ClassTypeHelper.isOverrider(m0, m1));
assertFalse(ClassTypeHelper.isOverrider(m1, m1));
assertFalse(ClassTypeHelper.isOverrider(m3, m1));
assertTrue(ClassTypeHelper.isOverrider(m2, m1));
assertTrue(ClassTypeHelper.isOverrider(m4, m1));
assertTrue(ClassTypeHelper.isOverrider(m5, m1));
assertFalse(ClassTypeHelper.isOverrider(m0, m2));
assertFalse(ClassTypeHelper.isOverrider(m1, m2));
assertFalse(ClassTypeHelper.isOverrider(m2, m2));
assertFalse(ClassTypeHelper.isOverrider(m3, m2));
assertFalse(ClassTypeHelper.isOverrider(m5, m2));
assertTrue(ClassTypeHelper.isOverrider(m4, m2));
ICPPMethod[] ors= ClassTypeHelper.findOverridden(m0);
assertEquals(0, ors.length);
ors= ClassTypeHelper.findOverridden(m1);
assertEquals(0, ors.length);
ors= ClassTypeHelper.findOverridden(m2);
assertEquals(1, ors.length);
assertSame(ors[0], m1);
ors= ClassTypeHelper.findOverridden(m3);
assertEquals(0, ors.length);
ors= ClassTypeHelper.findOverridden(m4);
assertEquals(2, ors.length);
assertSame(ors[0], m2);
assertSame(ors[1], m1);
ors= ClassTypeHelper.findOverridden(m5);
assertEquals(1, ors.length);
assertSame(ors[0], m1);
}
} }

View file

@ -14,6 +14,13 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp; package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
@ -24,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
@ -31,6 +39,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@ -38,13 +47,17 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType.CPPClassTypeProblem; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType.CPPClassTypeProblem;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.core.runtime.CoreException;
/** /**
* Holds common implementation of methods for ICPPClassType implementations that have * Holds common implementation of methods for ICPPClassType implementations that have
@ -155,27 +168,47 @@ public class ClassTypeHelper {
return (ICPPField[]) ArrayUtil.trim( ICPPField.class, result ); return (ICPPField[]) ArrayUtil.trim( ICPPField.class, result );
} }
public static ICPPMethod[] getAllDeclaredMethods(ICPPClassType ct) throws DOMException { public static ICPPClassType[] getAllBases(ICPPClassType ct) throws DOMException {
ICPPMethod[] methods = ct.getDeclaredMethods(); HashSet<ICPPClassType> result= new HashSet<ICPPClassType>();
ICPPBase [] bases = ct.getBases(); result.add(ct);
getAllBases(ct, result);
result.remove(ct);
return result.toArray(new ICPPClassType[result.size()]);
}
private static void getAllBases(ICPPClassType ct, HashSet<ICPPClassType> result) throws DOMException {
ICPPBase [] bases= ct.getBases();
for (ICPPBase base : bases) { for (ICPPBase base : bases) {
IBinding b = base.getBaseClass(); IBinding b= base.getBaseClass();
if( b instanceof ICPPClassType ) if (b instanceof ICPPClassType) {
methods = (ICPPMethod[]) ArrayUtil.addAll( ICPPMethod.class, methods, ((ICPPClassType)b).getAllDeclaredMethods() ); final ICPPClassType ctbase = (ICPPClassType) b;
if (result.add(ctbase)) {
getAllBases(ctbase, result);
}
}
}
}
public static ICPPMethod[] getAllDeclaredMethods(ICPPClassType ct) throws DOMException {
ICPPMethod[] methods= ct.getDeclaredMethods();
ICPPClassType[] bases= getAllBases(ct);
for (ICPPClassType base : bases) {
methods = (ICPPMethod[]) ArrayUtil.addAll(ICPPMethod.class, methods, base.getDeclaredMethods());
} }
return (ICPPMethod[]) ArrayUtil.trim( ICPPMethod.class, methods ); return (ICPPMethod[]) ArrayUtil.trim( ICPPMethod.class, methods );
} }
public static ICPPMethod[] getMethods(ICPPClassType ct) throws DOMException { public static ICPPMethod[] getMethods(ICPPClassType ct) throws DOMException {
ObjectSet<ICPPMethod> set = new ObjectSet<ICPPMethod>(4); ObjectSet<ICPPMethod> set= new ObjectSet<ICPPMethod>(4);
set.addAll(ct.getDeclaredMethods()); set.addAll(ct.getDeclaredMethods());
ICPPClassScope scope = (ICPPClassScope) ct.getCompositeScope(); ICPPClassScope scope= (ICPPClassScope) ct.getCompositeScope();
set.addAll(scope.getImplicitMethods()); set.addAll(scope.getImplicitMethods());
ICPPBase[] bases = ct.getBases();
for (ICPPBase base : bases) { ICPPClassType[] bases= getAllBases(ct);
IBinding b = base.getBaseClass(); for (ICPPClassType base : bases) {
if (b instanceof ICPPClassType) set.addAll(base.getDeclaredMethods());
set.addAll(((ICPPClassType) b).getMethods()); scope= (ICPPClassScope) base.getCompositeScope();
set.addAll(scope.getImplicitMethods());
} }
return set.keyArray(ICPPMethod.class); return set.keyArray(ICPPMethod.class);
} }
@ -300,13 +333,11 @@ public class ClassTypeHelper {
public static IField[] getFields(ICPPClassType ct) throws DOMException { public static IField[] getFields(ICPPClassType ct) throws DOMException {
IField[] fields = ct.getDeclaredFields(); IField[] fields = ct.getDeclaredFields();
ICPPBase [] bases = ct.getBases(); ICPPClassType[] bases = getAllBases(ct);
for (ICPPBase base : bases) { for (ICPPClassType base : bases) {
IBinding b = base.getBaseClass(); fields = (IField[]) ArrayUtil.addAll(IField.class, fields, base.getFields());
if( b instanceof ICPPClassType )
fields = (IField[]) ArrayUtil.addAll( IField.class, fields, ((ICPPClassType)b).getFields() );
} }
return (IField[]) ArrayUtil.trim( IField.class, fields ); return (IField[]) ArrayUtil.trim(IField.class, fields);
} }
public static IField findField(ICPPClassType ct, String name) throws DOMException { public static IField findField(ICPPClassType ct, String name) throws DOMException {
@ -325,4 +356,196 @@ public class ClassTypeHelper {
} }
return field; return field;
} }
/**
* Returns whether {@code method} is virtual. This is the case if it is declared to be virtual or
* overrides another virtual method.
*/
public static boolean isVirtual(ICPPMethod m) throws DOMException {
if (m instanceof ICPPConstructor)
return false;
if (m.isVirtual())
return true;
final char[] mname= m.getNameCharArray();
final ICPPClassType mcl= m.getClassOwner();
if (mcl != null) {
final IFunctionType mft= m.getType();
ICPPMethod[] allMethods= mcl.getMethods();
for (ICPPMethod method : allMethods) {
if (CharArrayUtils.equals(mname, method.getNameCharArray()) && mft.isSameType(method.getType())) {
if (method.isVirtual()) {
return true;
}
}
}
}
return false;
}
/**
* Returns {@code true} if {@code source} overrides {@code target}.
* @throws DOMException
*/
public static boolean isOverrider(ICPPMethod source, ICPPMethod target) throws DOMException {
if (source instanceof ICPPConstructor || target instanceof ICPPConstructor)
return false;
if (!isVirtual(target))
return false;
if (!source.getType().isSameType(target.getType()))
return false;
final ICPPClassType sourceClass= source.getClassOwner();
final ICPPClassType targetClass= target.getClassOwner();
if (sourceClass == null || targetClass == null)
return false;
ICPPClassType[] bases= getAllBases(sourceClass);
for (ICPPClassType base : bases) {
if (base.isSameType(targetClass))
return true;
}
return false;
}
/**
* Returns all methods that are overridden by the given {@code method}.
* @throws DOMException
*/
public static ICPPMethod[] findOverridden(ICPPMethod method) throws DOMException {
if (method instanceof ICPPConstructor)
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
final char[] mname= method.getNameCharArray();
final ICPPClassType mcl= method.getClassOwner();
if (mcl == null)
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
final HashMap<ICPPClassType, Boolean> virtualInClass= new HashMap<ICPPClassType, Boolean>();
final IFunctionType mft= method.getType();
virtualInClass.put(mcl, method.isVirtual());
ICPPBase[] bases= mcl.getBases();
for (ICPPBase base : bases) {
IBinding b= base.getBaseClass();
if (b instanceof ICPPClassType) {
findOverridden((ICPPClassType) b, mname, mft, virtualInClass, result);
}
}
// list is filled from most derived up to here, reverse it
Collections.reverse(result);
return result.toArray(new ICPPMethod[result.size()]);
}
/**
* Searches for overridden methods starting in {@code cl}. The map {@code virtualInClass} contains a mapping
* of classes that have been visited to the information whether they (or a base-class) contain an overridden
* method.
* Returns whether {@code cl} contains an overridden method.
*/
private static boolean findOverridden(ICPPClassType cl, char[] mname, IFunctionType mft,
HashMap<ICPPClassType, Boolean> virtualInClass, ArrayList<ICPPMethod> result) throws DOMException {
Boolean visitedBefore= virtualInClass.get(cl);
if (visitedBefore != null)
return visitedBefore;
ICPPMethod[] methods= cl.getDeclaredMethods();
ICPPMethod candidate= null;
boolean hasOverridden= false;
for (ICPPMethod method : methods) {
if (CharArrayUtils.equals(mname, method.getNameCharArray()) && mft.isSameType(method.getType())) {
candidate= method;
hasOverridden= method.isVirtual();
break;
}
}
// prevent recursion
virtualInClass.put(cl, hasOverridden);
ICPPBase[] bases= cl.getBases();
for (ICPPBase base : bases) {
IBinding b= base.getBaseClass();
if (b instanceof ICPPClassType) {
if (findOverridden((ICPPClassType) b, mname, mft, virtualInClass, result)) {
hasOverridden= true;
}
}
}
if (hasOverridden) {
// the candidate is virtual
if (candidate != null)
result.add(candidate);
virtualInClass.put(cl, hasOverridden);
}
return hasOverridden;
}
/**
* Returns all methods found in the index, that override the given {@code method}.
* @throws DOMException
* @throws CoreException
*/
public static ICPPMethod[] findOverriders(IIndex index, ICPPMethod method) throws DOMException, CoreException {
if (!isVirtual(method))
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
final ICPPClassType mcl= method.getClassOwner();
if (mcl == null)
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
final char[] mname= method.getNameCharArray();
final IFunctionType mft= method.getType();
ICPPClassType[] subclasses= getSubClasses(index, mcl);
for (ICPPClassType subClass : subclasses) {
ICPPMethod[] methods= subClass.getDeclaredMethods();
for (ICPPMethod candidate : methods) {
if (CharArrayUtils.equals(mname, candidate.getNameCharArray()) &&
mft.isSameType(candidate.getType())) {
result.add(candidate);
}
}
}
return result.toArray(new ICPPMethod[result.size()]);
}
private static ICPPClassType[] getSubClasses(IIndex index, ICPPClassType mcl) throws CoreException {
List<ICPPBinding> result= new LinkedList<ICPPBinding>();
HashSet<String> handled= new HashSet<String>();
getSubClasses(index, mcl, result, handled);
result.remove(0);
return result.toArray(new ICPPClassType[result.size()]);
}
private static void getSubClasses(IIndex index, ICPPBinding classOrTypedef, List<ICPPBinding> result, HashSet<String> handled) throws CoreException {
try {
final String key = CPPVisitor.renderQualifiedName(classOrTypedef.getQualifiedName());
if (!handled.add(key)) {
return;
}
} catch (DOMException e) {
return;
}
if (classOrTypedef instanceof ICPPClassType) {
result.add(classOrTypedef);
}
IIndexName[] names= index.findNames(classOrTypedef, IIndex.FIND_REFERENCES | IIndex.FIND_DEFINITIONS);
for (IIndexName indexName : names) {
if (indexName.isBaseSpecifier()) {
IIndexName subClassDef= indexName.getEnclosingDefinition();
if (subClassDef != null) {
IBinding subClass= index.findBinding(subClassDef);
if (subClass instanceof ICPPBinding) {
getSubClasses(index, (ICPPBinding) subClass, result, handled);
}
}
}
}
}
} }

View file

@ -12,19 +12,12 @@ package org.eclipse.cdt.internal.ui.callhierarchy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexBinding;
@ -32,9 +25,8 @@ import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.model.ext.ICElementHandle; import org.eclipse.cdt.internal.core.model.ext.ICElementHandle;
import org.eclipse.cdt.internal.ui.viewsupport.IndexUI; import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
@ -63,134 +55,20 @@ public class CHQueries {
IIndexBinding calleeBinding= IndexUI.elementToBinding(index, callee); IIndexBinding calleeBinding= IndexUI.elementToBinding(index, callee);
if (calleeBinding != null) { if (calleeBinding != null) {
findCalledBy(index, calleeBinding, true, project, result); findCalledBy(index, calleeBinding, true, project, result);
IBinding[] overriddenBindings= getOverriddenBindings(index, calleeBinding); if (calleeBinding instanceof ICPPMethod) {
for (IBinding overriddenBinding : overriddenBindings) { try {
findCalledBy(index, overriddenBinding, false, project, result); IBinding[] overriddenBindings= ClassTypeHelper.findOverridden((ICPPMethod) calleeBinding);
for (IBinding overriddenBinding : overriddenBindings) {
findCalledBy(index, overriddenBinding, false, project, result);
}
} catch (DOMException e) {
// index bindings don't throw DOMExceptions
}
} }
} }
return cp.createNodes(node, result); return cp.createNodes(node, result);
} }
private static IBinding[] getOverriddenBindings(IIndex index, IIndexBinding binding) {
if (binding instanceof ICPPMethod && !(binding instanceof ICPPConstructor)) {
try {
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
final ICPPMethod m= (ICPPMethod) binding;
final char[] mname= m.getNameCharArray();
final ICPPClassType mcl= m.getClassOwner();
if (mcl != null) {
final IFunctionType mft= m.getType();
boolean isVirtual= m.isVirtual();
ICPPMethod[] allMethods= mcl.getMethods();
for (ICPPMethod method : allMethods) {
if (CharArrayUtils.equals(mname, method.getNameCharArray()) && !mcl.isSameType(method.getClassOwner())) {
if (mft.isSameType(method.getType())) {
isVirtual= isVirtual || method.isVirtual();
result.add(method);
}
}
}
if (isVirtual) {
return result.toArray(new IBinding[result.size()]);
}
}
} catch (DOMException e) {
// index bindings don't throw DOMExceptions
}
}
return IBinding.EMPTY_BINDING_ARRAY;
}
private static IBinding[] getOverridingBindings(IIndex index, IBinding binding) throws CoreException {
if (binding instanceof ICPPMethod && !(binding instanceof ICPPConstructor)) {
try {
final ICPPMethod m= (ICPPMethod) binding;
if (isVirtual(m)) {
final ArrayList<ICPPMethod> result= new ArrayList<ICPPMethod>();
final char[] mname= m.getNameCharArray();
final ICPPClassType mcl= m.getClassOwner();
if (mcl != null) {
final IFunctionType mft= m.getType();
ICPPClassType[] subclasses= getSubClasses(index, mcl);
for (ICPPClassType subClass : subclasses) {
ICPPMethod[] methods= subClass.getDeclaredMethods();
for (ICPPMethod method : methods) {
if (CharArrayUtils.equals(mname, method.getNameCharArray()) &&
mft.isSameType(method.getType())) {
result.add(method);
}
}
}
return result.toArray(new IBinding[result.size()]);
}
}
} catch (DOMException e) {
// index bindings don't throw DOMExceptions
}
}
return IBinding.EMPTY_BINDING_ARRAY;
}
private static ICPPClassType[] getSubClasses(IIndex index, ICPPClassType mcl) throws CoreException {
List<ICPPBinding> result= new LinkedList<ICPPBinding>();
HashSet<String> handled= new HashSet<String>();
getSubClasses(index, mcl, result, handled);
result.remove(0);
return result.toArray(new ICPPClassType[result.size()]);
}
private static void getSubClasses(IIndex index, ICPPBinding classOrTypedef, List<ICPPBinding> result, HashSet<String> handled) throws CoreException {
try {
final String key = CPPVisitor.renderQualifiedName(classOrTypedef.getQualifiedName());
if (!handled.add(key)) {
return;
}
} catch (DOMException e) {
return;
}
if (classOrTypedef instanceof ICPPClassType) {
result.add(classOrTypedef);
}
IIndexName[] names= index.findNames(classOrTypedef, IIndex.FIND_REFERENCES | IIndex.FIND_DEFINITIONS);
for (IIndexName indexName : names) {
if (indexName.isBaseSpecifier()) {
IIndexName subClassDef= indexName.getEnclosingDefinition();
if (subClassDef != null) {
IBinding subClass= index.findBinding(subClassDef);
if (subClass instanceof ICPPBinding) {
getSubClasses(index, (ICPPBinding) subClass, result, handled);
}
}
}
}
}
private static boolean isVirtual(ICPPMethod m) {
try {
if (m.isVirtual()) {
return true;
}
final char[] mname= m.getNameCharArray();
final ICPPClassType mcl= m.getClassOwner();
if (mcl != null) {
final IFunctionType mft= m.getType();
ICPPMethod[] allMethods= mcl.getMethods();
for (ICPPMethod method : allMethods) {
if (CharArrayUtils.equals(mname, method.getNameCharArray()) && mft.isSameType(method.getType())) {
if (method.isVirtual()) {
return true;
}
}
}
}
} catch (DOMException e) {
// index bindings don't throw DOMExceptions
}
return false;
}
private static void findCalledBy(IIndex index, IBinding callee, boolean includeOrdinaryCalls, ICProject project, CalledByResult result) private static void findCalledBy(IIndex index, IBinding callee, boolean includeOrdinaryCalls, ICProject project, CalledByResult result)
throws CoreException { throws CoreException {
IIndexName[] names= index.findNames(callee, IIndex.FIND_REFERENCES | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); IIndexName[] names= index.findNames(callee, IIndex.FIND_REFERENCES | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
@ -220,18 +98,24 @@ public class CHQueries {
for (IIndexName name : refs) { for (IIndexName name : refs) {
IBinding binding= index.findBinding(name); IBinding binding= index.findBinding(name);
if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) { if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) {
IBinding[] virtualOverriders= getOverridingBindings(index, binding); ICElement[] defs= null;
ICElement[] defs; if (binding instanceof ICPPMethod) {
if (virtualOverriders.length == 0) { try {
defs = IndexUI.findRepresentative(index, binding); IBinding[] virtualOverriders= ClassTypeHelper.findOverriders(index, (ICPPMethod) binding);
} if (virtualOverriders.length > 0) {
else { ArrayList<ICElementHandle> list= new ArrayList<ICElementHandle>();
ArrayList<ICElementHandle> list= new ArrayList<ICElementHandle>(); list.addAll(Arrays.asList(IndexUI.findRepresentative(index, binding)));
list.addAll(Arrays.asList(IndexUI.findRepresentative(index, binding))); for (IBinding overrider : virtualOverriders) {
for (IBinding overrider : virtualOverriders) { list.addAll(Arrays.asList(IndexUI.findRepresentative(index, overrider)));
list.addAll(Arrays.asList(IndexUI.findRepresentative(index, overrider))); }
defs= list.toArray(new ICElement[list.size()]);
}
} catch (DOMException e) {
// index bindings don't throw DOMExceptions
} }
defs= list.toArray(new ICElement[list.size()]); }
if (defs == null) {
defs= IndexUI.findRepresentative(index, binding);
} }
if (defs != null && defs.length > 0) { if (defs != null && defs.length > 0) {
result.add(defs, name); result.add(defs, name);