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:
parent
04fa1f9ff5
commit
37c141ceab
3 changed files with 343 additions and 162 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ICPPClassType> result= new HashSet<ICPPClassType>();
|
||||
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) {
|
||||
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<ICPPMethod> set = new ObjectSet<ICPPMethod>(4);
|
||||
ObjectSet<ICPPMethod> set= new ObjectSet<ICPPMethod>(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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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)
|
||||
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<ICElementHandle> list= new ArrayList<ICElementHandle>();
|
||||
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<ICElementHandle> list= new ArrayList<ICElementHandle>();
|
||||
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue