mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-21 16:05:25 +02:00
Bug 372551. Codan support for writing checkers that invoke external
tools. Change-Id: Ia5cfd24d54ec6e67e08f24a367a6bc689ae407d0 Reviewed-on: https://git.eclipse.org/r/5586 Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com> IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com> Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
This commit is contained in:
parent
4a8860255e
commit
1f83e4aa21
52 changed files with 1983 additions and 105 deletions
|
@ -7,15 +7,13 @@ Bundle-Activator: org.eclipse.cdt.codan.core.cxx.Activator
|
|||
Require-Bundle: org.eclipse.core.runtime,
|
||||
org.eclipse.cdt.core,
|
||||
org.eclipse.cdt.codan.core,
|
||||
org.eclipse.core.resources
|
||||
org.eclipse.core.resources,
|
||||
org.eclipse.core.filesystem
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: org.eclipse.cdt.codan.core.cxx,
|
||||
org.eclipse.cdt.codan.core.cxx.internal.model;
|
||||
x-friends:="org.eclipse.cdt.codan.checkers.ui,
|
||||
org.eclipse.cdt.codan.ui,
|
||||
org.eclipse.cdt.codan.ui.cxx",
|
||||
org.eclipse.cdt.codan.core.cxx.internal.model.cfg;
|
||||
x-friends:="org.eclipse.cdt.codan.core.test",
|
||||
org.eclipse.cdt.codan.core.cxx.externaltool,
|
||||
org.eclipse.cdt.codan.core.cxx.internal.model;x-friends:="org.eclipse.cdt.codan.checkers.ui,org.eclipse.cdt.codan.ui,org.eclipse.cdt.codan.ui.cxx",
|
||||
org.eclipse.cdt.codan.core.cxx.internal.model.cfg;x-friends:="org.eclipse.cdt.codan.core.test",
|
||||
org.eclipse.cdt.codan.core.cxx.model
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-Vendor: %Bundle-Vendor
|
||||
|
|
|
@ -32,7 +32,7 @@ public class Activator extends Plugin {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
|
@ -44,7 +44,7 @@ public class Activator extends Plugin {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
|
@ -56,7 +56,7 @@ public class Activator extends Plugin {
|
|||
|
||||
/**
|
||||
* Returns the shared instance
|
||||
*
|
||||
*
|
||||
* @return the shared instance
|
||||
*/
|
||||
public static Activator getDefault() {
|
||||
|
@ -65,7 +65,7 @@ public class Activator extends Plugin {
|
|||
|
||||
/**
|
||||
* Logs the specified status with this plug-in's log.
|
||||
*
|
||||
*
|
||||
* @param status
|
||||
* status to log
|
||||
*/
|
||||
|
@ -74,22 +74,36 @@ public class Activator extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
* Logs an internal error with the specified throwable
|
||||
*
|
||||
* @param e
|
||||
* the exception to be logged
|
||||
* Logs an internal error with the specified {@code Throwable}.
|
||||
*
|
||||
* @param t
|
||||
* the {@code Throwable} to be logged
|
||||
*/
|
||||
public static void log(Throwable e) {
|
||||
log(new Status(IStatus.ERROR, PLUGIN_ID, 1, "Internal Error", e)); //$NON-NLS-1$
|
||||
public static void log(Throwable t) {
|
||||
log(new Status(IStatus.ERROR, PLUGIN_ID, 1, "Internal Error", t)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an internal error with the specified message.
|
||||
*
|
||||
*
|
||||
* @param message
|
||||
* the error message to log
|
||||
*/
|
||||
public static void log(String message) {
|
||||
log(new Status(IStatus.ERROR, PLUGIN_ID, 1, message, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an internal error with the specified message and {@code Throwable}.
|
||||
*
|
||||
* @param message
|
||||
* the error message to log
|
||||
* @param t
|
||||
* the {@code Throwable} to be logged
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public static void log(String message, Throwable t) {
|
||||
log(new Status(IStatus.ERROR, PLUGIN_ID, 1, message, t));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import static org.eclipse.cdt.core.ErrorParserContext.CODAN;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.cdt.codan.core.CodanRuntime;
|
||||
import org.eclipse.cdt.codan.core.cxx.Activator;
|
||||
import org.eclipse.cdt.codan.core.cxx.internal.externaltool.ExternalToolInvoker;
|
||||
import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
|
||||
import org.eclipse.cdt.codan.core.model.CheckerLaunchMode;
|
||||
import org.eclipse.cdt.codan.core.model.IProblem;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemLocationFactory;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
||||
import org.eclipse.cdt.codan.core.param.IProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.MapProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.RootProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.SharedRootProblemPreference;
|
||||
import org.eclipse.cdt.core.ErrorParserManager;
|
||||
import org.eclipse.cdt.core.IConsoleParser;
|
||||
import org.eclipse.cdt.core.IMarkerGenerator;
|
||||
import org.eclipse.cdt.core.ProblemMarkerInfo;
|
||||
import org.eclipse.core.filesystem.URIUtil;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Base class for checkers that invoke external command-line tools to perform code checking.
|
||||
* <p>
|
||||
* A file, to be processed by this type of checker, must:
|
||||
* <ol>
|
||||
* <li>be in the current active editor</li>
|
||||
* <li>not have any unsaved changes</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* By default, implementations of this checker are not allowed to run while the user types, since
|
||||
* external tools cannot see unsaved changes.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public abstract class AbstractExternalToolBasedChecker extends AbstractCheckerWithProblemPreferences
|
||||
implements IMarkerGenerator {
|
||||
private final IInvocationParametersProvider parametersProvider;
|
||||
private final ArgsSeparator argsSeparator;
|
||||
private final ConfigurationSettings settings;
|
||||
private final ExternalToolInvoker externalToolInvoker;
|
||||
private final RootProblemPreference preferences;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param settings user-configurable external tool configuration settings.
|
||||
*/
|
||||
public AbstractExternalToolBasedChecker(ConfigurationSettings settings) {
|
||||
this(new InvocationParametersProvider(), new ArgsSeparator(), settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param parametersProvider provides the parameters to pass when invoking the external tool.
|
||||
* @param argsSeparator separates the arguments to pass to the external tool executable. These
|
||||
* arguments are stored in a single {@code String}.
|
||||
* @param settings user-configurable external tool configuration settings.
|
||||
*/
|
||||
public AbstractExternalToolBasedChecker(IInvocationParametersProvider parametersProvider,
|
||||
ArgsSeparator argsSeparator, ConfigurationSettings settings) {
|
||||
this.parametersProvider = parametersProvider;
|
||||
this.argsSeparator = argsSeparator;
|
||||
this.settings = settings;
|
||||
externalToolInvoker = new ExternalToolInvoker();
|
||||
preferences = new SharedRootProblemPreference();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code false} because this checker cannot run "as you type" by default.
|
||||
* @return {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public boolean runInEditor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processResource(IResource resource) {
|
||||
process(resource);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void process(IResource resource) {
|
||||
try {
|
||||
InvocationParameters parameters = parametersProvider.createParameters(resource);
|
||||
if (parameters != null) {
|
||||
invokeExternalTool(parameters);
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
logResourceProcessingFailure(error, resource);
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeExternalTool(InvocationParameters parameters) throws Throwable {
|
||||
updateConfigurationSettingsFromPreferences(parameters.getActualFile());
|
||||
IConsoleParser[] parsers = new IConsoleParser[] { createErrorParserManager(parameters) };
|
||||
try {
|
||||
externalToolInvoker.invoke(parameters, settings, argsSeparator, parsers);
|
||||
} catch (InvocationFailure error) {
|
||||
handleInvocationFailure(error, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConfigurationSettingsFromPreferences(IResource fileToProcess) {
|
||||
IProblem problem = getProblemById(getReferenceProblemId(), fileToProcess);
|
||||
MapProblemPreference preferences = (MapProblemPreference) problem.getPreference();
|
||||
settings.updateValuesFrom(preferences);
|
||||
}
|
||||
|
||||
private ErrorParserManager createErrorParserManager(InvocationParameters parameters) {
|
||||
IProject project = parameters.getActualFile().getProject();
|
||||
URI workingDirectory = URIUtil.toURI(parameters.getWorkingDirectory());
|
||||
return new ErrorParserManager(project, workingDirectory, this, getParserIDs(), CODAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the IDs of the parsers to use to parse the output of the external tool.
|
||||
*/
|
||||
protected abstract String[] getParserIDs();
|
||||
|
||||
/**
|
||||
* Handles a failure reported when invoking the external tool. This implementation simply
|
||||
* logs the failure.
|
||||
* @param error the reported failure.
|
||||
* @param parameters the parameters passed to the external tool executable.
|
||||
*/
|
||||
protected void handleInvocationFailure(InvocationFailure error, InvocationParameters parameters) {
|
||||
logResourceProcessingFailure(error, parameters.getActualFile());
|
||||
}
|
||||
|
||||
private void logResourceProcessingFailure(Throwable error, IResource resource) {
|
||||
String location = resource.getLocation().toOSString();
|
||||
String msg = String.format("Unable to process resource %s", location); //$NON-NLS-1$
|
||||
Activator.log(msg, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the problem used as reference to obtain this checker's preferences. All
|
||||
* preferences in a external-tool-based checker are shared among its defined problems.
|
||||
* @return the id of the problem used as reference to obtain this checker's preferences.
|
||||
*/
|
||||
protected abstract String getReferenceProblemId();
|
||||
|
||||
@Override
|
||||
public void initPreferences(IProblemWorkingCopy problem) {
|
||||
super.initPreferences(problem);
|
||||
getLaunchModePreference(problem).enableInLaunchModes(
|
||||
CheckerLaunchMode.RUN_ON_FULL_BUILD,
|
||||
CheckerLaunchMode.RUN_ON_INC_BUILD,
|
||||
CheckerLaunchMode.RUN_ON_FILE_SAVE,
|
||||
CheckerLaunchMode.RUN_ON_DEMAND);
|
||||
addPreference(problem, settings.getPath());
|
||||
addPreference(problem, settings.getArgs());
|
||||
}
|
||||
|
||||
private void addPreference(IProblemWorkingCopy problem, SingleConfigurationSetting<?> setting) {
|
||||
IProblemPreference descriptor = (IProblemPreference) setting.getDescriptor();
|
||||
addPreference(problem, descriptor, setting.getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDefaultPreferenceValue(IProblemWorkingCopy problem, String key,
|
||||
Object defaultValue) {
|
||||
MapProblemPreference map = getTopLevelPreference(problem);
|
||||
map.setChildValue(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootProblemPreference getTopLevelPreference(IProblem problem) {
|
||||
RootProblemPreference map = (RootProblemPreference) problem.getPreference();
|
||||
if (map == null) {
|
||||
map = preferences;
|
||||
if (problem instanceof IProblemWorkingCopy) {
|
||||
((IProblemWorkingCopy) problem).setPreference(map);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void addMarker(IResource file, int lineNumber, String description, int severity,
|
||||
String variableName) {
|
||||
addMarker(new ProblemMarkerInfo(file, lineNumber, description, severity, variableName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMarker(ProblemMarkerInfo info) {
|
||||
reportProblem(getReferenceProblemId(), createProblemLocation(info), info.description);
|
||||
}
|
||||
|
||||
protected IProblemLocation createProblemLocation(ProblemMarkerInfo info) {
|
||||
IProblemLocationFactory factory = CodanRuntime.getInstance().getProblemLocationFactory();
|
||||
return factory.createProblemLocation(
|
||||
(IFile) info.file, info.startChar, info.endChar, info.lineNumber);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
// import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Separates the arguments, stored as a single {@code String}, to pass to an external tool. It uses
|
||||
* an empty space as the delimiter and supports quoted arguments.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class ArgsSeparator {
|
||||
private static final char BACKSLASH = '\\';
|
||||
private static final char DOUBLE_QUOTE = '"';
|
||||
private static final char SINGLE_QUOTE = '\'';
|
||||
private static final char SPACE = ' ';
|
||||
|
||||
private static final String[] NO_ARGS = {};
|
||||
|
||||
public String[] splitArguments(String s) {
|
||||
if (s == null || s.isEmpty()) {
|
||||
return NO_ARGS;
|
||||
}
|
||||
ParserState state = ParserState.NORMAL;
|
||||
StringBuilder current = new StringBuilder();
|
||||
List<String> args = new ArrayList<String>();
|
||||
boolean lastTokenInQuotes = false;
|
||||
char previous = 0;
|
||||
for (char c : s.toCharArray()) {
|
||||
switch (state) {
|
||||
case IN_SINGLE_QUOTE:
|
||||
if (previous != BACKSLASH && c == SINGLE_QUOTE) {
|
||||
lastTokenInQuotes = true;
|
||||
state = ParserState.NORMAL;
|
||||
} else {
|
||||
previous = c;
|
||||
current.append(c);
|
||||
}
|
||||
break;
|
||||
case IN_DOUBLE_QUOTE:
|
||||
if (previous != BACKSLASH && c == DOUBLE_QUOTE) {
|
||||
lastTokenInQuotes = true;
|
||||
state = ParserState.NORMAL;
|
||||
} else {
|
||||
previous = c;
|
||||
current.append(c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (c) {
|
||||
case SINGLE_QUOTE:
|
||||
if (previous != BACKSLASH) {
|
||||
state = ParserState.IN_SINGLE_QUOTE;
|
||||
}
|
||||
break;
|
||||
case DOUBLE_QUOTE:
|
||||
if (previous != BACKSLASH) {
|
||||
state = ParserState.IN_DOUBLE_QUOTE;
|
||||
}
|
||||
break;
|
||||
case SPACE:
|
||||
if (lastTokenInQuotes || current.length() != 0) {
|
||||
args.add(current.toString());
|
||||
current.setLength(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
previous = c;
|
||||
current.append(c);
|
||||
}
|
||||
lastTokenInQuotes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastTokenInQuotes || current.length() != 0) {
|
||||
args.add(current.toString());
|
||||
}
|
||||
if (state != ParserState.NORMAL) {
|
||||
throw new IllegalArgumentException("Unbalanced quotes in " + s); //$NON-NLS-1$
|
||||
}
|
||||
return args.toArray(new String[args.size()]);
|
||||
}
|
||||
|
||||
private static enum ParserState {
|
||||
NORMAL, IN_SINGLE_QUOTE, IN_DOUBLE_QUOTE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.internal.externaltool.ArgsSetting;
|
||||
import org.eclipse.cdt.codan.core.cxx.internal.externaltool.PathSetting;
|
||||
import org.eclipse.cdt.codan.core.param.MapProblemPreference;
|
||||
|
||||
/**
|
||||
* User-configurable external tool settings.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public final class ConfigurationSettings {
|
||||
private final PathSetting path;
|
||||
private final ArgsSetting args;
|
||||
private final String externalToolName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param externalToolName the name of the external tool. The name of the external tool is
|
||||
* used in the labels of the settings' input fields. For example, assuming that the external
|
||||
* tool's name is "Cppcheck", the input field for entering the path of the executable
|
||||
* will have the label "Cppcheck Path".
|
||||
* @param defaultPath the default path of the external tool.
|
||||
* @param defaultArgs the default arguments to pass when invoking the external tool.
|
||||
*/
|
||||
public ConfigurationSettings(String externalToolName, File defaultPath, String defaultArgs) {
|
||||
this.externalToolName = externalToolName;
|
||||
this.path = new PathSetting(externalToolName, defaultPath);
|
||||
this.args = new ArgsSetting(externalToolName, defaultArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the external tool, to be displayed to the user.
|
||||
* @return the name of the external tool, to be displayed to the user.
|
||||
*/
|
||||
public String getExternalToolName() {
|
||||
return externalToolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting that specifies the path and name of the external tool to invoke.
|
||||
* @return the setting that specifies the path and name of the external tool to invoke.
|
||||
*/
|
||||
public SingleConfigurationSetting<File> getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting that specifies the arguments to pass when invoking the external tool.
|
||||
* @return the setting that specifies the arguments to pass when invoking the external tool.
|
||||
*/
|
||||
public SingleConfigurationSetting<String> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the values of the configuration settings value with the ones stored in the given
|
||||
* preference map.
|
||||
* @param preferences the given preference map that may contain the values to set.
|
||||
* @throws ClassCastException if any of the values to set is not of the same type as the one
|
||||
* supported by a setting.
|
||||
*/
|
||||
public void updateValuesFrom(MapProblemPreference preferences) {
|
||||
path.updateValue(preferences);
|
||||
args.updateValue(preferences);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Provides the parameters to pass when invoking an external tool.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public interface IInvocationParametersProvider {
|
||||
/**
|
||||
* Creates the parameters to pass when invoking an external tool.
|
||||
* @param fileToProcess the file to process.
|
||||
* @return the created parameters.
|
||||
* @throws Throwable if something goes wrong.
|
||||
*/
|
||||
InvocationParameters createParameters(IResource fileToProcess) throws Throwable;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
/**
|
||||
* Indicates that invocation of an external tool failed.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class InvocationFailure extends Exception {
|
||||
private static final long serialVersionUID = 6727101323050538885L;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param message the detail message.
|
||||
*/
|
||||
public InvocationFailure(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param message the detail message.
|
||||
* @param cause the cause (which is saved for later retrieval by
|
||||
* the <code>{@link #getCause()}</code> method.)
|
||||
*/
|
||||
public InvocationFailure(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
/**
|
||||
* Parameters to pass when invoking an external tool.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public final class InvocationParameters {
|
||||
private final IResource originalFile;
|
||||
private final IResource actualFile;
|
||||
private final String actualFilePath;
|
||||
private final IPath workingDirectory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param originalFile the original file to process.
|
||||
* @param actualFile the actual file to process.
|
||||
* @param actualFilePath the path of {@code actual}, in a format that the external tool can
|
||||
* understand.
|
||||
* @param workingDirectory the directory where the external tool should be executed.
|
||||
* @see #getOriginalFile()
|
||||
* @see #getActualFile()
|
||||
*/
|
||||
public InvocationParameters(IResource originalFile, IResource actualFile, String actualFilePath,
|
||||
IPath workingDirectory) {
|
||||
this.originalFile = originalFile;
|
||||
this.actualFile = actualFile;
|
||||
this.actualFilePath = actualFilePath;
|
||||
this.workingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original file to process. This is the file that triggered execution of
|
||||
* a command-line tool when saved.
|
||||
* @return the original file to process.
|
||||
*/
|
||||
public IResource getOriginalFile() {
|
||||
return originalFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual file to process. It may not be the same as
|
||||
* <code>{@link #getOriginalFile()}</code>, depending on how the external tool works.
|
||||
* <p>
|
||||
* A good example is an external tool that can only process C++ source files but not header
|
||||
* files. If the <em>original</em> file is a header file, the checker could potentially find
|
||||
* a C++ file that includes such header and use it as the <em>actual</em> file to process.
|
||||
* </p>
|
||||
* <p>
|
||||
* We still need to keep a reference to the <em>actual</em> file, in order to add markers to
|
||||
* the editor in case of problems found.
|
||||
* </p>
|
||||
* @return the actual file to process.
|
||||
*/
|
||||
public IResource getActualFile() {
|
||||
return actualFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of <code>{@link #getActualFile()}</code>, in a format the external tool can
|
||||
* understand.
|
||||
* @return the path of the <em>actual</em> file to process.
|
||||
*/
|
||||
public String getActualFilePath() {
|
||||
return actualFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory where the external tool should be executed.
|
||||
* @return the directory where the external tool should be executed.
|
||||
*/
|
||||
public IPath getWorkingDirectory() {
|
||||
return workingDirectory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Default implementation of <code>{@link InvocationParameters}</code>
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class InvocationParametersProvider implements IInvocationParametersProvider {
|
||||
/**
|
||||
* Creates the parameters to pass when invoking an external tool.
|
||||
* <p>
|
||||
* In this implementation:
|
||||
* <ul>
|
||||
* <li>the <em>actual</em> file to process is the same as the <em>original</em> file</li>
|
||||
* <li>the path of the actual file is its absolute path in the file system</li>
|
||||
* <li>the working directory is {@code null}</li>
|
||||
* </ul>
|
||||
* @param fileToProcess the file to process.
|
||||
* @return the created parameters.
|
||||
*/
|
||||
@Override
|
||||
public InvocationParameters createParameters(IResource fileToProcess) {
|
||||
String path = fileToProcess.getLocation().toOSString();
|
||||
return new InvocationParameters(fileToProcess, fileToProcess, path, null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import org.eclipse.cdt.codan.core.param.IProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor;
|
||||
import org.eclipse.cdt.codan.core.param.MapProblemPreference;
|
||||
|
||||
/**
|
||||
* Single external tool configuration setting.
|
||||
* @param <T> the type of the value this setting stores.
|
||||
*
|
||||
* @noextend This class is not intended to be extended by clients.
|
||||
* @since 2.1
|
||||
*/
|
||||
public class SingleConfigurationSetting<T> {
|
||||
private final IProblemPreferenceDescriptor descriptor;
|
||||
private final T defaultValue;
|
||||
private final Class<T> valueType;
|
||||
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param descriptor meta-data that tells the UI how to display this setting.
|
||||
* @param defaultValue the setting's default value.
|
||||
* @param valueType the type of the value to store (used for safe casting.)
|
||||
*/
|
||||
public SingleConfigurationSetting(IProblemPreferenceDescriptor descriptor, T defaultValue,
|
||||
Class<T> valueType) {
|
||||
this.descriptor = descriptor;
|
||||
this.defaultValue = defaultValue;
|
||||
this.valueType = valueType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this setting's value.
|
||||
* @return this setting's value.
|
||||
*/
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the meta-data that tells the UI how to display this setting.
|
||||
* @return the meta-data that tells the UI how to display this setting.
|
||||
*/
|
||||
public IProblemPreferenceDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this setting's default value.
|
||||
* @return this setting's default value.
|
||||
*/
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this setting's value with the one stored in the given preference map.
|
||||
* @param preferences the given preference map that may contain the value to set.
|
||||
* @throws ClassCastException if the value to set is not of the same type as the one supported
|
||||
* by this setting.
|
||||
*/
|
||||
public void updateValue(MapProblemPreference preferences) {
|
||||
IProblemPreference childDescriptor = preferences.getChildDescriptor(descriptor.getKey());
|
||||
if (childDescriptor != null) {
|
||||
value = valueType.cast(childDescriptor.getValue());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import static org.eclipse.cdt.codan.core.cxx.internal.externaltool.Messages.ConfigurationSettings_args_format;
|
||||
import static org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType.TYPE_STRING;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.SingleConfigurationSetting;
|
||||
import org.eclipse.cdt.codan.core.param.BasicProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor;
|
||||
|
||||
/**
|
||||
* User-configurable setting that specifies the arguments to pass when invoking the external tool.
|
||||
* The arguments are stored in a single {@code String}.
|
||||
*/
|
||||
public class ArgsSetting extends SingleConfigurationSetting<String> {
|
||||
static final String KEY = "externalToolArgs"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param externalToolName the name of the external tool. The name of the external tool is
|
||||
* used in the label of this setting's input field.
|
||||
* @param defaultValue the default value of the setting.
|
||||
*/
|
||||
public ArgsSetting(String externalToolName, String defaultValue) {
|
||||
super(newPreferenceDescriptor(externalToolName), defaultValue, String.class);
|
||||
}
|
||||
|
||||
private static IProblemPreferenceDescriptor newPreferenceDescriptor(String externalToolName) {
|
||||
String label = String.format(ConfigurationSettings_args_format, externalToolName);
|
||||
return new BasicProblemPreference(KEY, label, TYPE_STRING);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
/**
|
||||
* The command to execute to invoke an external tool.
|
||||
*/
|
||||
class Command {
|
||||
private final IPath path;
|
||||
private final String[] args;
|
||||
|
||||
Command(IPath path, String[] args) {
|
||||
this.path = path;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
IPath getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
String[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.ArgsSeparator;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.ConfigurationSettings;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.InvocationParameters;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
/**
|
||||
* Creates the command to use to invoke an external tool.
|
||||
*/
|
||||
class CommandBuilder {
|
||||
Command buildCommand(InvocationParameters parameters, ConfigurationSettings settings,
|
||||
ArgsSeparator argsSeparator) {
|
||||
IPath executablePath = executablePath(settings);
|
||||
String[] args = argsToPass(parameters, settings, argsSeparator);
|
||||
return new Command(executablePath, args);
|
||||
}
|
||||
|
||||
private IPath executablePath(ConfigurationSettings configurationSettings) {
|
||||
File executablePath = configurationSettings.getPath().getValue();
|
||||
return new Path(executablePath.toString());
|
||||
}
|
||||
|
||||
private String[] argsToPass(InvocationParameters parameters,
|
||||
ConfigurationSettings configurationSettings, ArgsSeparator argsSeparator) {
|
||||
String actualFilePath = parameters.getActualFilePath();
|
||||
String[] args = configuredArgs(configurationSettings, argsSeparator);
|
||||
return addFilePathToArgs(actualFilePath, args);
|
||||
}
|
||||
|
||||
private String[] configuredArgs(ConfigurationSettings settings, ArgsSeparator argsSeparator) {
|
||||
String args = settings.getArgs().getValue();
|
||||
return argsSeparator.splitArguments(args);
|
||||
}
|
||||
|
||||
private String[] addFilePathToArgs(String actualFilePath, String[] configuredArgs) {
|
||||
int argCount = configuredArgs.length;
|
||||
String[] allArgs = new String[argCount + 1];
|
||||
allArgs[0] = actualFilePath;
|
||||
// Copy arguments
|
||||
System.arraycopy(configuredArgs, 0, allArgs, 1, argCount);
|
||||
return allArgs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.ArgsSeparator;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.ConfigurationSettings;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.InvocationFailure;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.InvocationParameters;
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.CommandLauncher;
|
||||
import org.eclipse.cdt.core.ICommandLauncher;
|
||||
import org.eclipse.cdt.core.IConsoleParser;
|
||||
import org.eclipse.cdt.core.resources.IConsole;
|
||||
import org.eclipse.cdt.internal.core.ConsoleOutputSniffer;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
|
||||
/**
|
||||
* Invokes an external tool to perform checks on a single file.
|
||||
*/
|
||||
public class ExternalToolInvoker {
|
||||
private static final String[] ENV = {};
|
||||
private static final NullProgressMonitor NULL_PROGRESS_MONITOR = new NullProgressMonitor();
|
||||
|
||||
private final CommandBuilder commandBuilder = new CommandBuilder();
|
||||
|
||||
/**
|
||||
* Invokes an external tool.
|
||||
* @param parameters the parameters to pass to the external tool executable.
|
||||
* @param settings user-configurable settings.
|
||||
* @param argsSeparator separates the arguments to pass to the external tool executable. These
|
||||
* arguments are stored in a single {@code String}.
|
||||
* @param parsers parse the output of the external tool.
|
||||
* @throws InvocationFailure if the external tool could not be invoked or if the external tool
|
||||
* itself reports that it cannot be executed (e.g. due to a configuration error).
|
||||
* @throws Throwable if something else goes wrong.
|
||||
*/
|
||||
public void invoke(InvocationParameters parameters, ConfigurationSettings settings,
|
||||
ArgsSeparator argsSeparator, IConsoleParser[] parsers)
|
||||
throws InvocationFailure, Throwable {
|
||||
Command command = commandBuilder.buildCommand(parameters, settings, argsSeparator);
|
||||
try {
|
||||
launchCommand(command, parsers, parameters);
|
||||
} finally {
|
||||
shutDown(parsers);
|
||||
}
|
||||
}
|
||||
|
||||
private void launchCommand(Command command, IConsoleParser[] parsers,
|
||||
InvocationParameters parameters) throws InvocationFailure, CoreException {
|
||||
IProject project = parameters.getActualFile().getProject();
|
||||
IConsole c = startConsole(project);
|
||||
ConsoleOutputSniffer sniffer =
|
||||
new ConsoleOutputSniffer(c.getOutputStream(), c.getErrorStream(), parsers);
|
||||
ICommandLauncher launcher = commandLauncher(project);
|
||||
Process p = launcher.execute(command.getPath(), command.getArgs(), ENV,
|
||||
parameters.getWorkingDirectory(), NULL_PROGRESS_MONITOR);
|
||||
if (p == null) {
|
||||
throw new InvocationFailure("Unable to launch external tool. Cause unknown."); //$NON-NLS-1$
|
||||
}
|
||||
try {
|
||||
p.getOutputStream().close();
|
||||
} catch (Throwable ignored) {}
|
||||
try {
|
||||
launcher.waitAndRead(sniffer.getOutputStream(), sniffer.getErrorStream(), NULL_PROGRESS_MONITOR);
|
||||
} finally {
|
||||
p.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private IConsole startConsole(IProject project) {
|
||||
IConsole console = CCorePlugin.getDefault().getConsole();
|
||||
console.start(project);
|
||||
return console;
|
||||
}
|
||||
|
||||
private ICommandLauncher commandLauncher(IProject project) {
|
||||
ICommandLauncher launcher = new CommandLauncher();
|
||||
launcher.showCommand(true);
|
||||
launcher.setProject(project);
|
||||
return launcher;
|
||||
}
|
||||
|
||||
private void shutDown(IConsoleParser[] parsers) {
|
||||
for (IConsoleParser parser : parsers) {
|
||||
parser.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
|
||||
public class Messages extends NLS {
|
||||
public static String ConfigurationSettings_args_format;
|
||||
public static String ConfigurationSettings_path_format;
|
||||
public static String ConfigurationSettings_should_display_output;
|
||||
|
||||
static {
|
||||
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
||||
}
|
||||
|
||||
private Messages() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2012 Google, Inc and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Contributors:
|
||||
# Alex Ruiz (Google) - initial API and implementation
|
||||
###############################################################################
|
||||
ConfigurationSettings_args_format=%s Args:
|
||||
ConfigurationSettings_path_format=%s Path:
|
||||
ConfigurationSettings_should_display_output=Display Output in Console
|
|
@ -0,0 +1,42 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.internal.externaltool;
|
||||
|
||||
import static org.eclipse.cdt.codan.core.cxx.internal.externaltool.Messages.ConfigurationSettings_path_format;
|
||||
import static org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType.TYPE_FILE;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.SingleConfigurationSetting;
|
||||
import org.eclipse.cdt.codan.core.param.BasicProblemPreference;
|
||||
import org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor;
|
||||
|
||||
/**
|
||||
* User-configurable setting that specifies the path and name of an external tool's executable.
|
||||
*/
|
||||
public class PathSetting extends SingleConfigurationSetting<File> {
|
||||
static final String KEY = "externalToolPath"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param externalToolName the name of the external tool. The name of the external tool is
|
||||
* used in the label of this setting's input field.
|
||||
* @param defaultValue the default value of the setting.
|
||||
*/
|
||||
public PathSetting(String externalToolName, File defaultValue) {
|
||||
super(newPreferenceDescriptor(externalToolName), defaultValue, File.class);
|
||||
}
|
||||
|
||||
private static IProblemPreferenceDescriptor newPreferenceDescriptor(String externalToolName) {
|
||||
String label = String.format(ConfigurationSettings_path_format, externalToolName);
|
||||
return new BasicProblemPreference(KEY, label, TYPE_FILE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.externaltool;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for <code>{@link ArgsSeparator}</code>.
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class ArgsSeparatorTest extends TestCase {
|
||||
private ArgsSeparator separator;
|
||||
|
||||
@Override
|
||||
protected void setUp() {
|
||||
separator = new ArgsSeparator();
|
||||
}
|
||||
|
||||
public void testWithSpaceAsDelimiter() {
|
||||
String[] args = separator.splitArguments("abc def ghi");
|
||||
assertArrayEquals(new String[] { "abc", "def", "ghi" }, args);
|
||||
}
|
||||
|
||||
public void testWithSingleQuote() {
|
||||
String[] args = separator.splitArguments("abc 'def ghi' jkl");
|
||||
assertArrayEquals(new String[] { "abc", "def ghi", "jkl" }, args);
|
||||
}
|
||||
|
||||
public void testWithDoubleQuote() {
|
||||
String[] args = separator.splitArguments("abc \"def ghi\" jkl");
|
||||
assertArrayEquals(new String[] { "abc", "def ghi", "jkl" }, args);
|
||||
}
|
||||
|
||||
public void testWithEscapedSingleQuote() {
|
||||
String[] args = separator.splitArguments("abc 'def \\' ghi' jkl");
|
||||
assertArrayEquals(new String[] { "abc", "def \\' ghi", "jkl" }, args);
|
||||
}
|
||||
|
||||
public void testWithEscapedDoubleQuote() {
|
||||
String[] args = separator.splitArguments("abc 'def \\\" ghi' jkl");
|
||||
assertArrayEquals(new String[] { "abc", "def \\\" ghi", "jkl" }, args);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,8 @@ Export-Package: org.eclipse.cdt.codan.core,
|
|||
x-friends:="org.eclipse.cdt.codan.core,
|
||||
org.eclipse.cdt.codan.core.cxx,
|
||||
org.eclipse.cdt.codan.core.test,
|
||||
org.eclipse.cdt.codan.ui",
|
||||
org.eclipse.cdt.codan.ui,
|
||||
org.eclipse.cdt.codan.ui.cxx",
|
||||
org.eclipse.cdt.codan.internal.core.cfg;x-friends:="org.eclipse.cdt.codan.core.cxx",
|
||||
org.eclipse.cdt.codan.internal.core.model;
|
||||
x-friends:="org.eclipse.cdt.codan.core.cxx,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<?eclipse version="3.4"?>
|
||||
<plugin>
|
||||
<extension-point id="checkers" name="%extension-point.name.CodeAnalysis" schema="schema/checkers.exsd"/>
|
||||
<extension-point id="checkerEnablement" name="Verification of checker enablement" schema="schema/checkerEnablement.exsd"/>
|
||||
|
||||
<extension
|
||||
id="codanBuilder"
|
||||
|
|
106
codan/org.eclipse.cdt.codan.core/schema/checkerEnablement.exsd
Normal file
106
codan/org.eclipse.cdt.codan.core/schema/checkerEnablement.exsd
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Schema file written by PDE -->
|
||||
<schema targetNamespace="org.eclipse.cdt.codan.core" xmlns="http://www.w3.org/2001/XMLSchema">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.schema plugin="org.eclipse.cdt.codan.core" id="checkerEnablement" name="Verification of checker enablement"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
Verifies that a checker should be executed on a given resource in a given launch mode.
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<element name="extension">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.element />
|
||||
</appinfo>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<attribute name="point" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The fully qualified name of this extension point.
|
||||
</documentation>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="id" type="string">
|
||||
<annotation>
|
||||
<documentation>
|
||||
ID of the extension point (Simple ID).
|
||||
</documentation>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="name" type="string">
|
||||
<annotation>
|
||||
<documentation>
|
||||
Name of the extension point.
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<meta.attribute translatable="true"/>
|
||||
</appinfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<element name="verifier">
|
||||
<annotation>
|
||||
<documentation>
|
||||
Specifies the implementation of ICheckerEnablementVerifier to use.
|
||||
</documentation>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<attribute name="class" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The implementation of ICheckerEnablementVerifier to use.
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<meta.attribute kind="java" basedOn=":org.eclipse.cdt.codan.internal.core.ICheckerEnablementVerifier"/>
|
||||
</appinfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="since"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
2.1
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="examples"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
<extension point="org.eclipse.cdt.codan.core.checkerEnablement">
|
||||
<verifier class="org.eclipse.cdt.codan.internal.ui.CheckerEnablementVerifier" />
|
||||
</extension>
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="apiinfo"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
Plug-ins that want to extend this extension point must implement org.eclipse.cdt.codan.internal.core.ICheckerEnablementVerifier interface.
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="implementation"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
The default implementation of this extension point is org.eclipse.cdt.codan.internal.ui.CheckerEnablementVerifier.
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
|
||||
</schema>
|
|
@ -11,15 +11,15 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.codan.core.CodanRuntime;
|
||||
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Convenience implementation of IChecker interface. Has a default
|
||||
* implementation for common methods.
|
||||
|
@ -37,10 +37,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
public AbstractChecker() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if checker is enabled in context of resource, if returns
|
||||
* false checker's "processResource" method won't be called
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean enabledInContext(IResource res) {
|
||||
return res.getType() == IResource.FILE;
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011, 2012 Alena Laskavaia 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:
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Alex Ruiz (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
/**
|
||||
|
@ -12,19 +23,25 @@ package org.eclipse.cdt.codan.core.model;
|
|||
*/
|
||||
public enum CheckerLaunchMode {
|
||||
/**
|
||||
* checker run when full build is running
|
||||
* Checker runs when full build is running.
|
||||
*/
|
||||
RUN_ON_FULL_BUILD,
|
||||
/**
|
||||
* checker run when incremental build is running
|
||||
* Checker runs when incremental build is running.
|
||||
*/
|
||||
RUN_ON_INC_BUILD,
|
||||
/**
|
||||
* checker run in editor as you type
|
||||
* Checker runs when a file is saved or opened. Checker will not run if the file is an editor
|
||||
* with unsaved changes.
|
||||
* @since 2.1
|
||||
*/
|
||||
RUN_ON_FILE_SAVE,
|
||||
/**
|
||||
* Checker runs in editor as you type.
|
||||
*/
|
||||
RUN_AS_YOU_TYPE,
|
||||
/**
|
||||
* checker run when explicit command is given
|
||||
* Checker runs when explicit command is given.
|
||||
*/
|
||||
RUN_ON_DEMAND,
|
||||
}
|
|
@ -72,7 +72,10 @@ public interface IChecker {
|
|||
*
|
||||
* @param resource the resource to run on.
|
||||
* @return true if checker should be run on this resource.
|
||||
* @deprecated Replaced by {@code CheckersRegistry.isCheckerEnabled((IChecker IResource, CheckerLaunchMode)}
|
||||
* and {@code ICheckerEnablementVerifier.isCheckerEnabled(IChecker IResource, CheckerLaunchMode)}.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean enabledInContext(IResource resource);
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.param;
|
||||
|
||||
/**
|
||||
* Preferences that can be shared among several problems.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class SharedRootProblemPreference extends RootProblemPreference {
|
||||
@Override
|
||||
public Object clone() {
|
||||
SharedRootProblemPreference map = (SharedRootProblemPreference) super.clone();
|
||||
// alruiz: sharing the internal hash is the only way I could make this work.
|
||||
map.hash = hash;
|
||||
return map;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.codan.core.CodanCorePlugin;
|
||||
|
@ -51,7 +52,9 @@ import org.osgi.service.prefs.Preferences;
|
|||
public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
||||
private static final String NAME_ATTR = "name"; //$NON-NLS-1$
|
||||
private static final String ID_ATTR = "id"; //$NON-NLS-1$
|
||||
private static final String EXTENSION_POINT_NAME = "checkers"; //$NON-NLS-1$
|
||||
private static final String CLASS_ATTR = "class"; //$NON-NLS-1$
|
||||
private static final String CHECKERS_EXTENSION_POINT_NAME = "checkers"; //$NON-NLS-1$
|
||||
private static final String CHECKER_ENABLEMENT_EXTENSION_POINT_NAME = "checkerEnablement"; //$NON-NLS-1$
|
||||
private static final String CHECKER_ELEMENT = "checker"; //$NON-NLS-1$
|
||||
private static final String PROBLEM_ELEMENT = "problem"; //$NON-NLS-1$
|
||||
private static final String CATEGORY_ELEMENT = "category"; //$NON-NLS-1$
|
||||
|
@ -60,19 +63,21 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
|||
private Collection<IChecker> checkers = new ArrayList<IChecker>();
|
||||
private static CheckersRegistry instance;
|
||||
private static boolean initialized = false;
|
||||
private HashMap<Object, IProblemProfile> profiles = new HashMap<Object, IProblemProfile>();
|
||||
private HashMap<IChecker, Collection<IProblem>> problemList = new HashMap<IChecker, Collection<IProblem>>();
|
||||
private Map<String, IChecker> problemCheckerMapping = new HashMap<String, IChecker>();
|
||||
private final Map<Object, IProblemProfile> profiles = new HashMap<Object, IProblemProfile>();
|
||||
private final Map<IChecker, Collection<IProblem>> problemList = new HashMap<IChecker, Collection<IProblem>>();
|
||||
private final Map<String, IChecker> problemCheckerMapping = new HashMap<String, IChecker>();
|
||||
private final List<ICheckerEnablementVerifier> checkerEnablementVerifiers = new ArrayList<ICheckerEnablementVerifier>();
|
||||
|
||||
private CheckersRegistry() {
|
||||
instance = this;
|
||||
profiles.put(DEFAULT, new ProblemProfile(DEFAULT));
|
||||
readCheckersRegistry();
|
||||
readCheckerEnablementVerifier();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void readCheckersRegistry() {
|
||||
IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(CodanCorePlugin.PLUGIN_ID, EXTENSION_POINT_NAME);
|
||||
IExtensionPoint ep = getExtensionPoint(CHECKERS_EXTENSION_POINT_NAME);
|
||||
if (ep == null)
|
||||
return;
|
||||
IConfigurationElement[] elements = ep.getConfigurationElements();
|
||||
|
@ -141,7 +146,7 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
|||
name = id;
|
||||
IChecker checkerObj = null;
|
||||
try {
|
||||
Object checker = configurationElement.createExecutableExtension("class"); //$NON-NLS-1$
|
||||
Object checker = configurationElement.createExecutableExtension(CLASS_ATTR);
|
||||
checkerObj = (IChecker) checker;
|
||||
addChecker(checkerObj);
|
||||
} catch (CoreException e) {
|
||||
|
@ -236,6 +241,21 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
|||
return elementValue;
|
||||
}
|
||||
|
||||
private void readCheckerEnablementVerifier() {
|
||||
IExtensionPoint ep = getExtensionPoint(CHECKER_ENABLEMENT_EXTENSION_POINT_NAME);
|
||||
for (IConfigurationElement ce : ep.getConfigurationElements()) {
|
||||
try {
|
||||
checkerEnablementVerifiers.add((ICheckerEnablementVerifier) ce.createExecutableExtension(CLASS_ATTR));
|
||||
} catch (CoreException e) {
|
||||
CodanCorePlugin.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IExtensionPoint getExtensionPoint(String extensionPointName) {
|
||||
return Platform.getExtensionRegistry().getExtensionPoint(CodanCorePlugin.PLUGIN_ID, extensionPointName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -459,7 +479,15 @@ public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry {
|
|||
* @param mode
|
||||
* @return <code>true</code> if the checker should run.
|
||||
*/
|
||||
public boolean isCheckerEnabledForLaunchMode(IChecker checker, IResource resource, CheckerLaunchMode mode) {
|
||||
public boolean isCheckerEnabled(IChecker checker, IResource resource, CheckerLaunchMode mode) {
|
||||
if (resource.getType() != IResource.FILE) {
|
||||
return false;
|
||||
}
|
||||
for (ICheckerEnablementVerifier verifier : checkerEnablementVerifiers) {
|
||||
if (!verifier.isCheckerEnabled(checker, resource, mode)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
IProblemProfile resourceProfile = getResourceProfile(resource);
|
||||
Collection<IProblem> refProblems = getRefProblems(checker);
|
||||
boolean enabled = false;
|
||||
|
|
|
@ -140,8 +140,7 @@ public class CodanBuilder extends IncrementalProjectBuilder implements ICodanBui
|
|||
if (monitor.isCanceled())
|
||||
return;
|
||||
if (doesCheckerSupportLaunchMode(checker, checkerLaunchMode)
|
||||
&& checker.enabledInContext(resource)
|
||||
&& chegistry.isCheckerEnabledForLaunchMode(checker, resource, checkerLaunchMode)) {
|
||||
&& chegistry.isCheckerEnabled(checker, resource, checkerLaunchMode)) {
|
||||
synchronized (checker) {
|
||||
try {
|
||||
checker.before(resource);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.internal.core;
|
||||
|
||||
import org.eclipse.cdt.codan.core.model.CheckerLaunchMode;
|
||||
import org.eclipse.cdt.codan.core.model.IChecker;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Verifies that an <code>{@link IChecker}</code> can be invoked.
|
||||
*/
|
||||
public interface ICheckerEnablementVerifier {
|
||||
/**
|
||||
* Indicates whether the given code checker can be invoked on the given resource in the given
|
||||
* launch mode.
|
||||
* @param checker the given code checker.
|
||||
* @param resource the resource to be checked.
|
||||
* @param mode the current launch mode.
|
||||
* @return {@code true} if the given code checker can be invoked, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isCheckerEnabled(IChecker checker, IResource resource, CheckerLaunchMode mode);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#Wed Feb 23 19:44:01 EST 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
|
@ -70,7 +69,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa
|
|||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
|
@ -149,9 +148,12 @@ org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
|||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
|
|
|
@ -11,7 +11,7 @@ Require-Bundle: org.eclipse.core.runtime,
|
|||
org.eclipse.cdt.core,
|
||||
org.eclipse.core.resources,
|
||||
org.eclipse.cdt.codan.ui;bundle-version="1.0.0"
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: org.eclipse.cdt.codan.examples,
|
||||
org.eclipse.cdt.codan.examples.checkers,
|
||||
|
|
|
@ -10,4 +10,15 @@
|
|||
###############################################################################
|
||||
#Properties file for org.eclipse.cdt.codan.examples
|
||||
Bundle-Vendor = Eclipse CDT
|
||||
Bundle-Name = Code Analysis Checker Examples
|
||||
Bundle-Name = Code Analysis Checker Examples
|
||||
|
||||
checker.name.Cppcheck = Cppcheck
|
||||
problem.description.Cppcheck.Error = Errors reported by Cppcheck (http://cppcheck.sourceforge.net/)
|
||||
problem.name.Cppcheck.Error = Errors
|
||||
problem.description.Cppcheck.Warning = Warnings reported by Cppcheck (http://cppcheck.sourceforge.net/)
|
||||
problem.name.Cppcheck.Warning = Warnings
|
||||
problem.description.Cppcheck.Syntax = Syntax problems reported by Cppcheck (http://cppcheck.sourceforge.net/)
|
||||
problem.name.Cppcheck.Syntax = Syntax Problems
|
||||
problem.messagePattern.Cppcheck.all = {0}
|
||||
|
||||
errorparser.name.cppcheck = Cppcheck Output Parser
|
|
@ -42,6 +42,42 @@
|
|||
name="Search string error">
|
||||
</problem>
|
||||
</checker>
|
||||
<category
|
||||
id="org.eclipse.cdt.codan.checkers.cppcheck"
|
||||
name="%checker.name.Cppcheck">
|
||||
</category>
|
||||
<checker
|
||||
class="org.eclipse.cdt.codan.examples.checkers.cppcheck.CppcheckChecker"
|
||||
id="org.eclipse.cdt.codan.checkers.CppcheckChecker"
|
||||
name="Cppcheck">
|
||||
<problem
|
||||
category="org.eclipse.cdt.codan.checkers.cppcheck"
|
||||
defaultEnabled="false"
|
||||
defaultSeverity="Error"
|
||||
description="%problem.description.Cppcheck.Error"
|
||||
id="org.eclipse.cdt.codan.checkers.cppcheck.error"
|
||||
messagePattern="%problem.messagePattern.Cppcheck.all"
|
||||
name="%problem.name.Cppcheck.Error">
|
||||
</problem>
|
||||
<problem
|
||||
category="org.eclipse.cdt.codan.checkers.cppcheck"
|
||||
defaultEnabled="false"
|
||||
defaultSeverity="Warning"
|
||||
description="%problem.description.Cppcheck.Warning"
|
||||
id="org.eclipse.cdt.codan.checkers.cppcheck.warning"
|
||||
messagePattern="%problem.messagePattern.Cppcheck.all"
|
||||
name="%problem.name.Cppcheck.Warning">
|
||||
</problem>
|
||||
<problem
|
||||
category="org.eclipse.cdt.codan.checkers.cppcheck"
|
||||
defaultEnabled="false"
|
||||
defaultSeverity="Warning"
|
||||
description="%problem.description.Cppcheck.Syntax"
|
||||
id="org.eclipse.cdt.codan.checkers.cppcheck.style"
|
||||
messagePattern="%problem.messagePattern.Cppcheck.all"
|
||||
name="%problem.name.Cppcheck.Syntax">
|
||||
</problem>
|
||||
</checker>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.cdt.codan.ui.codanProblemDetails">
|
||||
|
@ -54,4 +90,17 @@
|
|||
>
|
||||
</problemDetails>
|
||||
</extension>
|
||||
<extension
|
||||
id="CodanErrorParser"
|
||||
name="name"
|
||||
point="org.eclipse.cdt.core.ErrorParser">
|
||||
<errorparser
|
||||
class="org.eclipse.cdt.codan.examples.checkers.cppcheck.CppcheckOutputParser"
|
||||
id="org.eclipse.cdt.codan.checkers.externaltool.CppcheckChecker"
|
||||
name="%errorparser.name.cppcheck">
|
||||
<context
|
||||
type="codan">
|
||||
</context>
|
||||
</errorparser>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.examples.checkers.cppcheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.AbstractExternalToolBasedChecker;
|
||||
import org.eclipse.cdt.codan.core.cxx.externaltool.ConfigurationSettings;
|
||||
import org.eclipse.cdt.core.ProblemMarkerInfo;
|
||||
|
||||
/**
|
||||
* Checker that invokes <a href="http://cppcheck.sourceforge.net/">Cppcheck</a> when a C/C++ file is
|
||||
* saved.
|
||||
*/
|
||||
public class CppcheckChecker extends AbstractExternalToolBasedChecker {
|
||||
private static final String TOOL_NAME = Messages.CppcheckChecker_toolName;
|
||||
private static final String EXECUTABLE_NAME = "cppcheck"; //$NON-NLS-1$
|
||||
private static final String DEFAULT_ARGS = "--enable=all"; //$NON-NLS-1$
|
||||
|
||||
private static final String DESCRIPTION_FORMAT = "[" + TOOL_NAME + "] %s"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
private static final String ERROR_PROBLEM_ID;
|
||||
|
||||
// key: severity (error, warning, etc.) - value : problem ID associated to severity
|
||||
private static final Map<Severity, String> PROBLEM_IDS = new HashMap<Severity, String>();
|
||||
|
||||
static {
|
||||
ERROR_PROBLEM_ID = addProblemId(Severity.ERROR);
|
||||
addProblemId(Severity.WARNING);
|
||||
addProblemId(Severity.STYLE);
|
||||
}
|
||||
|
||||
private static String addProblemId(Severity severity) {
|
||||
String problemId = "org.eclipse.cdt.codan.checkers.cppcheck." + severity; //$NON-NLS-1$
|
||||
PROBLEM_IDS.put(severity, problemId);
|
||||
return problemId;
|
||||
}
|
||||
|
||||
public CppcheckChecker() {
|
||||
super(new ConfigurationSettings(TOOL_NAME, new File(EXECUTABLE_NAME), DEFAULT_ARGS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getParserIDs() {
|
||||
return new String[] { "org.eclipse.cdt.codan.checkers.externaltool.CppcheckChecker" }; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMarker(ProblemMarkerInfo info) {
|
||||
Severity severity = Severity.findSeverity(info.severity);
|
||||
String description = String.format(DESCRIPTION_FORMAT, info.description);
|
||||
reportProblem(PROBLEM_IDS.get(severity), createProblemLocation(info), description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getReferenceProblemId() {
|
||||
return ERROR_PROBLEM_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.examples.checkers.cppcheck;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.cdt.core.ErrorParserManager;
|
||||
import org.eclipse.cdt.core.IErrorParser;
|
||||
import org.eclipse.cdt.core.ProblemMarkerInfo;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
|
||||
/**
|
||||
* Parses the output of Cppcheck.
|
||||
*/
|
||||
public class CppcheckOutputParser implements IErrorParser {
|
||||
// sample line to parse:
|
||||
//
|
||||
// [/src/HelloWorld.cpp:19]: (style) The scope of the variable 'i' can be reduced
|
||||
// ----------1--------- -2 --3-- ------------------4-------------------------
|
||||
//
|
||||
// groups:
|
||||
// 1: file path and name
|
||||
// 2: line where problem was found
|
||||
// 3: problem severity
|
||||
// 4: problem description
|
||||
private static Pattern pattern = Pattern.compile("\\[(.*):(\\d+)\\]:\\s*\\((.*)\\)\\s*(.*)"); //$NON-NLS-1$
|
||||
|
||||
@Override
|
||||
public boolean processLine(String line, ErrorParserManager eoParser) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
return false;
|
||||
}
|
||||
IFile fileName = eoParser.findFileName(matcher.group(1));
|
||||
if (fileName != null) {
|
||||
int lineNumber = Integer.parseInt(matcher.group(2));
|
||||
String description = matcher.group(4);
|
||||
int severity = Severity.findSeverityCode(matcher.group(3));
|
||||
ProblemMarkerInfo info = new ProblemMarkerInfo(fileName, lineNumber, description, severity, null);
|
||||
eoParser.addProblemMarker(info);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.examples.checkers.cppcheck;
|
||||
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
|
||||
public class Messages extends NLS {
|
||||
public static String CppcheckChecker_toolName;
|
||||
|
||||
static {
|
||||
// initialize resource bundle
|
||||
Class<Messages> clazz = Messages.class;
|
||||
NLS.initializeMessages(clazz.getName(), clazz);
|
||||
}
|
||||
|
||||
private Messages() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2012 Google, Inc and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Contributors:
|
||||
# Alex Ruiz (Google) - initial API and implementation
|
||||
###############################################################################
|
||||
CppcheckChecker_toolName=Cppcheck
|
|
@ -0,0 +1,50 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.examples.checkers.cppcheck;
|
||||
|
||||
import org.eclipse.cdt.core.IMarkerGenerator;
|
||||
|
||||
enum Severity {
|
||||
ERROR(IMarkerGenerator.SEVERITY_ERROR_RESOURCE, "error"), //$NON-NLS-1$
|
||||
WARNING(IMarkerGenerator.SEVERITY_WARNING, "warning"), //$NON-NLS-1$
|
||||
STYLE(IMarkerGenerator.SEVERITY_INFO, "style"); //$NON-NLS-1$
|
||||
|
||||
private final int code;
|
||||
private final String text;
|
||||
|
||||
private Severity(int code, String text) {
|
||||
this.code = code;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
static int findSeverityCode(String text) {
|
||||
for (Severity severity : values()) {
|
||||
if (severity.text.equals(text)) {
|
||||
return severity.code;
|
||||
}
|
||||
}
|
||||
return STYLE.code;
|
||||
}
|
||||
|
||||
static Severity findSeverity(int code) {
|
||||
for (Severity severity : values()) {
|
||||
if (severity.code == code) {
|
||||
return severity;
|
||||
}
|
||||
}
|
||||
return STYLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ Require-Bundle: org.eclipse.ui,
|
|||
org.eclipse.ui.ide,
|
||||
org.eclipse.cdt.ui,
|
||||
org.eclipse.core.filesystem,
|
||||
org.eclipse.ui.console
|
||||
org.eclipse.ui.console,
|
||||
org.eclipse.ui.editors
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: org.eclipse.cdt.codan.internal.ui;x-friends:="org.eclipse.cdt.codan.ui.cxx",
|
||||
|
|
|
@ -238,4 +238,8 @@
|
|||
|
||||
</objectContribution>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.cdt.codan.core.checkerEnablement">
|
||||
<verifier class="org.eclipse.cdt.codan.internal.ui.CheckerEnablementVerifier" />
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.internal.ui;
|
||||
|
||||
import org.eclipse.cdt.codan.core.model.CheckerLaunchMode;
|
||||
import org.eclipse.cdt.codan.core.model.IChecker;
|
||||
import org.eclipse.cdt.codan.internal.core.ICheckerEnablementVerifier;
|
||||
import org.eclipse.cdt.codan.ui.CodanEditorUtility;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.editors.text.TextEditor;
|
||||
|
||||
/**
|
||||
* Default implementation of <code>{@link ICheckerEnablementVerifier}</code>.
|
||||
*/
|
||||
public class CheckerEnablementVerifier implements ICheckerEnablementVerifier {
|
||||
@Override
|
||||
public boolean isCheckerEnabled(IChecker checker, IResource resource, CheckerLaunchMode mode) {
|
||||
if (mode != CheckerLaunchMode.RUN_ON_FILE_SAVE) {
|
||||
return true;
|
||||
}
|
||||
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
|
||||
IWorkbenchPage page = window.getActivePage();
|
||||
for (IEditorReference reference : page.getEditorReferences()) {
|
||||
IEditorPart editor = reference.getEditor(false);
|
||||
if (!CodanEditorUtility.isResourceOpenInEditor(resource, editor)) {
|
||||
continue;
|
||||
}
|
||||
if (editor instanceof TextEditor) {
|
||||
TextEditor textEditor = (TextEditor) editor;
|
||||
return !textEditor.isDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -87,6 +87,7 @@ public class CodanUIMessages extends NLS {
|
|||
public static String LaunchModesPropertyPage_RunOnDemand;
|
||||
public static String LaunchModesPropertyPage_RunOnFullBuild;
|
||||
public static String LaunchModesPropertyPage_RunOnIncrementalBuild;
|
||||
public static String LaunchModesPropertyPage_RunOnFileSave;
|
||||
|
||||
static {
|
||||
NLS.initializeMessages(CodanUIMessages.class.getName(), CodanUIMessages.class);
|
||||
|
|
|
@ -96,3 +96,4 @@ LaunchModesPropertyPage_RunAsYouType=Run as you type
|
|||
LaunchModesPropertyPage_RunOnDemand=Run on demand
|
||||
LaunchModesPropertyPage_RunOnFullBuild=Run on full build
|
||||
LaunchModesPropertyPage_RunOnIncrementalBuild=Run on incremental build
|
||||
LaunchModesPropertyPage_RunOnFileSave=Run on file save or open
|
||||
|
|
|
@ -37,7 +37,11 @@ public class LaunchModesPropertyPage extends FieldEditorPreferencePage {
|
|||
super(GRID);
|
||||
CheckersRegistry registry = CheckersRegistry.getInstance();
|
||||
IChecker checker = registry.getCheckerForProblem(problem);
|
||||
runInEditor = (checker != null) ? Checkers.canCheckerRunAsYouType(checker) : false;
|
||||
if (checker != null) {
|
||||
runInEditor = Checkers.canCheckerRunAsYouType(checker);
|
||||
} else {
|
||||
runInEditor = false;
|
||||
}
|
||||
setPreferenceStore(prefStore);
|
||||
editors = new ArrayList<FieldEditor>();
|
||||
}
|
||||
|
@ -59,6 +63,7 @@ public class LaunchModesPropertyPage extends FieldEditorPreferencePage {
|
|||
addField(new BooleanFieldEditor(CheckerLaunchMode.RUN_ON_FULL_BUILD.name(), CodanUIMessages.LaunchModesPropertyPage_RunOnFullBuild, getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(CheckerLaunchMode.RUN_ON_INC_BUILD.name(), CodanUIMessages.LaunchModesPropertyPage_RunOnIncrementalBuild, getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(CheckerLaunchMode.RUN_ON_DEMAND.name(), CodanUIMessages.LaunchModesPropertyPage_RunOnDemand, getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(CheckerLaunchMode.RUN_ON_FILE_SAVE.name(), CodanUIMessages.LaunchModesPropertyPage_RunOnFileSave, getFieldEditorParent()));
|
||||
if (runInEditor) {
|
||||
addField(new BooleanFieldEditor(CheckerLaunchMode.RUN_AS_YOU_TYPE.name(), CodanUIMessages.LaunchModesPropertyPage_RunAsYouType, getFieldEditorParent()));
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ Export-Package: org.eclipse.cdt.core,
|
|||
org.eclipse.cdt.debug.core,
|
||||
org.eclipse.cdt.managedbuilder.core,
|
||||
org.eclipse.cdt.make.core,
|
||||
org.eclipse.cdt.make.ui",
|
||||
org.eclipse.cdt.make.ui,
|
||||
org.eclipse.cdt.codan.core.cxx",
|
||||
org.eclipse.cdt.internal.core.browser;x-friends:="org.eclipse.cdt.ui",
|
||||
org.eclipse.cdt.internal.core.cdtvariables;x-internal:=true,
|
||||
org.eclipse.cdt.internal.core.dom;x-internal:=true,
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<complexType>
|
||||
<sequence>
|
||||
<element ref="pattern" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<element ref="context" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</sequence>
|
||||
<attribute name="id" type="string">
|
||||
<annotation>
|
||||
|
@ -147,6 +148,33 @@
|
|||
</complexType>
|
||||
</element>
|
||||
|
||||
<element name="context">
|
||||
<annotation>
|
||||
<documentation>
|
||||
Use this element to specify the context where an error parser can be used. If none is specified, a default context type will be "build".
|
||||
|
||||
An error parser can be assigned to more than one context type. For example, an error parser can have two "context" elements, one for "build" and one for "codan".
|
||||
</documentation>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<attribute name="type" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The type of context where an error parser can be used. Valid values are "build" and "codan".
|
||||
</documentation>
|
||||
</annotation>
|
||||
<simpleType>
|
||||
<restriction base="string">
|
||||
<enumeration value="build">
|
||||
</enumeration>
|
||||
<enumeration value="codan">
|
||||
</enumeration>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<annotation>
|
||||
<appInfo>
|
||||
<meta.section type="since"/>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core;
|
||||
|
||||
/**
|
||||
* Indicates the context in which <code>{@link org.eclipse.cdt.core.IErrorParser}</code>s can be
|
||||
* used.
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
public class ErrorParserContext {
|
||||
public static final int BUILD = 1 << 0;
|
||||
public static final int CODAN = 1 << 1;
|
||||
|
||||
public static int getValue(String text) {
|
||||
if ("build".equals(text)) { //$NON-NLS-1$
|
||||
return BUILD;
|
||||
}
|
||||
if ("codan".equals(text)) { //$NON-NLS-1$
|
||||
return CODAN;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown context value: " + text); //$NON-NLS-1$
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core;
|
||||
|
||||
import static org.eclipse.cdt.core.ErrorParserContext.BUILD;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
|
@ -73,9 +75,9 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser,
|
|||
private final IMarkerGenerator fMarkerGenerator;
|
||||
|
||||
private Map<String, IErrorParser[]> fErrorParsers;
|
||||
private ArrayList<ProblemMarkerInfo> fErrors;
|
||||
private final ArrayList<ProblemMarkerInfo> fErrors;
|
||||
|
||||
private Vector<URI> fDirectoryStack;
|
||||
private final Vector<URI> fDirectoryStack;
|
||||
private final URI fBaseDirectoryURI;
|
||||
|
||||
private String previousLine;
|
||||
|
@ -147,27 +149,46 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser,
|
|||
* @since 5.1
|
||||
*/
|
||||
public ErrorParserManager(IProject project, URI baseDirectoryURI, IMarkerGenerator markerGenerator, String[] parsersIDs) {
|
||||
this(project, baseDirectoryURI, markerGenerator, parsersIDs, BUILD);
|
||||
}
|
||||
|
||||
/**
|
||||
* URI based constructor.
|
||||
*
|
||||
* @param project - project being built.
|
||||
* @param baseDirectoryURI - absolute location URI of working directory of where the build is performed.
|
||||
* @param markerGenerator - marker generator able to create markers.
|
||||
* @param parsersIDs - array of error parsers' IDs.
|
||||
* @param context - context where the error parser will be used. Valid values are defined by
|
||||
* <code>{@link ErrorParserContext}</code>.
|
||||
* @see ErrorParserContext
|
||||
* @since 5.4
|
||||
*/
|
||||
public ErrorParserManager(IProject project, URI baseDirectoryURI,
|
||||
IMarkerGenerator markerGenerator, String[] parsersIDs, int context) {
|
||||
fProject = project;
|
||||
fMarkerGenerator = markerGenerator;
|
||||
fDirectoryStack = new Vector<URI>();
|
||||
fErrors = new ArrayList<ProblemMarkerInfo>();
|
||||
enableErrorParsers(parsersIDs);
|
||||
enableErrorParsers(parsersIDs, context);
|
||||
|
||||
if (baseDirectoryURI != null)
|
||||
if (baseDirectoryURI != null) {
|
||||
fBaseDirectoryURI = baseDirectoryURI;
|
||||
else if (project != null)
|
||||
} else if (project != null) {
|
||||
fBaseDirectoryURI = project.getLocationURI();
|
||||
else
|
||||
}
|
||||
else {
|
||||
fBaseDirectoryURI = org.eclipse.core.filesystem.URIUtil.toURI(System.getProperty("user.dir")); // CWD //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
private void enableErrorParsers(String[] parsersIDs) {
|
||||
private void enableErrorParsers(String[] parsersIDs, int context) {
|
||||
if (parsersIDs == null) {
|
||||
parsersIDs = ErrorParserExtensionManager.getDefaultErrorParserIds();
|
||||
}
|
||||
fErrorParsers = new LinkedHashMap<String, IErrorParser[]>(parsersIDs.length);
|
||||
for (String parsersID : parsersIDs) {
|
||||
IErrorParser errorParser = getErrorParserCopy(parsersID);
|
||||
IErrorParser errorParser = getErrorParserCopy(parsersID, context);
|
||||
if (errorParser!=null) {
|
||||
fErrorParsers.put(parsersID, new IErrorParser[] {errorParser} );
|
||||
}
|
||||
|
@ -196,8 +217,9 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser,
|
|||
*/
|
||||
@Override
|
||||
public URI getWorkingDirectoryURI() {
|
||||
if (!fDirectoryStack.isEmpty())
|
||||
if (!fDirectoryStack.isEmpty()) {
|
||||
return fDirectoryStack.lastElement();
|
||||
}
|
||||
|
||||
// Fall back to the Project Location / Build directory
|
||||
return fBaseDirectoryURI;
|
||||
|
@ -214,12 +236,13 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser,
|
|||
if (dir != null) {
|
||||
URI uri;
|
||||
URI workingDirectoryURI = getWorkingDirectoryURI();
|
||||
if (!dir.isAbsolute())
|
||||
if (!dir.isAbsolute()) {
|
||||
uri = URIUtil.append(workingDirectoryURI, dir.toString());
|
||||
else {
|
||||
} else {
|
||||
uri = toURI(dir);
|
||||
if (uri == null) // Shouldn't happen; error logged
|
||||
if (uri == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
pushDirectoryURI(uri);
|
||||
}
|
||||
|
@ -235,10 +258,11 @@ public class ErrorParserManager extends OutputStream implements IConsoleParser,
|
|||
*/
|
||||
public void pushDirectoryURI(URI dir) {
|
||||
if (dir != null) {
|
||||
if (dir.isAbsolute())
|
||||
if (dir.isAbsolute()) {
|
||||
fDirectoryStack.addElement(dir);
|
||||
else
|
||||
} else {
|
||||
fDirectoryStack.addElement(URIUtil.makeAbsolute(dir, getWorkingDirectoryURI()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,8 +355,9 @@ outer:
|
|||
}
|
||||
if ((types & IErrorParser2.KEEP_LONGLINES) == 0) {
|
||||
// long lines are not given to parsers, unless it wants it
|
||||
if (lineTrimmed.length() > 1000)
|
||||
if (lineTrimmed.length() > 1000) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// standard behavior (pre 5.1) is to trim the line
|
||||
String lineToParse = lineTrimmed;
|
||||
|
@ -349,21 +374,24 @@ outer:
|
|||
consume = curr.processLine(lineToParse, this);
|
||||
} catch (Exception e){
|
||||
String id = ""; //$NON-NLS-1$
|
||||
if (parser instanceof IErrorParserNamed)
|
||||
if (parser instanceof IErrorParserNamed) {
|
||||
id = ((IErrorParserNamed)parser).getId();
|
||||
}
|
||||
@SuppressWarnings("nls")
|
||||
String message = "Errorparser " + id + " failed parsing line [" + lineToParse + "]";
|
||||
CCorePlugin.log(message, e);
|
||||
} finally {
|
||||
if (fErrors.size() > 0) {
|
||||
if (marker==null)
|
||||
if (marker==null) {
|
||||
marker = fErrors.get(0);
|
||||
}
|
||||
fErrors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (consume)
|
||||
if (consume) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
outputLine(line, marker);
|
||||
|
@ -377,7 +405,9 @@ outer:
|
|||
*/
|
||||
private void outputLine(String line, ProblemMarkerInfo marker) {
|
||||
String l = line + "\n"; //$NON-NLS-1$
|
||||
if ( outputStream == null ) return;
|
||||
if ( outputStream == null ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if ( marker != null && outputStream instanceof IErrorMarkeredOutputStream ) {
|
||||
IErrorMarkeredOutputStream s = (IErrorMarkeredOutputStream) outputStream;
|
||||
|
@ -417,8 +447,9 @@ outer:
|
|||
*/
|
||||
public IFile findFileName(String partialLoc) {
|
||||
if (partialLoc.equals(cachedFileName) && cachedWorkingDirectory != null &&
|
||||
org.eclipse.core.filesystem.URIUtil.equals(getWorkingDirectoryURI(), cachedWorkingDirectory))
|
||||
org.eclipse.core.filesystem.URIUtil.equals(getWorkingDirectoryURI(), cachedWorkingDirectory)) {
|
||||
return cachedFile;
|
||||
}
|
||||
|
||||
// To be able to parse Windows paths on Linux systems, see bug 263977
|
||||
IPath path = new Path(partialLoc.replace('\\', IPath.SEPARATOR));
|
||||
|
@ -433,17 +464,20 @@ outer:
|
|||
if (fProject != null) {
|
||||
IProject[] prjs = new IProject[] { fProject };
|
||||
files = ResourceLookup.findFilesByName(path, prjs, false);
|
||||
if (files.length == 0)
|
||||
if (files.length == 0) {
|
||||
files = ResourceLookup.findFilesByName(path, prjs, /* ignoreCase */ true);
|
||||
}
|
||||
}
|
||||
if (files == null || files.length == 0) {
|
||||
IProject[] prjs = ResourcesPlugin.getWorkspace().getRoot().getProjects();
|
||||
files = ResourceLookup.findFilesByName(path, prjs, false);
|
||||
if (files.length == 0)
|
||||
if (files.length == 0) {
|
||||
files = ResourceLookup.findFilesByName(path, prjs, /* ignoreCase */ true);
|
||||
}
|
||||
}
|
||||
if (files.length == 1)
|
||||
if (files.length == 1) {
|
||||
file = files[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Could be cygwin path
|
||||
|
@ -471,8 +505,9 @@ outer:
|
|||
}
|
||||
else {
|
||||
uri = toURI(path);
|
||||
if (uri == null) // Shouldn't happen; error logged
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return findFileInWorkspace(uri);
|
||||
}
|
||||
|
@ -485,12 +520,14 @@ outer:
|
|||
* @since 5.1
|
||||
*/
|
||||
protected IFile findFileInWorkspace(URI uri) {
|
||||
if (!uri.isAbsolute())
|
||||
if (!uri.isAbsolute()) {
|
||||
uri = URIUtil.makeAbsolute(uri, getWorkingDirectoryURI());
|
||||
}
|
||||
|
||||
IFile f = ResourceLookup.selectFileForLocationURI(uri, fProject);
|
||||
if (f != null && f.isAccessible())
|
||||
if (f != null && f.isAccessible()) {
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -581,8 +618,9 @@ outer:
|
|||
public void addProblemMarker(ProblemMarkerInfo problemMarkerInfo){
|
||||
fErrors.add(problemMarkerInfo);
|
||||
fMarkerGenerator.addMarker(problemMarkerInfo);
|
||||
if (problemMarkerInfo.severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE)
|
||||
if (problemMarkerInfo.severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,8 +670,9 @@ outer:
|
|||
*/
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if (outputStream != null)
|
||||
if (outputStream != null) {
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -668,8 +707,9 @@ outer:
|
|||
while ((i = buffer.indexOf('\n')) != -1) {
|
||||
String line = buffer.substring(0, i);
|
||||
// get rid of any trailing '\r'
|
||||
if (line.endsWith("\r")) //$NON-NLS-1$
|
||||
if (line.endsWith("\r")) { //$NON-NLS-1$
|
||||
line=line.substring(0,line.length()-1);
|
||||
}
|
||||
processLine(line);
|
||||
previousLine = line;
|
||||
buffer = buffer.substring(i + 1); // skip the \n and advance
|
||||
|
@ -718,8 +758,9 @@ outer:
|
|||
String uriString = path.toString();
|
||||
|
||||
// On Windows "C:/folder/" -> "/C:/folder/"
|
||||
if (path.isAbsolute() && uriString.charAt(0) != IPath.SEPARATOR)
|
||||
uriString = IPath.SEPARATOR + uriString;
|
||||
if (path.isAbsolute() && uriString.charAt(0) != IPath.SEPARATOR) {
|
||||
uriString = IPath.SEPARATOR + uriString;
|
||||
}
|
||||
|
||||
return EFSExtensionManager.getDefault().createNewURIFromPath(baseURI, uriString);
|
||||
}
|
||||
|
@ -829,6 +870,20 @@ outer:
|
|||
return ErrorParserExtensionManager.getErrorParserCopy(id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id - ID of error parser
|
||||
* @param context - context where the error parser will be used. Valid values are defined by
|
||||
* <code>{@link ErrorParserContext}</code>.
|
||||
* @return cloned copy of error parser or {@code null}.
|
||||
* Note that {@link ErrorParserNamedWrapper} returns shallow copy with the same instance
|
||||
* of underlying error parser.
|
||||
* @see ErrorParserContext
|
||||
* @since 5.4
|
||||
*/
|
||||
public static IErrorParserNamed getErrorParserCopy(String id, int context) {
|
||||
return ErrorParserExtensionManager.getErrorParserCopy(id, false, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id - ID of error parser
|
||||
* @return cloned copy of error parser as defined by its extension point or {@code null}.
|
||||
|
@ -860,5 +915,12 @@ outer:
|
|||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
for (IErrorParser[] parsers : fErrorParsers.values()) {
|
||||
for (IErrorParser parser : parsers) {
|
||||
if (parser instanceof IErrorParser3) {
|
||||
((IErrorParser3) parser).streamFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core;
|
||||
|
||||
/**
|
||||
* @since 5.4
|
||||
*/
|
||||
public interface IErrorParser3 extends IErrorParser2 {
|
||||
/**
|
||||
* Notification that the stream of data to parse has ended.
|
||||
*/
|
||||
void streamFinished();
|
||||
}
|
|
@ -35,6 +35,14 @@ public class ProblemMarkerInfo {
|
|||
|
||||
public IResource file;
|
||||
public int lineNumber;
|
||||
/**
|
||||
* @since 5.4
|
||||
*/
|
||||
public int startChar;
|
||||
/**
|
||||
* @since 5.4
|
||||
*/
|
||||
public int endChar;
|
||||
public String description;
|
||||
public int severity;
|
||||
public String variableName;
|
||||
|
@ -53,6 +61,24 @@ public class ProblemMarkerInfo {
|
|||
* @param variableName - the name of the variable involved in the error if any.
|
||||
*/
|
||||
public ProblemMarkerInfo(IResource file, int lineNumber, String description, int severity, String variableName) {
|
||||
this(file, lineNumber, -1,-1, description, severity, variableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ProblemMarkerInfo} object.
|
||||
*
|
||||
* @param file - the file where the problem has occurred.
|
||||
* @param lineNumber - the line number of the problem.
|
||||
* @param startChar - start char of the problem.
|
||||
* @param endChar - end char of the problem.
|
||||
* @param description - a description of the problem.
|
||||
* @param severity - the severity of the problem, see {@link IMarkerGenerator}
|
||||
* for acceptable severity values.
|
||||
* @param variableName - the name of the variable involved in the error if any.
|
||||
* @since 5.4
|
||||
*/
|
||||
public ProblemMarkerInfo(IResource file, int lineNumber, int startChar, int endChar,
|
||||
String description, int severity, String variableName) {
|
||||
this.file = (file != null) ? file : ResourcesPlugin.getWorkspace().getRoot();
|
||||
this.lineNumber = lineNumber;
|
||||
this.description = description;
|
||||
|
@ -61,6 +87,8 @@ public class ProblemMarkerInfo {
|
|||
this.externalPath = null ;
|
||||
this.type = null;
|
||||
this.attributes = new HashMap<String, String>();
|
||||
this.startChar = -1;
|
||||
this.endChar = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,24 +11,29 @@
|
|||
|
||||
package org.eclipse.cdt.internal.errorparsers;
|
||||
|
||||
import static org.eclipse.cdt.core.ErrorParserContext.BUILD;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.ErrorParserManager;
|
||||
import org.eclipse.cdt.core.ErrorParserContext;
|
||||
import org.eclipse.cdt.core.IErrorParser;
|
||||
import org.eclipse.cdt.core.IErrorParserNamed;
|
||||
import org.eclipse.cdt.core.IMarkerGenerator;
|
||||
import org.eclipse.cdt.core.errorparsers.ErrorParserNamedWrapper;
|
||||
import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
|
||||
import org.eclipse.cdt.core.errorparsers.RegexErrorPattern;
|
||||
import org.eclipse.cdt.internal.core.Pair;
|
||||
import org.eclipse.cdt.internal.core.XmlUtil;
|
||||
import org.eclipse.core.filesystem.URIUtil;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
@ -56,6 +61,7 @@ public class ErrorParserExtensionManager {
|
|||
private static final String NONE = ""; //$NON-NLS-1$
|
||||
|
||||
private static final String EXTENSION_POINT_ERROR_PARSER = "org.eclipse.cdt.core.ErrorParser"; //$NON-NLS-1$
|
||||
private static final String ELEM_CONTEXT = "context"; //$NON-NLS-1$
|
||||
private static final String ELEM_PLUGIN = "plugin"; //$NON-NLS-1$
|
||||
private static final String ELEM_EXTENSION = "extension"; //$NON-NLS-1$
|
||||
private static final String ELEM_ERRORPARSER = "errorparser"; //$NON-NLS-1$
|
||||
|
@ -64,7 +70,9 @@ public class ErrorParserExtensionManager {
|
|||
private static final String ATTR_ID = "id"; //$NON-NLS-1$
|
||||
private static final String ATTR_NAME = "name"; //$NON-NLS-1$
|
||||
private static final String ATTR_POINT = "point"; //$NON-NLS-1$
|
||||
private static final String ATTR_TYPE = "type"; //$NON-NLS-1$
|
||||
|
||||
|
||||
private static final String ATTR_REGEX = "regex"; //$NON-NLS-1$
|
||||
private static final String ATTR_SEVERITY = "severity"; //$NON-NLS-1$
|
||||
private static final String ATTR_FILE = "file-expr"; //$NON-NLS-1$
|
||||
|
@ -78,8 +86,10 @@ public class ErrorParserExtensionManager {
|
|||
private static final String ATTR_VALUE_INFO = "Info"; //$NON-NLS-1$
|
||||
private static final String ATTR_VALUE_IGNORE = "Ignore"; //$NON-NLS-1$
|
||||
|
||||
private static final LinkedHashMap<String, IErrorParserNamed> fExtensionErrorParsers = new LinkedHashMap<String, IErrorParserNamed>();
|
||||
private static final LinkedHashMap<String, IErrorParserNamed> fAvailableErrorParsers = new LinkedHashMap<String, IErrorParserNamed>();
|
||||
// Key: error parser id. Value: pair of error parser and contexts value
|
||||
private static final LinkedHashMap<String, Pair<IErrorParserNamed, Integer>> fExtensionErrorParsers = new LinkedHashMap<String, Pair<IErrorParserNamed, Integer>>();
|
||||
// Key: error parser id. Value: pair of error parser and contexts value
|
||||
private static final LinkedHashMap<String, Pair<IErrorParserNamed, Integer>> fAvailableErrorParsers = new LinkedHashMap<String, Pair<IErrorParserNamed, Integer>>();
|
||||
private static LinkedHashMap<String, IErrorParserNamed> fUserDefinedErrorParsers = null;
|
||||
private static List<String> fDefaultErrorParserIds = null;
|
||||
|
||||
|
@ -112,6 +122,18 @@ public class ErrorParserExtensionManager {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ErrorParserAndContextComparator implements Comparator<Pair<IErrorParserNamed, Integer>> {
|
||||
private static final ErrorParserComparator DELEGATE = new ErrorParserComparator();
|
||||
|
||||
@Override
|
||||
public int compare(Pair<IErrorParserNamed, Integer> pair1,
|
||||
Pair<IErrorParserNamed, Integer> pair2) {
|
||||
IErrorParserNamed parser1 = pair1.first;
|
||||
IErrorParserNamed parser2 = pair2.first;
|
||||
return DELEGATE.compare(parser1, parser2);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
loadUserDefinedErrorParsers();
|
||||
loadDefaultErrorParserIds();
|
||||
|
@ -202,12 +224,13 @@ public class ErrorParserExtensionManager {
|
|||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
synchronized public static void loadErrorParserExtensions() {
|
||||
Set<IErrorParserNamed> sortedErrorParsers = new TreeSet<IErrorParserNamed>(new ErrorParserComparator());
|
||||
Set<Pair<IErrorParserNamed, Integer>> sortedErrorParsers =
|
||||
new TreeSet<Pair<IErrorParserNamed, Integer>>(new ErrorParserAndContextComparator());
|
||||
loadErrorParserExtensions(Platform.getExtensionRegistry(), sortedErrorParsers);
|
||||
|
||||
fExtensionErrorParsers.clear();
|
||||
for (IErrorParserNamed errorParser : sortedErrorParsers) {
|
||||
fExtensionErrorParsers.put(errorParser.getId(), errorParser);
|
||||
for (Pair<IErrorParserNamed, Integer> pair : sortedErrorParsers) {
|
||||
fExtensionErrorParsers.put(pair.first.getId(), pair);
|
||||
}
|
||||
recalculateAvailableErrorParsers();
|
||||
}
|
||||
|
@ -218,7 +241,8 @@ public class ErrorParserExtensionManager {
|
|||
* @param registry - extension registry
|
||||
* @param errorParsers - resulting set of error parsers
|
||||
*/
|
||||
private static void loadErrorParserExtensions(IExtensionRegistry registry, Set<IErrorParserNamed> errorParsers) {
|
||||
private static void loadErrorParserExtensions(IExtensionRegistry registry,
|
||||
Set<Pair<IErrorParserNamed, Integer>> errorParsers) {
|
||||
errorParsers.clear();
|
||||
IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, CCorePlugin.ERROR_PARSER_SIMPLE_ID);
|
||||
if (extension != null) {
|
||||
|
@ -232,8 +256,9 @@ public class ErrorParserExtensionManager {
|
|||
if (cfgEl.getName().equals(ELEM_ERRORPARSER)) {
|
||||
IErrorParserNamed errorParser = createErrorParserCarcass(oldStyleId, oldStyleName, cfgEl);
|
||||
if (errorParser!=null) {
|
||||
configureErrorParser(errorParser, cfgEl);
|
||||
errorParsers.add(errorParser);
|
||||
Pair<IErrorParserNamed, Integer> configured =
|
||||
configureErrorParser(errorParser, cfgEl);
|
||||
errorParsers.add(configured);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,42 +279,50 @@ public class ErrorParserExtensionManager {
|
|||
List<String> ids = new ArrayList<String>();
|
||||
if (fDefaultErrorParserIds!=null) {
|
||||
for (String id : fDefaultErrorParserIds) {
|
||||
Pair<IErrorParserNamed, Integer> pair = null;
|
||||
IErrorParserNamed errorParser = null;
|
||||
if (fUserDefinedErrorParsers!=null) {
|
||||
errorParser = fUserDefinedErrorParsers.get(id);
|
||||
}
|
||||
if (errorParser==null) {
|
||||
errorParser = fExtensionErrorParsers.get(id);
|
||||
if (errorParser != null) {
|
||||
pair = errorParserForBuild(errorParser);
|
||||
} else {
|
||||
pair = fExtensionErrorParsers.get(id);
|
||||
}
|
||||
if (errorParser!=null) {
|
||||
fAvailableErrorParsers.put(id, errorParser);
|
||||
if (pair != null) {
|
||||
fAvailableErrorParsers.put(id, pair);
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// then the rest in the order defined by comparator
|
||||
Set<IErrorParserNamed> sortedErrorParsers = new TreeSet<IErrorParserNamed>(new ErrorParserComparator());
|
||||
Set<Pair<IErrorParserNamed, Integer>> sortedErrorParsers =
|
||||
new TreeSet<Pair<IErrorParserNamed, Integer>>(new ErrorParserAndContextComparator());
|
||||
|
||||
if (fUserDefinedErrorParsers!=null) {
|
||||
for (String id : fUserDefinedErrorParsers.keySet()) {
|
||||
if (!ids.contains(id)) {
|
||||
IErrorParserNamed errorParser = fUserDefinedErrorParsers.get(id);
|
||||
sortedErrorParsers.add(errorParser);
|
||||
sortedErrorParsers.add(errorParserForBuild(errorParser));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String id : fExtensionErrorParsers.keySet()) {
|
||||
if (!ids.contains(id)) {
|
||||
IErrorParserNamed errorParser = fExtensionErrorParsers.get(id);
|
||||
sortedErrorParsers.add(errorParser);
|
||||
Pair<IErrorParserNamed, Integer> pair = fExtensionErrorParsers.get(id);
|
||||
sortedErrorParsers.add(pair);
|
||||
}
|
||||
}
|
||||
|
||||
for (IErrorParserNamed errorParser : sortedErrorParsers) {
|
||||
fAvailableErrorParsers.put(errorParser.getId(), errorParser);
|
||||
for (Pair<IErrorParserNamed, Integer> pairs : sortedErrorParsers) {
|
||||
fAvailableErrorParsers.put(pairs.first.getId(), pairs);
|
||||
}
|
||||
}
|
||||
|
||||
private static Pair<IErrorParserNamed, Integer> errorParserForBuild(IErrorParserNamed errorParser) {
|
||||
return new Pair<IErrorParserNamed, Integer>(errorParser, ErrorParserContext.BUILD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize error parsers in workspace level storage.
|
||||
*
|
||||
|
@ -544,7 +577,8 @@ public class ErrorParserExtensionManager {
|
|||
* @param cfgEl - extension configuration element
|
||||
* @throws CoreException
|
||||
*/
|
||||
private static void configureErrorParser(IErrorParserNamed errorParser, IConfigurationElement cfgEl) throws CoreException {
|
||||
private static Pair<IErrorParserNamed, Integer> configureErrorParser(
|
||||
IErrorParserNamed errorParser, IConfigurationElement cfgEl) throws CoreException {
|
||||
String id = cfgEl.getAttribute(ATTR_ID);
|
||||
if (id!=null && id.length()>0)
|
||||
errorParser.setId(id);
|
||||
|
@ -569,6 +603,31 @@ public class ErrorParserExtensionManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
int contexts = contextTypes(cfgEl);
|
||||
return new Pair<IErrorParserNamed, Integer>(errorParser, contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bit mask of contexts where an error parser can be used. Valid values for context
|
||||
* are defined in <code>{@link ErrorParserContext}</code>.
|
||||
*
|
||||
* @param errorParserElement represents an "errorparser" element in the extension point
|
||||
* "org.eclipse.cdt.core.ErrorParser".
|
||||
* @return the contexts in which an error parser can be used, or
|
||||
* <code>{@link ErrorParserContext#BUILD BUILD}</code> is none is specified.
|
||||
* @see ErrorParserContext
|
||||
*/
|
||||
private static int contextTypes(IConfigurationElement errorParserElement) {
|
||||
IConfigurationElement[] contextElements = errorParserElement.getChildren(ELEM_CONTEXT);
|
||||
if (contextElements.length == 0) {
|
||||
return BUILD;
|
||||
}
|
||||
int contexts = 0;
|
||||
for (IConfigurationElement contextElement : contextElements) {
|
||||
String contextType = contextElement.getAttribute(ATTR_TYPE);
|
||||
contexts = contexts | ErrorParserContext.getValue(contextType);
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -581,7 +640,8 @@ public class ErrorParserExtensionManager {
|
|||
* @return internal instance of error parser
|
||||
*/
|
||||
public static IErrorParser getErrorParserInternal(String id) {
|
||||
IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
|
||||
Pair<IErrorParserNamed, Integer> pair = fAvailableErrorParsers.get(id);
|
||||
IErrorParserNamed errorParser = pair.first;
|
||||
if (errorParser instanceof ErrorParserNamedWrapper)
|
||||
return ((ErrorParserNamedWrapper)errorParser).getErrorParser();
|
||||
return errorParser;
|
||||
|
@ -626,14 +686,25 @@ public class ErrorParserExtensionManager {
|
|||
* from workspace
|
||||
*/
|
||||
public static String[] getErrorParserAvailableIds() {
|
||||
return fAvailableErrorParsers.keySet().toArray(new String[0]);
|
||||
return getErrorParserIds(fAvailableErrorParsers, BUILD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IDs of error parsers contributed through error parser extension point.
|
||||
*/
|
||||
public static String[] getErrorParserExtensionIds() {
|
||||
return fExtensionErrorParsers.keySet().toArray(new String[0]);
|
||||
return getErrorParserIds(fExtensionErrorParsers, BUILD);
|
||||
}
|
||||
|
||||
private static String[] getErrorParserIds(
|
||||
Map<String, Pair<IErrorParserNamed, Integer>> parsers, int context) {
|
||||
List<String> ids = new ArrayList<String>();
|
||||
for (Map.Entry<String, Pair<IErrorParserNamed, Integer>> entry : parsers.entrySet()) {
|
||||
if (isInContext(entry.getValue(), context)) {
|
||||
ids.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
return ids.toArray(new String[ids.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -690,8 +761,26 @@ public class ErrorParserExtensionManager {
|
|||
* shallow copy with the same instance of underlying error parser.
|
||||
*/
|
||||
public static IErrorParserNamed getErrorParserCopy(String id, boolean isExtension) {
|
||||
IErrorParserNamed errorParser = isExtension ? fExtensionErrorParsers.get(id) : fAvailableErrorParsers.get(id);
|
||||
return getErrorParserCopy(id, isExtension, BUILD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id - ID of error parser
|
||||
* @param isExtension - if {@code true} get unmodified copy of error parser defined as extension
|
||||
* @param context - context where the error parser will be used. Valid values are defined by
|
||||
* <code>{@link ErrorParserContext}</code>.
|
||||
* @return cloned copy of error parser. Note that {@link ErrorParserNamedWrapper} returns
|
||||
* shallow copy with the same instance of underlying error parser.
|
||||
* @see ErrorParserContext
|
||||
*/
|
||||
public static IErrorParserNamed getErrorParserCopy(String id, boolean isExtension,
|
||||
int context) {
|
||||
Pair<IErrorParserNamed, Integer> pair =
|
||||
isExtension ? fExtensionErrorParsers.get(id) : fAvailableErrorParsers.get(id);
|
||||
if (!isInContext(pair, context)) {
|
||||
return null;
|
||||
}
|
||||
IErrorParserNamed errorParser = pair.first;
|
||||
try {
|
||||
if (errorParser instanceof RegexErrorParser) {
|
||||
return (RegexErrorParser) ((RegexErrorParser)errorParser).clone();
|
||||
|
@ -703,5 +792,8 @@ public class ErrorParserExtensionManager {
|
|||
}
|
||||
return errorParser;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isInContext(Pair<IErrorParserNamed, Integer> pair, int context) {
|
||||
return (pair.second & context) != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Google, Inc and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alex Ruiz (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core;
|
||||
|
||||
/**
|
||||
* A pair of values.
|
||||
*/
|
||||
public class Pair<F, S> {
|
||||
public final F first;
|
||||
public final S second;
|
||||
|
||||
public Pair(F first, S second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<"); //$NON-NLS-1$
|
||||
builder.append(first);
|
||||
builder.append(">, <"); //$NON-NLS-1$
|
||||
builder.append(second);
|
||||
builder.append(">"); //$NON-NLS-1$
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue