diff --git a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF
index 76a25897400..b1ce271023e 100644
--- a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF
+++ b/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF
@@ -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
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/Activator.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/Activator.java
index 5251574a137..168bd3f2d0f 100644
--- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/Activator.java
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/Activator.java
@@ -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));
+ }
}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/AbstractExternalToolBasedChecker.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/AbstractExternalToolBasedChecker.java
new file mode 100644
index 00000000000..6797af3a3ca
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/AbstractExternalToolBasedChecker.java
@@ -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.
+ *
+ * A file, to be processed by this type of checker, must:
+ *
+ *
be in the current active editor
+ *
not have any unsaved changes
+ *
+ *
+ * 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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparator.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparator.java
new file mode 100644
index 00000000000..e3b37a83094
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparator.java
@@ -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 args = new ArrayList();
+ 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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ConfigurationSettings.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ConfigurationSettings.java
new file mode 100644
index 00000000000..a983225b6c1
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/ConfigurationSettings.java
@@ -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 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 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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/IInvocationParametersProvider.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/IInvocationParametersProvider.java
new file mode 100644
index 00000000000..6682a95305e
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/IInvocationParametersProvider.java
@@ -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;
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationFailure.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationFailure.java
new file mode 100644
index 00000000000..e37a63d13f4
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationFailure.java
@@ -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 {@link #getCause()} method.)
+ */
+ public InvocationFailure(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParameters.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParameters.java
new file mode 100644
index 00000000000..74dac3863f8
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParameters.java
@@ -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
+ * {@link #getOriginalFile()}, depending on how the external tool works.
+ *
+ * A good example is an external tool that can only process C++ source files but not header
+ * files. If the original file is a header file, the checker could potentially find
+ * a C++ file that includes such header and use it as the actual file to process.
+ *
+ *
+ * We still need to keep a reference to the actual file, in order to add markers to
+ * the editor in case of problems found.
+ *
+ * @return the actual file to process.
+ */
+ public IResource getActualFile() {
+ return actualFile;
+ }
+
+ /**
+ * Returns the path of {@link #getActualFile()}, in a format the external tool can
+ * understand.
+ * @return the path of the actual 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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParametersProvider.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParametersProvider.java
new file mode 100644
index 00000000000..486ca98d20d
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/InvocationParametersProvider.java
@@ -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 {@link InvocationParameters}
+ *
+ * @since 2.1
+ */
+public class InvocationParametersProvider implements IInvocationParametersProvider {
+ /**
+ * Creates the parameters to pass when invoking an external tool.
+ *
+ * In this implementation:
+ *
+ *
the actual file to process is the same as the original file
+ *
the path of the actual file is its absolute path in the file system
+ *
the working directory is {@code null}
+ *
+ * @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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/SingleConfigurationSetting.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/SingleConfigurationSetting.java
new file mode 100644
index 00000000000..8a0db6e63c0
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/SingleConfigurationSetting.java
@@ -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 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 {
+ private final IProblemPreferenceDescriptor descriptor;
+ private final T defaultValue;
+ private final Class 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 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());
+ }
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ArgsSetting.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ArgsSetting.java
new file mode 100644
index 00000000000..f4ee8ddc7e1
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ArgsSetting.java
@@ -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 {
+ 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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Command.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Command.java
new file mode 100644
index 00000000000..d5e9ef8d86f
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Command.java
@@ -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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/CommandBuilder.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/CommandBuilder.java
new file mode 100644
index 00000000000..2e128087367
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/CommandBuilder.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java
new file mode 100644
index 00000000000..f8726c488cc
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/ExternalToolInvoker.java
@@ -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();
+ }
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.java
new file mode 100644
index 00000000000..6cbca3443fa
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.java
@@ -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() {
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.properties b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.properties
new file mode 100644
index 00000000000..577aec794fd
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/Messages.properties
@@ -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
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/PathSetting.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/PathSetting.java
new file mode 100644
index 00000000000..adc458a4039
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/externaltool/PathSetting.java
@@ -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 {
+ 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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparatorTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparatorTest.java
new file mode 100644
index 00000000000..0623c6477a3
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cxx/externaltool/ArgsSeparatorTest.java
@@ -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 {@link ArgsSeparator}.
+ */
+@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);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF
index 332b1beefa8..3690b87d098 100644
--- a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF
+++ b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF
@@ -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,
diff --git a/codan/org.eclipse.cdt.codan.core/plugin.xml b/codan/org.eclipse.cdt.codan.core/plugin.xml
index a3af004ed87..27f4e1f212f 100644
--- a/codan/org.eclipse.cdt.codan.core/plugin.xml
+++ b/codan/org.eclipse.cdt.codan.core/plugin.xml
@@ -2,6 +2,7 @@
+
+
+
+
+
+
+
+
+ Verifies that a checker should be executed on a given resource in a given launch mode.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The fully qualified name of this extension point.
+
+
+
+
+
+
+ ID of the extension point (Simple ID).
+
+
+
+
+
+
+ Name of the extension point.
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the implementation of ICheckerEnablementVerifier to use.
+
+
+
+
+
+
+ The implementation of ICheckerEnablementVerifier to use.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.1
+
+
+
+
+
+
+
+
+ <extension point="org.eclipse.cdt.codan.core.checkerEnablement">
+ <verifier class="org.eclipse.cdt.codan.internal.ui.CheckerEnablementVerifier" />
+</extension>
+
+
+
+
+
+
+
+
+ Plug-ins that want to extend this extension point must implement org.eclipse.cdt.codan.internal.core.ICheckerEnablementVerifier interface.
+
+
+
+
+
+
+
+
+ The default implementation of this extension point is org.eclipse.cdt.codan.internal.ui.CheckerEnablementVerifier.
+
+
+
+
+
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
index 3767d9005d8..374355aedaa 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
@@ -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;
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CheckerLaunchMode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CheckerLaunchMode.java
index 4f1e7559954..677bb75051c 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CheckerLaunchMode.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/CheckerLaunchMode.java
@@ -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,
}
\ No newline at end of file
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java
index 8ef378a970d..3f1e0b66fb6 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java
@@ -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);
/**
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SharedRootProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SharedRootProblemPreference.java
new file mode 100644
index 00000000000..09f6e266a80
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SharedRootProblemPreference.java
@@ -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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java
index 1e9a97d723b..ebd6a506424 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java
@@ -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, 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, ICheckersRegistry {
private Collection checkers = new ArrayList();
private static CheckersRegistry instance;
private static boolean initialized = false;
- private HashMap
@@ -54,4 +90,17 @@
>
+
+
+
+
+
+
diff --git a/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckChecker.java b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckChecker.java
new file mode 100644
index 00000000000..c82a4d7f74b
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckChecker.java
@@ -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 Cppcheck 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 PROBLEM_IDS = new HashMap();
+
+ 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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckOutputParser.java b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckOutputParser.java
new file mode 100644
index 00000000000..c9ff4ce889e
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/CppcheckOutputParser.java
@@ -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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.java b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.java
new file mode 100644
index 00000000000..b194e9f2b4f
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.java
@@ -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 clazz = Messages.class;
+ NLS.initializeMessages(clazz.getName(), clazz);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.properties b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.properties
new file mode 100644
index 00000000000..8dda9c9c3ec
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Messages.properties
@@ -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
diff --git a/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Severity.java b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Severity.java
new file mode 100644
index 00000000000..f8f91cfda46
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.examples/src/org/eclipse/cdt/codan/examples/checkers/cppcheck/Severity.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF
index 9517be08f76..d8980d5d46d 100644
--- a/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF
+++ b/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF
@@ -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",
diff --git a/codan/org.eclipse.cdt.codan.ui/plugin.xml b/codan/org.eclipse.cdt.codan.ui/plugin.xml
index 73de0766544..9dbef631ff0 100644
--- a/codan/org.eclipse.cdt.codan.ui/plugin.xml
+++ b/codan/org.eclipse.cdt.codan.ui/plugin.xml
@@ -238,4 +238,8 @@
+
+
+
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CheckerEnablementVerifier.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CheckerEnablementVerifier.java
new file mode 100644
index 00000000000..114456dc469
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CheckerEnablementVerifier.java
@@ -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 {@link ICheckerEnablementVerifier}.
+ */
+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;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
index 0ed0f2917ce..cc8c5539b3f 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
@@ -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);
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.properties b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.properties
index 2c02d8329c7..414ab1e20e3 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.properties
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.properties
@@ -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
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/LaunchModesPropertyPage.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/LaunchModesPropertyPage.java
index 380862d445d..733f7c191c7 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/LaunchModesPropertyPage.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/LaunchModesPropertyPage.java
@@ -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();
}
@@ -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()));
}
diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
index b4582b3b0ab..9f82f059e8e 100644
--- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
@@ -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,
diff --git a/core/org.eclipse.cdt.core/schema/ErrorParser.exsd b/core/org.eclipse.cdt.core/schema/ErrorParser.exsd
index 0ab67eae5a2..d2709fa6939 100644
--- a/core/org.eclipse.cdt.core/schema/ErrorParser.exsd
+++ b/core/org.eclipse.cdt.core/schema/ErrorParser.exsd
@@ -48,6 +48,7 @@
+
@@ -147,6 +148,33 @@
+
+
+
+ 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".
+
+
+
+
+
+
+ The type of context where an error parser can be used. Valid values are "build" and "codan".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserContext.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserContext.java
new file mode 100644
index 00000000000..cbfefa9ba99
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserContext.java
@@ -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 {@link org.eclipse.cdt.core.IErrorParser}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$
+ }
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java
index ee224f5fa4c..9f39ff8e319 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java
@@ -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 fErrorParsers;
- private ArrayList fErrors;
+ private final ArrayList fErrors;
- private Vector fDirectoryStack;
+ private final Vector 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
+ * {@link ErrorParserContext}.
+ * @see ErrorParserContext
+ * @since 5.4
+ */
+ public ErrorParserManager(IProject project, URI baseDirectoryURI,
+ IMarkerGenerator markerGenerator, String[] parsersIDs, int context) {
fProject = project;
fMarkerGenerator = markerGenerator;
fDirectoryStack = new Vector();
fErrors = new ArrayList();
- 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(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
+ * {@link ErrorParserContext}.
+ * @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();
+ }
+ }
+ }
}
}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IErrorParser3.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IErrorParser3.java
new file mode 100644
index 00000000000..61bfda836ba
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IErrorParser3.java
@@ -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();
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java
index b44f270c0b5..a81a635054b 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ProblemMarkerInfo.java
@@ -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();
+ this.startChar = -1;
+ this.endChar = -1;
}
/**
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java
index df2a4d6c5bd..b3b58aa4a1a 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java
@@ -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 fExtensionErrorParsers = new LinkedHashMap();
- private static final LinkedHashMap fAvailableErrorParsers = new LinkedHashMap();
+ // Key: error parser id. Value: pair of error parser and contexts value
+ private static final LinkedHashMap> fExtensionErrorParsers = new LinkedHashMap>();
+ // Key: error parser id. Value: pair of error parser and contexts value
+ private static final LinkedHashMap> fAvailableErrorParsers = new LinkedHashMap>();
private static LinkedHashMap fUserDefinedErrorParsers = null;
private static List fDefaultErrorParserIds = null;
@@ -112,6 +122,18 @@ public class ErrorParserExtensionManager {
}
}
+ private static class ErrorParserAndContextComparator implements Comparator> {
+ private static final ErrorParserComparator DELEGATE = new ErrorParserComparator();
+
+ @Override
+ public int compare(Pair pair1,
+ Pair 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 sortedErrorParsers = new TreeSet(new ErrorParserComparator());
+ Set> sortedErrorParsers =
+ new TreeSet>(new ErrorParserAndContextComparator());
loadErrorParserExtensions(Platform.getExtensionRegistry(), sortedErrorParsers);
fExtensionErrorParsers.clear();
- for (IErrorParserNamed errorParser : sortedErrorParsers) {
- fExtensionErrorParsers.put(errorParser.getId(), errorParser);
+ for (Pair 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 errorParsers) {
+ private static void loadErrorParserExtensions(IExtensionRegistry registry,
+ Set> 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 configured =
+ configureErrorParser(errorParser, cfgEl);
+ errorParsers.add(configured);
}
}
}
@@ -254,42 +279,50 @@ public class ErrorParserExtensionManager {
List ids = new ArrayList();
if (fDefaultErrorParserIds!=null) {
for (String id : fDefaultErrorParserIds) {
+ Pair 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 sortedErrorParsers = new TreeSet(new ErrorParserComparator());
+ Set> sortedErrorParsers =
+ new TreeSet>(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 pair = fExtensionErrorParsers.get(id);
+ sortedErrorParsers.add(pair);
}
}
- for (IErrorParserNamed errorParser : sortedErrorParsers) {
- fAvailableErrorParsers.put(errorParser.getId(), errorParser);
+ for (Pair pairs : sortedErrorParsers) {
+ fAvailableErrorParsers.put(pairs.first.getId(), pairs);
}
}
+ private static Pair errorParserForBuild(IErrorParserNamed errorParser) {
+ return new Pair(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 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(errorParser, contexts);
+ }
+
+ /**
+ * Returns a bit mask of contexts where an error parser can be used. Valid values for context
+ * are defined in {@link ErrorParserContext}.
+ *
+ * @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
+ * {@link ErrorParserContext#BUILD BUILD} 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 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> parsers, int context) {
+ List ids = new ArrayList();
+ for (Map.Entry> 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
+ * {@link ErrorParserContext}.
+ * @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 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 pair, int context) {
+ return (pair.second & context) != 0;
+ }
}
diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Pair.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Pair.java
new file mode 100644
index 00000000000..3be11ee6541
--- /dev/null
+++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/internal/core/Pair.java
@@ -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 {
+ 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();
+ }
+}