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.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
ICPPClassType[] bases= getAllBases(ct);
|
||||||
|
for (ICPPClassType base : bases) {
|
||||||
|
set.addAll(base.getDeclaredMethods());
|
||||||
|
scope= (ICPPClassScope) base.getCompositeScope();
|
||||||
set.addAll(scope.getImplicitMethods());
|
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());
|
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
try {
|
||||||
|
IBinding[] overriddenBindings= ClassTypeHelper.findOverridden((ICPPMethod) calleeBinding);
|
||||||
for (IBinding overriddenBinding : overriddenBindings) {
|
for (IBinding overriddenBinding : overriddenBindings) {
|
||||||
findCalledBy(index, overriddenBinding, false, project, result);
|
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,12 +98,11 @@ 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) {
|
||||||
|
@ -233,6 +110,13 @@ public class CHQueries {
|
||||||
}
|
}
|
||||||
defs= list.toArray(new ICElement[list.size()]);
|
defs= list.toArray(new ICElement[list.size()]);
|
||||||
}
|
}
|
||||||
|
} catch (DOMException e) {
|
||||||
|
// index bindings don't throw DOMExceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue