1
0
Fork 0
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:
Markus Schorn 2007-12-19 09:40:18 +00:00
parent 0d7a561440
commit 0ce745690b
4 changed files with 271 additions and 18 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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];
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);
}