diff options
Diffstat (limited to 'codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/AbstractExternalToolBasedChecker.java')
-rw-r--r-- | codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/externaltool/AbstractExternalToolBasedChecker.java | 214 |
1 files changed, 214 insertions, 0 deletions
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. + * <p> + * A file, to be processed by this type of checker, must: + * <ol> + * <li>be in the current active editor</li> + * <li>not have any unsaved changes</li> + * </ol> + * </p> + * By default, implementations of this checker are not allowed to run while the user types, since + * external tools cannot see unsaved changes. + * + * @since 2.1 + */ +public abstract class AbstractExternalToolBasedChecker extends AbstractCheckerWithProblemPreferences + implements IMarkerGenerator { + private final IInvocationParametersProvider parametersProvider; + private final ArgsSeparator argsSeparator; + private final ConfigurationSettings settings; + private final ExternalToolInvoker externalToolInvoker; + private final RootProblemPreference preferences; + + /** + * Constructor. + * @param settings user-configurable external tool configuration settings. + */ + public AbstractExternalToolBasedChecker(ConfigurationSettings settings) { + this(new InvocationParametersProvider(), new ArgsSeparator(), settings); + } + + /** + * Constructor. + * @param parametersProvider provides the parameters to pass when invoking the external tool. + * @param argsSeparator separates the arguments to pass to the external tool executable. These + * arguments are stored in a single {@code String}. + * @param settings user-configurable external tool configuration settings. + */ + public AbstractExternalToolBasedChecker(IInvocationParametersProvider parametersProvider, + ArgsSeparator argsSeparator, ConfigurationSettings settings) { + this.parametersProvider = parametersProvider; + this.argsSeparator = argsSeparator; + this.settings = settings; + externalToolInvoker = new ExternalToolInvoker(); + preferences = new SharedRootProblemPreference(); + } + + /** + * Returns {@code false} because this checker cannot run "as you type" by default. + * @return {@code false}. + */ + @Override + public boolean runInEditor() { + return false; + } + + @Override + public boolean processResource(IResource resource) { + process(resource); + return false; + } + + private void process(IResource resource) { + try { + InvocationParameters parameters = parametersProvider.createParameters(resource); + if (parameters != null) { + invokeExternalTool(parameters); + } + } catch (Throwable error) { + logResourceProcessingFailure(error, resource); + } + } + + private void invokeExternalTool(InvocationParameters parameters) throws Throwable { + updateConfigurationSettingsFromPreferences(parameters.getActualFile()); + IConsoleParser[] parsers = new IConsoleParser[] { createErrorParserManager(parameters) }; + try { + externalToolInvoker.invoke(parameters, settings, argsSeparator, parsers); + } catch (InvocationFailure error) { + handleInvocationFailure(error, parameters); + } + } + + private void updateConfigurationSettingsFromPreferences(IResource fileToProcess) { + IProblem problem = getProblemById(getReferenceProblemId(), fileToProcess); + MapProblemPreference preferences = (MapProblemPreference) problem.getPreference(); + settings.updateValuesFrom(preferences); + } + + private ErrorParserManager createErrorParserManager(InvocationParameters parameters) { + IProject project = parameters.getActualFile().getProject(); + URI workingDirectory = URIUtil.toURI(parameters.getWorkingDirectory()); + return new ErrorParserManager(project, workingDirectory, this, getParserIDs(), CODAN); + } + + /** + * @return the IDs of the parsers to use to parse the output of the external tool. + */ + protected abstract String[] getParserIDs(); + + /** + * Handles a failure reported when invoking the external tool. This implementation simply + * logs the failure. + * @param error the reported failure. + * @param parameters the parameters passed to the external tool executable. + */ + protected void handleInvocationFailure(InvocationFailure error, InvocationParameters parameters) { + logResourceProcessingFailure(error, parameters.getActualFile()); + } + + private void logResourceProcessingFailure(Throwable error, IResource resource) { + String location = resource.getLocation().toOSString(); + String msg = String.format("Unable to process resource %s", location); //$NON-NLS-1$ + Activator.log(msg, error); + } + + /** + * Returns the id of the problem used as reference to obtain this checker's preferences. All + * preferences in a external-tool-based checker are shared among its defined problems. + * @return the id of the problem used as reference to obtain this checker's preferences. + */ + protected abstract String getReferenceProblemId(); + + @Override + public void initPreferences(IProblemWorkingCopy problem) { + super.initPreferences(problem); + getLaunchModePreference(problem).enableInLaunchModes( + CheckerLaunchMode.RUN_ON_FULL_BUILD, + CheckerLaunchMode.RUN_ON_INC_BUILD, + CheckerLaunchMode.RUN_ON_FILE_SAVE, + CheckerLaunchMode.RUN_ON_DEMAND); + addPreference(problem, settings.getPath()); + addPreference(problem, settings.getArgs()); + } + + private void addPreference(IProblemWorkingCopy problem, SingleConfigurationSetting<?> setting) { + IProblemPreference descriptor = (IProblemPreference) setting.getDescriptor(); + addPreference(problem, descriptor, setting.getDefaultValue()); + } + + @Override + protected void setDefaultPreferenceValue(IProblemWorkingCopy problem, String key, + Object defaultValue) { + MapProblemPreference map = getTopLevelPreference(problem); + map.setChildValue(key, defaultValue); + } + + @Override + public RootProblemPreference getTopLevelPreference(IProblem problem) { + RootProblemPreference map = (RootProblemPreference) problem.getPreference(); + if (map == null) { + map = preferences; + if (problem instanceof IProblemWorkingCopy) { + ((IProblemWorkingCopy) problem).setPreference(map); + } + } + return map; + } + + @Deprecated + @Override + public void addMarker(IResource file, int lineNumber, String description, int severity, + String variableName) { + addMarker(new ProblemMarkerInfo(file, lineNumber, description, severity, variableName)); + } + + @Override + public void addMarker(ProblemMarkerInfo info) { + reportProblem(getReferenceProblemId(), createProblemLocation(info), info.description); + } + + protected IProblemLocation createProblemLocation(ProblemMarkerInfo info) { + IProblemLocationFactory factory = CodanRuntime.getInstance().getProblemLocationFactory(); + return factory.createProblemLocation( + (IFile) info.file, info.startChar, info.endChar, info.lineNumber); + } +} |