From 3115bb4e228e7d1903aaba91178d7ec9742c190e Mon Sep 17 00:00:00 2001 From: Alex Ruiz Date: Thu, 23 Feb 2012 12:25:05 -0800 Subject: [PATCH] Initial take on external-tool-based checkers. --- .../META-INF/MANIFEST.MF | 4 +- .../org.eclipse.cdt.codan.checkers/plugin.xml | 36 +++ .../internal/checkers/CppcheckChecker.java | 73 ++++++ .../checkers/CppcheckOutputParser.java | 76 +++++++ .../checkers/CppcheckOutputParserFactory.java | 32 +++ .../META-INF/MANIFEST.MF | 3 +- .../cdt/codan/core/cxx/util/FileTypes.java | 68 ++++++ .../META-INF/MANIFEST.MF | 1 + .../codan/core/externaltool/ArgsSetting.java | 34 +++ .../externaltool/ConfigurationSettings.java | 114 ++++++++++ .../core/externaltool/IArgsSeparator.java | 31 +++ .../core/externaltool/ICommandInvoker.java | 39 ++++ .../IInvocationParametersProvider.java | 28 +++ .../core/externaltool/IOutputParser.java | 34 +++ .../externaltool/IOutputParserFactory.java | 29 +++ .../core/externaltool/IProblemDisplay.java | 35 +++ .../ISupportedResourceVerifier.java | 38 ++++ .../core/externaltool/InvocationFailure.java | 38 ++++ .../externaltool/InvocationParameters.java | 88 ++++++++ .../InvocationParametersProvider.java | 38 ++++ .../cdt/codan/core/externaltool/Messages.java | 30 +++ .../core/externaltool/Messages.properties | 3 + .../codan/core/externaltool/PathSetting.java | 35 +++ .../ShouldDisplayOutputSetting.java | 34 +++ .../SingleConfigurationSetting.java | 76 +++++++ .../SpaceDelimitedArgsSeparator.java | 33 +++ .../AbstractExternalToolBasedChecker.java | 209 ++++++++++++++++++ .../param/SharedRootProblemPreference.java | 27 +++ .../externaltool/ExternalToolInvoker.java | 102 +++++++++ .../META-INF/MANIFEST.MF | 3 +- .../codan/ui/cxx/externaltool/CEditors.java | 42 ++++ .../CxxSupportedResourceVerifier.java | 59 +++++ .../META-INF/MANIFEST.MF | 4 +- .../codan/internal/ui/CodanUIActivator.java | 14 +- .../cdt/codan/ui/CodanEditorUtility.java | 5 +- .../codan/ui/externaltool/CommandInvoker.java | 113 ++++++++++ .../codan/ui/externaltool/ConsolePrinter.java | 54 +++++ .../ui/externaltool/ConsolePrinterImpl.java | 81 +++++++ 38 files changed, 1756 insertions(+), 7 deletions(-) create mode 100644 codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckChecker.java create mode 100644 codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParser.java create mode 100644 codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParserFactory.java create mode 100644 codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/util/FileTypes.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ArgsSetting.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ConfigurationSettings.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IArgsSeparator.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ICommandInvoker.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IInvocationParametersProvider.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParser.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParserFactory.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IProblemDisplay.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ISupportedResourceVerifier.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationFailure.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParameters.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParametersProvider.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.properties create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/PathSetting.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ShouldDisplayOutputSetting.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SingleConfigurationSetting.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SpaceDelimitedArgsSeparator.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractExternalToolBasedChecker.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SharedRootProblemPreference.java create mode 100644 codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/externaltool/ExternalToolInvoker.java create mode 100644 codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CEditors.java create mode 100644 codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CxxSupportedResourceVerifier.java create mode 100644 codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/CommandInvoker.java create mode 100644 codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinter.java create mode 100644 codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinterImpl.java diff --git a/codan/org.eclipse.cdt.codan.checkers/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.checkers/META-INF/MANIFEST.MF index 927ef1364fe..016debe39c0 100644 --- a/codan/org.eclipse.cdt.codan.checkers/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.checkers/META-INF/MANIFEST.MF @@ -8,7 +8,9 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources;bundle-version="3.5.0", org.eclipse.cdt.codan.core;bundle-version="1.0.0", org.eclipse.cdt.core;bundle-version="5.1.0", - org.eclipse.cdt.codan.core.cxx;bundle-version="1.0.0" + org.eclipse.cdt.codan.core.cxx;bundle-version="1.0.0", + org.eclipse.cdt.codan.ui.cxx;bundle-version="3.0.0", + org.eclipse.cdt.codan.ui;bundle-version="2.0.1" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-Vendor: %Bundle-Vendor diff --git a/codan/org.eclipse.cdt.codan.checkers/plugin.xml b/codan/org.eclipse.cdt.codan.checkers/plugin.xml index 0f3f1c76678..944b52af252 100644 --- a/codan/org.eclipse.cdt.codan.checkers/plugin.xml +++ b/codan/org.eclipse.cdt.codan.checkers/plugin.xml @@ -398,5 +398,41 @@ name="%problem.name.ClassMembersInitialization"> + + + + + + + + + + diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckChecker.java new file mode 100644 index 00000000000..607b5cd7773 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckChecker.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.checkers; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.codan.core.externaltool.ConfigurationSettings; +import org.eclipse.cdt.codan.core.externaltool.InvocationParametersProvider; +import org.eclipse.cdt.codan.core.externaltool.SpaceDelimitedArgsSeparator; +import org.eclipse.cdt.codan.core.model.AbstractExternalToolBasedChecker; +import org.eclipse.cdt.codan.core.model.IProblemLocation; +import org.eclipse.cdt.codan.ui.cxx.externaltool.CxxSupportedResourceVerifier; +import org.eclipse.cdt.codan.ui.externaltool.CommandInvoker; + +/** + * Checker that invokes Cppcheck when a C/C++ is + * saved. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CppcheckChecker extends AbstractExternalToolBasedChecker { + private static final String TOOL_NAME = "Cppcheck"; //$NON-NLS-1$ + private static final String EXECUTABLE_NAME = "cppcheck"; //$NON-NLS-1$ + private static final String DEFAULT_ARGS = ""; //$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("error"); //$NON-NLS-1$ + addProblemId("warning"); //$NON-NLS-1$ + addProblemId("style"); //$NON-NLS-1$ + } + private static String addProblemId(String severity) { + String problemId = "org.eclipse.cdt.codan.checkers.cppcheck." + severity; //$NON-NLS-1$ + PROBLEM_IDS.put(severity, problemId); + return problemId; + } + + public CppcheckChecker() { + super(new InvocationParametersProvider(), new CxxSupportedResourceVerifier(), + new SpaceDelimitedArgsSeparator(), new CommandInvoker(), + new CppcheckOutputParserFactory(), + new ConfigurationSettings(TOOL_NAME, new File(EXECUTABLE_NAME), DEFAULT_ARGS)); + } + + @Override + public void reportProblem(IProblemLocation location, String description, String severity) { + String problemId = PROBLEM_IDS.get(severity); + if (problemId == null) { + problemId = getReferenceProblemId(); + } + super.reportProblem(problemId, location, String.format(DESCRIPTION_FORMAT, description)); + } + + @Override + protected String getReferenceProblemId() { + return ERROR_PROBLEM_ID; + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParser.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParser.java new file mode 100644 index 00000000000..96a27e62867 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParser.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.checkers; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.codan.core.CodanRuntime; +import org.eclipse.cdt.codan.core.externaltool.IOutputParser; +import org.eclipse.cdt.codan.core.externaltool.IProblemDisplay; +import org.eclipse.cdt.codan.core.externaltool.InvocationParameters; +import org.eclipse.cdt.codan.core.model.IProblemLocation; +import org.eclipse.cdt.codan.core.model.IProblemLocationFactory; +import org.eclipse.core.resources.IFile; + +/** + * Parses the output of Cppcheck. + * + * @author alruiz@google.com (Alex Ruiz) + */ +class CppcheckOutputParser implements IOutputParser { + // the pattern for parsing the message is: + // + // [/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$ + + private final InvocationParameters parameters; + private final IProblemDisplay problemDisplay; + + CppcheckOutputParser(InvocationParameters parameters, IProblemDisplay problemDisplay) { + this.parameters = parameters; + this.problemDisplay = problemDisplay; + } + + @Override + public boolean parse(String line) { + Matcher matcher = pattern.matcher(line); + if (!matcher.matches()) { + return false; + } + String filePath = matcher.group(1); + if (parameters.getActualFilePath().equals(filePath)) { + int lineNumber = Integer.parseInt(matcher.group(2)); + String severity = matcher.group(3); + String description = matcher.group(4); + IProblemLocation location = createProblemLocation(lineNumber); + problemDisplay.reportProblem(location, description, severity); + } + return true; + } + + private IProblemLocation createProblemLocation(int lineNumber) { + IProblemLocationFactory factory = CodanRuntime.getInstance().getProblemLocationFactory(); + IFile actualFile = (IFile) parameters.getActualFile(); + return factory.createProblemLocation(actualFile, -1, -1, lineNumber); + } + + @Override + public void reset() {} +} diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParserFactory.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParserFactory.java new file mode 100644 index 00000000000..f29f58ba2fc --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CppcheckOutputParserFactory.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.checkers; + +import static java.util.Collections.singletonList; + +import java.util.List; + +import org.eclipse.cdt.codan.core.externaltool.IOutputParser; +import org.eclipse.cdt.codan.core.externaltool.IOutputParserFactory; +import org.eclipse.cdt.codan.core.externaltool.IProblemDisplay; +import org.eclipse.cdt.codan.core.externaltool.InvocationParameters; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +class CppcheckOutputParserFactory implements IOutputParserFactory { + @Override + public List createParsers(InvocationParameters parameters, + IProblemDisplay problemDisplay) { + IOutputParser parser = new CppcheckOutputParser(parameters, problemDisplay); + return singletonList(parser); + } +} 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 5ae26879718..e62db6bffce 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 @@ -12,6 +12,7 @@ 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.model + org.eclipse.cdt.codan.core.cxx.model, + org.eclipse.cdt.codan.core.cxx.util 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/util/FileTypes.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/util/FileTypes.java new file mode 100644 index 00000000000..819a5c42a45 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/util/FileTypes.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.cxx.util; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +/** + * Utility methods related to C++ file types. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public final class FileTypes { + private static final String[] CPP_FILE_EXTENSIONS = { + "cc", //$NON-NLS-1$ + "cpp", //$NON-NLS-1$ + "cxx" //$NON-NLS-1$ + }; + private static final String[] HEADER_FILE_EXTENSIONS = { "h" }; //$NON-NLS-1$ + + /** + * Indicates whether the given {@link IResource} is a C++ file. + * @param resource the {@code IResource} to check. + * @return {@code true} if the given {@code IResource} is a C++ file; {@code false} otherwise. + */ + public static boolean isCppFile(IResource resource) { + return isFileWithExtension(resource, CPP_FILE_EXTENSIONS); + } + + /** + * Indicates whether the given {@link IResource} is a header file. + * @param resource the {@code IResource} to check. + * @return {@code true} if the given {@code IResource} is a header file; {@code false} + * otherwise. + */ + public static boolean isHeaderFile(IResource resource) { + return isFileWithExtension(resource, HEADER_FILE_EXTENSIONS); + } + + private static boolean isFileWithExtension(IResource resource, String[] validExtensions) { + if (!(resource instanceof IFile)) { + return false; + } + IPath path = resource.getFullPath(); + return doesPathHaveExtension(path, validExtensions); + } + + private static boolean doesPathHaveExtension(IPath path, String[] validExtensions) { + String fileExtension = path.getFileExtension(); + for (String extension : validExtensions) { + if (extension.equalsIgnoreCase(fileExtension)) { + return true; + } + } + return false; + } + + private FileTypes() {} +} 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 674cf7b6a00..3f2598e76bd 100644 --- a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF @@ -10,6 +10,7 @@ Require-Bundle: org.eclipse.core.runtime, Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Export-Package: org.eclipse.cdt.codan.core, + org.eclipse.cdt.codan.core.externaltool, org.eclipse.cdt.codan.core.model, org.eclipse.cdt.codan.core.model.cfg;x-friends:="org.eclipse.cdt.codan.core.cxx,org.eclipse.cdt.codan.checkers", org.eclipse.cdt.codan.core.param, diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ArgsSetting.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ArgsSetting.java new file mode 100644 index 00000000000..311b04b7622 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ArgsSetting.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import static org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType.TYPE_STRING; + +import org.eclipse.cdt.codan.core.param.BasicProblemPreference; + +/** + * User-configurable setting that specifies the arguments to pass when invoking the external tool. + * The arguments are stored in a single {@code String}. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ArgsSetting extends SingleConfigurationSetting { + private static final String KEY = "externalToolArgs"; //$NON-NLS-1$ + + /** + * Constructor. + * @param label the label to be displayed in the UI. + * @param defaultValue the default value of the setting. + */ + public ArgsSetting(String label, String defaultValue) { + super(new BasicProblemPreference(KEY, label, TYPE_STRING), defaultValue, String.class); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ConfigurationSettings.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ConfigurationSettings.java new file mode 100644 index 00000000000..62cb816756e --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ConfigurationSettings.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import static org.eclipse.cdt.codan.core.externaltool.Messages.ConfigurationSettings_args_format; +import static org.eclipse.cdt.codan.core.externaltool.Messages.ConfigurationSettings_path_format; +import static org.eclipse.cdt.codan.core.externaltool.Messages.ConfigurationSettings_should_display_output; + +import java.io.File; + +import org.eclipse.cdt.codan.core.param.MapProblemPreference; + +/** + * User-configurable external tool settings. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ConfigurationSettings { + private final PathSetting path; + private final ArgsSetting args; + private final ShouldDisplayOutputSetting shouldDisplayOutput; + private final String externalToolName; + + /** + * Constructor. + *

+ * Note: this constructor uses {@code false} as the default value of the + * {@link ShouldDisplayOutputSetting} to create. + *

+ * @param externalToolName the name of the external tool, to be displayed to the user. + * @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; + String pathLabel = String.format(ConfigurationSettings_path_format, externalToolName); + this.path = new PathSetting(pathLabel, defaultPath); + String argsLabel = String.format(ConfigurationSettings_args_format, externalToolName); + this.args = new ArgsSetting(argsLabel, defaultArgs); + String shouldDisplayOutputLabel = ConfigurationSettings_should_display_output; + this.shouldDisplayOutput = new ShouldDisplayOutputSetting(shouldDisplayOutputLabel, false); + } + + /** + * Constructor. + * @param externalToolName the name of the external tool, to be displayed to the user. + * @param path specifies the path and name of the external tool to invoke. + * @param args specifies the arguments to pass when invoking the external tool. + * @param shouldDisplayOutput specifies whether the output of the external tools should be + * displayed in an Eclipse console. + */ + public ConfigurationSettings(String externalToolName, PathSetting path, ArgsSetting args, + ShouldDisplayOutputSetting shouldDisplayOutput) { + this.externalToolName = externalToolName; + this.path = path; + this.args = args; + this.shouldDisplayOutput = shouldDisplayOutput; + } + + /** + * 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 PathSetting 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 ArgsSetting getArgs() { + return args; + } + + /** + * Returns the setting that specifies whether the output of the external tools should be + * displayed in an Eclipse console. + * @return the shouldDisplayOutput the setting that specifies whether the output of the external + * tools should be displayed in an Eclipse console. + */ + public ShouldDisplayOutputSetting getShouldDisplayOutput() { + return shouldDisplayOutput; + } + + /** + * 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); + shouldDisplayOutput.updateValue(preferences); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IArgsSeparator.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IArgsSeparator.java new file mode 100644 index 00000000000..5c687a1fa35 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IArgsSeparator.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +/** + * Parses and separates the value of an {@link ArgsSetting} into an array of + * {@code String}s. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public interface IArgsSeparator { + /** + * Indicates that there are no arguments to pass to the external tool executable. + */ + String[] NO_ARGS = new String[0]; + + /** + * Parses and separates the given value. + * @param args contains the arguments to pass to the external tool executable. + * @return the separated argument values. + */ + String[] separateArgs(String args); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ICommandInvoker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ICommandInvoker.java new file mode 100644 index 00000000000..37e98361a11 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ICommandInvoker.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +/** + * @author alruiz@google.com (Alex Ruiz) + * + */ +public interface ICommandInvoker { + /** + * Builds and launches the command necessary to invoke an external tool. + * @param project the current project. + * @param externalToolName the name of the external tool. + * @param executablePath the path and name of the external tool executable. + * @param args the arguments to pass to the external tool executable. + * @param workingDirectory the directory where the external tool should be executed. + * @param shouldDisplayOutput indicates whether the output of the external tools should be + * displayed in an Eclipse console. + * @param parsers parse the output of the external tool. + * @throws InvocationFailure if the external tool reports that it cannot be executed. + * @throws Throwable if the external tool cannot be launched. + */ + void buildAndLaunchCommand(IProject project, String externalToolName, IPath executablePath, + String[] args, IPath workingDirectory, boolean shouldDisplayOutput, + List parsers) throws InvocationFailure, Throwable; +} \ No newline at end of file diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IInvocationParametersProvider.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IInvocationParametersProvider.java new file mode 100644 index 00000000000..b2d6bb2b3e6 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IInvocationParametersProvider.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.core.resources.IResource; + +/** + * Provides the parameters to pass when invoking an external tool. + * + * @author alruiz@google.com (Alex Ruiz) + */ +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/src/org/eclipse/cdt/codan/core/externaltool/IOutputParser.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParser.java new file mode 100644 index 00000000000..ddd460cb274 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParser.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +/** + * Parses the output of an external tool. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public interface IOutputParser { + /** + * Parses one line of output. Implementations are free to create markers from the information + * retrieved from the parsed output. + * @param line the line to parse. + * @return {@code true} if the line was successfully parsed; {@code false} otherwise. + * @throws InvocationFailure if the output indicates that the invocation of the external tool + * failed. + */ + boolean parse(String line) throws InvocationFailure; + + /** + * Resets the value of this parser, usually after the execution of the external tool is + * finished. + */ + void reset(); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParserFactory.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParserFactory.java new file mode 100644 index 00000000000..008bb5ba1dc --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IOutputParserFactory.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import java.util.List; + +/** + * Factory of instances of {@link IOutputParser}. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public interface IOutputParserFactory { + /** + * Creates instances of {@link IOutputParser}. + * @param parameters the parameters to pass when invoking an external tool. + * @param problemDisplay displays problems found by the external tool. + * @return the created parsers. + */ + List createParsers(InvocationParameters parameters, + IProblemDisplay problemDisplay); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IProblemDisplay.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IProblemDisplay.java new file mode 100644 index 00000000000..a4a054d7478 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/IProblemDisplay.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.cdt.codan.core.model.IProblemLocation; + +/** + * Reports problems found in code, reported by an external tool. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public interface IProblemDisplay { + /** + * Reports a problem found by an external tool. + * @param location the problem's location (e.g. file and line number.) + * @param description the description of the problem. + */ + void reportProblem(IProblemLocation location, String description); + + /** + * Reports a problem found by an external tool. + * @param location the problem's location (e.g. file and line number.) + * @param description the description of the problem. + * @param severity the problem's severity (e.g. "error", "warning", etc.) + */ + void reportProblem(IProblemLocation location, String description, String severity); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ISupportedResourceVerifier.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ISupportedResourceVerifier.java new file mode 100644 index 00000000000..210ac8d326f --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ISupportedResourceVerifier.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; + +/** + * Verifies that a {@link IResource} can be processed by an external tool. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public interface ISupportedResourceVerifier { + /** + * Indicates whether the external tool is capable of processing the given + * {@link IResource}. + *

+ * The minimum requirements that the given {@code IResource} should satisfy are: + *

    + *
  • should be an {@link IFile}
  • + *
  • should be displayed in the current active editor
  • + *
  • should not have any unsaved changes
  • + *
+ *

+ * @param resource the given {@code IResource}. + * @return {@code true} if the external tool is capable of processing the given file, + * {@code false} otherwise. + */ + boolean isSupported(IResource resource); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationFailure.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationFailure.java new file mode 100644 index 00000000000..4e9236bf218 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationFailure.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +/** + * Indicates that invocation of an external tool failed. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class InvocationFailure extends Exception { + private static final long serialVersionUID = 1L; + + /** + * 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/src/org/eclipse/cdt/codan/core/externaltool/InvocationParameters.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParameters.java new file mode 100644 index 00000000000..118886e21ad --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParameters.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +/** + * Parameters to pass when invoking an external tool. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public 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 #getActualFile()}, depending on how the external tool works. + *

+ * A good example is an external tool that can only process C++ files but 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/src/org/eclipse/cdt/codan/core/externaltool/InvocationParametersProvider.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParametersProvider.java new file mode 100644 index 00000000000..b5fc6867f2b --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/InvocationParametersProvider.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.core.resources.IResource; + +/** + * Default implementation of {@link InvocationParameters} + * + * @author alruiz@google.com (Alex Ruiz) + */ +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/src/org/eclipse/cdt/codan/core/externaltool/Messages.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.java new file mode 100644 index 00000000000..c3f391382f4 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import org.eclipse.osgi.util.NLS; + +/** + * @author alruiz@google.com (Alex Ruiz) + */ +@SuppressWarnings("javadoc") +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 { + Class clazz = Messages.class; + NLS.initializeMessages(clazz.getName(), clazz); + } + + private Messages() {} +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.properties b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.properties new file mode 100644 index 00000000000..fefe189a583 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/Messages.properties @@ -0,0 +1,3 @@ +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/src/org/eclipse/cdt/codan/core/externaltool/PathSetting.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/PathSetting.java new file mode 100644 index 00000000000..fb11bd6d5a5 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/PathSetting.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import static org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType.TYPE_FILE; + +import java.io.File; + +import org.eclipse.cdt.codan.core.param.BasicProblemPreference; + +/** + * User-configurable setting that specifies the path and name of an external tool's executable. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class PathSetting extends SingleConfigurationSetting { + private static final String KEY = "externalToolPath"; //$NON-NLS-1$ + + /** + * Constructor. + * @param label the label to be displayed in the UI. + * @param defaultValue the default value of the setting. + */ + public PathSetting(String label, File defaultValue) { + super(new BasicProblemPreference(KEY, label, TYPE_FILE), defaultValue, File.class); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ShouldDisplayOutputSetting.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ShouldDisplayOutputSetting.java new file mode 100644 index 00000000000..6ffb934dc8d --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/ShouldDisplayOutputSetting.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import static org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType.TYPE_BOOLEAN; + +import org.eclipse.cdt.codan.core.param.BasicProblemPreference; + +/** + * User-configurable setting that specifies whether the output of an external tool should be + * displayed in an Eclipse console. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ShouldDisplayOutputSetting extends SingleConfigurationSetting { + private static final String KEY = "externalToolShouldDisplayOutput"; //$NON-NLS-1$ + + /** + * Constructor. + * @param label the label to be displayed in the UI. + * @param defaultValue the default value of the setting. + */ + public ShouldDisplayOutputSetting(String label, boolean defaultValue) { + super(new BasicProblemPreference(KEY, label, TYPE_BOOLEAN), defaultValue, Boolean.class); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SingleConfigurationSetting.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SingleConfigurationSetting.java new file mode 100644 index 00000000000..6c795b4c758 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SingleConfigurationSetting.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +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. + * + * @author alruiz@google.com (Alex Ruiz) + */ +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) { + Object o = preferences.getChildValue(descriptor.getKey()); + value = valueType.cast(o); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SpaceDelimitedArgsSeparator.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SpaceDelimitedArgsSeparator.java new file mode 100644 index 00000000000..0a79dbcf624 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/externaltool/SpaceDelimitedArgsSeparator.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.externaltool; + +import java.util.regex.Pattern; + +/** + * Separates the value of an {@link ArgsSetting} using an empty space as delimiter. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class SpaceDelimitedArgsSeparator implements IArgsSeparator { + private static final Pattern EMPTY_SPACE_PATTERN = Pattern.compile("\\s+"); //$NON-NLS-1$ + + /** + * {@inheritDoc} + */ + @Override + public String[] separateArgs(String args) { + if (args == null || args.isEmpty()) { + return NO_ARGS; + } + return EMPTY_SPACE_PATTERN.split(args); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractExternalToolBasedChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractExternalToolBasedChecker.java new file mode 100644 index 00000000000..928465eda14 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractExternalToolBasedChecker.java @@ -0,0 +1,209 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package org.eclipse.cdt.codan.core.model; + +import java.util.List; + +import org.eclipse.cdt.codan.core.CodanCorePlugin; +import org.eclipse.cdt.codan.core.externaltool.ConfigurationSettings; +import org.eclipse.cdt.codan.core.externaltool.IArgsSeparator; +import org.eclipse.cdt.codan.core.externaltool.ICommandInvoker; +import org.eclipse.cdt.codan.core.externaltool.IInvocationParametersProvider; +import org.eclipse.cdt.codan.core.externaltool.IOutputParser; +import org.eclipse.cdt.codan.core.externaltool.IOutputParserFactory; +import org.eclipse.cdt.codan.core.externaltool.IProblemDisplay; +import org.eclipse.cdt.codan.core.externaltool.ISupportedResourceVerifier; +import org.eclipse.cdt.codan.core.externaltool.InvocationFailure; +import org.eclipse.cdt.codan.core.externaltool.InvocationParameters; +import org.eclipse.cdt.codan.core.externaltool.SingleConfigurationSetting; +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.codan.internal.core.externaltool.ExternalToolInvoker; +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: + *

    + *
  1. be in the current active editor
  2. + *
  3. not have any unsaved changes
  4. + *
+ *

+ * By default, implementations of this checker are not enable to run while the user types, since + * external tools cannot see unsaved changes. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public abstract class AbstractExternalToolBasedChecker extends AbstractCheckerWithProblemPreferences + implements IProblemDisplay { + private static final boolean DO_NOT_TRAVERSE_CHILDREN = false; + + private final IInvocationParametersProvider parametersProvider; + private final ISupportedResourceVerifier supportedResourceVerifier; + private final IArgsSeparator argsSeparator; + private final IOutputParserFactory outputParserFactory; + private final ConfigurationSettings configurationSettings; + private final ExternalToolInvoker externalToolInvoker; + private final RootProblemPreference preferences; + + /** + * Constructor. + * @param parametersProvider provides the parameters to pass when invoking the external tool. + * @param supportedResourceVerifier indicates whether a resource can be processed by 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 commandInvoker builds and launches the command necessary to invoke the external tool. + * @param outputParserFactory creates parsers for the output of the external tool. + * @param configurationSettings user-configurable external tool configuration settings. + */ + public AbstractExternalToolBasedChecker(IInvocationParametersProvider parametersProvider, + ISupportedResourceVerifier supportedResourceVerifier, IArgsSeparator argsSeparator, + ICommandInvoker commandInvoker, IOutputParserFactory outputParserFactory, + ConfigurationSettings configurationSettings) { + this.parametersProvider = parametersProvider; + this.supportedResourceVerifier = supportedResourceVerifier; + this.argsSeparator = argsSeparator; + this.outputParserFactory = outputParserFactory; + this.configurationSettings = configurationSettings; + externalToolInvoker = new ExternalToolInvoker(commandInvoker); + preferences = new SharedRootProblemPreference(); + } + + /** + * Indicates whether this checker can process the given resource. For more details, please + * see {@link ISupportedResourceVerifier#isSupported(IResource)}. + * @param resource the given resource. + * @return {@code true} if this checker can process the given resource, {@code false} otherwise. + */ + @Override + public boolean enabledInContext(IResource resource) { + return supportedResourceVerifier.isSupported(resource); + } + + /** + * Indicates whether this checker is enabled to run while the user types. By default, this + * method returns {@code false}. + *

+ * Running command-line based checkers while the user types is unnecessary and wasteful, since + * command-line tools are expensive to call (they run in a separate process) and they cannot + * see unsaved changes. + *

+ * @return {@code false}. + */ + @Override + public boolean runInEditor() { + return false; + } + + @Override + public boolean processResource(IResource resource) { + process(resource); + return DO_NOT_TRAVERSE_CHILDREN; + } + + 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()); + List parsers = outputParserFactory.createParsers(parameters, this); + try { + externalToolInvoker.invoke(parameters, configurationSettings, argsSeparator, parsers); + } catch (InvocationFailure error) { + handleInvocationFailure(error, parameters); + } + } + + private void updateConfigurationSettingsFromPreferences(IResource fileToProcess) { + IProblem problem = getProblemById(getReferenceProblemId(), fileToProcess); + MapProblemPreference preferences = (MapProblemPreference) problem.getPreference(); + configurationSettings.updateValuesFrom(preferences); + } + + /** + * 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$ + CodanCorePlugin.log(msg, error); + } + + /** {@inheritDoc} */ + @Override + public void reportProblem(IProblemLocation location, String description) { + String severity = null; + reportProblem(location, description, severity); + } + + /** {@inheritDoc} */ + @Override + public void reportProblem(IProblemLocation location, String description, String severity) { + super.reportProblem(getReferenceProblemId(), location, description); + } + + /** + * 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(); + + /** + * Initializes the preferences of the given problem. All preferences in a external-tool-based + * checker are shared among its defined problems. + * @param problem the given problem. + */ + @Override + public void initPreferences(IProblemWorkingCopy problem) { + super.initPreferences(problem); + addPreference(problem, configurationSettings.getPath()); + addPreference(problem, configurationSettings.getArgs()); + addPreference(problem, configurationSettings.getShouldDisplayOutput()); + } + + private void addPreference(IProblemWorkingCopy problem, SingleConfigurationSetting setting) { + IProblemPreference descriptor = (IProblemPreference) setting.getDescriptor(); + addPreference(problem, descriptor, setting.getDefaultValue()); + } + + /** {@inheritDoc} */ + @Override + protected void setDefaultPreferenceValue(IProblemWorkingCopy problem, String key, + Object defaultValue) { + MapProblemPreference map = getTopLevelPreference(problem); + map.setChildValue(key, defaultValue); + } + + /** {@inheritDoc} */ + @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; + } +} 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..dea9e27f01e --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/SharedRootProblemPreference.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.param; + + +/** + * Preferences that can be shared among several problems. + * + * @author alruiz@google.com (Alex Ruiz) + */ +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/externaltool/ExternalToolInvoker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/externaltool/ExternalToolInvoker.java new file mode 100644 index 00000000000..e5aa17f23a4 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/externaltool/ExternalToolInvoker.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.externaltool; + +import java.io.File; +import java.util.List; + +import org.eclipse.cdt.codan.core.externaltool.ConfigurationSettings; +import org.eclipse.cdt.codan.core.externaltool.IArgsSeparator; +import org.eclipse.cdt.codan.core.externaltool.ICommandInvoker; +import org.eclipse.cdt.codan.core.externaltool.IOutputParser; +import org.eclipse.cdt.codan.core.externaltool.InvocationFailure; +import org.eclipse.cdt.codan.core.externaltool.InvocationParameters; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +/** + * Invokes an external tool to perform checks on a single file. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class ExternalToolInvoker { + private final ICommandInvoker commandInvoker; + + /** + * Constructor. + * @param commandInvoker builds and launches the command necessary to invoke the external tool. + */ + public ExternalToolInvoker(ICommandInvoker commandInvoker) { + this.commandInvoker = commandInvoker; + } + + /** + * Invokes an external tool. + * @param parameters the parameters to pass to the external tool executable. + * @param configurationSettings 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 reports that it cannot be executed. + * @throws Throwable if the external tool cannot be launched. + */ + public void invoke(InvocationParameters parameters, ConfigurationSettings configurationSettings, + IArgsSeparator argsSeparator, List parsers) throws InvocationFailure, + Throwable { + IPath executablePath = executablePath(configurationSettings); + String[] args = argsToPass(parameters, configurationSettings, argsSeparator); + boolean shouldDisplayOutput = configurationSettings.getShouldDisplayOutput().getValue(); + IProject project = parameters.getActualFile().getProject(); + try { + commandInvoker.buildAndLaunchCommand(project, + configurationSettings.getExternalToolName(), executablePath, args, + parameters.getWorkingDirectory(), shouldDisplayOutput, parsers); + } finally { + reset(parsers); + } + } + + private IPath executablePath(ConfigurationSettings configurationSettings) { + File executablePath = configurationSettings.getPath().getValue(); + return new Path(executablePath.toString()); + } + + private String[] argsToPass(InvocationParameters parameters, + ConfigurationSettings configurationSettings, IArgsSeparator argsSeparator) { + String[] configuredArgs = configuredArgs(configurationSettings, argsSeparator); + String actualFilePath = parameters.getActualFilePath(); + return addFilePathToArgs(actualFilePath, configuredArgs); + } + + private String[] configuredArgs(ConfigurationSettings configurationSettings, + IArgsSeparator argsSeparator) { + String args = configurationSettings.getArgs().getValue(); + return argsSeparator.separateArgs(args); + } + + private String[] addFilePathToArgs(String actualFilePath, String[] configuredArgs) { + int argCount = configuredArgs.length; + String[] allArgs = new String[argCount + 1]; + // add file to process as the first argument + allArgs[0] = actualFilePath; + for (int i = 0; i < argCount; i++) { + allArgs[i + 1] = configuredArgs[i]; + } + return allArgs; + } + + private void reset(List parsers) { + for (IOutputParser parser : parsers) { + parser.reset(); + } + } +} diff --git a/codan/org.eclipse.cdt.codan.ui.cxx/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.ui.cxx/META-INF/MANIFEST.MF index abedd163a05..80bc1e757d1 100644 --- a/codan/org.eclipse.cdt.codan.ui.cxx/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.ui.cxx/META-INF/MANIFEST.MF @@ -19,4 +19,5 @@ Require-Bundle: org.eclipse.ui, Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.cdt.codan.internal.ui.cxx;x-internal:=true, - org.eclipse.cdt.codan.ui + org.eclipse.cdt.codan.ui, + org.eclipse.cdt.codan.ui.cxx.externaltool diff --git a/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CEditors.java b/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CEditors.java new file mode 100644 index 00000000000..b9b3c9e902d --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CEditors.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.ui.cxx.externaltool; + +import org.eclipse.cdt.internal.ui.editor.CEditor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.editors.text.TextEditor; + +/** + * Utility methods related to {@link CEditor}. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@SuppressWarnings("restriction") // CEditor is internal API +final class CEditors { + + static TextEditor activeCEditor() { + IWorkbench workbench = PlatformUI.getWorkbench(); + for (IWorkbenchWindow w : workbench.getWorkbenchWindows()) { + IWorkbenchPage activePage = w.getActivePage(); + IEditorPart editor = activePage.getActiveEditor(); + if (editor instanceof CEditor) { + return (CEditor) editor; + } + } + return null; + } + + private CEditors() {} +} diff --git a/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CxxSupportedResourceVerifier.java b/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CxxSupportedResourceVerifier.java new file mode 100644 index 00000000000..4667d3b9731 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cxx/src/org/eclipse/cdt/codan/ui/cxx/externaltool/CxxSupportedResourceVerifier.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.ui.cxx.externaltool; + +import static org.eclipse.cdt.codan.core.cxx.util.FileTypes.isCppFile; +import static org.eclipse.cdt.codan.core.cxx.util.FileTypes.isHeaderFile; +import static org.eclipse.cdt.codan.ui.CodanEditorUtility.isResourceOpenInEditor; +import static org.eclipse.cdt.codan.ui.cxx.externaltool.CEditors.activeCEditor; + +import org.eclipse.cdt.codan.core.externaltool.ISupportedResourceVerifier; +import org.eclipse.core.resources.IResource; +import org.eclipse.ui.editors.text.TextEditor; + +/** + * Implemenation of {@link ISupportedResourceVerifier} for C/C++ files. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CxxSupportedResourceVerifier implements ISupportedResourceVerifier { + /** + * Indicates whether the external tool is capable of processing the given + * {@link IResource}. + *

+ * The minimum requirements that the given {@code IResource} should satisfy are: + *

    + *
  • should be C/C++ file
  • + *
  • should be displayed in the current active {@code CEditor}
  • + *
  • should not have any unsaved changes
  • + *
+ *

+ * @param resource the given {@code IResource}. + * @return {@code true} if the external tool is capable of processing the given file, + * {@code false} otherwise. + */ + @Override + public boolean isSupported(IResource resource) { + return isFileOfSupportedType(resource) && isOpenInActiveCEditor(resource); + } + + private boolean isFileOfSupportedType(IResource resource) { + return isCppFile(resource) || isHeaderFile(resource); + } + + private boolean isOpenInActiveCEditor(IResource resource) { + TextEditor activeCEditor = activeCEditor(); + if (activeCEditor == null) { + return false; + } + return !activeCEditor.isDirty() && isResourceOpenInEditor(resource, activeCEditor); + } +} 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 af09ae68a77..f915a5f0dd0 100644 --- a/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.ui/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.jface.text, org.eclipse.ui.ide, org.eclipse.cdt.ui, - org.eclipse.core.filesystem + org.eclipse.core.filesystem, + org.eclipse.ui.console;bundle-version="3.5.100" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.cdt.codan.internal.ui;x-friends:="org.eclipse.cdt.codan.ui.cxx", @@ -23,5 +24,6 @@ Export-Package: org.eclipse.cdt.codan.internal.ui;x-friends:="org.eclipse.cdt.co org.eclipse.cdt.codan.internal.ui.views;x-internal:=true, org.eclipse.cdt.codan.internal.ui.widgets;x-internal:=true, org.eclipse.cdt.codan.ui, + org.eclipse.cdt.codan.ui.externaltool, org.eclipse.cdt.codan.ui.handlers diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIActivator.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIActivator.java index fcd4c9049b6..20800ee4011 100644 --- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIActivator.java +++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIActivator.java @@ -83,7 +83,7 @@ public class CodanUIActivator extends AbstractUIPlugin { } /** - * Logs an internal error with the specified throwable + * Logs an internal error with the specified {@code Throwable}. * * @param e * the exception to be logged @@ -102,6 +102,18 @@ public class CodanUIActivator extends AbstractUIPlugin { 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 e + * the exception to be logged + */ + public static void log(String message, Throwable e) { + log(new Status(IStatus.ERROR, PLUGIN_ID, 1, message, e)); + } + /** * @return */ diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/CodanEditorUtility.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/CodanEditorUtility.java index 8c5c40e8c51..7cb3830985c 100644 --- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/CodanEditorUtility.java +++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/CodanEditorUtility.java @@ -158,9 +158,10 @@ public class CodanEditorUtility { } /** - * @return + * Returns the active workbench page. + * @return the active workbench page, or {@code null} if none can be found. */ - private static IWorkbenchPage getActivePage() { + public static IWorkbenchPage getActivePage() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (activeWorkbenchWindow == null) return null; diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/CommandInvoker.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/CommandInvoker.java new file mode 100644 index 00000000000..5140080c4bf --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/CommandInvoker.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.ui.externaltool; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; + +import org.eclipse.cdt.codan.core.externaltool.ICommandInvoker; +import org.eclipse.cdt.codan.core.externaltool.IOutputParser; +import org.eclipse.cdt.codan.core.externaltool.InvocationFailure; +import org.eclipse.cdt.codan.internal.ui.CodanUIActivator; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.ui.PartInitException; + +/** + * Invokes an external tool command. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class CommandInvoker implements ICommandInvoker { + private static final String[] ENVIRONMENT_VARIABLE_SETTINGS = {}; + + @Override + public void buildAndLaunchCommand(IProject project, String externalToolName, + IPath executablePath, String[] args, IPath workingDirectory, boolean shouldDisplayOutput, + List parsers) throws InvocationFailure, Throwable { + ConsolePrinter consolePrinter = consolePrinter(externalToolName, shouldDisplayOutput); + String command = buildCommand(executablePath, args); + Process process = null; + try { + consolePrinter.clear(); + consolePrinter.println(command); + consolePrinter.println(); + try { + process = invoke(command, workingDirectory); + } catch (IOException e) { + throw new InvocationFailure("Unable to start " + externalToolName, e); //$NON-NLS-1$ + } + processStream(process.getInputStream(), parsers, consolePrinter); + processStream(process.getErrorStream(), parsers, consolePrinter); + } finally { + if (process != null) { + process.destroy(); + } + consolePrinter.close(); + } + } + + private ConsolePrinter consolePrinter(String externalToolName, boolean shouldDisplayOutput) { + if (shouldDisplayOutput) { + try { + return ConsolePrinterImpl.createOrFindConsole(externalToolName); + } catch (PartInitException e) { + CodanUIActivator.log("Unable to create/find console", e); //$NON-NLS-1$ + } + } + return ConsolePrinter.NullImpl; + } + + private String buildCommand(IPath executablePath, String[] args) { + StringBuilder builder = new StringBuilder(); + builder.append(executablePath.toOSString()); + for (String arg : args) { + builder.append(" ").append(arg); //$NON-NLS-1$ + } + return builder.toString(); + } + + private Process invoke(String command, IPath workingDirectory) throws IOException { + Runtime runtime = Runtime.getRuntime(); + if (workingDirectory == null) { + return runtime.exec(command); + } + return runtime.exec(command, ENVIRONMENT_VARIABLE_SETTINGS, workingDirectory.toFile()); + } + + private void processStream(InputStream inputStream, List parsers, + ConsolePrinter consolePrinter) throws IOException, InvocationFailure { + Reader reader = null; + try { + reader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(reader); + String line = null; + while ((line = bufferedReader.readLine()) != null) { + consolePrinter.println(line); + for (IOutputParser parser : parsers) { + if (parser.parse(line)) { + break; + } + } + } + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignored) {} + } + } + } +} diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinter.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinter.java new file mode 100644 index 00000000000..41ac71312b4 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinter.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.ui.externaltool; + +/** + * Prints the output of an external tool to an Eclipse console. It uses the name of the external + * tool as the console ID. + * + * @author alruiz@google.com (Alex Ruiz) + */ +interface ConsolePrinter { + ConsolePrinter NullImpl = new ConsolePrinter() { + @Override + public void clear() {} + + @Override + public void println(String message) {} + + @Override + public void println() {} + + @Override + public void close() {} + }; + + /** + * Clears the contents of the console. + */ + void clear(); + + /** + * Prints the specified message to the console, followed by a line separator string. + * @param message the message to print. + */ + void println(String message); + + /** + * Prints a line separator to the console. + */ + void println(); + + /** + * Closes the output stream of the console. + */ + void close(); +} diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinterImpl.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinterImpl.java new file mode 100644 index 00000000000..abaf246d10a --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/ui/externaltool/ConsolePrinterImpl.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alex Ruiz - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.ui.externaltool; + +import static org.eclipse.ui.console.IConsoleConstants.ID_CONSOLE_VIEW; + +import java.io.IOException; + +import org.eclipse.cdt.codan.ui.CodanEditorUtility; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.IConsoleManager; +import org.eclipse.ui.console.IConsoleView; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; + +/** + * Default implementation of {@link ConsolePrinter}. + * + * @author alruiz@google.com (Alex Ruiz) + */ +class ConsolePrinterImpl implements ConsolePrinter { + private final MessageConsole console; + private final MessageConsoleStream out; + + static ConsolePrinter createOrFindConsole(String externalToolName) + throws PartInitException { + MessageConsole console = findConsole(externalToolName); + IWorkbenchPage page = CodanEditorUtility.getActivePage(); + if (page != null) { + IConsoleView view = (IConsoleView) page.showView(ID_CONSOLE_VIEW); + view.display(console); + } + return new ConsolePrinterImpl(console); + } + + private static MessageConsole findConsole(String externalToolName) { + IConsoleManager consoleManager = ConsolePlugin.getDefault().getConsoleManager(); + for (IConsole console : consoleManager.getConsoles()) { + if (externalToolName.equals(console.getName()) && console instanceof MessageConsole) { + return (MessageConsole) console; + } + } + MessageConsole console = new MessageConsole(externalToolName, null); + consoleManager.addConsoles(new IConsole[] { console }); + return console; + } + + private ConsolePrinterImpl(MessageConsole console) { + this.console = console; + out = console.newMessageStream(); + } + + public void clear() { + console.clearConsole(); + } + + public void println(String s) { + out.println(s); + } + + public void println() { + out.println(); + } + + public void close() { + try { + out.close(); + } catch (IOException ignored) {} + } +}