blob: da659dd23eadc65ea4828d918cc28bb640b179bc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 Red Hat, Inc.
* 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:
* Elliott Baron <ebaron@redhat.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.profiling.ui;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
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.index.IndexFilter;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementVisitor;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.sourcelookup.ISourceLookupResult;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.linuxtools.internal.profiling.ui.ProfileUIPlugin;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
public class ProfileUIUtils {
/**
* Opens the specified file in an editor (or selects an already open
* editor) and highlights the specified line.
* @param path - absolute path of file to open
* @param line - line number to select, 0 to not select a line
* @throws PartInitException - Failed to open editor
* @throws BadLocationException - Line number not valid in file
*/
public static void openEditorAndSelect(String path, int line) throws PartInitException, BadLocationException {
Path p = new Path(path);
if (p.toFile().exists()) {
IWorkbenchPage activePage = ProfileUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
IFileStore file = EFS.getLocalFileSystem().getStore(p);
IEditorPart editor = IDE.openEditorOnFileStore(activePage, file);
if (editor instanceof ITextEditor) {
ITextEditor textEditor = (ITextEditor) editor;
if (line > 0) {
IDocumentProvider provider = textEditor.getDocumentProvider();
IDocument document = provider.getDocument(textEditor.getEditorInput());
int start = document.getLineOffset(line - 1); //zero-indexed
textEditor.selectAndReveal(start, 0);
}
}
}
}
/**
* Opens an editor on the given file and selects the line.
* @param file The file to open.
* @param line The line to select.
* @throws PartInitException If opening editor failed.
* @throws BadLocationException If line number is invalid.
*
* @since 2.0
*/
public static void openEditorAndSelect(IFile file, int line) throws PartInitException, BadLocationException {
if (file.exists()) {
IWorkbenchPage activePage = ProfileUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = IDE.openEditor(activePage, file);
if (editor instanceof ITextEditor) {
ITextEditor textEditor = (ITextEditor) editor;
if (line > 0) {
IDocumentProvider provider = textEditor.getDocumentProvider();
IDocument document = provider.getDocument(textEditor.getEditorInput());
int start = document.getLineOffset(line - 1); //zero-indexed
textEditor.selectAndReveal(start, 0);
}
}
}
}
/**
* Opens the specified file in an editor (or selects an already open
* editor) and highlights the specified line.
* @param result - result of performing source lookup with a ISourceLocator
* @param line - line number to select, 0 to not select a line
* @throws PartInitException - Failed to open editor
* @throws BadLocationException - Line number not valid in file
* @see DebugUITools#lookupSource(Object, ISourceLocator)
*/
public static void openEditorAndSelect(ISourceLookupResult result, int line) throws PartInitException, BadLocationException {
IEditorInput input = result.getEditorInput();
String editorID = result.getEditorId();
if (input == null || editorID == null) {
// Consult the CDT DebugModelPresentation
Object sourceElement = result.getSourceElement();
if (sourceElement != null) {
// Resolve IResource in case we get a LocalFileStorage object
if (sourceElement instanceof LocalFileStorage) {
IPath filePath = ((LocalFileStorage) sourceElement).getFullPath();
URI fileURI = URIUtil.toURI(filePath);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile[] files = root.findFilesForLocationURI(fileURI);
if (files.length > 0) {
// Take the first match
sourceElement = files[0];
}
}
IDebugModelPresentation pres = DebugUITools.newDebugModelPresentation(CDebugCorePlugin.getUniqueIdentifier());
input = pres.getEditorInput(sourceElement);
editorID = pres.getEditorId(input, sourceElement);
pres.dispose();
}
}
if (input != null && editorID != null) {
// Open the editor
IWorkbenchPage activePage = ProfileUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = IDE.openEditor(activePage, input, editorID);
// Select the line
if (editor instanceof ITextEditor) {
ITextEditor textEditor = (ITextEditor) editor;
if (line > 0) {
IDocumentProvider provider = textEditor.getDocumentProvider();
IDocument document = provider.getDocument(textEditor.getEditorInput());
IRegion lineRegion = document.getLineInformation(line - 1); //zero-indexed
textEditor.selectAndReveal(lineRegion.getOffset(), lineRegion.getLength());
}
}
}
}
/**
* Open a file in the Editor at the specified offset, highlighting the given length
*
* @param path : Absolute path pointing to the file which will be opened.
* @param offset : Offset of the function to be highlighted.
* @param length : Length of the function to be highlighted.
* @throws PartInitException if the editor could not be initialized
*/
public static void openEditorAndSelect(String path, int offset, int length) throws PartInitException {
Path p = new Path (path);
if (p.toFile().exists()) {
IWorkbenchPage activePage = ProfileUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
IFileStore fileStore = EFS.getLocalFileSystem().getStore(p);
IEditorPart editor = IDE.openEditorOnFileStore(activePage, fileStore);
if (editor instanceof ITextEditor) {
ITextEditor text = (ITextEditor) editor;
text.selectAndReveal(offset, length);
}
}
}
/**
* Find an ICProject that contains the specified absolute path.
*
* @param absPath An absolute path (usually to some file/folder in a project)
* @return an ICProject corresponding to the project that contains the absolute path
* @throws CoreException
*/
public static ICProject findCProjectWithAbsolutePath(final String absPath) throws CoreException{
final String workspaceLoc = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString();
final ArrayList<ICProject> ret = new ArrayList<>();
// visitor object to check for the matching path string
ICElementVisitor vis = new ICElementVisitor() {
@Override
public boolean visit(ICElement element) {
if (element.getElementType() == ICElement.C_CCONTAINER
|| element.getElementType() == ICElement.C_PROJECT){
return true;
}else if (absPath.equals(workspaceLoc+element.getPath().toFile().getAbsolutePath())){
ret.add(element.getCProject());
}
return false;
}};
ICProject[] cProjects = CCorePlugin.getDefault().getCoreModel().getCModel().getCProjects();
for (ICProject proj : cProjects){
// visit every project
proj.accept(vis);
}
// is it possible to find more than one matching project ?
return ret.isEmpty() ? null : ret.get(0);
}
/**
* Get a mapping between a file name, and the data relevant to locating
* the corresponding function name for a given project.
*
* @param project : C Project Type
* @param functionName : Name of a function
* @param numArgs : The number of arguments this function is expected to have.
* A value of -1 will ignore the number of arguments when searching.
* @param fileHint : The name of the file where we expect to find functionName.
* It is null if we do not want to use this option.
* @return Absolute paths of files and the function's corresponding node-offset and length.
* @since 3.0
*/
public static Map<String,int[]> findFunctionsInProject(ICProject project, String functionName,
int numArgs, String fileHint) {
HashMap<String,int[]> files = new HashMap<>() ;
IIndexManager manager = CCorePlugin.getIndexManager();
IIndex index = null;
try {
index = manager.getIndex(project);
index.acquireReadLock();
IBinding[] bindings = index.findBindings(functionName.toCharArray(), IndexFilter.ALL, null);
for (IBinding bind : bindings) {
if (bind instanceof IFunction
&& (numArgs == -1 || ((IFunction)bind).getParameters().length == numArgs)) {
IFunction ifunction = (IFunction) bind;
IIndexName[] names = index.findNames(ifunction, IIndex.FIND_DEFINITIONS);
for (IIndexName iname : names) {
IIndexFile file = iname.getFile();
if (file != null) {
String loc = file.getLocation().getURI().getPath();
if (fileHint != null){
if (loc.equals(new File(fileHint).getCanonicalPath())){
//TODO: Consider changing data structure so that we can
// store multiple same-named functions (different args)
// from the same file.
files.put(loc, new int [] {iname.getNodeOffset(), iname.getNodeLength()});
}
}else{
files.put(loc, new int [] {iname.getNodeOffset(), iname.getNodeLength()});
}
}
}
}
}
} catch (CoreException | InterruptedException | IOException e) {
e.printStackTrace();
} finally{
index.releaseReadLock();
}
return files;
}
/**
* Helper function for findFunctionsInProject
* @param project
* @param functionName
* @param numArgs
* @param fileHint
* @param needResult True if the function should relax constraints in order
* to return some value. False if a failure to find the function(s) is acceptable.
* @return The functions found.
* @since 3.0
*/
public static Map<String,int[]> findFunctionsInProject(ICProject project, String functionName,
int numArgs, String fileHint, boolean needResult){
Map<String, int []> map = findFunctionsInProject(project, functionName, numArgs, fileHint);
if (needResult && map.isEmpty()){
map = findFunctionsInProject(project, functionName, -1, fileHint);
if (map.isEmpty()){
return findFunctionsInProject(project, functionName, -1, null);
}
}
return map;
}
}