/*******************************************************************************
* Copyright (c) 2006, 2010 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.callhierarchy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
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.model.ITranslationUnit;
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;
/**
* Access to high level queries in the index.
* @since 4.0
*/
public class CHQueries {
private static final CHNode[] EMPTY_NODES= new CHNode[0];
private CHQueries() {}
/**
* Searches for functions and methods that call a given element.
*/
public static CHNode[] findCalledBy(CHContentProvider cp, CHNode node, IIndex index, IProgressMonitor pm)
throws CoreException {
CalledByResult result= new CalledByResult();
ICElement callee= node.getRepresentedDeclaration();
if (!(callee instanceof ISourceReference)) {
return EMPTY_NODES;
}
boolean done= false;
int linkageID= node.getLinkageID();
if (linkageID == -1) {
final ITranslationUnit tu = ((ISourceReference) callee).getTranslationUnit();
if (tu == null)
return EMPTY_NODES;
final String ct = tu.getContentTypeId();
if (ct.equals(CCorePlugin.CONTENT_TYPE_CXXHEADER)) {
// bug 260262: in a header file we need to consider c and c++
findCalledBy(callee, ILinkage.C_LINKAGE_ID, index, result);
findCalledBy(callee, ILinkage.CPP_LINKAGE_ID, index, result);
done= true;
}
}
if (!done) {
findCalledBy(callee, linkageID, index, result);
}
return cp.createNodes(node, result);
}
private static void findCalledBy(ICElement callee, int linkageID, IIndex index, CalledByResult result)
throws CoreException {
final ICProject project = callee.getCProject();
IIndexBinding calleeBinding= IndexUI.elementToBinding(index, callee, linkageID);
if (calleeBinding != null) {
findCalledBy1(index, calleeBinding, true, project, result);
if (calleeBinding instanceof ICPPMethod) {
IBinding[] overriddenBindings= ClassTypeHelper.findOverridden((ICPPMethod) calleeBinding);
for (IBinding overriddenBinding : overriddenBindings) {
findCalledBy1(index, overriddenBinding, false, project, result);
}
}
}
}
private static void findCalledBy1(IIndex index, IBinding callee, boolean includeOrdinaryCalls,
ICProject project, CalledByResult result) throws CoreException {
findCalledBy2(index, callee, includeOrdinaryCalls, project, result);
List<? extends IBinding> specializations = IndexUI.findSpecializations(callee);
for (IBinding spec : specializations) {
findCalledBy2(index, spec, includeOrdinaryCalls, project, result);
}
}
private static void findCalledBy2(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);
for (IIndexName rname : names) {
if (includeOrdinaryCalls || rname.couldBePolymorphicMethodCall()) {
IIndexName caller= rname.getEnclosingDefinition();
if (caller != null) {
ICElement elem= IndexUI.getCElementForName(project, index, caller);
if (elem != null) {
result.add(elem, rname);
}
}
}
}
}
/**
* Searches for all calls that are made within a given range.
*/
public static CHNode[] findCalls(CHContentProvider cp, CHNode node, IIndex index, IProgressMonitor pm)
throws CoreException {
ICElement caller= node.getRepresentedDeclaration();
CallsToResult result= new CallsToResult();
IIndexName callerName= IndexUI.elementToName(index, caller);
if (callerName != null) {
IIndexName[] refs= callerName.getEnclosedNames();
for (IIndexName name : refs) {
IBinding binding= index.findBinding(name);
if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) {
while (true) {
ICElement[] defs= null;
if (binding instanceof ICPPMethod) {
defs = findOverriders(index, (ICPPMethod) binding);
}
if (defs == null) {
defs= IndexUI.findRepresentative(index, binding);
}
if (defs != null && defs.length > 0) {
result.add(defs, name);
} else if (binding instanceof ICPPSpecialization) {
binding= ((ICPPSpecialization) binding).getSpecializedBinding();
if (binding != null)
continue;
}
break;
}
}
}
}
return cp.createNodes(node, result);
}
/**
* Searches for overriders of method and converts them to ICElement, returns null,
* if there are none.
*/
static ICElement[] findOverriders(IIndex index, ICPPMethod binding) throws CoreException {
IBinding[] virtualOverriders= ClassTypeHelper.findOverriders(index, 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)));
}
return list.toArray(new ICElement[list.size()]);
}
return null;
}
}