mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Consider polymorphic method calls in call hierarchy, bug 156689.
This commit is contained in:
parent
0d7a561440
commit
0ce745690b
4 changed files with 271 additions and 18 deletions
|
@ -16,6 +16,7 @@ import junit.framework.Test;
|
|||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IPageLayout;
|
||||
import org.eclipse.ui.IViewPart;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
|
@ -29,6 +30,7 @@ import org.eclipse.cdt.ui.CUIPlugin;
|
|||
|
||||
import org.eclipse.cdt.internal.ui.callhierarchy.CHViewPart;
|
||||
import org.eclipse.cdt.internal.ui.callhierarchy.CallHierarchyUI;
|
||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
||||
|
||||
|
||||
public class CallHierarchyBugs extends CallHierarchyBaseTest {
|
||||
|
@ -143,9 +145,108 @@ public class CallHierarchyBugs extends CallHierarchyBaseTest {
|
|||
CallHierarchyUI.open(workbenchWindow, (ICElement) obj);
|
||||
}
|
||||
|
||||
private void openEditor(IFile file) throws WorkbenchException {
|
||||
private CEditor openEditor(IFile file) throws WorkbenchException {
|
||||
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
|
||||
IDE.openEditor(page, file, true);
|
||||
IEditorPart editor= IDE.openEditor(page, file, true);
|
||||
runEventQueue(0);
|
||||
return (CEditor) editor;
|
||||
}
|
||||
|
||||
// class Base {
|
||||
// public:
|
||||
// virtual void vmethod();
|
||||
// void method();
|
||||
// };
|
||||
// class Derived : public Base {
|
||||
// public:
|
||||
// void vmethod();
|
||||
// void method();
|
||||
// }
|
||||
// void vrefs() {
|
||||
// Base* b= 0;
|
||||
// b->vmethod(); b->method();
|
||||
// }
|
||||
// void regRefs() {
|
||||
// Base* b= 0;
|
||||
// b->Base::vmethod(); b->Base::method();
|
||||
// }
|
||||
public void testPolyMorphicMethodCalls_156689() throws Exception {
|
||||
String content= getContentsForTest(1)[0].toString();
|
||||
IFile file= createFile(getProject(), "SomeClass.cpp", content);
|
||||
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
|
||||
final CHViewPart ch= (CHViewPart) activateView(CUIPlugin.ID_CALL_HIERARCHY);
|
||||
final IWorkbenchWindow workbenchWindow = ch.getSite().getWorkbenchWindow();
|
||||
|
||||
// open editor, check outline
|
||||
CEditor editor= openEditor(file);
|
||||
int idx = content.indexOf("vmethod");
|
||||
editor.selectAndReveal(idx, 0);
|
||||
openCallHierarchy(editor);
|
||||
|
||||
Tree chTree= checkTreeNode(ch, 0, "Base::vmethod()").getParent();
|
||||
checkTreeNode(chTree, 0, 0, "regRefs()");
|
||||
checkTreeNode(chTree, 0, 1, "vrefs()");
|
||||
checkTreeNode(chTree, 0, 2, null);
|
||||
|
||||
idx = content.indexOf("vmethod", idx+1);
|
||||
editor.selectAndReveal(idx, 0);
|
||||
openCallHierarchy(editor);
|
||||
|
||||
chTree= checkTreeNode(ch, 0, "Derived::vmethod()").getParent();
|
||||
checkTreeNode(chTree, 0, 0, "vrefs()");
|
||||
checkTreeNode(chTree, 0, 1, null);
|
||||
|
||||
idx = content.indexOf(" method")+1;
|
||||
editor.selectAndReveal(idx, 0);
|
||||
openCallHierarchy(editor);
|
||||
|
||||
chTree= checkTreeNode(ch, 0, "Base::method()").getParent();
|
||||
checkTreeNode(chTree, 0, 0, "regRefs()");
|
||||
checkTreeNode(chTree, 0, 1, "vrefs()");
|
||||
checkTreeNode(chTree, 0, 2, null);
|
||||
|
||||
idx = content.indexOf(" method", idx+1)+1;
|
||||
editor.selectAndReveal(idx, 0);
|
||||
openCallHierarchy(editor);
|
||||
|
||||
chTree= checkTreeNode(ch, 0, "Derived::method()").getParent();
|
||||
checkTreeNode(chTree, 0, 0, null);
|
||||
}
|
||||
|
||||
// class Base {
|
||||
// public:
|
||||
// virtual void vmethod();
|
||||
// };
|
||||
// class Derived : public Base {
|
||||
// public:
|
||||
// void vmethod();
|
||||
// }
|
||||
// void vrefs() {
|
||||
// Base* b= 0;
|
||||
// b->vmethod();
|
||||
// }
|
||||
public void testReversePolyMorphicMethodCalls_156689() throws Exception {
|
||||
String content= getContentsForTest(1)[0].toString();
|
||||
IFile file= createFile(getProject(), "SomeClass.cpp", content);
|
||||
waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
|
||||
final CHViewPart ch= (CHViewPart) activateView(CUIPlugin.ID_CALL_HIERARCHY);
|
||||
final IWorkbenchWindow workbenchWindow = ch.getSite().getWorkbenchWindow();
|
||||
|
||||
// open editor, check outline
|
||||
CEditor editor= openEditor(file);
|
||||
int idx = content.indexOf("vrefs");
|
||||
editor.selectAndReveal(idx, 0);
|
||||
openCallHierarchy(editor, false);
|
||||
|
||||
Tree chTree= checkTreeNode(ch, 0, "vrefs()").getParent();
|
||||
TreeItem item= checkTreeNode(chTree, 0, 0, "Base::vmethod()");
|
||||
checkTreeNode(chTree, 0, 1, null);
|
||||
|
||||
expandTreeItem(item);
|
||||
checkTreeNode(item, 0, "Base::vmethod()");
|
||||
checkTreeNode(item, 1, "Derived::vmethod()");
|
||||
checkTreeNode(item, 2, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,9 +65,9 @@ public class CppCallHierarchyTest extends CallHierarchyBaseTest {
|
|||
IFile headerFile= createFile(getProject(), "testMethods.h", header);
|
||||
IFile sourceFile= createFile(getProject(), "testMethods.cpp", source);
|
||||
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
|
||||
CEditor editor= (CEditor) IDE.openEditor(page, sourceFile);
|
||||
waitForIndexer(fIndex, sourceFile, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
|
||||
CEditor editor= (CEditor) IDE.openEditor(page, sourceFile);
|
||||
editor.selectAndReveal(source.indexOf("method"), 2);
|
||||
openCallHierarchy(editor);
|
||||
Tree tree = getCHTreeViewer().getTree();
|
||||
|
@ -188,10 +188,9 @@ public class CppCallHierarchyTest extends CallHierarchyBaseTest {
|
|||
IFile sourceFile1= createFile(getProject(), "testMethods1.cpp", source1);
|
||||
IFile sourceFile2= createFile(getProject(), "testMethods2.cpp", source2);
|
||||
|
||||
CEditor editor= openFile(sourceFile1);
|
||||
CCorePlugin.getIndexManager().reindex(fCProject);
|
||||
waitForIndexer(fIndex, sourceFile2, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
|
||||
|
||||
CEditor editor= openFile(sourceFile1);
|
||||
editor.selectAndReveal(source1.indexOf("method3"), 2);
|
||||
openCallHierarchy(editor);
|
||||
TreeViewer tv = getCHTreeViewer();
|
||||
|
@ -380,5 +379,4 @@ public class CppCallHierarchyTest extends CallHierarchyBaseTest {
|
|||
checkTreeNode(node, 0, "cfunc()");
|
||||
checkTreeNode(node, 1, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006 Wind River Systems, Inc. and others.
|
||||
* Copyright (c) 2006, 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -13,8 +13,8 @@ package org.eclipse.cdt.internal.ui.callhierarchy;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
|
@ -22,7 +22,7 @@ import org.eclipse.cdt.core.model.ICElement;
|
|||
import org.eclipse.cdt.internal.ui.viewsupport.WorkingSetFilterUI;
|
||||
|
||||
public class CElementSet {
|
||||
private Set fSet= new HashSet();
|
||||
private Set fSet= new LinkedHashSet();
|
||||
private int fHashCode;
|
||||
|
||||
CElementSet( ICElement[] elements) {
|
||||
|
|
|
@ -11,15 +11,31 @@
|
|||
|
||||
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;
|
||||
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.CPPVisitor;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
|
||||
|
||||
|
@ -43,18 +59,143 @@ public class CHQueries {
|
|||
if (! (callee instanceof ISourceReference)) {
|
||||
return EMPTY_NODES;
|
||||
}
|
||||
IBinding calleeBinding= IndexUI.elementToBinding(index, callee);
|
||||
findCalledBy(index, calleeBinding, callee.getCProject(), result);
|
||||
|
||||
final ICProject project = callee.getCProject();
|
||||
IIndexBinding calleeBinding= IndexUI.elementToBinding(index, callee);
|
||||
if (calleeBinding != null) {
|
||||
findCalledBy(index, calleeBinding, true, project, result);
|
||||
IBinding[] overriddenBindings= getOverriddenBindings(index, calleeBinding);
|
||||
for (int i = 0; i < overriddenBindings.length; i++) {
|
||||
findCalledBy(index, overriddenBindings[i], false, project, result);
|
||||
}
|
||||
}
|
||||
return cp.createNodes(node, result);
|
||||
}
|
||||
|
||||
private static void findCalledBy(IIndex index, IBinding callee, ICProject project, CalledByResult 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();
|
||||
final IFunctionType mft= m.getType();
|
||||
boolean isVirtual= m.isVirtual();
|
||||
ICPPMethod[] allMethods= mcl.getMethods();
|
||||
for (int i = 0; i < allMethods.length; i++) {
|
||||
ICPPMethod method = allMethods[i];
|
||||
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 (IBinding[]) 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();
|
||||
final IFunctionType mft= m.getType();
|
||||
ICPPClassType[] subclasses= getSubClasses(index, mcl);
|
||||
for (int i = 0; i < subclasses.length; i++) {
|
||||
ICPPClassType subClass = subclasses[i];
|
||||
ICPPMethod[] methods= subClass.getDeclaredMethods();
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
ICPPMethod method = methods[j];
|
||||
if (CharArrayUtils.equals(mname, method.getNameCharArray()) &&
|
||||
mft.isSameType(method.getType())) {
|
||||
result.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (IBinding[]) 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 (ICPPClassType[]) 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 (int i = 0; i < names.length; i++) {
|
||||
IIndexName indexName = names[i];
|
||||
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();
|
||||
final IFunctionType mft= m.getType();
|
||||
ICPPMethod[] allMethods= mcl.getMethods();
|
||||
for (int i = 0; i < allMethods.length; i++) {
|
||||
ICPPMethod method = allMethods[i];
|
||||
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 {
|
||||
if (callee != null) {
|
||||
IIndexName[] names= index.findNames(callee, IIndex.FIND_REFERENCES | IIndex.SEARCH_ACCROSS_LANGUAGE_BOUNDARIES);
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
IIndexName rname = names[i];
|
||||
IIndexName[] names= index.findNames(callee, IIndex.FIND_REFERENCES | IIndex.SEARCH_ACCROSS_LANGUAGE_BOUNDARIES);
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
IIndexName rname = names[i];
|
||||
if (includeOrdinaryCalls || rname.couldBePolymorphicMethodCall()) {
|
||||
IIndexName caller= rname.getEnclosingDefinition();
|
||||
if (caller != null) {
|
||||
ICElement elem= IndexUI.getCElementForName(project, index, caller);
|
||||
|
@ -80,7 +221,20 @@ public class CHQueries {
|
|||
IIndexName name = refs[i];
|
||||
IBinding binding= index.findBinding(name);
|
||||
if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) {
|
||||
ICElement[] defs = IndexUI.findRepresentative(index, 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 (int j = 0; j < virtualOverriders.length; j++) {
|
||||
IBinding overrider = virtualOverriders[j];
|
||||
list.addAll(Arrays.asList(IndexUI.findRepresentative(index, overrider)));
|
||||
}
|
||||
defs= (ICElement[]) list.toArray(new ICElement[list.size()]);
|
||||
}
|
||||
if (defs != null && defs.length > 0) {
|
||||
result.add(defs, name);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue