From 485b4d73de721068c4f8de7b52c0cea56a74a54b Mon Sep 17 00:00:00 2001 From: John Cortell Date: Mon, 11 Jan 2010 20:52:55 +0000 Subject: [PATCH] [299317] Executables view source remapping does not take into account launch configurations --- .../org/eclipse/cdt/core/ISourceFinder.java | 107 ++++++ .../.settings/.api_filters | 24 +- debug/org.eclipse.cdt.debug.core/plugin.xml | 11 +- .../schema/SourceRemappingProvider.exsd | 29 +- .../debug/core/executables/Executable.java | 22 +- .../core/executables/ExecutablesManager.java | 34 +- .../ISourceFileRemappingFactory.java | 23 ++ .../StandardExecutableProvider.java | 10 +- .../StandardSourceFileRemapping.java | 47 +-- .../StandardSourceFileRemappingFactory.java | 26 ++ .../core/srcfinder/CSourceFinder.java | 363 ++++++++++++++++++ .../core/srcfinder/CSourceFinderFactory.java | 42 ++ .../views/executables/SourceFilesViewer.java | 44 ++- 13 files changed, 694 insertions(+), 88 deletions(-) create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ISourceFinder.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFileRemappingFactory.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemappingFactory.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinderFactory.java diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ISourceFinder.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ISourceFinder.java new file mode 100644 index 00000000000..1be3717280d --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ISourceFinder.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core; + +import java.io.File; + +import org.eclipse.cdt.internal.core.model.Binary; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; + +/** + * This interface is available for a {@link Binary} via the adapter mechanism. It is used to translate the + * source specification of a source file that was used to produce the executable to its local counterpart. In + * other words, the debug information in the binary tells us what source files where involved in building it. + * Such a file specification may be a simple file name, a relative path, or an absolute path that might be + * invalid on the local machine (the executable may have been built on another machine). In all cases, the + * file is found on the local machine by using source locators (see ISourceLocator). ISourceFinder is a front + * end to that search capability. + * + *

+ * In CDT, there is/are: + *

+ * + *

+ * So, when trying to translate a source file specification in the debug information to a local file, there + * are a variety of locators that need to be considered. An ISourceFinder shields client code from having to + * worry about those details. A client simply wants to find a file locally. + * + *

+ * This interface provides two choices for searching. One caters to logic involved in actively debugging a + * binary (e.g., a breakpoint is hit). The other is for use when there is no debug-session context (double + * clicking on a child file element of a Binary object in the Projects view). The former will search using + * only the locator associated with the ILaunch. The latter will use the locator of any relevant launch or + * launch configuration. In all cases, the global locator is consulted if no other locator has converted the + * file. + * + * @since 5.2 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ISourceFinder { + /** + * Use this method to find a file if you do not have a debug context. The implementation will consult + * locators in the following order: + *

    + *
  1. If there is an ongoing debug session on that binary, use that's ILaunch's locator. If there are + * multiple such debug sessions going on, the first one encountered is used. + *
  2. If there are no ongoing debug sessions on that binary that provide a locator, search for a CDT + * launch configuration that references the binary. Use the locator of the first matching configuration. + *
  3. If the above locator did not find the file, use the global locators. + *
+ * + * In the first two cases, only the first locator of the first matching launch or launch configuration is + * used, even if that locator doesn't find the file. Potentially, another matching one could find the + * file, but it could easily get very expensive to iterate through numerous matches that way. Searching + * for a file using a single launch/config's locator is expensive enough (it has numerous source + * containers). Searching through multiple ones could make this method unbearably slow. And because + * finding a matching launch/config can itself be a bit expensive, once a match has been found, its + * locator is used from that point on in all subsequent calls to this method. The implementation listens + * for launch and configurations changes, though, so we find a new locator when the active locator is no + * longer relevant. Note that calls to {@link #toLocalPath(IAdaptable, String)} have no effect on the + * active locator we use in this method. + * + * @param compilationPath + * the path of a file as found in the debug information + * @return if we are able to find the file, the location on the host machine, otherwise null. The result + * is in OS specific format, specifically what {@link File#getCanonicalPath()} returns. Note that + * by "on the host machine", we simply mean a specification that is accessible by the host + * machine. The file may be on a network drive, e.g., and thus not really be "local". + */ + public String toLocalPath(String compilationPath); + + /** + * Use this method to find a file if you have a debug context. The implementation will consult the source + * locator associated with the given ILaunch. If there is no such locator or it does not find the file, + * the global source locator is consulted. + * + * @param launch + * an IAdaptable that will queried for an ILaunch. Pass in an ILaunch instance or something + * that can be adapted to one. If the object does not adapt to ILaunch, null is returned. + * @param compilationPath + * the path of a file as found in the debug information + * @return if we are able to find the file, the location on the host machine, otherwise null. The result + * is in OS specific format, along the lines of what {@link IPath#toOSString()} would return. Note + * that by "on the host machine", we simply mean a specification that is accessible by the host + * machine. The file may be on a network drive, e.g., and thus not really be "local". + */ + public String toLocalPath(IAdaptable launch, String compilationPath); + + +} diff --git a/debug/org.eclipse.cdt.debug.core/.settings/.api_filters b/debug/org.eclipse.cdt.debug.core/.settings/.api_filters index 3dbc6bccf2a..e7851004d85 100644 --- a/debug/org.eclipse.cdt.debug.core/.settings/.api_filters +++ b/debug/org.eclipse.cdt.debug.core/.settings/.api_filters @@ -1,10 +1,18 @@ - + - - - - - - - + + + + + + + + + + + + + + + diff --git a/debug/org.eclipse.cdt.debug.core/plugin.xml b/debug/org.eclipse.cdt.debug.core/plugin.xml index f29545570b0..0745c828ead 100644 --- a/debug/org.eclipse.cdt.debug.core/plugin.xml +++ b/debug/org.eclipse.cdt.debug.core/plugin.xml @@ -337,5 +337,14 @@ - + + + + + + diff --git a/debug/org.eclipse.cdt.debug.core/schema/SourceRemappingProvider.exsd b/debug/org.eclipse.cdt.debug.core/schema/SourceRemappingProvider.exsd index 97d9101e7cb..fad60fb6746 100644 --- a/debug/org.eclipse.cdt.debug.core/schema/SourceRemappingProvider.exsd +++ b/debug/org.eclipse.cdt.debug.core/schema/SourceRemappingProvider.exsd @@ -2,9 +2,9 @@ - + - + This extension points allows you to extened the executables manager in CDT by providing your own source remapping provider. @@ -12,9 +12,9 @@ - + - + @@ -39,9 +39,9 @@ - + - + @@ -54,27 +54,27 @@ - - - + + + - + - + CDT 7.0 - + - + <extension point="org.eclipse.cdt.debug.core.SourceRemappingProvider"> @@ -83,4 +83,7 @@ + + + diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java index 7242eda6f18..08e85f93c39 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java @@ -89,6 +89,7 @@ public class Executable extends PlatformObject { private final Map remappedPaths; private final ArrayList sourceFiles; private boolean refreshSourceFiles; + private ISourceFileRemapping[] remappers; public IPath getPath() { return executablePath; @@ -98,11 +99,15 @@ public class Executable extends PlatformObject { return project; } - public Executable(IPath path, IProject project, IResource resource) { + /** + * @since 7.0 + */ + public Executable(IPath path, IProject project, IResource resource, ISourceFileRemapping[] sourceFileRemappings) { this.executablePath = path; this.project = project; this.name = new File(path.toOSString()).getName(); this.resource = resource; + this.remappers = sourceFileRemappings; remappedPaths = new HashMap(); sourceFiles = new ArrayList(); refreshSourceFiles = true; @@ -121,7 +126,7 @@ public class Executable extends PlatformObject { return name; } - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") @Override public Object getAdapter(Class adapter) { if (adapter.equals(IResource.class)) @@ -131,6 +136,17 @@ public class Executable extends PlatformObject { return this.getProject(); return super.getAdapter(adapter); } + + private String remapSourceFile(String filename) { + for (ISourceFileRemapping remapper : remappers) { + String remapped = remapper.remapSourceFile(this.getPath(), filename); + if (!remapped.equals(filename)) { + return remapped; + } + } + return filename; + } + /** * @noreference This method is not intended to be referenced by clients. @@ -157,7 +173,7 @@ public class Executable extends PlatformObject { for (String filename : symReaderSources) { String orgPath = filename; - filename = ExecutablesManager.getExecutablesManager().remapSourceFile(this, filename); + filename = remapSourceFile(filename); // Sometimes the path in the symbolics will have a different // case than the actual file system path. Even if the file diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java index 9f2e25da034..fabcf55bd9b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java @@ -27,7 +27,7 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.internal.core.executables.StandardExecutableImporter; -import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFileRemapping; +import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFileRemappingFactory; import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFilesProvider; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; @@ -73,7 +73,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang private List changeListeners = Collections.synchronizedList(new ArrayList()); private List executableProviders; private List sourceFileProviders; - private List sourceFileRemappings; + private List sourceFileRemappingFactories; private List executableImporters; private boolean DEBUG; @@ -164,7 +164,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang // add the standard providers executableProviders.add(0, new StandardExecutableProvider()); sourceFileProviders.add(0, new StandardSourceFilesProvider()); - sourceFileRemappings.add(0, new StandardSourceFileRemapping()); + sourceFileRemappingFactories.add(0, new StandardSourceFileRemappingFactory()); executableImporters.add(0, new StandardExecutableImporter()); // listen for events we're interested in @@ -266,26 +266,6 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang return executables; } - /** - * Attempt to remap the path to the given source file in the given executable using - * source file mapping extensions - * @param executable the executable - * @param filePath the absolute path to the source file - * @return the new path to the source file, which was remapped if possible - * - * @since 6.0 - */ - public String remapSourceFile(Executable executable, String filePath) { - synchronized (sourceFileRemappings) { - for (ISourceFileRemapping remapping : sourceFileRemappings) { - String remappedPath = remapping.remapSourceFile(executable.getPath(), filePath); - if (!remappedPath.equals(filePath)) - return remappedPath; - } - } - return filePath; - } - /** * Import the given executables into the manager * @param fileNames the absolute paths of the executables to import @@ -650,6 +630,10 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang return provider; } + + ISourceFileRemappingFactory[] getSourceFileRemappingFactories() { + return sourceFileRemappingFactories.toArray(new ISourceFileRemappingFactory[sourceFileRemappingFactories.size()]); + } private void loadExecutableProviderExtensions() { executableProviders = Collections.synchronizedList(new ArrayList()); @@ -714,7 +698,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang } private void loadSoureRemappingExtensions() { - sourceFileRemappings = Collections.synchronizedList(new ArrayList()); + sourceFileRemappingFactories = Collections.synchronizedList(new ArrayList()); IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(CDebugCorePlugin.PLUGIN_ID + ".SourceRemappingProvider"); //$NON-NLS-1$ @@ -729,7 +713,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang try { Object extObject = element.createExecutableExtension("class"); //$NON-NLS-1$ if (extObject instanceof ISourceFileRemapping) { - sourceFileRemappings.add((ISourceFileRemapping)extObject); + sourceFileRemappingFactories.add((ISourceFileRemappingFactory)extObject); } else { failed = true; } diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFileRemappingFactory.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFileRemappingFactory.java new file mode 100644 index 00000000000..15783f24cc2 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFileRemappingFactory.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.executables; + +import org.eclipse.cdt.core.model.IBinary; + +/** + * Factory that creates an ISourceFileRemapping instance for a particular binary + * object + * + * @since 7.0 + */ +public interface ISourceFileRemappingFactory { + public ISourceFileRemapping createRemapper(IBinary binary); +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableProvider.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableProvider.java index 67ab7b1c2dc..c5047f5a3b6 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableProvider.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableProvider.java @@ -65,7 +65,15 @@ public class StandardExecutableProvider implements IProjectExecutablesProvider { IPath exePath = binary.getResource().getLocation(); if (exePath == null) exePath = binary.getPath(); - executables.add(new Executable(exePath, project, binary.getResource())); + List srcRemappers = new ArrayList(2); + ISourceFileRemappingFactory[] factories = ExecutablesManager.getExecutablesManager().getSourceFileRemappingFactories(); + for (ISourceFileRemappingFactory factory : factories) { + ISourceFileRemapping remapper = factory.createRemapper(binary); + if (remapper != null) { + srcRemappers.add(remapper); + } + } + executables.add(new Executable(exePath, project, binary.getResource(), srcRemappers.toArray(new ISourceFileRemapping[srcRemappers.size()]))); } progress.worked(1); diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemapping.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemapping.java index b5902c16687..5fe4fcfc644 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemapping.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemapping.java @@ -11,48 +11,25 @@ package org.eclipse.cdt.debug.internal.core.executables; -import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.core.ISourceFinder; +import org.eclipse.cdt.core.model.IBinary; import org.eclipse.cdt.debug.core.executables.ISourceFileRemapping; -import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocator; -import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.ILaunch; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.debug.core.model.ISourceLocator; -import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; public class StandardSourceFileRemapping implements ISourceFileRemapping { + ISourceFinder srcFinder; + + public StandardSourceFileRemapping(IBinary binary) { + srcFinder = (ISourceFinder) binary.getAdapter(ISourceFinder.class); + } + public String remapSourceFile(IPath executable, String filePath) { - - try { - Object[] foundElements = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().findSourceElements(filePath); - - if (foundElements.length == 0) { - Object foundElement = null; - ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager(); - ILaunch[] launches = launchMgr.getLaunches(); - for (ILaunch launch : launches) { - ISourceLocator locator = launch.getSourceLocator(); - if (locator instanceof ICSourceLocator || locator instanceof CSourceLookupDirector) { - if (locator instanceof ICSourceLocator) - foundElement = ((ICSourceLocator) locator).findSourceElement(filePath); - else - foundElement = ((CSourceLookupDirector) locator).getSourceElement(filePath); - } - } - if (foundElement != null) - foundElements = new Object[] { foundElement }; + if (srcFinder != null) { + String mappedPath = srcFinder.toLocalPath(filePath); + if (mappedPath != null) { + return mappedPath; } - - if (foundElements.length == 1 && foundElements[0] instanceof LocalFileStorage) { - LocalFileStorage newLocation = (LocalFileStorage) foundElements[0]; - filePath = newLocation.getFullPath().toOSString(); - } - - } catch (CoreException e) { } return filePath; } diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemappingFactory.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemappingFactory.java new file mode 100644 index 00000000000..a8f6fb9c251 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/executables/StandardSourceFileRemappingFactory.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core.executables; + +import org.eclipse.cdt.core.model.IBinary; +import org.eclipse.cdt.debug.core.executables.ISourceFileRemapping; +import org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory; + +public class StandardSourceFileRemappingFactory implements ISourceFileRemappingFactory{ + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory#createRemapper(org.eclipse.cdt.core.model.IBinary) + */ + public ISourceFileRemapping createRemapper(IBinary binary) { + return new StandardSourceFileRemapping(binary); + } + +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java new file mode 100644 index 00000000000..e57805c716b --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java @@ -0,0 +1,363 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core.srcfinder; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.ISourceFinder; +import org.eclipse.cdt.core.model.IBinary; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; +import org.eclipse.cdt.internal.core.model.ExternalTranslationUnit; +import org.eclipse.core.filesystem.URIUtil; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationListener; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.ILaunchesListener; +import org.eclipse.debug.core.model.IPersistableSourceLocator; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2; +import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; +import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; + +public class CSourceFinder implements ISourceFinder, ILaunchConfigurationListener, ILaunchesListener { + + /** + * The binary we are searching files for. We need this reference to find a + * matching ILaunch or ILaunchConfiguration if the caller needs to search + * for files when it doesn't have a debug context. + */ + private IBinary fBinary; + + /** + * The locator tied to an ILaunch or an ILaunchConfiguration that is + * associated with the binary. Used for searching when the caller has no + * debug context. See {@link ISourceFinder#toLocalPath(String)} for + * performance considerations that dictate how the locator is chosen. Access + * this only from synchronized blocks as the field is subject to be changed + * by listener invocations. + */ + private ISourceLookupDirector fLaunchLocator; + + /** + * A launch configuration doesn't have a source locator instance tied to it. + * Instead, one is created on the fly as needed from attributes in the + * launch config. This is a heavy operation. As an optimization, we cache + * the locators we create and discard when the launch config changes or is + * disposed. Collection is subject to be changed by listener invocations. + * + * @see CSourceFinder#getLocator(ILaunchConfiguration) + */ + private Map fConfigLocators = Collections.synchronizedMap(new HashMap()); + + /** + * Constructor. + * + * @param binary + * the executable whose source files we will be asked to find + * locally + */ + public CSourceFinder(IBinary binary) { + assert(binary != null); + fBinary = binary; + + ILaunchManager lmgr = DebugPlugin.getDefault().getLaunchManager(); + lmgr.addLaunchConfigurationListener(this); + lmgr.addLaunchListener(this); + + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.ISourceFinder#toLocalPath(java.lang.String) + */ + synchronized public String toLocalPath(String compilationPath) { + try { + Object foundElement = null; + + // Find a suitable launch/config locator if we haven't found one yet + if (fLaunchLocator == null) { + ILaunchManager lmgr = DebugPlugin.getDefault().getLaunchManager(); + + // See if there are any active debug sessions (running, or + // terminated but still in the Debug view) that are targeting + // our executable. If there are then use the first one to + // provide a locator + ILaunch[] launches = lmgr.getLaunches(); + for (ILaunch launch : launches) { + ILaunchConfiguration config = launch.getLaunchConfiguration(); + if (isMatch(config)) { + ISourceLocator launchLocator = launch.getSourceLocator(); + // in practice, a launch locator is always an ISourceLookupDirector + if (launchLocator instanceof ISourceLookupDirector) { + fLaunchLocator = (ISourceLookupDirector)launchLocator; + break; + } + } + } + + // If there were no matching launches or none of them + // provided a locator, search the launch configurations + if (fLaunchLocator == null) { + for (ILaunchConfiguration config : lmgr.getLaunchConfigurations()) { + if (isMatch(config)) { + // Search our cache of locators that we + // instantiate for configurations. Create one if + // not found + ISourceLocator configLocator = fConfigLocators.get(config); + if (configLocator == null) { + configLocator = getLocator(config); // heavy operation + fConfigLocators.put(config, configLocator); // cache to avoid next time + } + // In practice, a config's locator is always an ISourceLookupDirector + if (configLocator instanceof ISourceLookupDirector) { + fLaunchLocator = (ISourceLookupDirector)configLocator; + break; + } + } + } + } + } + + // Search for the file using the launch/config locator + if (fLaunchLocator != null) { + foundElement = fLaunchLocator.getSourceElement(compilationPath); + } + + // If not found, look in the global (common) locator + if (foundElement == null) { + CSourceLookupDirector locator = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector(); + foundElement = locator.getSourceElement(compilationPath); + } + + return foundElementToPath(foundElement); + } + catch (CoreException exc) { + CDebugCorePlugin.log(exc); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.ISourceFinder#toLocalPath(org.eclipse.core.runtime.IAdaptable, java.lang.String) + */ + public String toLocalPath(IAdaptable _launch, String compilationPath) { + Object foundElement = null; + + ILaunch launch = (ILaunch)_launch.getAdapter(ILaunch.class); + if (launch != null) { + ISourceLocator locator = launch.getSourceLocator(); + // in practice, a launch locator is always an ISourceLookupDirector + if (locator instanceof ISourceLookupDirector) { + foundElement = ((ISourceLookupDirector)locator).getSourceElement(compilationPath); + } + } + + // If not found, look in the global (common) locator + if (foundElement == null) { + CSourceLookupDirector locator = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector(); + foundElement = locator.getSourceElement(compilationPath); + } + + return foundElementToPath(foundElement); + } + + /** + * Utility method to convert the element found by the source locators to a + * canonical file path + * + * @param foundElement + * the element found by the source locator, or null if not found + * @return the canonical file path of the element + */ + private static String foundElementToPath(Object foundElement) { + if (foundElement != null) { + try { + if (foundElement instanceof IFile) { + IPath path = ((IFile)foundElement).getLocation(); + if (path != null) { + File file = path.toFile(); + if (file != null) { + return file.getCanonicalPath(); + } + } + + } + else if (foundElement instanceof LocalFileStorage) { + File file = ((LocalFileStorage)foundElement).getFile(); + if (file != null) { + return file.getCanonicalPath(); + } + } + else if (foundElement instanceof ExternalTranslationUnit) { + URI uri = ((ExternalTranslationUnit)foundElement).getLocationURI(); + if (uri != null) { + IPath path = URIUtil.toPath(uri); + if (path != null) { + File file = path.toFile(); + if (file != null) { + return file.getCanonicalPath(); + } + } + } + } + } catch (IOException e) { + CDebugCorePlugin.log(e); + } + } + + return null; + } + + /** + * Utility method to determine if the given launch configuration targets the Binary we are associated with + * @param config + * @return true if the launch config targets our binary, false otherwise + */ + private boolean isMatch(ILaunchConfiguration config) { + IResource resource = (IResource)fBinary.getAdapter(IResource.class); + if (resource != null) { + String binaryPath = resource.getFullPath().toString(); + try { + String projectNameConfig = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$ + String programNameConfig = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$ + IProject project = resource.getProject(); + if (project != null && project.getName().equals(projectNameConfig)) { + Path path = new Path(programNameConfig); + if (!path.isEmpty()) { + IFile file = project.getFile(path); + if (file != null) { + String fullPath = file.getFullPath().toString(); + return fullPath.equals(binaryPath); + } + } + } + } catch (CoreException e) { + // Problem getting attribute from launch config? Not expecting that. + CDebugCorePlugin.log(e); + } + } + + return false; + } + + /** + * Utility method to instantiate a source locator for a launch + * configuration. A launch configuration doesn't have a source locator + * instance tied to it. Transient instances are created as needed. from + * attributes in the launch config. This is a heavy operation. + * + * @param config + * the launch configuration to create the locator for + * @return the source locator + * @throws CoreException + */ + static private ISourceLocator getLocator(ILaunchConfiguration config) throws CoreException { + String type = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null); + if (type == null) { + type = config.getType().getSourceLocatorId(); + } + if (type != null) { + IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type); + String memento = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null); + if (memento == null) { + locator.initializeDefaults(config); + } else { + if(locator instanceof IPersistableSourceLocator2) + ((IPersistableSourceLocator2)locator).initializeFromMemento(memento, config); + else + locator.initializeFromMemento(memento); + } + return locator; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationAdded(ILaunchConfiguration config) { + // Don't care. + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationChanged(ILaunchConfiguration config) { + // We don't care if it's a working copy. + if (config.isWorkingCopy()) { + return; + } + // the source locator attribute may have changed + fConfigLocators.remove(config); + if ((fLaunchLocator != null) && (fLaunchLocator.getLaunchConfiguration() == config)) { + fLaunchLocator = null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationRemoved(ILaunchConfiguration config) { + fConfigLocators.remove(config); + if ((fLaunchLocator != null) && (fLaunchLocator.getLaunchConfiguration() == config)) { + fLaunchLocator = null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(org.eclipse.debug.core.ILaunch[]) + */ + synchronized public void launchesRemoved(ILaunch[] launches) { + for (ILaunch launch : launches) { + if (launch.getSourceLocator() == fLaunchLocator) { + fLaunchLocator = null; + return; + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(org.eclipse.debug.core.ILaunch[]) + */ + synchronized public void launchesAdded(ILaunch[] launches) { + // If there's a new launch in town, we need to take it into + // consideration. E.g., if it targets our binary, and we're currently + // searching using an inactive launch configuration's locator, then the + // new launch's locator should take precedence + for (ILaunch launch : launches) { + if (isMatch(launch.getLaunchConfiguration())) { + fLaunchLocator = null; + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(org.eclipse.debug.core.ILaunch[]) + */ + public void launchesChanged(ILaunch[] launches) { + // don't care. I don't think setting a new locator in a launch would result in us getting notified + } +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinderFactory.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinderFactory.java new file mode 100644 index 00000000000..1e2df9c70de --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinderFactory.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core.srcfinder; + +import org.eclipse.cdt.core.ISourceFinder; +import org.eclipse.cdt.core.model.IBinary; +import org.eclipse.core.runtime.IAdapterFactory; + +/** + * Adapter factory that adapts an IBinary object to an ISourceFinder + */ +public class CSourceFinderFactory implements IAdapterFactory { + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class) + */ + @SuppressWarnings("rawtypes") + public Object getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof IBinary) { + if (adapterType.equals(ISourceFinder.class)) { + return new CSourceFinder((IBinary)adaptableObject); + } + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList() + */ + @SuppressWarnings("rawtypes") + public Class[] getAdapterList() { + return new Class[] { ISourceFinder.class }; + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java index 51c582e7d7c..165d436ccac 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java @@ -24,6 +24,9 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationListener; import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; import org.eclipse.jface.viewers.IOpenListener; @@ -46,7 +49,7 @@ import org.eclipse.ui.progress.UIJob; * Displays the list of source files for the executable selected in the * ExecutablesViewer. */ -public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant { +public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant, ILaunchConfigurationListener { private static final String P_COLUMN_ORDER_KEY_SF = "columnOrderKeySF"; //$NON-NLS-1$ private static final String P_SORTED_COLUMN_INDEX_KEY_SF = "sortedColumnIndexKeySF"; //$NON-NLS-1$ @@ -79,6 +82,11 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic // source lookup as this viewer shows both original and remapped // locations CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().addParticipants(new ISourceLookupParticipant[] { this }); + + // We also look for launch configuration changes, since their source + // locators are involved in source path remapping, too + DebugPlugin.getDefault().getLaunchManager().addLaunchConfigurationListener(this); + sourceFilesTree.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { @@ -169,7 +177,7 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic if (sortType == ExecutablesView.ORG_LOCATION) { return new ExecutablesViewerComparator(sortType, column_sort_order[ExecutablesView.ORG_LOCATION]) { - @SuppressWarnings("unchecked") //$NON-NLS-1$ + @SuppressWarnings("unchecked") public int compare(Viewer viewer, Object e1, Object e2) { if (e1 instanceof ITranslationUnit && e2 instanceof ITranslationUnit) { ITranslationUnit entry1 = (ITranslationUnit) e1; @@ -201,6 +209,10 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic } public void sourceContainersChanged(ISourceLookupDirector director) { + refreshContent(); + } + + private void refreshContent() { UIJob refreshJob = new UIJob(Messages.SourceFilesViewer_RefreshSourceFiles) { @Override @@ -241,4 +253,32 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic // default visible columns return "1,1,0,0,0,0"; //$NON-NLS-1$ } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationAdded(ILaunchConfiguration configuration) { + if (!configuration.isWorkingCopy()) { + refreshContent(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationChanged(ILaunchConfiguration configuration) { + if (!configuration.isWorkingCopy()) { + refreshContent(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration) + */ + public void launchConfigurationRemoved(ILaunchConfiguration configuration) { + if (!configuration.isWorkingCopy()) { + refreshContent(); + } + } + } \ No newline at end of file