diff options
author | Daniel Pesch | 2014-01-16 08:39:12 +0000 |
---|---|---|
committer | Doug Schaefer | 2014-01-16 15:46:50 +0000 |
commit | eb5c0c8a55d92f360c73bb17efb4a9718cbf08f5 (patch) | |
tree | c1c2365df722bef06b815895925fd98ea5309a88 | |
parent | 93c60329b8abc3cfa003d3fd16c6a8715e5f3ba2 (diff) | |
download | org.eclipse.cdt-eb5c0c8a55d92f360c73bb17efb4a9718cbf08f5.tar.gz org.eclipse.cdt-eb5c0c8a55d92f360c73bb17efb4a9718cbf08f5.tar.xz org.eclipse.cdt-eb5c0c8a55d92f360c73bb17efb4a9718cbf08f5.zip |
Bug 425538 - Syntax errors in QML reported as "C/C++ Problems" because errors from Qt Linguist
The problem is solved by allowing to ignore duplicated markers in case
there is already loaded a plugin that could handle QML files
The ProblemMarkerFilter extension point allows to filter out unneeded
problem markers. For example during building of Qt base project with QML
files tool Qt Linguist could report syntax errors in some qml file.
These errors are presented as "C/C++ Problems" in qml files because they
match format CDT expects for errors. If there is already installed plug-in
that handles QML files it is a wise to ignore such errors because they
are already reported as "QML Problems" with more meaningful descriptions.
Change-Id: I3a0a1b58e9690bed9c2774e4328760c695d54a54
Signed-off-by: Daniel Pesch <dpesch@blackberry.com>
Reviewed-on: https://git.eclipse.org/r/20581
Tested-by: Hudson CI
Reviewed-by: Andrew Eidsness <eclipse@jfront.com>
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
7 files changed, 450 insertions, 0 deletions
diff --git a/core/org.eclipse.cdt.core/plugin.properties b/core/org.eclipse.cdt.core/plugin.properties index f06189e829e..9f72cc6d3a7 100755 --- a/core/org.eclipse.cdt.core/plugin.properties +++ b/core/org.eclipse.cdt.core/plugin.properties @@ -138,3 +138,5 @@ uncPathConverter.name = UNC Path Converter ScannerInfoExtensionLanguageSettingsProvider.name=Contributed ScannerInfo Entries PathEntryScannerInfoLanguageSettingsProvider.name=Contributed PathEntry Containers ReferencedProjectsLanguageSettingsProvider.name=Exported Entries from Referenced Projects + +problemMarkerFilter.name=Problem Marker Filter diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index 3d6764c38ec..9bfaba5143d 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -675,6 +675,7 @@ <extension-point id="RefreshExclusionFactory" name="%refreshExclusionFactory.name" schema="schema/RefreshExclusionFactory.exsd"/> <extension-point id="LanguageSettingsProvider" name="%LanguageSettingsProvider.name" schema="schema/LanguageSettingsProvider.exsd"/> <extension-point id="UNCPathConverter" name="%uncPathConverter.name" schema="schema/UNCPathConverter.exsd"/> + <extension-point id="ProblemMarkerFilter" name="%problemMarkerFilter.name" schema="schema/ProblemMarkerFilter.exsd"/> <extension point="org.eclipse.cdt.core.templateProcessTypes"> diff --git a/core/org.eclipse.cdt.core/schema/ProblemMarkerFilter.exsd b/core/org.eclipse.cdt.core/schema/ProblemMarkerFilter.exsd new file mode 100644 index 00000000000..3a575f9f9e7 --- /dev/null +++ b/core/org.eclipse.cdt.core/schema/ProblemMarkerFilter.exsd @@ -0,0 +1,135 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- Schema file written by PDE --> +<schema targetNamespace="org.eclipse.cdt.core" xmlns="http://www.w3.org/2001/XMLSchema"> +<annotation> + <appInfo> + <meta.schema plugin="org.eclipse.cdt.core" id="ProblemMarkerFilter" name="Problem Marker Filter"/> + </appInfo> + <documentation> + This extension point allows to filter out unneeded problem markers. + For example during building of Qt base project with QML files tool Qt Linguist + could report syntax errors in some qml file. These errors are presented as + "C/C++ Problems" in qml files because they match format CDT expects for errors. + If there is already installed plug-in that handles QML files it is a wise to ignore such + errors because they are already reported as "QML Problems" with more meaningful descriptions. + </documentation> + </annotation> + + <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> + + <element name="extension"> + <annotation> + <appInfo> + <meta.element /> + </appInfo> + </annotation> + <complexType> + <sequence> + <element ref="problemMarkerFilter" minOccurs="1" maxOccurs="unbounded"/> + </sequence> + <attribute name="point" type="string" use="required"> + <annotation> + <documentation> + a fully qualified identifier of the target extension point + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + an optional identifier of the extension instance + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + an optional name of the extension instance + </documentation> + <appInfo> + <meta.attribute translatable="true"/> + </appInfo> + </annotation> + </attribute> + </complexType> + </element> + + <element name="problemMarkerFilter"> + <complexType> + <sequence> + <element ref="enablement" minOccurs="0" maxOccurs="1"/> + </sequence> + <attribute name="class" type="string" use="required"> + <annotation> + <documentation> + Implementation of Problem Marker Filter that allows to filter out unneded or duplicit problem markers. + </documentation> + <appinfo> + <meta.attribute kind="java" basedOn=":org.eclipse.cdt.core.IProblemMarkerFilter"/> + </appinfo> + </annotation> + </attribute> + </complexType> + </element> + + <annotation> + <appInfo> + <meta.section type="since"/> + </appInfo> + <documentation> + 8.3 + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="examples"/> + </appInfo> + <documentation> + The following is an example of a qmakeEnvProvider contribution: +<p> +<pre> +<extension + point="org.eclipse.cdt.core.ProblemMarkerFilter" + id="example" + name="Example QMake Env Provider Extension"> + <problemMarkerFilter + class="com.example.internal.ProblemMarkerFilter"> + <enablement> + <with variable="projectNatures"> + <iterate operator="or"> + <equals value="com.example.my-nature"/> + </iterate> + </with> + </enablement> + </problemMarkerFilter> +</extension> +</pre> +</p> + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="apiinfo"/> + </appInfo> + <documentation> + The contributed class must implement <code>org.eclipse.cdt.core.IProblemMarkerFilter</code>. + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="implementation"/> + </appInfo> + <documentation> + Copyright (c) 2014 BlackBerry Limited 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 + </documentation> + </annotation> + + +</schema> diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java index 735d8ce086a..12c4ab08e0d 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java @@ -30,6 +30,7 @@ import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker import org.eclipse.cdt.core.resources.ACBuilder; import org.eclipse.cdt.internal.core.Cygwin; import org.eclipse.cdt.internal.core.IErrorMarkeredOutputStream; +import org.eclipse.cdt.internal.core.ProblemMarkerFilterManager; import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.cdt.internal.errorparsers.ErrorParserExtensionManager; import org.eclipse.cdt.utils.EFSExtensionManager; @@ -588,6 +589,8 @@ outer: * @since 5.4 */ public void addProblemMarker(ProblemMarkerInfo problemMarkerInfo){ + if ( ! ProblemMarkerFilterManager.getInstance().acceptMarker(problemMarkerInfo) ) + return; fErrors.add(problemMarkerInfo); fMarkerGenerator.addMarker(problemMarkerInfo); if (problemMarkerInfo.severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE) { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IProblemMarkerFilter.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IProblemMarkerFilter.java new file mode 100644 index 00000000000..9bdb22b8907 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IProblemMarkerFilter.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 BlackBerry Limited 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 + */ +package org.eclipse.cdt.core; + +/** + * The purpose of IProblemMarkerFilter is to provide filtering function for problem markers. + * ProblemMarkerFilter extension point are required to implements this interface. + * + * @since 5.6 + */ +public interface IProblemMarkerFilter { + + /** + * Decide if a problem marker should be reported or ignored. + * + * @param markerInfo description of the problem marker that is going to be reported + * @return true if markers should be reported, false if should be ignored + */ + boolean acceptMarker(ProblemMarkerInfo markerInfo); +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterDesc.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterDesc.java new file mode 100644 index 00000000000..b794a21f5df --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterDesc.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2014 BlackBerry Limited 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 + */ +package org.eclipse.cdt.internal.core; + +import java.util.Arrays; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.IProblemMarkerFilter; +import org.eclipse.cdt.core.ProblemMarkerInfo; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.expressions.ExpressionTagNames; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; + +/** + * The purpose of ProblemMarkerFilterDesc is to manage information about + * one instance ProblemMarkerFilter extension point. + */ +class ProblemMarkerFilterDesc { + + /** + * XML attribute for name of class that implements this extension point + */ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + + /** + * Variable name for projectNatures for enablement expression + */ + private static final String VAR_PROJECTNATURES = "projectNatures"; //$NON-NLS-1$ + + /** + * Configuration element for this extension point + */ + private final IConfigurationElement element; + + /** + * Expression that allows conditionally enable/disable extension point + */ + private final Expression enablementExpression; + + /** + * Status of this extension point. + * False = disabled because of expression error + * True = enabled because of missing enablementExpression + * null = evaluate the expression for particular project + */ + private Boolean fStatus = null; + + /** + * Unique id of this extension point + */ + private String id; + + /** + * + */ + private IProblemMarkerFilter filter; + + /** + * Filter that accept any marker. + * + */ + private static final IProblemMarkerFilter NULL_FILTER = new IProblemMarkerFilter() { + + @Override + public boolean acceptMarker(ProblemMarkerInfo markerInfo) { + return true; + } + + }; + + /** + * Constructor + * + * @param element configuration element with optional enablementExpression + */ + ProblemMarkerFilterDesc(IConfigurationElement element) { + this.element = element; + + Expression expr = null; + IConfigurationElement[] children = element.getChildren(ExpressionTagNames.ENABLEMENT); + switch (children.length) { + case 0: + fStatus = Boolean.TRUE; + break; + case 1: + try { + ExpressionConverter parser = ExpressionConverter.getDefault(); + expr = parser.perform(children[0]); + } catch (CoreException e) { + CCorePlugin.log("Error in enablement expression of " + id, e); //$NON-NLS-1$ + fStatus = Boolean.FALSE; + } + break; + default: + CCorePlugin.log("Too many enablement expressions for " + id); //$NON-NLS-1$ + fStatus = Boolean.FALSE; + break; + } + enablementExpression = expr; + } + + /** + * Evaluate enablement expression + * + * @param project project for which we had to evaluate the expression + * @return value of enablement expression + */ + public boolean matches(IProject project) { + // If the enablement expression is missing or structurally invalid, then return immediately + if (fStatus != null) + return fStatus.booleanValue(); + + if (enablementExpression != null) + try { + EvaluationContext evalContext = new EvaluationContext(null, project); + String[] natures = project.getDescription().getNatureIds(); + evalContext.addVariable(VAR_PROJECTNATURES, Arrays.asList(natures)); + return enablementExpression.evaluate(evalContext) == EvaluationResult.TRUE; + } catch (CoreException e) { + CCorePlugin.log("Error while evaluating enablement expression for " + id, e); //$NON-NLS-1$ + } + + return false; + } + + /** + * Return filter interface + * @return Filter interface or NULL_FILER if filter could not be created + */ + IProblemMarkerFilter getFilter() { + if (filter == null) + synchronized (this) { + if (filter == null) { + try { + filter = (IProblemMarkerFilter) element.createExecutableExtension(ATTR_CLASS); + } catch (CoreException e) { + String id = element.getDeclaringExtension().getNamespaceIdentifier() + '.' + + element.getDeclaringExtension().getSimpleIdentifier(); + CCorePlugin.log("Error in class attribute of " + id, e); //$NON-NLS-1$ + + // mark the filter with an empty implementation to prevent future load attempts + filter = NULL_FILTER; + } + } + } + + return filter; + } + +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterManager.java new file mode 100644 index 00000000000..5409cd262a8 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/ProblemMarkerFilterManager.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 BlackBerry Limited 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 + */ +package org.eclipse.cdt.internal.core; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.IProblemMarkerFilter; +import org.eclipse.cdt.core.ProblemMarkerInfo; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; + +/** + * The purpose of ProblemMarkerFilterManager is to manage ProblemMarkerFilter extension points. + * {@link ErrorParserManager} use this manager to filter out unnecessary problem markers + * + * @noextend This class is not intended to be subclassed by clients. + */ +public class ProblemMarkerFilterManager { + + /** + * Name of ProblemMarkerFilter extension point + */ + private final static String EXTENSION_POINT = "ProblemMarkerFilter"; //$NON-NLS-1$ + + /** + * Singleton instance of ProblemMarkerFilterManager + */ + private final static ProblemMarkerFilterManager INSTANCE = new ProblemMarkerFilterManager(); + + /** + * List of all executable extension registered in Extension Registry + */ + private final List<ProblemMarkerFilterDesc> filters = new ArrayList<ProblemMarkerFilterDesc>(); + + /** + * Cache of active filters for known projects. + * This cache allow to skip evaluation of enablementExpression for every marker. + */ + private final Map<IProject, List<ProblemMarkerFilterDesc>> filtersCache = new WeakHashMap<IProject, List<ProblemMarkerFilterDesc>>(); + + /** + * Return singleton instance of ProblemMarkerFilterManager + * + * @return singleton instance of ProblemMarkerFilterManager + */ + public static ProblemMarkerFilterManager getInstance() { + return INSTANCE; + } + + /** + * Constructor. + * + * Creates instances of executable extension for ProblemMarkerFilter extension point + * + */ + private ProblemMarkerFilterManager() { + IExtensionRegistry reg = Platform.getExtensionRegistry(); + IConfigurationElement[] extensions = reg + .getConfigurationElementsFor(CCorePlugin.PLUGIN_ID, EXTENSION_POINT); + for (int i = 0; i < extensions.length; i++) { + IConfigurationElement element = extensions[i]; + ProblemMarkerFilterDesc filterDesc = new ProblemMarkerFilterDesc(element); + filters.add(filterDesc); + } + } + + /** + * Called by {@link ErrorParserManager#addProblemMarker(ProblemMarkerInfo)} to filter out unnecessary problem markers + * + * Problem marker is ignored if any plug-in that implements ProblemMarkerFilter extension point rejects it. + * + * @see IProblemMarkerFilter#acceptMarker(ProblemMarkerInfo) + * + * @param markerInfo description of the problem marker that is going to be added + * @return true if markers should be reported, false if should be ignored + */ + public boolean acceptMarker(ProblemMarkerInfo markerInfo) { + IProject project = markerInfo.file.getProject(); + if (project == null || !project.isOpen()) + return true; + List<ProblemMarkerFilterDesc> enabledFilters = findEnabledFilters(project); + for (ProblemMarkerFilterDesc filterDesc: enabledFilters) { + if ( ! filterDesc.getFilter().acceptMarker(markerInfo) ) { + return false; + } + } + return true; + } + + /** + * Try to find enabled filter for project and cache results + * @param project project for which we want know enabled filters + * @return list of enabled filters + */ + private List<ProblemMarkerFilterDesc> findEnabledFilters(IProject project) { + synchronized (filtersCache) { + List<ProblemMarkerFilterDesc> result = filtersCache.get(project); + if (result == null) { + result = new ArrayList<ProblemMarkerFilterDesc>(); + for (ProblemMarkerFilterDesc filterDesc: filters) { + if ( filterDesc.matches(project) ) { + result.add(filterDesc); + } + } + filtersCache.put(project, result); + } + return result; + } + } + +} |