/******************************************************************************* * Copyright (c) 2006, 2011 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 * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.callhierarchy; import java.util.ArrayList; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.swt.widgets.Display; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IMethod; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IVariable; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.corext.util.CModelUtil; import org.eclipse.cdt.internal.ui.viewsupport.AsyncTreeContentProvider; import org.eclipse.cdt.internal.ui.viewsupport.IndexUI; import org.eclipse.cdt.internal.ui.viewsupport.WorkingSetFilterUI; /** * This is the content provider for the call hierarchy. */ public class CHContentProvider extends AsyncTreeContentProvider { private static final IProgressMonitor NPM = new NullProgressMonitor(); private boolean fComputeReferencedBy = true; private WorkingSetFilterUI fFilter; private CHViewPart fView; /** * Constructs the content provider. */ public CHContentProvider(CHViewPart view, Display disp) { super(disp); fView= view; } @Override public Object getParent(Object element) { if (element instanceof CHNode) { CHNode node = (CHNode) element; return node.getParent(); } return super.getParent(element); } @Override protected Object[] syncronouslyComputeChildren(Object parentElement) { if (parentElement instanceof CHMultiDefNode) { return ((CHMultiDefNode) parentElement).getChildNodes(); } if (parentElement instanceof CHNode) { CHNode node = (CHNode) parentElement; if (node.isRecursive() || node.getRepresentedDeclaration() == null) { return NO_CHILDREN; } if (fComputeReferencedBy) { if (node.isInitializer()) { return NO_CHILDREN; } } else if (node.isVariableOrEnumerator() || node.isMacro()) { return NO_CHILDREN; } } // Allow for async computation return null; } @Override protected Object[] asyncronouslyComputeChildren(Object parentElement, IProgressMonitor monitor) { try { if (parentElement instanceof ICElement) { return asyncComputeRoot((ICElement) parentElement); } if (parentElement instanceof CHNode) { CHNode node = (CHNode) parentElement; if (fComputeReferencedBy) { return asyncronouslyComputeReferencedBy(node); } return asyncronouslyComputeRefersTo(node); } } catch (CoreException e) { CUIPlugin.log(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return NO_CHILDREN; } private Object[] asyncComputeRoot(final ICElement input) throws CoreException, InterruptedException { IIndex index= CCorePlugin.getIndexManager().getIndex(input.getCProject()); index.acquireReadLock(); try { ICElement element= input; if (!IndexUI.isIndexed(index, input)) { getDisplay().asyncExec(new Runnable() { public void run() { fView.reportNotIndexed(input); } }); } else { element= IndexUI.attemptConvertionToHandle(index, input); final ICElement finalElement= element; getDisplay().asyncExec(new Runnable() { public void run() { fView.reportInputReplacement(input, finalElement); } }); } ITranslationUnit tu= CModelUtil.getTranslationUnit(element); if (!fComputeReferencedBy && element instanceof IMethod) { IIndexName methodName= IndexUI.elementToName(index, element); if (methodName != null) { IBinding methodBinding= index.findBinding(methodName); if (methodBinding instanceof ICPPMethod) { ICElement[] defs= CHQueries.findOverriders(index, (ICPPMethod) methodBinding); if (defs != null && defs.length > 0) { return new Object[] { new CHMultiDefNode(null, tu, 0, defs, methodBinding.getLinkage().getLinkageID()) }; } } } } return new Object[] { new CHNode(null, tu, 0, element, -1) }; } finally { index.releaseReadLock(); } } private Object[] asyncronouslyComputeReferencedBy(CHNode parent) throws CoreException, InterruptedException { ICProject[] scope= CoreModel.getDefault().getCModel().getCProjects(); IIndex index= CCorePlugin.getIndexManager().getIndex(scope, IIndexManager.ADD_EXTENSION_FRAGMENTS); index.acquireReadLock(); try { return CHQueries.findCalledBy(this, parent, index, NPM); } finally { index.releaseReadLock(); } } private Object[] asyncronouslyComputeRefersTo(CHNode parent) throws CoreException, InterruptedException { ICProject[] scope= CoreModel.getDefault().getCModel().getCProjects(); IIndex index= CCorePlugin.getIndexManager().getIndex(scope, IIndexManager.ADD_EXTENSION_FRAGMENTS); index.acquireReadLock(); try { return CHQueries.findCalls(this, parent, index, NPM); } finally { index.releaseReadLock(); } } public void setComputeReferencedBy(boolean value) { fComputeReferencedBy = value; } public boolean getComputeReferencedBy() { return fComputeReferencedBy; } public void setWorkingSetFilter(WorkingSetFilterUI filterUI) { fFilter= filterUI; recompute(); } CHNode[] createNodes(CHNode node, CalledByResult result) throws CoreException { ArrayList<CHNode> nodes= new ArrayList<CHNode>(); ICElement[] elements= result.getElements(); for (ICElement element : elements) { if (element != null) { if (fFilter == null || fFilter.isPartOfWorkingSet(element)) { IIndexName[] refs= result.getReferences(element); if (refs != null && refs.length > 0) { CHNode newNode = createRefbyNode(node, element, refs); nodes.add(newNode); } } } } return nodes.toArray(new CHNode[nodes.size()]); } private CHNode createRefbyNode(CHNode parent, ICElement element, IIndexName[] refs) throws CoreException { ITranslationUnit tu= CModelUtil.getTranslationUnit(element); final IIndexFile file = refs[0].getFile(); CHNode node= new CHNode(parent, tu, file.getTimestamp(), element, file.getLinkageID()); if (element instanceof IVariable || element instanceof IEnumerator) { node.setInitializer(true); } boolean readAccess= false; boolean writeAccess= false; for (IIndexName reference : refs) { node.addReference(new CHReferenceInfo(reference.getNodeOffset(), reference.getNodeLength())); readAccess= (readAccess || reference.isReadAccess()); writeAccess= (writeAccess || reference.isWriteAccess()); } node.setRWAccess(readAccess, writeAccess); node.sortReferencesByOffset(); return node; } CHNode[] createNodes(CHNode node, CallsToResult callsTo) throws CoreException { ITranslationUnit tu= CModelUtil.getTranslationUnit(node.getRepresentedDeclaration()); ArrayList<CHNode> result= new ArrayList<CHNode>(); CElementSet[] elementSets= callsTo.getElementSets(); for (CElementSet elementSet : elementSets) { CElementSet set = elementSet; if (!set.isEmpty()) { IIndexName[] refs= callsTo.getReferences(set); ICElement[] elements= set.getElements(fFilter); if (elements.length > 0) { CHNode childNode = createReftoNode(node, tu, elements, refs); result.add(childNode); } } } return result.toArray(new CHNode[result.size()]); } private CHNode createReftoNode(CHNode parent, ITranslationUnit tu, ICElement[] elements, IIndexName[] references) throws CoreException { assert elements.length > 0; final IIndexFile file = references[0].getFile(); final long timestamp= file.getTimestamp(); final int linkageID= file.getLinkageID(); CHNode node; if (elements.length == 1) { node= new CHNode(parent, tu, timestamp, elements[0], linkageID); } else { node= new CHMultiDefNode(parent, tu, timestamp, elements, linkageID); } boolean readAccess= false; boolean writeAccess= false; for (IIndexName reference : references) { node.addReference(new CHReferenceInfo(reference.getNodeOffset(), reference.getNodeLength())); readAccess= (readAccess || reference.isReadAccess()); writeAccess= (writeAccess || reference.isWriteAccess()); } node.sortReferencesByOffset(); node.setRWAccess(readAccess, writeAccess); return node; } }