From 37c141ceab66b02b6960affa1b9496f96224d266 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Thu, 9 Oct 2008 14:06:00 +0000 Subject: [PATCH] Utility methods to work with virtual methods, bug 248846. --- .../core/parser/tests/ast2/AST2CPPTests.java | 74 +++++ .../core/dom/parser/cpp/ClassTypeHelper.java | 261 ++++++++++++++++-- .../internal/ui/callhierarchy/CHQueries.java | 170 ++---------- 3 files changed, 343 insertions(+), 162 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index cd95d776b5c..f75107f7747 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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.util.CharArrayUtils; 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.semantics.CPPSemantics; 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); 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); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index b8eccf6183d..8646eebeccd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -14,6 +14,13 @@ *******************************************************************************/ 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.IASTDeclSpecifier; 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.IBinding; 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.cpp.ICPPASTCompositeTypeSpecifier; 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.ICPPASTUsingDeclaration; 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.ICPPClassType; 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.ICPPUsingDeclaration; 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.CharArrayUtils; 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.ProblemBinding; 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.CPPVisitor; +import org.eclipse.core.runtime.CoreException; /** * Holds common implementation of methods for ICPPClassType implementations that have @@ -155,27 +168,47 @@ public class ClassTypeHelper { return (ICPPField[]) ArrayUtil.trim( ICPPField.class, result ); } - public static ICPPMethod[] getAllDeclaredMethods(ICPPClassType ct) throws DOMException { - ICPPMethod[] methods = ct.getDeclaredMethods(); - ICPPBase [] bases = ct.getBases(); + public static ICPPClassType[] getAllBases(ICPPClassType ct) throws DOMException { + HashSet result= new HashSet(); + result.add(ct); + getAllBases(ct, result); + result.remove(ct); + return result.toArray(new ICPPClassType[result.size()]); + } + + private static void getAllBases(ICPPClassType ct, HashSet result) throws DOMException { + ICPPBase [] bases= ct.getBases(); for (ICPPBase base : bases) { - IBinding b = base.getBaseClass(); - if( b instanceof ICPPClassType ) - methods = (ICPPMethod[]) ArrayUtil.addAll( ICPPMethod.class, methods, ((ICPPClassType)b).getAllDeclaredMethods() ); + IBinding b= base.getBaseClass(); + if (b instanceof ICPPClassType) { + 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 ); } public static ICPPMethod[] getMethods(ICPPClassType ct) throws DOMException { - ObjectSet set = new ObjectSet(4); + ObjectSet set= new ObjectSet(4); set.addAll(ct.getDeclaredMethods()); - ICPPClassScope scope = (ICPPClassScope) ct.getCompositeScope(); + ICPPClassScope scope= (ICPPClassScope) ct.getCompositeScope(); set.addAll(scope.getImplicitMethods()); - ICPPBase[] bases = ct.getBases(); - for (ICPPBase base : bases) { - IBinding b = base.getBaseClass(); - if (b instanceof ICPPClassType) - set.addAll(((ICPPClassType) b).getMethods()); + + ICPPClassType[] bases= getAllBases(ct); + for (ICPPClassType base : bases) { + set.addAll(base.getDeclaredMethods()); + scope= (ICPPClassScope) base.getCompositeScope(); + set.addAll(scope.getImplicitMethods()); } return set.keyArray(ICPPMethod.class); } @@ -300,13 +333,11 @@ public class ClassTypeHelper { public static IField[] getFields(ICPPClassType ct) throws DOMException { IField[] fields = ct.getDeclaredFields(); - ICPPBase [] bases = ct.getBases(); - for (ICPPBase base : bases) { - IBinding b = base.getBaseClass(); - if( b instanceof ICPPClassType ) - fields = (IField[]) ArrayUtil.addAll( IField.class, fields, ((ICPPClassType)b).getFields() ); + ICPPClassType[] bases = getAllBases(ct); + for (ICPPClassType base : bases) { + fields = (IField[]) ArrayUtil.addAll(IField.class, fields, base.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 { @@ -325,4 +356,196 @@ public class ClassTypeHelper { } 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 result= new ArrayList(); + final HashMap virtualInClass= new HashMap(); + 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 virtualInClass, ArrayList 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 result= new ArrayList(); + 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 result= new LinkedList(); + HashSet handled= new HashSet(); + getSubClasses(index, mcl, result, handled); + result.remove(0); + return result.toArray(new ICPPClassType[result.size()]); + } + + private static void getSubClasses(IIndex index, ICPPBinding classOrTypedef, List result, HashSet 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); + } + } + } + } + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java index 729a31a3df3..6d3616220b1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHQueries.java @@ -12,19 +12,12 @@ package org.eclipse.cdt.internal.ui.callhierarchy; import java.util.ArrayList; 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.IProgressMonitor; import org.eclipse.cdt.core.dom.ast.DOMException; 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.index.IIndex; 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.ICProject; 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.ui.viewsupport.IndexUI; @@ -63,134 +55,20 @@ public class CHQueries { IIndexBinding calleeBinding= IndexUI.elementToBinding(index, callee); if (calleeBinding != null) { findCalledBy(index, calleeBinding, true, project, result); - IBinding[] overriddenBindings= getOverriddenBindings(index, calleeBinding); - for (IBinding overriddenBinding : overriddenBindings) { - findCalledBy(index, overriddenBinding, false, project, result); + if (calleeBinding instanceof ICPPMethod) { + try { + 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); } - private static IBinding[] getOverriddenBindings(IIndex index, IIndexBinding binding) { - if (binding instanceof ICPPMethod && !(binding instanceof ICPPConstructor)) { - try { - final ArrayList result= new ArrayList(); - 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 result= new ArrayList(); - 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 result= new LinkedList(); - HashSet handled= new HashSet(); - getSubClasses(index, mcl, result, handled); - result.remove(0); - return result.toArray(new ICPPClassType[result.size()]); - } - - private static void getSubClasses(IIndex index, ICPPBinding classOrTypedef, List result, HashSet 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) throws CoreException { IIndexName[] names= index.findNames(callee, IIndex.FIND_REFERENCES | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); @@ -220,18 +98,24 @@ public class CHQueries { for (IIndexName name : refs) { IBinding binding= index.findBinding(name); if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) { - IBinding[] virtualOverriders= getOverridingBindings(index, binding); - ICElement[] defs; - if (virtualOverriders.length == 0) { - defs = IndexUI.findRepresentative(index, binding); - } - else { - ArrayList list= new ArrayList(); - list.addAll(Arrays.asList(IndexUI.findRepresentative(index, binding))); - for (IBinding overrider : virtualOverriders) { - list.addAll(Arrays.asList(IndexUI.findRepresentative(index, overrider))); + ICElement[] defs= null; + if (binding instanceof ICPPMethod) { + try { + IBinding[] virtualOverriders= ClassTypeHelper.findOverriders(index, (ICPPMethod) binding); + if (virtualOverriders.length > 0) { + ArrayList list= new ArrayList(); + list.addAll(Arrays.asList(IndexUI.findRepresentative(index, binding))); + for (IBinding overrider : virtualOverriders) { + 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) { result.add(defs, name);