mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
[299317] Executables view source remapping does not take into account launch configurations
This commit is contained in:
parent
76547b9958
commit
485b4d73de
13 changed files with 694 additions and 88 deletions
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* In CDT, there is/are:
|
||||
* <ul>
|
||||
* <li>A global (common) source locator. Its containers are defined via Window > Preferences > C/C++ > Debug >
|
||||
* Common Source Lookup Path
|
||||
* <li>Launch configuration source locators. The containers of such a locator are defined via the 'Source' tab
|
||||
* in a CDT launch configuration.
|
||||
* <li>Launch source locators. Typically, a launch's locator is the one defined in the launch configuration
|
||||
* that spawned the launch, but technically, they could be different. The ILaunch API allows any source
|
||||
* locator to be associated with a launch.
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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:
|
||||
* <ol>
|
||||
* <li>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.
|
||||
* <li>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.
|
||||
* <li>If the above locator did not find the file, use the global locators.
|
||||
* </ol>
|
||||
*
|
||||
* 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 <i>accessible by the host
|
||||
* machine</i>. 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 <i>accessible by the host
|
||||
* machine</i>. The file may be on a network drive, e.g., and thus not really be "local".
|
||||
*/
|
||||
public String toLocalPath(IAdaptable launch, String compilationPath);
|
||||
|
||||
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component id="org.eclipse.cdt.debug.core" version="2">
|
||||
<resource path="src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java" type="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants">
|
||||
<filter id="403853384">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java" type="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants">
|
||||
<filter id="403853384">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java" type="org.eclipse.cdt.debug.internal.core.srcfinder.CSourceFinder">
|
||||
<filter id="574619656">
|
||||
<message_arguments>
|
||||
<message_argument value="ISourceFinder"/>
|
||||
<message_argument value="CSourceFinder"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
</component>
|
||||
|
|
|
@ -337,5 +337,14 @@
|
|||
<sourceContainer
|
||||
id="org.eclipse.debug.core.containerType.project"/>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.core.runtime.adapters">
|
||||
<factory
|
||||
adaptableType="org.eclipse.cdt.core.model.IBinary"
|
||||
class="org.eclipse.cdt.debug.internal.core.srcfinder.CSourceFinderFactory">
|
||||
<adapter
|
||||
type="org.eclipse.cdt.core.ISourceFinder">
|
||||
</adapter>
|
||||
</factory>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<!-- Schema file written by PDE -->
|
||||
<schema targetNamespace="org.eclipse.cdt.debug.core" xmlns="http://www.w3.org/2001/XMLSchema">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<appInfo>
|
||||
<meta.schema plugin="org.eclipse.cdt.debug.core" id="SourceRemappingProvider" name="Source Remapping Provider"/>
|
||||
</appinfo>
|
||||
</appInfo>
|
||||
<documentation>
|
||||
This extension points allows you to extened the executables manager in CDT by providing your own source remapping provider.
|
||||
</documentation>
|
||||
|
@ -12,9 +12,9 @@
|
|||
|
||||
<element name="extension">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<appInfo>
|
||||
<meta.element />
|
||||
</appinfo>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<sequence>
|
||||
|
@ -39,9 +39,9 @@
|
|||
<documentation>
|
||||
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<appInfo>
|
||||
<meta.attribute translatable="true"/>
|
||||
</appinfo>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
|
@ -54,27 +54,27 @@
|
|||
<documentation>
|
||||
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<meta.attribute kind="java" basedOn="org.eclipse.cdt.debug.core.executables.ISourceFileRemapping"/>
|
||||
</appinfo>
|
||||
<appInfo>
|
||||
<meta.attribute kind="java" basedOn=":org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory"/>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<appInfo>
|
||||
<meta.section type="since"/>
|
||||
</appinfo>
|
||||
</appInfo>
|
||||
<documentation>
|
||||
CDT 7.0
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<appInfo>
|
||||
<meta.section type="examples"/>
|
||||
</appinfo>
|
||||
</appInfo>
|
||||
<documentation>
|
||||
<extension
|
||||
point="org.eclipse.cdt.debug.core.SourceRemappingProvider">
|
||||
|
@ -83,4 +83,7 @@
|
|||
</documentation>
|
||||
</annotation>
|
||||
|
||||
|
||||
|
||||
|
||||
</schema>
|
||||
|
|
|
@ -89,6 +89,7 @@ public class Executable extends PlatformObject {
|
|||
private final Map<ITranslationUnit, String> remappedPaths;
|
||||
private final ArrayList<ITranslationUnit> 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<ITranslationUnit, String>();
|
||||
sourceFiles = new ArrayList<ITranslationUnit>();
|
||||
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))
|
||||
|
@ -132,6 +137,17 @@ public class Executable extends PlatformObject {
|
|||
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.
|
||||
* @since 6.0
|
||||
|
@ -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
|
||||
|
|
|
@ -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<IExecutablesChangeListener> changeListeners = Collections.synchronizedList(new ArrayList<IExecutablesChangeListener>());
|
||||
private List<IProjectExecutablesProvider> executableProviders;
|
||||
private List<ISourceFilesProvider> sourceFileProviders;
|
||||
private List<ISourceFileRemapping> sourceFileRemappings;
|
||||
private List<ISourceFileRemappingFactory> sourceFileRemappingFactories;
|
||||
private List<IExecutableImporter> 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
|
||||
|
@ -651,6 +631,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<IProjectExecutablesProvider>());
|
||||
|
||||
|
@ -714,7 +698,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
|
|||
}
|
||||
|
||||
private void loadSoureRemappingExtensions() {
|
||||
sourceFileRemappings = Collections.synchronizedList(new ArrayList<ISourceFileRemapping>());
|
||||
sourceFileRemappingFactories = Collections.synchronizedList(new ArrayList<ISourceFileRemappingFactory>());
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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<ISourceFileRemapping> srcRemappers = new ArrayList<ISourceFileRemapping>(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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<ILaunchConfiguration, ISourceLocator> fConfigLocators = Collections.synchronizedMap(new HashMap<ILaunchConfiguration, ISourceLocator>());
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
|
@ -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 };
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue