Skip to main content
summaryrefslogtreecommitdiffstats
path: root/build
diff options
context:
space:
mode:
authorAndrew Gvozdev2012-04-12 01:01:23 -0400
committerAndrew Gvozdev2012-04-12 01:01:23 -0400
commitb1b320f94e5081bcd17089efa202205900f0cbf1 (patch)
treeb1150a44a428f01d1a5220987d94d8e350a241dc /build
parent1a0bdf2d5d4f59a1afb73b772fcb459eea9c9ff0 (diff)
downloadorg.eclipse.cdt-b1b320f94e5081bcd17089efa202205900f0cbf1.tar.gz
org.eclipse.cdt-b1b320f94e5081bcd17089efa202205900f0cbf1.tar.xz
org.eclipse.cdt-b1b320f94e5081bcd17089efa202205900f0cbf1.zip
bug 371797: [sd90] Implement language settings providers in build
plugins
Diffstat (limited to 'build')
-rw-r--r--build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java45
-rw-r--r--build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java66
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF1
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml10
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java6
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/AllLanguageSettingsProvidersMBSTests.java32
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/BuiltinSpecsDetectorTest.java569
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java2208
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuiltinSpecsDetectorTest.java366
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF3
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/plugin.xml34
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/core/scannerconfig/ScannerConfigBuilder.java97
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigInfoFactory2.java9
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java10
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java12
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java27
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuilderCorePlugin.java54
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/PluginResources.properties11
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/MBSLanguageSettingsProvider.java118
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java280
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java745
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java1073
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuildCommandParser.java84
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuiltinSpecsDetector.java133
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/ToolchainBuiltinSpecsDetector.java105
25 files changed, 5983 insertions, 115 deletions
diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java
index 7275c8e80f..9a6eb5609c 100644
--- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java
+++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/MakeBuilder.java
@@ -26,8 +26,17 @@ import org.eclipse.cdt.core.CommandLauncher;
import org.eclipse.cdt.core.ErrorParserManager;
import org.eclipse.cdt.core.ICommandLauncher;
import org.eclipse.cdt.core.IConsoleParser;
+import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
+import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
+import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
+import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.internal.core.BuildRunnerHelper;
import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser;
import org.eclipse.cdt.make.internal.core.MakeMessages;
@@ -175,6 +184,7 @@ public class MakeBuilder extends ACBuilder {
String[] targets = getTargets(kind, info);
if (targets.length != 0 && targets[targets.length - 1].equals(info.getCleanBuildTarget()))
isClean = true;
+ boolean isOnlyClean = isClean && (targets.length == 1);
String[] args = getCommandArguments(info, targets);
@@ -187,8 +197,17 @@ public class MakeBuilder extends ACBuilder {
ErrorParserManager epm = new ErrorParserManager(getProject(), workingDirectoryURI, this, errorParsers);
List<IConsoleParser> parsers = new ArrayList<IConsoleParser>();
- IScannerInfoConsoleParser parserSD = ScannerInfoConsoleParserFactory.getScannerInfoConsoleParser(project, workingDirectoryURI, this);
- parsers.add(parserSD);
+ if (!isOnlyClean) {
+ ICProjectDescription prjDescription = CoreModel.getDefault().getProjectDescription(project);
+ if (prjDescription != null) {
+ ICConfigurationDescription cfgDescription = prjDescription.getActiveConfiguration();
+ collectLanguageSettingsConsoleParsers(cfgDescription, epm, parsers);
+ }
+ if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(project)) {
+ IScannerInfoConsoleParser parserSD = ScannerInfoConsoleParserFactory.getScannerInfoConsoleParser(project, workingDirectoryURI, this);
+ parsers.add(parserSD);
+ }
+ }
buildRunnerHelper.setLaunchParameters(launcher, buildCommand, args, workingDirectoryURI, envp);
buildRunnerHelper.prepareStreams(epm, parsers, console, new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
@@ -307,4 +326,26 @@ public class MakeBuilder extends ACBuilder {
private String[] makeArray(String string) {
return CommandLineUtil.argumentsToArray(string);
}
+
+ private static void collectLanguageSettingsConsoleParsers(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker, List<IConsoleParser> parsers) {
+ if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
+ List<ILanguageSettingsProvider> lsProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders();
+ for (ILanguageSettingsProvider lsProvider : lsProviders) {
+ ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(lsProvider);
+ if (rawProvider instanceof ICBuildOutputParser) {
+ ICBuildOutputParser consoleParser = (ICBuildOutputParser) rawProvider;
+ try {
+ consoleParser.startup(cfgDescription, cwdTracker);
+ parsers.add(consoleParser);
+ } catch (CoreException e) {
+ MakeCorePlugin.log(new Status(IStatus.ERROR, MakeCorePlugin.PLUGIN_ID,
+ "Language Settings Provider failed to start up", e)); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ }
+
+
}
diff --git a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
index 304a6c78e1..9a256489cd 100644
--- a/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
+++ b/build/org.eclipse.cdt.make.core/src/org/eclipse/cdt/make/core/scannerconfig/ScannerConfigBuilder.java
@@ -13,6 +13,8 @@ package org.eclipse.cdt.make.core.scannerconfig;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
+import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
@@ -30,12 +32,12 @@ import org.eclipse.core.runtime.SubProgressMonitor;
/**
* Runs after standard make builder.
* Consolidates discovered scanner configuration and updates project's scanner configuration.
- *
+ *
* @deprecated as of CDT 4.0. Used by legacy CDT 3.X projects.
* Replaced by ScannerConfigBuilder in org.eclipse.cdt.managedbuilder.core.
- *
+ *
* @see IncrementalProjectBuilder
- *
+ *
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@@ -60,34 +62,39 @@ public class ScannerConfigBuilder extends ACBuilder {
// boolean autodiscoveryEnabled;
if(buildNewStyle(getProject(), monitor))
return getProject().getReferencedProjects();
+
+ if (!ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(getProject())) {
+ return getProject().getReferencedProjects();
+ }
+
boolean autodiscoveryEnabled2;
IScannerConfigBuilderInfo2 buildInfo2 = null;
try {
// IScannerConfigBuilderInfo buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(getProject(), BUILDER_ID);
// autodiscoveryEnabled = buildInfo.isAutoDiscoveryEnabled();
-//
+//
// if (autodiscoveryEnabled) {
// monitor.beginTask("ScannerConfigBuilder.Invoking_Builder", 100); //$NON-NLS-1$
-// monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
+// monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
// getProject().getName());
// ScannerInfoCollector.getInstance().updateScannerConfiguration(getProject(), new SubProgressMonitor(monitor, 100));
// }
-
+
buildInfo2 = ScannerConfigProfileManager.createScannerConfigBuildInfo2(getProject());
autodiscoveryEnabled2 = buildInfo2.isAutoDiscoveryEnabled();
if (autodiscoveryEnabled2) {
monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder"), 100); //$NON-NLS-1$
- monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
+ monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
getProject().getName());
-
+
// get scanner info from all external providers
SCJobsUtil.getProviderScannerInfo(getProject(), buildInfo2, new SubProgressMonitor(monitor, 70));
// update and persist scanner configuration
SCJobsUtil.updateScannerConfiguration(getProject(), buildInfo2, new SubProgressMonitor(monitor, 30));
}
- }
+ }
catch (CoreException e) {
// builder not installed or disabled
// autodiscoveryEnabled = false;
@@ -96,12 +103,12 @@ public class ScannerConfigBuilder extends ACBuilder {
}
return getProject().getReferencedProjects();
}
-
+
protected boolean buildNewStyle(IProject project, IProgressMonitor monitor) throws CoreException{
ICProjectDescription des = CCorePlugin.getDefault().getProjectDescription(project, false);
if(!CCorePlugin.getDefault().isNewStyleProject(des))
return false;
-
+
ICConfigurationDescription[] cfgs = des.getConfigurations();
IScannerConfigBuilderInfo2Set container = ScannerConfigProfileManager.createScannerConfigBuildInfo2Set(project);
monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.0"), cfgs.length + 1); //$NON-NLS-1$
@@ -119,32 +126,33 @@ public class ScannerConfigBuilder extends ACBuilder {
if(build(project, context, info, new SubProgressMonitor(monitor, 1)))
wasbuilt = true;
}
-
+
if(wasbuilt)
CCorePlugin.getDefault().updateProjectDescriptions(new IProject[]{project}, new SubProgressMonitor(monitor, 1));
-
+
monitor.done();
return true;
}
-
+
protected boolean build(IProject project, InfoContext context, IScannerConfigBuilderInfo2 buildInfo2, IProgressMonitor monitor){
- boolean autodiscoveryEnabled2 = buildInfo2.isAutoDiscoveryEnabled();
+ if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(getProject())) {
+ boolean autodiscoveryEnabled2 = buildInfo2.isAutoDiscoveryEnabled();
+ if (autodiscoveryEnabled2) {
+ monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder"), 100); //$NON-NLS-1$
+ monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
+ getProject().getName());
- if (autodiscoveryEnabled2) {
- monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder"), 100); //$NON-NLS-1$
- monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
- getProject().getName());
-
- // get scanner info from all external providers
- SCJobsUtil.getProviderScannerInfo(getProject(), context, buildInfo2, new SubProgressMonitor(monitor, 70));
+ // get scanner info from all external providers
+ SCJobsUtil.getProviderScannerInfo(getProject(), context, buildInfo2, new SubProgressMonitor(monitor, 70));
- // update and persist scanner configuration
- SCJobsUtil.updateScannerConfiguration(getProject(), context, buildInfo2, new SubProgressMonitor(monitor, 30));
- return true;
- }
- return false;
+ // update and persist scanner configuration
+ SCJobsUtil.updateScannerConfiguration(getProject(), context, buildInfo2, new SubProgressMonitor(monitor, 30));
+ return true;
+ }
+ }
+ return false;
}
-
-
+
+
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF
index 8c5591f6aa..6c7f02b07f 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF
@@ -7,6 +7,7 @@ Bundle-Activator: org.eclipse.cdt.managedbuilder.testplugin.CTestPlugin
Bundle-Vendor: Eclipse CDT
Bundle-Localization: plugin
Export-Package: org.eclipse.cdt.managedbuilder.core.tests,
+ org.eclipse.cdt.managedbuilder.language.settings.providers.tests,
org.eclipse.cdt.managedbuilder.templateengine.tests,
org.eclipse.cdt.managedbuilder.testplugin,
org.eclipse.cdt.managedbuilder.tests.suite,
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
index 9e0a06463e..67494d80a5 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/plugin.xml
@@ -9301,4 +9301,14 @@
</matchObject>
</conflictDefinition>
</extension>
+ <extension
+ id="org.eclipse.cdt.managedbuilder.core.tests.ErrorParsers"
+ name="org.eclipse.cdt.managedbuilder.core.tests ErrorParsers"
+ point="org.eclipse.cdt.core.ErrorParser">
+ <errorparser
+ class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser$GCCBuildCommandPatternHighlighter"
+ id="org.eclipse.cdt.core.tests.managedbuilder.core.GCCBuildCommandPatternHighlighter"
+ name="Test Plugin GCC BOP Patterns Highlighter">
+ </errorparser>
+ </extension>
</plugin>
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java
index d90c1e4add..0ae86b7db2 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/suite/org/eclipse/cdt/managedbuilder/tests/suite/AllManagedBuildTests.java
@@ -4,7 +4,7 @@
* 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:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
@@ -39,6 +39,7 @@ import org.eclipse.cdt.managedbuilder.core.tests.OptionCategoryEnablementTests;
import org.eclipse.cdt.managedbuilder.core.tests.OptionEnablementTests;
import org.eclipse.cdt.managedbuilder.core.tests.PathConverterTest;
import org.eclipse.cdt.managedbuilder.core.tests.ResourceBuildCoreTests;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.tests.AllLanguageSettingsProvidersMBSTests;
import org.eclipse.cdt.managedbuilder.templateengine.tests.AllTemplateEngineTests;
import org.eclipse.cdt.projectmodel.tests.BackwardCompatiblityTests;
import org.eclipse.cdt.projectmodel.tests.CProjectDescriptionSerializationTests;
@@ -61,6 +62,9 @@ public class AllManagedBuildTests {
suite.addTest(CfgScannerConfigProfileManagerTests.suite());
suite.addTestSuite(GCCSpecsConsoleParserTest.class);
+ // language settings providers tests
+ suite.addTest(AllLanguageSettingsProvidersMBSTests.suite());
+
// managedbuilder.core.tests
suite.addTest(ManagedBuildDependencyLibsTests.suite());
suite.addTest(ManagedBuildCoreTests20.suite());
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/AllLanguageSettingsProvidersMBSTests.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/AllLanguageSettingsProvidersMBSTests.java
new file mode 100644
index 0000000000..4ab865896a
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/AllLanguageSettingsProvidersMBSTests.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers.tests;
+
+import junit.framework.TestSuite;
+
+/**
+ * Test suite to test language settings providers defined in cdt.managedbuilder.core.
+ */
+public class AllLanguageSettingsProvidersMBSTests extends TestSuite {
+
+ public static TestSuite suite() {
+ return new AllLanguageSettingsProvidersMBSTests();
+ }
+
+ public AllLanguageSettingsProvidersMBSTests() {
+ super(AllLanguageSettingsProvidersMBSTests.class.getName());
+
+ addTestSuite(GCCBuildCommandParserTest.class);
+ addTestSuite(BuiltinSpecsDetectorTest.class);
+ addTestSuite(GCCBuiltinSpecsDetectorTest.class);
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/BuiltinSpecsDetectorTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/BuiltinSpecsDetectorTest.java
new file mode 100644
index 0000000000..4460d40c9e
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/BuiltinSpecsDetectorTest.java
@@ -0,0 +1,569 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - Initial API and implementation
+ *******************************************************************************/
+ package org.eclipse.cdt.managedbuilder.language.settings.providers.tests;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.ICommandLauncher;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.settings.model.CIncludeFileEntry;
+import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
+import org.eclipse.cdt.core.settings.model.CLibraryFileEntry;
+import org.eclipse.cdt.core.settings.model.CLibraryPathEntry;
+import org.eclipse.cdt.core.settings.model.CMacroEntry;
+import org.eclipse.cdt.core.settings.model.CMacroFileEntry;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.cdt.core.testplugin.ResourceHelper;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.internal.core.XmlUtil;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.AbstractBuiltinSpecsDetector;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.jobs.Job;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Test cases to test built-in specs detectors.
+ */
+public class BuiltinSpecsDetectorTest extends BaseTestCase {
+ private static final String PROVIDER_ID = "provider.id";
+ private static final String PROVIDER_NAME = "provider name";
+ private static final String LANGUAGE_ID = "language.test.id";
+ private static final String CUSTOM_PARAMETER = "customParameter";
+ private static final String CUSTOM_PARAMETER_2 = "customParameter2";
+ private static final String ELEM_TEST = "test";
+
+ // those attributes must match that in AbstractBuiltinSpecsDetector
+ private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$
+ private static final String ATTR_CONSOLE = "console"; //$NON-NLS-1$
+
+ /**
+ * Mock built-in specs detector to test basic functionality of {@link AbstractBuiltinSpecsDetector}.
+ */
+ private class MockBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector {
+ @Override
+ protected List<String> parseOptions(String line) {
+ return null;
+ }
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return null;
+ }
+ @Override
+ protected String getCompilerCommand(String languageId) {
+ return null;
+ }
+
+ @Override
+ protected void startupForLanguage(String languageId) throws CoreException {
+ super.startupForLanguage(languageId);
+ }
+ @Override
+ protected void shutdownForLanguage() {
+ super.shutdownForLanguage();
+ }
+ }
+
+ /**
+ * Mock built-in specs detector to test execute() functionality.
+ */
+ private class MockBuiltinSpecsDetectorExecutedFlag extends AbstractBuiltinSpecsDetector {
+ @Override
+ protected List<String> parseOptions(String line) {
+ return null;
+ }
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return null;
+ }
+ @Override
+ protected String getCompilerCommand(String languageId) {
+ return null;
+ }
+
+ @Override
+ protected void execute() {
+ super.execute();
+ }
+ protected boolean isExecuted() {
+ return isExecuted;
+ }
+ }
+
+ /**
+ * Mock built-in specs detector to test parsing functionality.
+ */
+ private class MockConsoleBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector {
+ @SuppressWarnings("nls")
+ private final AbstractOptionParser[] optionParsers = {
+ new MacroOptionParser("#define (\\S*) *(\\S*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY),
+ };
+ @Override
+ protected int runProgramForLanguage(String languageId, String command, String[] envp, URI workingDirectoryURI, OutputStream consoleOut, OutputStream consoleErr, IProgressMonitor monitor) throws CoreException, IOException {
+ String line = "#define MACRO VALUE";
+ consoleOut.write((line + '\n').getBytes());
+ consoleOut.flush();
+ return ICommandLauncher.OK;
+ }
+ @Override
+ protected IStatus runForEachLanguage(IProgressMonitor monitor) {
+ return super.runForEachLanguage(monitor);
+ }
+ @Override
+ protected List<String> parseOptions(final String line) {
+ return new ArrayList<String>() {{ add(line); }};
+ }
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return optionParsers;
+ }
+ @Override
+ protected String getCompilerCommand(String languageId) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ Job.getJobManager().join(AbstractBuiltinSpecsDetector.JOB_FAMILY_BUILTIN_SPECS_DETECTOR, null);
+ } catch (Exception e) {
+ // ignore
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Helper method to fetch configuration descriptions.
+ */
+ private ICConfigurationDescription[] getConfigurationDescriptions(IProject project) {
+ CoreModel coreModel = CoreModel.getDefault();
+ ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager();
+ // project description
+ ICProjectDescription projectDescription = mngr.getProjectDescription(project, false);
+ assertNotNull(projectDescription);
+ assertEquals(1, projectDescription.getConfigurations().length);
+ // configuration description
+ ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations();
+ return cfgDescriptions;
+ }
+
+ /**
+ * Test configure, getters and setters.
+ */
+ public void testAbstractBuiltinSpecsDetector_GettersSetters() throws Exception {
+ {
+ // provider configured with null parameters
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ provider.configureProvider(PROVIDER_ID, PROVIDER_NAME, null, null, null);
+
+ assertEquals(PROVIDER_ID, provider.getId());
+ assertEquals(PROVIDER_NAME, provider.getName());
+ assertEquals(null, provider.getLanguageScope());
+ assertEquals(null, provider.getSettingEntries(null, null, null));
+ assertEquals("", provider.getCommand());
+ assertEquals(false, provider.isExecuted());
+ assertEquals(false, provider.isConsoleEnabled());
+ }
+
+ {
+ // provider configured with non-null parameters
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ List<String> languages = new ArrayList<String>();
+ languages.add(LANGUAGE_ID);
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(ATTR_PARAMETER, CUSTOM_PARAMETER);
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+ ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ entries.add(entry);
+
+ provider.configureProvider(PROVIDER_ID, PROVIDER_NAME, languages, entries, properties);
+ assertEquals(PROVIDER_ID, provider.getId());
+ assertEquals(PROVIDER_NAME, provider.getName());
+ assertEquals(languages, provider.getLanguageScope());
+ assertEquals(entries, provider.getSettingEntries(null, null, null));
+ assertEquals(CUSTOM_PARAMETER, provider.getCommand());
+ assertEquals(false, provider.isConsoleEnabled());
+ assertEquals(false, provider.isExecuted());
+
+ // setters
+ provider.setCommand(CUSTOM_PARAMETER_2);
+ assertEquals(CUSTOM_PARAMETER_2, provider.getCommand());
+ provider.setConsoleEnabled(true);
+ assertEquals(true, provider.isConsoleEnabled());
+
+ provider.execute();
+ assertEquals(true, provider.isExecuted());
+ }
+ }
+
+ /**
+ * Test clone() and equals().
+ */
+ public void testAbstractBuiltinSpecsDetector_CloneAndEquals() throws Exception {
+ // define mock detector
+ class MockDetectorCloneable extends MockBuiltinSpecsDetectorExecutedFlag implements Cloneable {
+ @Override
+ public MockDetectorCloneable clone() throws CloneNotSupportedException {
+ return (MockDetectorCloneable) super.clone();
+ }
+ @Override
+ public MockDetectorCloneable cloneShallow() throws CloneNotSupportedException {
+ return (MockDetectorCloneable) super.cloneShallow();
+ }
+ }
+
+ // create instance to compare to
+ MockDetectorCloneable provider = new MockDetectorCloneable();
+
+ List<String> languages = new ArrayList<String>();
+ languages.add(LANGUAGE_ID);
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+ ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ entries.add(entry);
+
+ // check clone after initialization
+ MockDetectorCloneable clone0 = provider.clone();
+ assertTrue(provider.equals(clone0));
+
+ // configure provider
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(ATTR_PARAMETER, CUSTOM_PARAMETER);
+ provider.configureProvider(PROVIDER_ID, PROVIDER_NAME, languages, entries, properties);
+ assertEquals(false, provider.isConsoleEnabled());
+ provider.setConsoleEnabled(true);
+ provider.execute();
+ assertEquals(true, provider.isExecuted());
+ assertFalse(provider.equals(clone0));
+
+ // check another clone after configuring
+ {
+ MockDetectorCloneable clone = provider.clone();
+ assertTrue(provider.equals(clone));
+ }
+
+ // check custom parameter
+ {
+ MockDetectorCloneable clone = provider.clone();
+ clone.setCommand("changed");
+ assertFalse(provider.equals(clone));
+ }
+
+ // check language scope
+ {
+ MockDetectorCloneable clone = provider.clone();
+ clone.setLanguageScope(null);
+ assertFalse(provider.equals(clone));
+ }
+
+ // check console flag
+ {
+ MockDetectorCloneable clone = provider.clone();
+ boolean isConsoleEnabled = clone.isConsoleEnabled();
+ clone.setConsoleEnabled( ! isConsoleEnabled );
+ assertFalse(provider.equals(clone));
+ }
+
+ // check isExecuted flag
+ {
+ MockDetectorCloneable clone = provider.clone();
+ assertEquals(true, clone.isExecuted());
+ clone.clear();
+ assertEquals(false, clone.isExecuted());
+ assertFalse(provider.equals(clone));
+ }
+
+ // check entries
+ {
+ MockDetectorCloneable clone = provider.clone();
+ clone.setSettingEntries(null, null, null, null);
+ assertFalse(provider.equals(clone));
+ }
+
+ // check cloneShallow()
+ {
+ MockDetectorCloneable provider2 = provider.clone();
+ MockDetectorCloneable clone = provider2.cloneShallow();
+ assertEquals(false, clone.isExecuted());
+ assertFalse(provider2.equals(clone));
+
+ provider2.setSettingEntries(null, null, null, null);
+ assertFalse(provider2.equals(clone));
+
+ clone.execute();
+ assertTrue(provider2.equals(clone));
+ }
+ }
+
+ /**
+ * Test basic serialization functionality.
+ */
+ public void testAbstractBuiltinSpecsDetector_SerializeDOM() throws Exception {
+ {
+ // create empty XML
+ Document doc = XmlUtil.newDocument();
+ Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST);
+
+ // initialize provider
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ assertEquals(false, provider.isExecuted());
+ // load the XML to new provider
+ provider.load(rootElement);
+ assertEquals(false, provider.isConsoleEnabled());
+ assertEquals(false, provider.isExecuted());
+ }
+
+ Element elementProvider;
+ {
+ // define mock detector
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ assertEquals(false, provider.isConsoleEnabled());
+ assertEquals(false, provider.isExecuted());
+
+ // redefine the settings
+ provider.setConsoleEnabled(true);
+ assertEquals(true, provider.isConsoleEnabled());
+
+ // serialize in XML
+ Document doc = XmlUtil.newDocument();
+ Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST);
+ elementProvider = provider.serialize(rootElement);
+ String xmlString = XmlUtil.toString(doc);
+
+ assertTrue(xmlString.contains(ATTR_CONSOLE));
+ }
+ {
+ // create another instance of the provider
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ assertEquals(false, provider.isConsoleEnabled());
+ assertEquals(false, provider.isExecuted());
+
+ // load element
+ provider.load(elementProvider);
+ assertEquals(true, provider.isConsoleEnabled());
+ assertEquals(false, provider.isExecuted());
+ }
+ }
+
+ /**
+ * Test serialization of entries and "isExecuted" flag handling.
+ */
+ public void testAbstractBuiltinSpecsDetector_SerializeEntriesDOM() throws Exception {
+ Element rootElement;
+ {
+ // create provider
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+ entries.add(new CIncludePathEntry("path0", 1));
+ provider.setSettingEntries(null, null, null, entries);
+ // serialize entries
+ Document doc = XmlUtil.newDocument();
+ rootElement = XmlUtil.appendElement(doc, ELEM_TEST);
+ provider.serializeEntries(rootElement);
+ // check XML
+ String xmlString = XmlUtil.toString(doc);
+ assertTrue(xmlString.contains("path0"));
+ }
+
+ {
+ // create new provider
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ assertEquals(true, provider.isEmpty());
+ assertEquals(false, provider.isExecuted());
+
+ // load the XML to the new provider
+ provider.load(rootElement);
+ List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, null, null);
+ assertNotNull(entries);
+ assertTrue(entries.size() > 0);
+ assertEquals(new CIncludePathEntry("path0", 1), entries.get(0));
+ assertEquals(false, provider.isEmpty());
+ assertEquals(true, provider.isExecuted());
+
+ // clear the new provider
+ provider.clear();
+ assertEquals(true, provider.isEmpty());
+ assertEquals(false, provider.isExecuted());
+ }
+
+ {
+ // create new provider
+ MockBuiltinSpecsDetectorExecutedFlag provider = new MockBuiltinSpecsDetectorExecutedFlag();
+ assertEquals(true, provider.isEmpty());
+ assertEquals(false, provider.isExecuted());
+
+ // execute provider
+ provider.execute();
+ List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, null, null);
+ assertEquals(null, entries);
+ // executed provider should NOT appear as empty even with no entries set
+ assertEquals(false, provider.isEmpty());
+ assertEquals(true, provider.isExecuted());
+ }
+ }
+
+ /**
+ * Smoke test exercising passing {@code null} to the functions.
+ */
+ public void testAbstractBuiltinSpecsDetector_Nulls() throws Exception {
+ {
+ // test AbstractBuiltinSpecsDetector.processLine(...) flow
+ MockBuiltinSpecsDetector provider = new MockBuiltinSpecsDetector();
+ provider.startup(null, null);
+ provider.startupForLanguage(null);
+ provider.processLine(null);
+ provider.shutdownForLanguage();
+ provider.shutdown();
+ }
+ {
+ // test AbstractBuiltinSpecsDetector.processLine(...) flow
+ MockConsoleBuiltinSpecsDetector provider = new MockConsoleBuiltinSpecsDetector();
+ provider.startup(null, null);
+ provider.runForEachLanguage(null);
+ provider.shutdown();
+ }
+ }
+
+ /**
+ * Test basic parsing functionality.
+ */
+ public void testAbstractBuiltinSpecsDetector_RunConfiguration() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ MockConsoleBuiltinSpecsDetector provider = new MockConsoleBuiltinSpecsDetector();
+ provider.setLanguageScope(new ArrayList<String>() {{add(LANGUAGE_ID);}});
+
+ // Run provider
+ provider.startup(cfgDescription, null);
+ provider.runForEachLanguage(null);
+ provider.shutdown();
+
+ assertFalse(provider.isEmpty());
+
+ List<ICLanguageSettingEntry> noentries = provider.getSettingEntries(null, null, null);
+ assertNull(noentries);
+
+ // Check parsed entries
+ List<ICLanguageSettingEntry> entries = provider.getSettingEntries(cfgDescription, null, LANGUAGE_ID);
+ ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ assertEquals(expected, entries.get(0));
+ }
+
+ /**
+ * Smoke test running as global provider on workspace level.
+ */
+ public void testAbstractBuiltinSpecsDetector_RunGlobal() throws Exception {
+ // Create provider
+ MockConsoleBuiltinSpecsDetector provider = new MockConsoleBuiltinSpecsDetector();
+ provider.setLanguageScope(new ArrayList<String>() {{add(LANGUAGE_ID);}});
+
+ // Run provider
+ provider.startup(null, null);
+ provider.runForEachLanguage(null);
+ provider.shutdown();
+
+ assertFalse(provider.isEmpty());
+
+ // Check parsed entries
+ List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, null, LANGUAGE_ID);
+ ICLanguageSettingEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ assertEquals(expected, entries.get(0));
+ }
+
+ /**
+ * Check that entries get grouped by kinds by stock built-in specs detector.
+ */
+ public void testAbstractBuiltinSpecsDetector_GroupSettings() throws Exception {
+ // define benchmarks
+ final CIncludePathEntry includePath_1 = new CIncludePathEntry("/include/path_1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CIncludePathEntry includePath_2 = new CIncludePathEntry("/include/path_2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CIncludeFileEntry includeFile_1 = new CIncludeFileEntry(new Path("/include.file1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CIncludeFileEntry includeFile_2 = new CIncludeFileEntry(new Path("/include.file2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CMacroEntry macro_1 = new CMacroEntry("MACRO_1", "", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CMacroEntry macro_2 = new CMacroEntry("MACRO_2", "", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY |ICSettingEntry.UNDEFINED);
+ final CMacroFileEntry macroFile_1 = new CMacroFileEntry(new Path("/macro.file1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CMacroFileEntry macroFile_2 = new CMacroFileEntry(new Path("/macro.file2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CLibraryPathEntry libraryPath_1 = new CLibraryPathEntry(new Path("/lib/path_1"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CLibraryPathEntry libraryPath_2 = new CLibraryPathEntry(new Path("/lib/path_2"), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CLibraryFileEntry libraryFile_1 = new CLibraryFileEntry("lib_1.a", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ final CLibraryFileEntry libraryFile_2 = new CLibraryFileEntry("lib_2.a", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+
+ // Define mock detector adding unorganized entries
+ MockBuiltinSpecsDetector provider = new MockBuiltinSpecsDetector() {
+ @Override
+ public boolean processLine(String line) {
+ detectedSettingEntries.add(libraryFile_1);
+ detectedSettingEntries.add(libraryPath_1);
+ detectedSettingEntries.add(macroFile_1);
+ detectedSettingEntries.add(macro_1);
+ detectedSettingEntries.add(includeFile_1);
+ detectedSettingEntries.add(includePath_1);
+
+ detectedSettingEntries.add(includePath_2);
+ detectedSettingEntries.add(includeFile_2);
+ detectedSettingEntries.add(macro_2);
+ detectedSettingEntries.add(macroFile_2);
+ detectedSettingEntries.add(libraryPath_2);
+ detectedSettingEntries.add(libraryFile_2);
+ return true;
+ }
+ };
+
+ // run specs detector
+ provider.startup(null, null);
+ provider.startupForLanguage(null);
+ provider.processLine("");
+ provider.shutdownForLanguage();
+ provider.shutdown();
+
+ // compare benchmarks, expected well-sorted
+ List<ICLanguageSettingEntry> entries = provider.getSettingEntries(null, null, null);
+
+ int i = 0;
+ assertEquals(includePath_1, entries.get(i++));
+ assertEquals(includePath_2, entries.get(i++));
+ assertEquals(includeFile_1, entries.get(i++));
+ assertEquals(includeFile_2, entries.get(i++));
+ assertEquals(macro_1, entries.get(i++));
+ assertEquals(macro_2, entries.get(i++));
+ assertEquals(macroFile_1, entries.get(i++));
+ assertEquals(macroFile_2, entries.get(i++));
+ assertEquals(libraryPath_1, entries.get(i++));
+ assertEquals(libraryPath_2, entries.get(i++));
+ assertEquals(libraryFile_1, entries.get(i++));
+ assertEquals(libraryFile_2, entries.get(i++));
+
+ assertEquals(12, entries.size());
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java
new file mode 100644
index 0000000000..8f49f26aa2
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuildCommandParserTest.java
@@ -0,0 +1,2208 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.language.settings.providers.tests;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.settings.model.CIncludeFileEntry;
+import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
+import org.eclipse.cdt.core.settings.model.CLibraryFileEntry;
+import org.eclipse.cdt.core.settings.model.CLibraryPathEntry;
+import org.eclipse.cdt.core.settings.model.CMacroEntry;
+import org.eclipse.cdt.core.settings.model.CMacroFileEntry;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.cdt.core.testplugin.ResourceHelper;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.internal.core.XmlUtil;
+import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.AbstractBuildCommandParser;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.core.runtime.content.IContentTypeSettings;
+import org.eclipse.core.runtime.jobs.Job;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Test cases to test build command parsers.
+ */
+public class GCCBuildCommandParserTest extends BaseTestCase {
+ // ID of the parser taken from the extension point
+ private static final String GCC_BUILD_COMMAND_PARSER_EXT = "org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"; //$NON-NLS-1$
+
+ private static final String PROVIDER_ID = "provider.id";
+ private static final String PROVIDER_NAME = "provider name";
+ private static final String LANGUAGE_ID = "language.test.id";
+ private static final String CUSTOM_PARAMETER = "customParameter";
+ private static final String CUSTOM_PARAMETER_2 = "customParameter2";
+ private static final String ELEM_TEST = "test";
+ private static final String LANG_CPP = GPPLanguage.ID;
+
+ // those attributes must match that in AbstractBuildCommandParser
+ private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$
+ private static final String ATTR_KEEP_RELATIVE_PATHS = "keep-relative-paths"; //$NON-NLS-1$
+
+ /**
+ * Mock build command parser.
+ */
+ private class MockBuildCommandParser extends AbstractBuildCommandParser implements Cloneable {
+ public MockBuildCommandParser() {
+ setId("GCCBuildCommandParserTest.MockBuildCommandParser");
+ }
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return new AbstractOptionParser[] {};
+ }
+ @Override
+ public MockBuildCommandParser cloneShallow() throws CloneNotSupportedException {
+ return (MockBuildCommandParser) super.cloneShallow();
+ }
+ @Override
+ public MockBuildCommandParser clone() throws CloneNotSupportedException {
+ return (MockBuildCommandParser) super.clone();
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ Job.getJobManager().join(AbstractBuildCommandParser.JOB_FAMILY_BUILD_COMMAND_PARSER, null);
+ } catch (Exception e) {
+ // ignore
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Helper method to fetch configuration descriptions.
+ */
+ private ICConfigurationDescription[] getConfigurationDescriptions(IProject project) {
+ CoreModel coreModel = CoreModel.getDefault();
+ ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager();
+ // project description
+ ICProjectDescription projectDescription = mngr.getProjectDescription(project, false);
+ assertNotNull(projectDescription);
+ assertEquals(1, projectDescription.getConfigurations().length);
+ // configuration description
+ ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations();
+ return cfgDescriptions;
+ }
+
+ /**
+ * Sets build working directory for DefaultSettingConfiguration being tested.
+ */
+ private void setBuilderCWD(IProject project, IPath buildCWD) throws CoreException {
+ CProjectDescriptionManager manager = CProjectDescriptionManager.getInstance();
+ {
+ ICProjectDescription prjDescription = manager.getProjectDescription(project, true);
+ assertNotNull(prjDescription);
+ ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration();
+ assertNotNull(cfgDescription);
+
+ cfgDescription.getBuildSetting().setBuilderCWD(buildCWD);
+ manager.setProjectDescription(project, prjDescription);
+ // doublecheck builderCWD
+ IPath actualBuildCWD = cfgDescription.getBuildSetting().getBuilderCWD();
+ assertEquals(buildCWD, actualBuildCWD);
+ }
+ {
+ // triplecheck builderCWD for different project/configuration descriptions
+ ICProjectDescription prjDescription = CProjectDescriptionManager.getInstance().getProjectDescription(project, false);
+ assertNotNull(prjDescription);
+ ICConfigurationDescription cfgDescription = prjDescription.getDefaultSettingConfiguration();
+ assertNotNull(cfgDescription);
+
+ }
+ }
+
+ /**
+ * Helper method to set reference project.
+ */
+ private void setReference(IProject project, final IProject projectReferenced) throws CoreException {
+ {
+ CoreModel coreModel = CoreModel.getDefault();
+ ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager();
+ // project description
+ ICProjectDescription projectDescription = mngr.getProjectDescription(project);
+ assertNotNull(projectDescription);
+ assertEquals(1, projectDescription.getConfigurations().length);
+ // configuration description
+ ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations();
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ final ICConfigurationDescription cfgDescriptionReferenced = getConfigurationDescriptions(projectReferenced)[0];
+ cfgDescription.setReferenceInfo(new HashMap<String, String>() {{ put(projectReferenced.getName(), cfgDescriptionReferenced.getId()); }});
+ coreModel.setProjectDescription(project, projectDescription);
+ }
+
+ {
+ // doublecheck that it's set as expected
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+ Map<String,String> refs = cfgDescription.getReferenceInfo();
+ assertEquals(1, refs.size());
+ Set<String> referencedProjectsNames = new LinkedHashSet<String>(refs.keySet());
+ assertEquals(projectReferenced.getName(), referencedProjectsNames.toArray()[0]);
+ }
+
+ }
+
+
+ /**
+ * Test getters and setters.
+ */
+ public void testAbstractBuildCommandParser_GettersSetters() throws Exception {
+ {
+ // provider configured with null parameters
+ MockBuildCommandParser provider = new MockBuildCommandParser();
+ provider.configureProvider(PROVIDER_ID, PROVIDER_NAME, null, null, null);
+
+ assertEquals(PROVIDER_ID, provider.getId());
+ assertEquals(PROVIDER_NAME, provider.getName());
+ assertEquals(null, provider.getLanguageScope());
+ assertEquals(null, provider.getSettingEntries(null, null, null));
+ assertEquals("", provider.getCompilerPattern());
+ assertEquals(AbstractBuildCommandParser.ResourceScope.FILE, provider.getResourceScope());
+ }
+
+ {
+ // provider configured with non-null parameters
+ MockBuildCommandParser provider = new MockBuildCommandParser();
+ List<String> languages = new ArrayList<String>();
+ languages.add(LANGUAGE_ID);
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(ATTR_PARAMETER, CUSTOM_PARAMETER);
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+ ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY);
+ entries.add(entry);
+
+ provider.configureProvider(PROVIDER_ID, PROVIDER_NAME, languages, entries, properties);
+ assertEquals(PROVIDER_ID, provider.getId());
+ assertEquals(PROVIDER_NAME, provider.getName());
+ assertEquals(languages, provider.getLanguageScope());
+ assertEquals(entries, provider.getSettingEntries(null, null, null));
+ assertEquals(CUSTOM_PARAMETER, provider.getCompilerPattern());
+
+ // setters
+ provider.setCompilerPattern(CUSTOM_PARAMETER_2);
+ assertEquals(CUSTOM_PARAMETER_2, provider.getCompilerPattern());
+ provider.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, provider.getResourceScope());
+ }
+ }
+
+ /**
+ * Test clone() and equals().
+ */
+ public void testAbstractBuildCommandParser_CloneAndEquals() throws Exception {
+ // create instance to compare to
+ MockBuildCommandParser parser = new MockBuildCommandParser();
+ assertEquals(true, parser.isResolvingPaths());
+
+ // check clone after initialization
+ MockBuildCommandParser clone0 = parser.clone();
+ assertTrue(parser.equals(clone0));
+
+ // configure provider
+ parser.setResolvingPaths(false);
+ assertFalse(parser.equals(clone0));
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope());
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.FOLDER, parser.getResourceScope());
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FILE);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.FILE, parser.getResourceScope());
+
+ // check another clone after changing settings
+ {
+ parser.setResolvingPaths(false);
+ assertFalse(parser.equals(clone0));
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope());
+ MockBuildCommandParser clone = parser.clone();
+ assertTrue(parser.equals(clone));
+ assertEquals(parser.isResolvingPaths(), clone.isResolvingPaths());
+ assertEquals(parser.getResourceScope(), clone.getResourceScope());
+ }
+
+ // check 'expand relative paths' flag
+ {
+ MockBuildCommandParser clone = parser.clone();
+ boolean expandRelativePaths = clone.isResolvingPaths();
+ clone.setResolvingPaths( ! expandRelativePaths );
+ assertFalse(parser.equals(clone));
+ }
+
+ // check resource scope
+ {
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+ assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, parser.getResourceScope());
+ MockBuildCommandParser clone = parser.clone();
+ assertEquals(AbstractBuildCommandParser.ResourceScope.PROJECT, clone.getResourceScope());
+ clone.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER);
+ assertFalse(parser.equals(clone));
+ }
+
+ // check cloneShallow()
+ {
+ MockBuildCommandParser parser2 = parser.clone();
+ MockBuildCommandParser clone = parser2.cloneShallow();
+ assertTrue(parser2.equals(clone));
+ }
+
+ }
+
+ /**
+ * Test basic serialization functionality.
+ */
+ public void testAbstractBuildCommandParser_SerializeDOM() throws Exception {
+ {
+ // create empty XML
+ Document doc = XmlUtil.newDocument();
+ Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST);
+
+ // load it to new provider
+ MockBuildCommandParser parser = new MockBuildCommandParser();
+ parser.load(rootElement);
+ assertEquals(true, parser.isResolvingPaths());
+ }
+
+ Element elementProvider;
+ {
+ // define mock parser
+ MockBuildCommandParser parser = new MockBuildCommandParser();
+ assertEquals(true, parser.isResolvingPaths());
+
+ // redefine the settings
+ parser.setResolvingPaths(false);
+ assertEquals(false, parser.isResolvingPaths());
+
+ // serialize in XML
+ Document doc = XmlUtil.newDocument();
+ Element rootElement = XmlUtil.appendElement(doc, ELEM_TEST);
+ elementProvider = parser.serialize(rootElement);
+ String xmlString = XmlUtil.toString(doc);
+
+ assertTrue(xmlString.contains(ATTR_KEEP_RELATIVE_PATHS));
+ }
+ {
+ // create another instance of the provider
+ MockBuildCommandParser parser = new MockBuildCommandParser();
+ assertEquals(true, parser.isResolvingPaths());
+
+ // load element
+ parser.load(elementProvider);
+ assertEquals(false, parser.isResolvingPaths());
+ }
+ }
+
+ /**
+ * Smoke test exercising passing {@code null} to the functions.
+ */
+ public void testAbstractBuildCommandParser_Nulls() throws Exception {
+ MockBuildCommandParser parser = new MockBuildCommandParser();
+ parser.startup(null, null);
+ parser.processLine(null);
+ parser.shutdown();
+
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(null, null, null);
+ assertNull(entries);
+ }
+
+ /**
+ * Test basic parsing functionality.
+ */
+ public void testAbstractBuildCommandParser_Basic() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ final IFile file=ResourceHelper.createFile(project, "file.cpp");
+
+ // create test class
+ AbstractBuildCommandParser parser = new MockBuildCommandParser() {
+ @Override
+ public boolean processLine(String line) {
+ // pretending that we parsed the line
+ currentResource = file;
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+ ICLanguageSettingEntry entry = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN);
+ entries.add(entry);
+ setSettingEntries(entries);
+ return true;
+ }
+ };
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -DMACRO=VALUE file.cpp");
+ parser.shutdown();
+
+ // sanity check that it does not return same values for all inputs
+ List<ICLanguageSettingEntry> noentries = parser.getSettingEntries(null, null, null);
+ assertNull(noentries);
+
+ // check populated entries
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CMacroEntry expected = new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN);
+ assertEquals(expected, entries.get(0));
+ }
+
+ /**
+ * Test parsing of one typical entry.
+ */
+ public void testOneEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath path = new Path("/path0").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Test possible variations of compiler command.
+ */
+ public void testGccFlavors() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file1=ResourceHelper.createFile(project, "file1.cpp");
+ IFile file2=ResourceHelper.createFile(project, "file2.cpp");
+ IFile file3=ResourceHelper.createFile(project, "file3.cpp");
+ IFile file4=ResourceHelper.createFile(project, "file4.cpp");
+ IFile file5=ResourceHelper.createFile(project, "file5.cpp");
+ IFile file6=ResourceHelper.createFile(project, "file6.cpp");
+ IFile file7=ResourceHelper.createFile(project, "file7.cpp");
+ IFile file8=ResourceHelper.createFile(project, "file8.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file1.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file1.cpp");
+ parser.processLine("gcc-4.2 -I/path0 file2.cpp");
+ parser.processLine("g++ -I/path0 file3.cpp");
+ parser.processLine("c++ -I/path0 file4.cpp");
+ parser.processLine("\"gcc\" -I/path0 file5.cpp");
+ parser.processLine("/absolute/path/gcc -I/path0 file6.cpp");
+ parser.processLine(" \"/absolute/path/gcc\" -I/path0 file7.cpp");
+ parser.processLine("../relative/path/gcc -I/path0 file8.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file1, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file2, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file3, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file4, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file5, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file6, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file7, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file8, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ }
+ }
+
+ /**
+ * Parse variations of -I options.
+ */
+ public void testCIncludePathEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc"
+ // regular
+ + " -I/path0 "
+ // space after -I
+ + " -I /path1 "
+ // unknown option, should be ignored
+ + " -? "
+ // double-quoted path with spaces
+ + " -I\"/path with spaces\""
+ // single-quoted path with spaces
+ + " -I'/path with spaces2'"
+ // second single-quoted and space after -I
+ + " -I '/path with spaces3'"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath path = new Path("/path0").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/path1").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(1);
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/path with spaces").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(2);
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/path with spaces2").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(3);
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/path with spaces3").setDevice(project.getLocation().getDevice());
+ CIncludePathEntry expected = new CIncludePathEntry(path, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(4);
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Parse variations of -D options.
+ */
+ public void testCMacroEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -DMACRO0"
+ + " -DMACRO1=value"
+ + " -DMACRO2=\"value with spaces\""
+ + " -DMACRO3='value with spaces'"
+ + " -DMACRO4='\"quoted value\"'"
+ + " -D'MACRO5=\"quoted value\"'"
+ + " -DMACRO6=\\\"escape-quoted value\\\""
+ + " -DMACRO7=\"'single-quoted value'\""
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO0", "", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO1", "value", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(1);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO2", "value with spaces", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(2);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO3", "value with spaces", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(3);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO4", "\"quoted value\"", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(4);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO5", "\"quoted value\"", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(5);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO6", "\"escape-quoted value\"", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(6);
+ assertEquals(expected, entry);
+ }
+ {
+ CMacroEntry expected = new CMacroEntry("MACRO7", "'single-quoted value'", 0);
+ CMacroEntry entry = (CMacroEntry)entries.get(7);
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Parse -U option.
+ */
+ public void testCMacroEntry_undef() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -UMACRO"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CMacroEntry("MACRO", null, ICSettingEntry.UNDEFINED), entries.get(0));
+ }
+ }
+
+ /**
+ * Parse variations of -include options.
+ */
+ public void testCIncludeFileEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -include /include.file1"
+ + " -include '/include.file with spaces'"
+ + " -include ../../include.file2"
+ + " -include include.file3"
+ + " -include ../../include-file-with-dashes"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath incFile = new Path("/include.file1").setDevice(project.getLocation().getDevice());
+ CIncludeFileEntry expected = new CIncludeFileEntry(incFile, 0);
+ CIncludeFileEntry entry = (CIncludeFileEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+
+ {
+ IPath incFile = new Path("/include.file with spaces").setDevice(project.getLocation().getDevice());
+ assertEquals(new CIncludeFileEntry(incFile, 0), entries.get(1));
+ }
+ {
+ assertEquals(new CIncludeFileEntry(project.getLocation().removeLastSegments(2).append("include.file2"), 0), entries.get(2));
+ assertEquals(new CIncludeFileEntry(project.getFullPath().append("include.file3"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3));
+ assertEquals(new CIncludeFileEntry(project.getLocation().removeLastSegments(2).append("include-file-with-dashes"), 0), entries.get(4));
+ }
+ }
+
+ /**
+ * Parse variations of -macros options.
+ */
+ public void testCMacroFileEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -macros macro.file file.cpp");
+ parser.processLine("gcc "
+ + " -macros /macro.file"
+ + " -macros '/macro.file with spaces'"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath path = new Path("/macro.file").setDevice(project.getLocation().getDevice());
+ CMacroFileEntry expected = new CMacroFileEntry(path, 0);
+ CMacroFileEntry entry = (CMacroFileEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/macro.file with spaces").setDevice(project.getLocation().getDevice());
+ CMacroFileEntry expected = new CMacroFileEntry(path, 0);
+ CMacroFileEntry entry = (CMacroFileEntry)entries.get(1);
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Parse variations of -L options.
+ */
+ public void testCLibraryPathEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -L/path0"
+ + " -L'/path with spaces'"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath path = new Path("/path0").setDevice(project.getLocation().getDevice());
+ CLibraryPathEntry expected = new CLibraryPathEntry(path, 0);
+ CLibraryPathEntry entry = (CLibraryPathEntry)entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+ {
+ IPath path = new Path("/path with spaces").setDevice(project.getLocation().getDevice());
+ CLibraryPathEntry expected = new CLibraryPathEntry(path, 0);
+ CLibraryPathEntry entry = (CLibraryPathEntry)entries.get(1);
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Parse variations of -l options.
+ */
+ public void testCLibraryFileEntry() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -ldomain file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CLibraryFileEntry expected = new CLibraryFileEntry("libdomain.a", 0);
+ CLibraryFileEntry entry = (CLibraryFileEntry) entries.get(0);
+ assertEquals(expected.getName(), entry.getName());
+ assertEquals(expected.getValue(), entry.getValue());
+ assertEquals(expected.getKind(), entry.getKind());
+ assertEquals(expected.getFlags(), entry.getFlags());
+ assertEquals(expected, entry);
+ }
+
+ /**
+ * Parse mixed options in the same command.
+ */
+ public void testMixedSettingEntries() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc"
+ + " -I/path0 "
+ + " -DMACRO1=value"
+ + " -v"
+ + " -ldomain"
+ + " -E"
+ + " -I /path1 "
+ + " -DMACRO2=\"value with spaces\""
+ + " -I\"/path with spaces\""
+ + " -o file.exe"
+ + " -L/usr/lib"
+ + " file.cpp"
+ + " -mtune=pentiumpro"
+ );
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ String device = project.getLocation().getDevice();
+// + " -I/path0 "
+ assertEquals(new CIncludePathEntry(new Path("/path0").setDevice(device), 0), entries.get(0));
+// + " -I /path1 "
+ assertEquals(new CIncludePathEntry(new Path("/path1").setDevice(device), 0), entries.get(1));
+// + " -I\"/path with spaces\""
+ assertEquals(new CIncludePathEntry(new Path("/path with spaces").setDevice(device), 0), entries.get(2));
+// + " -DMACRO1=value"
+ assertEquals(new CMacroEntry("MACRO1", "value", 0), entries.get(3));
+// + " -DMACRO2=\"value with spaces\""
+ assertEquals(new CMacroEntry("MACRO2", "value with spaces", 0), entries.get(4));
+// + " -L/usr/lib"
+ assertEquals(new CLibraryPathEntry(new Path("/usr/lib").setDevice(device), 0), entries.get(5));
+// + " -ldomain"
+ assertEquals(new CLibraryFileEntry("libdomain.a", 0), entries.get(6));
+ assertEquals(7, entries.size());
+ }
+
+ /**
+ * Parse command where resource is missing.
+ */
+ public void testFileMissing() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 missing.cpp");
+ parser.shutdown();
+
+ // check entries
+ assertTrue(parser.isEmpty());
+ }
+
+ /**
+ * Parsing of absolute path to the file being compiled.
+ */
+ public void testFileAbsolutePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + "-I/path0 "
+ + "-I. "
+ + file.getLocation().toOSString());
+ parser.shutdown();
+
+ // check entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+ }
+
+ /**
+ * Parsing of absolute path to the file being compiled where provider is global.
+ */
+ public void testFileAbsolutePath_NoProject() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(null, null);
+ parser.processLine("gcc "
+ + "-I/path0 "
+ + "-I. "
+ + file.getLocation().toOSString());
+ parser.shutdown();
+
+ // check entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(null, file, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ assertEquals(new CIncludePathEntry(file.getParent().getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+ }
+
+ /**
+ * Parsing where the name of the file being compiled contains spaces.
+ */
+ public void testFileWithSpaces() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file1=ResourceHelper.createFile(project, "file with spaces 1.cpp");
+ IFile file2=ResourceHelper.createFile(project, "file with spaces 2.cpp");
+ IFile file3=ResourceHelper.createFile(project, "file with spaces 3.cpp");
+ IFile file4=ResourceHelper.createFile(project, "file with spaces 4.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file1.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 'file with spaces 1.cpp'");
+ parser.processLine("gcc -I/path0 \"file with spaces 2.cpp\"");
+ parser.processLine("gcc -I/path0 'file with spaces 3.cpp'\n");
+ parser.processLine("gcc -I/path0 'file with spaces 4.cpp'\r\n");
+ parser.shutdown();
+
+ // check populated entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ // in single quotes
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file1, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+ {
+ // in double quotes
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file2, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+ {
+ // Unix EOL
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file3, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+ {
+ // Windows EOL
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file4, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+ }
+
+ /**
+ * Resolve disagreement between working directory and path to the file being compiled.
+ */
+ public void testFileIgnoreWrongBuildDir() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ IFolder folder1=ResourceHelper.createFolder(project, "Folder1");
+ IFile file=ResourceHelper.createFile(project, "Folder1/Folder2/file.cpp");
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+ // Shift build directory, that could happen if Make Target from folder1 was run
+ // Build directory points to /project/Folder1/
+ IFolder buildDir = folder1;
+ epm.pushDirectoryURI(buildDir.getLocationURI());
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + "-I/path0 "
+ + "-I. "
+ // This implies the build working directory is /project/
+ + "Folder1/Folder2/file.cpp");
+ parser.shutdown();
+
+ // check entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(new CIncludePathEntry(path0, 0), entries.get(0));
+ // Information from build output should take precedence over build dir
+ assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+ }
+
+ /**
+ * Test various ends of lines for the lines being parsed.
+ */
+ public void testEndOfLine() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file0=ResourceHelper.createFile(project, "file0.cpp");
+ IFile file1=ResourceHelper.createFile(project, "file1.cpp");
+ IFile file2=ResourceHelper.createFile(project, "file2.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file0.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file0.cpp");
+ parser.processLine("gcc -I/path0 file1.cpp\n");
+ parser.processLine("gcc -I/path0 file2.cpp\r\n");
+ parser.shutdown();
+
+ // check populated entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file0, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(0);
+ assertEquals(expected, entry);
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file1, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(0);
+ assertEquals(expected, entry);
+ }
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file2, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ CIncludePathEntry entry = (CIncludePathEntry)entries.get(0);
+ assertEquals(expected, entry);
+ }
+ }
+
+ /**
+ * Test parsing of paths located on a different drive on Windows.
+ */
+ public void testPathEntry_DriveLetter() throws Exception {
+ // do not test on non-windows systems where drive letters are not supported
+ if (! Platform.getOS().equals(Platform.OS_WIN32))
+ return;
+
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResolvingPaths(true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -IX:\\path"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(new CIncludePathEntry(new Path("X:\\path"), 0), entries.get(0));
+ }
+
+ /**
+ * Test various relative paths provided in options with resolving.
+ */
+ public void testPathEntry_ExpandRelativePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ IFolder folder=ResourceHelper.createFolder(project, "Folder");
+ IFolder folderComposite=ResourceHelper.createFolder(project, "Folder-Icomposite");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResolvingPaths(true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I.."
+ + " -IFolder"
+ + " -IFolder-Icomposite" // to test case when "-I" is a part of folder name
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ // check that relative paths are relative to CWD which is the location of the project
+ assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(project.getLocation().removeLastSegments(1), 0), entries.get(1));
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2));
+ assertEquals(new CIncludePathEntry(folderComposite.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3));
+ }
+ }
+
+ /**
+ * Test various relative paths provided in options without resolving.
+ */
+ public void testPathEntry_DoNotExpandRelativePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ @SuppressWarnings("unused")
+ IFolder folder=ResourceHelper.createFolder(project, "Folder");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser with expandRelativePaths=false
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResolvingPaths(false);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I.."
+ + " -IFolder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(".", 0), entries.get(0));
+ assertEquals(new CIncludePathEntry("..", 0), entries.get(1));
+ assertEquals(new CIncludePathEntry("Folder", 0), entries.get(2));
+ }
+ }
+
+ /**
+ * Ensure that duplicate paths are ignored.
+ */
+ public void testPathEntry_DuplicatePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ IFolder folder=ResourceHelper.createFolder(project, "Folder");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResolvingPaths(true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -IFolder"
+ + " -IFolder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+ }
+
+ /**
+ * Test that working directory supplied by ErrorParserManager is considered.
+ */
+ public void testPathEntry_FollowCWD() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir");
+ IFolder folder=ResourceHelper.createFolder(project, "BuildDir/Folder");
+ IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp");
+ @SuppressWarnings("unused")
+ IFile fakeFile=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+ // Set different working directory
+ epm.pushDirectoryURI(buildDir.getLocationURI());
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I.."
+ + " -I../../.."
+ + " -IFolder"
+ + " -IMissingFolder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().removeLastSegments(1), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ assertEquals(new CIncludePathEntry(buildDir.getLocation().removeLastSegments(3), 0), entries.get(2));
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(4));
+ }
+ }
+
+ /**
+ * Determine working directory basing on file being compiled.
+ */
+ public void testPathEntry_GuessCWD() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder folder=ResourceHelper.createFolder(project, "BuildDir/Folder");
+ IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -IFolder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ }
+
+ /**
+ * Test case when build command indicates impossible working directory.
+ */
+ public void testPathEntry_NonExistentCWD_Workspace() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder buildDir=project.getFolder("Missing/Folder");
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+ // define working directory
+ epm.pushDirectoryURI(buildDir.getLocationURI());
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I.."
+ + " -IFolder"
+ // indicates non-existing working directory
+ + " ../file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().removeLastSegments(1), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("Folder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2));
+ }
+ }
+
+ /**
+ * Test case when build command indicates impossible working directory and
+ * ErrorParserManager indicates non-existing working directory.
+ */
+ public void testPathEntry_NonExistentCWD_Filesystem() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+ URI uriBuildDir = new URI("file:/non-existing/path");
+ // define non-existing working directory
+ epm.pushDirectoryURI(uriBuildDir);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I.."
+ + " -IFolder"
+ // indicates non-existing working directory
+ + " ../file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ IPath buildPath = new Path(uriBuildDir.getPath()).setDevice(project.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(buildPath, 0), entries.get(0));
+ assertEquals(new CIncludePathEntry(buildPath.removeLastSegments(1), 0), entries.get(1));
+ assertEquals(new CIncludePathEntry(buildPath.append("Folder"), 0), entries.get(2));
+ }
+ }
+
+ /**
+ * Simulate mapping of a sub-folder in the project to remote URI.
+ */
+ public void testPathEntry_MappedRemoteFolder() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder buildDir=ResourceHelper.createFolder(project, "Local/BuildDir");
+ IFolder folder=ResourceHelper.createFolder(project, "Local/BuildDir/Folder");
+ IFolder folder2=ResourceHelper.createFolder(project, "Local/BuildDir/Folder2");
+ IFile file=ResourceHelper.createFile(project, "Local/BuildDir/file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+ // define working directory as URI pointing outside workspace
+ URI uriBuildDir = new URI("file:/BuildDir");
+ epm.pushDirectoryURI(uriBuildDir);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I."
+ + " -I/BuildDir/Folder"
+ + " -I../BuildDir/Folder2"
+ + " -I/BuildDir/MissingFolder"
+ + " -I../BuildDir/MissingFolder2"
+ + " /BuildDir/file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ assertEquals(new CIncludePathEntry(folder2.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(2));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(3));
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath().append("MissingFolder2"), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(4));
+ }
+ }
+
+ /**
+ * Test mapping folders heuristics - inside a project.
+ */
+ public void testPathEntry_MappedFolderInProject() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp");
+ IFolder mappedFolder=ResourceHelper.createFolder(project, "Mapped/Folder");
+ IFolder folder=ResourceHelper.createFolder(project, "Mapped/Folder/Subfolder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder1=ResourceHelper.createFolder(project, "One/Ambiguous/Folder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder2=ResourceHelper.createFolder(project, "Another/Ambiguous/Folder");
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I/Folder/Subfolder"
+ + " -I/Mapped/Folder"
+ + " -I/Ambiguous/Folder"
+ + " -I/Missing/Folder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(mappedFolder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+ {
+ IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(path, 0), entries.get(2));
+ }
+ {
+ IPath path = new Path("/Missing/Folder").setDevice(file.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(path, 0), entries.get(3));
+ }
+ }
+
+ /**
+ * Test mapping folders heuristics - mapping to another project.
+ */
+ public void testPathEntry_MappedFolderInAnotherProject() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ // create files and folders
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ // another project
+ IProject anotherProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-another");
+ IFolder folder=ResourceHelper.createFolder(anotherProject, "Mapped/Folder/Subfolder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder1=ResourceHelper.createFolder(anotherProject, "One/Ambiguous/Folder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder2=ResourceHelper.createFolder(anotherProject, "Another/Ambiguous/Folder");
+
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I/Folder/Subfolder"
+ + " -I/Ambiguous/Folder"
+ + " -I/Missing/Folder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ }
+ {
+ IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(path, 0), entries.get(1));
+ }
+ {
+ IPath path = new Path("/Missing/Folder").setDevice(file.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(path, 0), entries.get(2));
+ }
+ }
+
+ /**
+ * Test mapping folders heuristics - mapping to a referenced project.
+ */
+ public void testPathEntry_MappedFolderInReferencedProject() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+
+ // create main project
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+
+ // create another project (non-referenced)
+ IProject anotherProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-another");
+ @SuppressWarnings("unused")
+ IFolder folderInAnotherProject=ResourceHelper.createFolder(anotherProject, "Mapped/Folder/Subfolder");
+
+ // create referenced project
+ IProject referencedProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-referenced");
+ IFolder folderInReferencedProject=ResourceHelper.createFolder(referencedProject, "Mapped/Folder/Subfolder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder1=ResourceHelper.createFolder(referencedProject, "One/Ambiguous/Folder");
+ @SuppressWarnings("unused")
+ IFolder ambiguousFolder2=ResourceHelper.createFolder(referencedProject, "Another/Ambiguous/Folder");
+
+ setReference(project, referencedProject);
+
+ // get cfgDescription and language to work with
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I/Folder/Subfolder"
+ + " -I/Ambiguous/Folder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(folderInReferencedProject.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+
+ IPath path = new Path("/Ambiguous/Folder").setDevice(file.getLocation().getDevice());
+ assertEquals(new CIncludePathEntry(path, 0), entries.get(1));
+ }
+ }
+
+ /**
+ * Test ".." in symbolic links where the symbolic link is present as absolute path.
+ */
+ public void testPathEntry_NavigateSymbolicLinkUpAbsolute() throws Exception {
+ // do not test on systems where symbolic links are not supported
+ if (!ResourceHelper.isSymbolicLinkSupported())
+ return;
+
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ String languageId = LANG_CPP;
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+
+ // create link on the filesystem
+ IPath dir1 = ResourceHelper.createTemporaryFolder();
+ IPath dir2 = dir1.removeLastSegments(1);
+ IPath linkPath = dir1.append("linked");
+ ResourceHelper.createSymbolicLink(linkPath, dir2);
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ // "../" should navigate along filesystem path, not along the link itself
+ parser.processLine("gcc -I"+linkPath.toString()+"/.."+" file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(dir2.removeLastSegments(1), 0);
+ assertEquals(expected, entries.get(0));
+ }
+ }
+
+ /**
+ * Test ".." in symbolic links where the symbolic link is present as relative path.
+ */
+ public void testPathEntry_NavigateSymbolicLinkUpRelative() throws Exception {
+ // do not test on systems where symbolic links are not supported
+ if (!ResourceHelper.isSymbolicLinkSupported())
+ return;
+
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ String languageId = LANG_CPP;
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+
+ // create link
+ IFolder folder = ResourceHelper.createFolder(project, "folder");
+ IFolder subfolder = ResourceHelper.createFolder(project, "folder/subfolder");
+ IPath linkPath = project.getLocation().append("linked");
+ ResourceHelper.createSymbolicLink(linkPath, subfolder.getLocation());
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ // "../" should navigate along filesystem path, not along the link itself
+ parser.processLine("gcc -Ilinked/.."+" file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
+ assertEquals(expected, entries.get(0));
+ }
+ }
+
+ /**
+ * Determine working directory from configuration builder settings.
+ */
+ public void testPathEntry_BuildDirDefinedByConfiguration_RelativePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ // Create resources trying to confuse the parser
+ @SuppressWarnings("unused")
+ IFile fileInProjectRoot=ResourceHelper.createFile(project, "file.cpp");
+ @SuppressWarnings("unused")
+ IFolder includeDirInProjectRoot=ResourceHelper.createFolder(project, "include");
+ // Create resources meant to be found
+ IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir");
+ IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp");
+ IFolder includeDir=ResourceHelper.createFolder(project, "BuildDir/include");
+ // Change build dir
+ setBuilderCWD(project, buildDir.getLocation());
+
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -I."
+ + " -Iinclude"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(includeDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+ }
+
+ /**
+ * Test where working directory from command line disagrees with configuration builder settings.
+ */
+ public void testPathEntry_BuildDirDefinedByConfiguration_AbsolutePath() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ // Create resources trying to confuse the parser
+ @SuppressWarnings("unused")
+ IFile fileInProjectRoot=ResourceHelper.createFile(project, "file.cpp");
+ @SuppressWarnings("unused")
+ IFolder includeDirInProjectRoot=ResourceHelper.createFolder(project, "include");
+ // Create resources meant to be found
+ IFolder buildDir=ResourceHelper.createFolder(project, "BuildDir");
+ IFile file=ResourceHelper.createFile(project, "BuildDir/file.cpp");
+ IFolder includeDir=ResourceHelper.createFolder(project, "BuildDir/include");
+ // Change build dir
+ setBuilderCWD(project, buildDir.getLocation());
+
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc "
+ + " -I."
+ + " -Iinclude"
+ + " " + file.getLocation().toOSString()
+ );
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ assertEquals(new CIncludePathEntry(buildDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(includeDir.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(1));
+ }
+
+ }
+
+ /**
+ * Smoke test when non-C files appear in output, should not choke.
+ */
+ public void testContentType_None() throws Exception {
+ MockBuildCommandParser parser = new MockBuildCommandParser() {
+ @Override
+ protected String parseResourceName(String line) {
+ return "file.wrong-content-type";
+ }
+ };
+ parser.startup(null, null);
+ parser.processLine("gcc file.wrong-content-type");
+ parser.shutdown();
+
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(null, null, null);
+ assertNull(entries);
+ }
+
+ /**
+ * Test that unsupported language is ignored.
+ */
+ public void testContentType_Mismatch() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+ ResourceHelper.createFile(project, "file.c");
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ // restrict the parser's language scope to C++ only
+ parser.setLanguageScope(new ArrayList<String>() {{add(LANG_CPP);}});
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file.c");
+ parser.shutdown();
+
+ assertTrue(parser.isEmpty());
+ }
+
+ /**
+ * Test custom file extensions defined in content type.
+ */
+ public void testContentType_FileExtensions() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ String languageId = LANG_CPP;
+ // add custom extension to C++ content type
+ IContentTypeManager manager = Platform.getContentTypeManager();
+ IContentType contentType = manager.findContentTypeFor("file.cpp");
+ contentType.addFileSpec("x++", IContentTypeSettings.FILE_EXTENSION_SPEC);
+
+ IFile file=ResourceHelper.createFile(project, "file.x++");
+ IContentType contentTypeX = manager.findContentTypeFor("file.x++");
+ assertEquals(contentType, contentTypeX);
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file.x++");
+ parser.shutdown();
+
+ // check populated entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+
+ // cleanup
+ contentType.removeFileSpec("x++", IContentTypeSettings.FILE_EXTENSION_SPEC);
+ }
+
+ /**
+ * Test filenames appearing in upper-case.
+ */
+ public void testUpperCase() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ String languageId = LANG_CPP;
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc -I/path0 FILE.CPP");
+ parser.shutdown();
+
+ // check populated entries
+ IPath path0 = new Path("/path0").setDevice(project.getLocation().getDevice());
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ CIncludePathEntry expected = new CIncludePathEntry(path0, 0);
+ assertEquals(expected, entries.get(0));
+ }
+ }
+
+ /**
+ * Test sample output of boost builder utility bjam.
+ */
+ public void testBoostBjam() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "libs/python/src/numeric.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ // "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -mthreads -DBOOST_ALL_NO_LIB=1 -DBOOST_PYTHON_SOURCE -DBOOST_PYTHON_STATIC_LIB -I"." -I"/Python25/Include" -c -o "bin.v2/libs/python/build/gcc-mingw-3.4.5/debug/link-static/threading-multi/numeric.o" "libs/python/src/numeric.cpp"
+ parser.processLine(" \"g++\"" +
+ " -ftemplate-depth-128 -O0 -fno-inline -Wall -g -mthreads" +
+ " -DBOOST_ALL_NO_LIB=1" +
+ " -DBOOST_PYTHON_SOURCE" +
+ " -DBOOST_PYTHON_STATIC_LIB" +
+ " -I\".\"" +
+ " -I\"/Python1025/Include\"" +
+ " -c -o \"bin.v2/libs/python/build/gcc-mingw-3.4.5/debug/link-static/threading-multi/numeric.o\"" +
+ " libs/python/src/numeric.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ {
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(new CIncludePathEntry(project.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(new Path("/Python1025/Include").setDevice(project.getLocation().getDevice()), 0), entries.get(1));
+ assertEquals(new CMacroEntry("BOOST_ALL_NO_LIB", "1", 0), entries.get(2));
+ assertEquals(new CMacroEntry("BOOST_PYTHON_SOURCE", "", 0), entries.get(3));
+ assertEquals(new CMacroEntry("BOOST_PYTHON_STATIC_LIB", "", 0), entries.get(4));
+ assertEquals(5, entries.size());
+ }
+ }
+
+ /**
+ * Test resource file residing on EFS file-system.
+ */
+ public void testPathEntry_Efs() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ // create folder structure
+ @SuppressWarnings("unused")
+ IFolder buildDir=ResourceHelper.createEfsFolder(project, "BuildDir", new URI("mem:/EfsProject/BuildDir"));
+ IFolder folder=ResourceHelper.createEfsFolder(project, "BuildDir/Folder", new URI("mem:/EfsProject/BuildDir/Folder"));
+ IFile file=ResourceHelper.createEfsFile(project, "BuildDir/file.cpp", new URI("mem:/EfsProject/BuildDir/file.cpp"));
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -IFolder"
+ + " -I/Absolute/Folder"
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ String device = project.getLocation().getDevice();
+ assertEquals(new CIncludePathEntry(folder.getFullPath(), ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED), entries.get(0));
+ assertEquals(new CIncludePathEntry(new Path("/Absolute/Folder").setDevice(device), 0), entries.get(1));
+ }
+ }
+
+ /**
+ * Test mapping entries to EFS.
+ */
+ public void testPathEntry_EfsMappedFolder() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ // create folder structure
+ @SuppressWarnings("unused")
+ IFolder buildDir=ResourceHelper.createEfsFolder(project, "BuildDir", new URI("mem:/MappedEfsProject/BuildDir"));
+ @SuppressWarnings("unused")
+ IFolder folder=ResourceHelper.createEfsFolder(project, "BuildDir/Folder", new URI("mem:/MappedEfsProject/BuildDir/Folder"));
+ IFile file=ResourceHelper.createEfsFile(project, "BuildDir/file.cpp", new URI("mem:/MappedEfsProject/BuildDir/file.cpp"));
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ ErrorParserManager epm = new ErrorParserManager(project, null);
+
+ // parse line
+ parser.startup(cfgDescription, epm);
+ parser.processLine("gcc "
+ + " -I/BeingMappedFrom/Folder" // mapped to local folder in EFSExtensionProvider extension point
+ + " file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file, languageId);
+ {
+ String device = project.getLocation().getDevice();
+ assertEquals(new CIncludePathEntry(new Path("/LocallyMappedTo/Folder").setDevice(device), 0), entries.get(0));
+ }
+ }
+
+ /**
+ * Test assigning entries on file level.
+ */
+ public void testEntriesFileLevel() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder folder=ResourceHelper.createFolder(project, "folder");
+ IFile file=ResourceHelper.createFile(project, "folder/file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FILE);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 folder/file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> expected = new ArrayList<ICLanguageSettingEntry>();
+ expected.add(new CIncludePathEntry(new Path("/path0").setDevice(project.getLocation().getDevice()), 0));
+
+ List<ICLanguageSettingEntry> entriesFile = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(expected, entriesFile);
+ List<ICLanguageSettingEntry> entriesFolder = parser.getSettingEntries(cfgDescription, folder, languageId);
+ assertEquals(null, entriesFolder);
+ List<ICLanguageSettingEntry> entriesProject = parser.getSettingEntries(cfgDescription, project, languageId);
+ assertEquals(null, entriesProject);
+ }
+
+ /**
+ * Test assigning entries on folder level.
+ */
+ public void testEntriesFolderLevel() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder folder=ResourceHelper.createFolder(project, "folder");
+ IFile file=ResourceHelper.createFile(project, "folder/file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.FOLDER);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 folder/file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> expected = new ArrayList<ICLanguageSettingEntry>();
+ expected.add(new CIncludePathEntry(new Path("/path0").setDevice(project.getLocation().getDevice()), 0));
+
+ List<ICLanguageSettingEntry> entriesFile = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(null, entriesFile);
+ List<ICLanguageSettingEntry> entriesFolder = parser.getSettingEntries(cfgDescription, folder, languageId);
+ assertEquals(expected, entriesFolder);
+ List<ICLanguageSettingEntry> entriesProject = parser.getSettingEntries(cfgDescription, project, languageId);
+ assertEquals(null, entriesProject);
+ }
+
+ /**
+ * Test assigning entries on project level.
+ */
+ public void testEntriesProjectLevel() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFolder folder=ResourceHelper.createFolder(project, "folder");
+ IFile file=ResourceHelper.createFile(project, "folder/file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 folder/file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> expected = new ArrayList<ICLanguageSettingEntry>();
+ expected.add(new CIncludePathEntry(new Path("/path0").setDevice(project.getLocation().getDevice()), 0));
+
+ List<ICLanguageSettingEntry> entriesFile = parser.getSettingEntries(cfgDescription, file, languageId);
+ assertEquals(null, entriesFile);
+ List<ICLanguageSettingEntry> entriesFolder = parser.getSettingEntries(cfgDescription, folder, languageId);
+ assertEquals(null, entriesFolder);
+ List<ICLanguageSettingEntry> entriesProject = parser.getSettingEntries(cfgDescription, project, languageId);
+ assertEquals(expected, entriesProject);
+ }
+
+ /**
+ * Test assigning entries for global provider.
+ */
+ public void testEntriesProjectLevelGlobalProvider() throws Exception {
+ // Create model project and accompanied descriptions
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
+ ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
+ ICConfigurationDescription cfgDescription = cfgDescriptions[0];
+
+ IFile file=ResourceHelper.createFile(project, "file.cpp");
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file.getProjectRelativePath(), true);
+ String languageId = ls.getLanguageId();
+
+ // create GCCBuildCommandParser
+ ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(GCC_BUILD_COMMAND_PARSER_EXT);
+ GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getRawProvider(wspProvider);
+ parser.setResourceScope(AbstractBuildCommandParser.ResourceScope.PROJECT);
+
+ // parse line
+ parser.startup(cfgDescription, null);
+ parser.processLine("gcc -I/path0 file.cpp");
+ parser.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> expected = new ArrayList<ICLanguageSettingEntry>();
+ expected.add(new CIncludePathEntry(new Path("/path0").setDevice(project.getLocation().getDevice()), 0));
+ assertEquals(expected, parser.getSettingEntries(null, project, languageId));
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuiltinSpecsDetectorTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuiltinSpecsDetectorTest.java
new file mode 100644
index 0000000000..b9dfedc77d
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/GCCBuiltinSpecsDetectorTest.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - Initial API and implementation
+ *******************************************************************************/
+ package org.eclipse.cdt.managedbuilder.language.settings.providers.tests;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.dom.ast.gnu.c.GCCLanguage;
+import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
+import org.eclipse.cdt.core.settings.model.CMacroEntry;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.cdt.core.testplugin.ResourceHelper;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Test cases to test GCC built-in specs detector.
+ */
+public class GCCBuiltinSpecsDetectorTest extends BaseTestCase {
+ private static final String LANGUAGE_ID_C = GCCLanguage.ID;
+
+ /**
+ * Mock GCCBuiltinSpecsDetector to gain access to protected methods.
+ */
+ class MockGCCBuiltinSpecsDetector extends GCCBuiltinSpecsDetector {
+ @Override
+ public void startupForLanguage(String languageId) throws CoreException {
+ super.startupForLanguage(languageId);
+ }
+ @Override
+ public void shutdownForLanguage() {
+ super.shutdownForLanguage();
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test expansion of variables in build command.
+ */
+ public void testGCCBuiltinSpecsDetector_ResolvedCommand() throws Exception {
+ class MockGCCBuiltinSpecsDetectorLocal extends GCCBuiltinSpecsDetector {
+ @Override
+ public String resolveCommand(String languageId) throws CoreException {
+ return super.resolveCommand(languageId);
+ }
+ }
+ {
+ MockGCCBuiltinSpecsDetectorLocal detector = new MockGCCBuiltinSpecsDetectorLocal();
+ detector.setLanguageScope(new ArrayList<String>() {{add(LANGUAGE_ID_C);}});
+ detector.setCommand("${COMMAND} -E -P -v -dD ${INPUTS}");
+
+ String resolvedCommand = detector.resolveCommand(LANGUAGE_ID_C);
+ assertTrue(resolvedCommand.startsWith("gcc -E -P -v -dD "));
+ assertTrue(resolvedCommand.endsWith("spec.c"));
+ }
+ {
+ MockGCCBuiltinSpecsDetectorLocal detector = new MockGCCBuiltinSpecsDetectorLocal();
+ detector.setLanguageScope(new ArrayList<String>() {{add(LANGUAGE_ID_C);}});
+ detector.setCommand("${COMMAND} -E -P -v -dD file.${EXT}");
+
+ String resolvedCommand = detector.resolveCommand(LANGUAGE_ID_C);
+ assertTrue(resolvedCommand.startsWith("gcc -E -P -v -dD "));
+ assertTrue(resolvedCommand.endsWith("file.c"));
+ }
+ }
+
+ /**
+ * Test parsing of macro without value.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_NoValue() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO", null, ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro with ordinary value.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_Simple() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO VALUE");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro with value in round brackets.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_Const() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO (3)");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO", "(3)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition with tabs.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_WhiteSpaces() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define \t MACRO_1 VALUE");
+ detector.processLine("#define MACRO_2 \t VALUE");
+ detector.processLine("#define MACRO_3 VALUE \t");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ int index = 0;
+ assertEquals(new CMacroEntry("MACRO_1", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CMacroEntry("MACRO_2", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CMacroEntry("MACRO_3", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(index, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition with empty argument list.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_EmptyArgList() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO() VALUE");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO()", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition with unused parameter.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_ParamUnused() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO(X) VALUE");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO(X)", "VALUE", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition with multiple parameters.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_ParamSpace() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO(P1, P2) VALUE(P1, P2)");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO(P1, P2)", "VALUE(P1, P2)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition with multiple parameters and no value.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_ArgsNoValue() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define MACRO(P1, P2) ");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CMacroEntry("MACRO(P1, P2)", null, ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition having white spaces in various places.
+ */
+ public void testGCCBuiltinSpecsDetector_Macro_Args_WhiteSpaces() throws Exception {
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#define \t MACRO_1(P1, P2) VALUE(P1, P2)");
+ detector.processLine("#define MACRO_2(P1, P2) \t VALUE(P1, P2)");
+ detector.processLine("#define MACRO_3(P1, P2) VALUE(P1, P2) \t");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ int index = 0;
+ assertEquals(new CMacroEntry("MACRO_1(P1, P2)", "VALUE(P1, P2)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CMacroEntry("MACRO_2(P1, P2)", "VALUE(P1, P2)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CMacroEntry("MACRO_3(P1, P2)", "VALUE(P1, P2)", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(index, entries.size());
+ }
+
+ /**
+ * Test parsing of include directives.
+ */
+ public void testGCCBuiltinSpecsDetector_Includes() throws Exception {
+ // Create model project and folders to test
+ String projectName = getName();
+ IProject project = ResourceHelper.createCDTProject(projectName);
+ IPath tmpPath = ResourceHelper.createTemporaryFolder();
+ ResourceHelper.createFolder(project, "/misplaced/include1");
+ ResourceHelper.createFolder(project, "/local/include");
+ ResourceHelper.createFolder(project, "/usr/include");
+ ResourceHelper.createFolder(project, "/usr/include2");
+ ResourceHelper.createFolder(project, "/misplaced/include2");
+ ResourceHelper.createFolder(project, "/System/Library/Frameworks");
+ ResourceHelper.createFolder(project, "/Library/Frameworks");
+ ResourceHelper.createFolder(project, "/misplaced/include3");
+ String loc = tmpPath.toString();
+
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+
+ detector.processLine(" "+loc+"/misplaced/include1");
+ detector.processLine("#include \"...\" search starts here:");
+ detector.processLine(" "+loc+"/local/include");
+ detector.processLine("#include <...> search starts here:");
+ detector.processLine(" "+loc+"/usr/include");
+ detector.processLine(" "+loc+"/usr/include/../include2");
+ detector.processLine(" "+loc+"/missing/folder");
+ detector.processLine(" "+loc+"/Library/Frameworks (framework directory)");
+ detector.processLine("End of search list.");
+ detector.processLine(" "+loc+"/misplaced/include2");
+ detector.processLine("Framework search starts here:");
+ detector.processLine(" "+loc+"/System/Library/Frameworks");
+ detector.processLine("End of framework search list.");
+ detector.processLine(" "+loc+"/misplaced/include3");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ int index = 0;
+ assertEquals(new CIncludePathEntry(loc+"/local/include", ICSettingEntry.LOCAL | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/usr/include", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/usr/include2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/missing/folder", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/System/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(index, entries.size());
+ }
+
+ /**
+ * Test parsing of macro definition of include directives having white spaces.
+ */
+ public void testGCCBuiltinSpecsDetector_Includes_WhiteSpaces() throws Exception {
+ String loc = ResourceHelper.createTemporaryFolder().toString();
+
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+
+ detector.processLine("#include \"...\" search starts here:");
+ detector.processLine(" \t "+loc+"/local/include");
+ detector.processLine("#include <...> search starts here:");
+ detector.processLine(loc+"/usr/include");
+ detector.processLine(" "+loc+"/Library/Frameworks \t (framework directory)");
+ detector.processLine("End of search list.");
+ detector.processLine("Framework search starts here:");
+ detector.processLine(" "+loc+"/System/Library/Frameworks \t ");
+ detector.processLine("End of framework search list.");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ int index = 0;
+ assertEquals(new CIncludePathEntry(loc+"/local/include", ICSettingEntry.LOCAL | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/usr/include", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(new CIncludePathEntry(loc+"/System/Library/Frameworks", ICSettingEntry.FRAMEWORKS_MAC | ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(index++));
+ assertEquals(index, entries.size());
+ }
+
+ /**
+ * Test parsing of include directives incorporating symbolic links.
+ */
+ public void testGCCBuiltinSpecsDetector_Includes_SymbolicLinkUp() throws Exception {
+ // do not test on systems where symbolic links are not supported
+ if (!ResourceHelper.isSymbolicLinkSupported())
+ return;
+
+ // Create model project and folders to test
+ String projectName = getName();
+ @SuppressWarnings("unused")
+ IProject project = ResourceHelper.createCDTProject(projectName);
+ // create link on the filesystem
+ IPath dir1 = ResourceHelper.createTemporaryFolder();
+ IPath dir2 = dir1.removeLastSegments(1);
+ IPath linkPath = dir1.append("linked");
+ ResourceHelper.createSymbolicLink(linkPath, dir2);
+
+ MockGCCBuiltinSpecsDetector detector = new MockGCCBuiltinSpecsDetector();
+
+ detector.startup(null, null);
+ detector.startupForLanguage(null);
+ detector.processLine("#include <...> search starts here:");
+ detector.processLine(" "+linkPath.toString()+"/..");
+ detector.processLine("End of search list.");
+ detector.shutdownForLanguage();
+ detector.shutdown();
+
+ // check populated entries
+ List<ICLanguageSettingEntry> entries = detector.getSettingEntries(null, null, null);
+ assertEquals(new CIncludePathEntry(dir2.removeLastSegments(1), ICSettingEntry.BUILTIN | ICSettingEntry.READONLY), entries.get(0));
+ assertEquals(1, entries.size());
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
index 363db3a759..d08600713b 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
@@ -15,9 +15,12 @@ Export-Package: org.eclipse.cdt.build.core.scannerconfig,
org.eclipse.cdt.managedbuilder.envvar,
org.eclipse.cdt.managedbuilder.internal.buildmodel;x-friends:="org.eclipse.cdt.managedbuilder.ui",
org.eclipse.cdt.managedbuilder.internal.core;x-friends:="org.eclipse.cdt.managedbuilder.ui",
+ org.eclipse.cdt.managedbuilder.internal.dataprovider;x-internal:=true,
org.eclipse.cdt.managedbuilder.internal.envvar;x-internal:=true,
+ org.eclipse.cdt.managedbuilder.internal.language.settings.providers;x-internal:=true,
org.eclipse.cdt.managedbuilder.internal.macros;x-friends:="org.eclipse.cdt.managedbuilder.ui",
org.eclipse.cdt.managedbuilder.internal.scannerconfig;x-internal:=true,
+ org.eclipse.cdt.managedbuilder.language.settings.providers,
org.eclipse.cdt.managedbuilder.macros,
org.eclipse.cdt.managedbuilder.makegen,
org.eclipse.cdt.managedbuilder.makegen.gnu,
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
index a34109351c..ae8c2baf88 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
@@ -598,6 +598,40 @@
</application>
</extension>
<extension
+ point="org.eclipse.cdt.core.LanguageSettingsProvider">
+ <provider
+ class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.MBSLanguageSettingsProvider"
+ id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider"
+ name="CDT Managed Build Setting Entries">
+ </provider>
+ <provider
+ class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector"
+ id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector"
+ name="CDT GCC Builtin Compiler Settings"
+ parameter="${COMMAND} -E -P -v -dD ${INPUTS}">
+ <language-scope id="org.eclipse.cdt.core.gcc"/>
+ <language-scope id="org.eclipse.cdt.core.g++"/>
+ </provider>
+ <provider
+ class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser"
+ id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"
+ name="CDT GCC Build Output Parser"
+ parameter="(gcc)|([gc]\+\+)"
+ prefer-non-shared="true">
+ </provider>
+ </extension>
+ <extension
+ id="scanner.discovery.problem"
+ name="C/C++ Scanner Discovery Problem"
+ point="org.eclipse.core.resources.markers">
+ <super
+ type="org.eclipse.core.resources.problemmarker">
+ </super>
+ <persistent
+ value="true">
+ </persistent>
+ </extension>
+ <extension
id="headlessSettings"
name="HeadlessBuilder Additional Settings"
point="org.eclipse.cdt.core.externalSettingsProvider">
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/core/scannerconfig/ScannerConfigBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/core/scannerconfig/ScannerConfigBuilder.java
index e20b258eb6..78099dbd61 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/core/scannerconfig/ScannerConfigBuilder.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/core/scannerconfig/ScannerConfigBuilder.java
@@ -20,6 +20,7 @@ import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfil
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager;
+import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
@@ -41,9 +42,9 @@ import org.eclipse.core.runtime.SubProgressMonitor;
/**
* Runs after standard make builder.
* Consolidates discovered scanner configuration and updates project's scanner configuration.
- *
+ *
* @see IncrementalProjectBuilder
- *
+ *
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@@ -55,7 +56,7 @@ public class ScannerConfigBuilder extends ACBuilder {
* tells the discovery mechanism to perform core settings update
*/
public static final int PERFORM_CORE_UPDATE = 1;
-
+
/**
* force the discovery, i.e. run the discovery even if it is disabled
*/
@@ -67,7 +68,7 @@ public class ScannerConfigBuilder extends ACBuilder {
public static final int SKIP_SI_DISCOVERY = 1 << 2;
public final static String BUILDER_ID = ManagedBuilderCorePlugin.getUniqueIdentifier() + ".ScannerConfigBuilder"; //$NON-NLS-1$
-
+
public ScannerConfigBuilder() {
super();
}
@@ -120,22 +121,22 @@ public class ScannerConfigBuilder extends ACBuilder {
}
}
}
-
+
CfgDiscoveredPathManager.getInstance().updateCoreSettings(getProject(), cfgs);
}
-
-
+
+
return getProject().getReferencedProjects();
}
-
+
public static void build(IConfiguration cfg, int flags, IProgressMonitor monitor){
if(cfg != null){
// IScannerConfigBuilderInfo buildInfo = MakeCorePlugin.createScannerConfigBuildInfo(getProject(), BUILDER_ID);
// autodiscoveryEnabled = buildInfo.isAutoDiscoveryEnabled();
- //
+ //
// if (autodiscoveryEnabled) {
// monitor.beginTask("ScannerConfigBuilder.Invoking_Builder", 100); //$NON-NLS-1$
- // monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
+ // monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
// getProject().getName());
// ScannerInfoCollector.getInstance().updateScannerConfiguration(getProject(), new SubProgressMonitor(monitor, 100));
// }
@@ -164,7 +165,7 @@ public class ScannerConfigBuilder extends ACBuilder {
}
}
-
+
private static Properties calcEnvironment(IConfiguration cfg){
Properties envProps = new Properties();
ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(cfg);
@@ -173,45 +174,47 @@ public class ScannerConfigBuilder extends ACBuilder {
for(int i = 0; i < vars.length; i++){
envProps.setProperty(vars[i].getName(), vars[i].getValue());
}
-
+
return envProps;
}
-
+
public static SCProfileInstance build(CfgInfoContext context, IScannerConfigBuilderInfo2 buildInfo2, int flags, Properties env, IProgressMonitor monitor) throws CoreException{
IConfiguration cfg = context.getConfiguration();
- IProject project = cfg.getOwner().getProject();
- boolean autodiscoveryEnabled2 = buildInfo2.isAutoDiscoveryEnabled();
-
- if (autodiscoveryEnabled2 || ((flags & FORCE_DISCOVERY) != 0)) {
- monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder"), 100); //$NON-NLS-1$
- monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
- project.getName());
-
- if(env == null)
- env = calcEnvironment(cfg);
-
- // get scanner info from all external providers
- SCProfileInstance instance = ScannerConfigProfileManager.getInstance().
- getSCProfileInstance(project, context.toInfoContext(), buildInfo2.getSelectedProfileId());
- // if there are any providers call job to pull scanner info
- if ((flags & SKIP_SI_DISCOVERY) == 0) {
- if ((instance == null) || !buildInfo2.getProviderIdList().isEmpty())
- instance = CfgSCJobsUtil.getProviderScannerInfo(project, context, instance, buildInfo2, env, new SubProgressMonitor(monitor, 70));
- }
-
- // update and persist scanner configuration
- CfgSCJobsUtil.updateScannerConfiguration(project, context, instance, buildInfo2, new SubProgressMonitor(monitor, 30));
-
- // Remove the previous discovered path info to ensure it get's regenerated.
- // TODO we should really only do this if the information has changed
- CfgDiscoveredPathManager.getInstance().removeDiscoveredInfo(project, context, false);
-
- if((flags & PERFORM_CORE_UPDATE) != 0)
- CfgDiscoveredPathManager.getInstance().updateCoreSettings(project, new IConfiguration[]{cfg});
-
- return instance;
- }
-
- return null;
+ if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(ManagedBuildManager.getDescriptionForConfiguration(cfg))) {
+ IProject project = cfg.getOwner().getProject();
+ boolean autodiscoveryEnabled2 = buildInfo2.isAutoDiscoveryEnabled();
+
+ if (autodiscoveryEnabled2 || ((flags & FORCE_DISCOVERY) != 0)) {
+ monitor.beginTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder"), 100); //$NON-NLS-1$
+ monitor.subTask(MakeMessages.getString("ScannerConfigBuilder.Invoking_Builder") + //$NON-NLS-1$
+ project.getName());
+
+ if(env == null)
+ env = calcEnvironment(cfg);
+
+ // get scanner info from all external providers
+ SCProfileInstance instance = ScannerConfigProfileManager.getInstance().
+ getSCProfileInstance(project, context.toInfoContext(), buildInfo2.getSelectedProfileId());
+ // if there are any providers call job to pull scanner info
+ if ((flags & SKIP_SI_DISCOVERY) == 0) {
+ if ((instance == null) || !buildInfo2.getProviderIdList().isEmpty())
+ instance = CfgSCJobsUtil.getProviderScannerInfo(project, context, instance, buildInfo2, env, new SubProgressMonitor(monitor, 70));
+ }
+
+ // update and persist scanner configuration
+ CfgSCJobsUtil.updateScannerConfiguration(project, context, instance, buildInfo2, new SubProgressMonitor(monitor, 30));
+
+ // Remove the previous discovered path info to ensure it get's regenerated.
+ // TODO we should really only do this if the information has changed
+ CfgDiscoveredPathManager.getInstance().removeDiscoveredInfo(project, context, false);
+
+ if((flags & PERFORM_CORE_UPDATE) != 0)
+ CfgDiscoveredPathManager.getInstance().updateCoreSettings(project, new IConfiguration[]{cfg});
+
+ return instance;
+ }
+ }
+
+ return null;
}
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigInfoFactory2.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigInfoFactory2.java
index 1ef7c4dae8..a98370b3da 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigInfoFactory2.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/build/internal/core/scannerconfig2/CfgScannerConfigInfoFactory2.java
@@ -19,6 +19,7 @@ import java.util.Map.Entry;
import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext;
import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set;
import org.eclipse.cdt.build.internal.core.scannerconfig.CfgScannerConfigUtil;
+import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.make.core.MakeCorePlugin;
@@ -36,6 +37,7 @@ import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.internal.core.Configuration;
import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildConfigurationData;
+import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.QualifiedName;
@@ -213,7 +215,12 @@ public class CfgScannerConfigInfoFactory2 {
}
}
if (id == null) {
- id = CfgScannerConfigUtil.getDefaultProfileId(context, true);
+ // Language Settings Providers are meant to replace legacy scanner discovery
+ // so do not try to find default profile
+ ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(cfg);
+ if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(cfgDescription)) {
+ id = CfgScannerConfigUtil.getDefaultProfileId(context, true);
+ }
}
InfoContext baseContext = context.toInfoContext();
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java
index 0ca03ae2c6..75ffcba919 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ExternalBuildRunner.java
@@ -30,6 +30,7 @@ import org.eclipse.cdt.core.IConsoleParser;
import org.eclipse.cdt.core.IMarkerGenerator;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager;
+import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.internal.core.BuildRunnerHelper;
@@ -96,6 +97,7 @@ public class ExternalBuildRunner extends AbstractBuildRunner {
String[] targets = getTargets(kind, builder);
if (targets.length != 0 && targets[targets.length - 1].equals(builder.getCleanBuildTarget()))
isClean = true;
+ boolean isOnlyClean = isClean && (targets.length == 1);
String[] args = getCommandArguments(builder, targets);
@@ -108,7 +110,13 @@ public class ExternalBuildRunner extends AbstractBuildRunner {
ErrorParserManager epm = new ErrorParserManager(project, workingDirectoryURI, markerGenerator, errorParsers);
List<IConsoleParser> parsers = new ArrayList<IConsoleParser>();
- collectScannerInfoConsoleParsers(project, configuration, workingDirectoryURI, markerGenerator, parsers);
+ if (!isOnlyClean) {
+ ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(configuration);
+ ManagedBuildManager.collectLanguageSettingsConsoleParsers(cfgDescription, epm, parsers);
+ if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(cfgDescription)) {
+ collectScannerInfoConsoleParsers(project, configuration, workingDirectoryURI, markerGenerator, parsers);
+ }
+ }
buildRunnerHelper.setLaunchParameters(launcher, buildCommand, args, workingDirectoryURI, envp);
buildRunnerHelper.prepareStreams(epm, parsers, console, new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR));
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java
index 3d86bdda88..92e447a093 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/InternalBuildRunner.java
@@ -14,11 +14,15 @@ package org.eclipse.cdt.managedbuilder.core;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
import org.eclipse.cdt.core.ErrorParserManager;
import org.eclipse.cdt.core.ICommandLauncher;
+import org.eclipse.cdt.core.IConsoleParser;
import org.eclipse.cdt.core.IMarkerGenerator;
import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.internal.core.BuildRunnerHelper;
import org.eclipse.cdt.managedbuilder.buildmodel.BuildDescriptionManager;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildDescription;
@@ -77,9 +81,10 @@ public class InternalBuildRunner extends AbstractBuildRunner {
flags = BuildDescriptionManager.REBUILD | BuildDescriptionManager.REMOVED | BuildDescriptionManager.DEPS;
// delta = getDelta(currentProject);
// }
-
boolean buildIncrementaly = delta != null;
+ ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(configuration);
+
// Prepare launch parameters for BuildRunnerHelper
String cfgName = configuration.getName();
String toolchainName = configuration.getToolChain().getName();
@@ -90,7 +95,10 @@ public class InternalBuildRunner extends AbstractBuildRunner {
String[] errorParsers = builder.getErrorParsers();
ErrorParserManager epm = new ErrorParserManager(project, workingDirectoryURI, markerGenerator, errorParsers);
- buildRunnerHelper.prepareStreams(epm, null, console, new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR));
+ List<IConsoleParser> parsers = new ArrayList<IConsoleParser>();
+ ManagedBuildManager.collectLanguageSettingsConsoleParsers(cfgDescription, epm, parsers);
+
+ buildRunnerHelper.prepareStreams(epm, parsers, console, new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR));
IBuildDescription des = BuildDescriptionManager.createBuildDescription(configuration, cBS, delta, flags);
DescriptionBuilder dBuilder = null;
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
index 7c3d89a536..590ce24560 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuildManager.java
@@ -49,6 +49,12 @@ import javax.xml.transform.stream.StreamResult;
import org.eclipse.cdt.core.AbstractCExtension;
import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IConsoleParser;
+import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
+import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.parser.IScannerInfo;
@@ -148,7 +154,6 @@ import org.w3c.dom.ProcessingInstruction;
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public class ManagedBuildManager extends AbstractCExtension {
-
// private static final QualifiedName buildInfoProperty = new QualifiedName(ManagedBuilderCorePlugin.PLUGIN_ID, "managedBuildInfo"); //$NON-NLS-1$
private static final String ROOT_NODE_NAME = "ManagedProjectBuildInfo"; //$NON-NLS-1$
public static final String SETTINGS_FILE_NAME = ".cdtbuild"; //$NON-NLS-1$
@@ -4721,4 +4726,24 @@ public class ManagedBuildManager extends AbstractCExtension {
return true; // no target platform - nothing to check.
}
+ /*package*/ static void collectLanguageSettingsConsoleParsers(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker, List<IConsoleParser> parsers) {
+ if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
+ List<ILanguageSettingsProvider> lsProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders();
+ for (ILanguageSettingsProvider lsProvider : lsProviders) {
+ ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(lsProvider);
+ if (rawProvider instanceof ICBuildOutputParser) {
+ ICBuildOutputParser consoleParser = (ICBuildOutputParser) rawProvider;
+ try {
+ consoleParser.startup(cfgDescription, cwdTracker);
+ parsers.add(consoleParser);
+ } catch (CoreException e) {
+ ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ "Language Settings Provider failed to start up", e)); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ }
+
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuilderCorePlugin.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuilderCorePlugin.java
index d8baa7c6af..03b68fa445 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuilderCorePlugin.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/ManagedBuilderCorePlugin.java
@@ -36,7 +36,7 @@ import org.osgi.framework.BundleContext;
/**
* ManagedBuilderCorePlugin is the life-cycle owner of the managedbuilder core plug-in.
- *
+ *
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@@ -48,12 +48,12 @@ public class ManagedBuilderCorePlugin extends Plugin {
// The attribute name for the makefile generator
public static final String MAKEGEN_ID ="makefileGenerator"; //$NON-NLS-1$
public static final String COMMANDLINEGEN_ID = "commandlineGenerator"; //$NON-NLS-1$
- // The unique id for all managed make projects
+ // The unique id for all managed make projects
public static final String MANAGED_MAKE_PROJECT_ID = ManagedBuilderCorePlugin.getUniqueIdentifier() + ".managedMake"; //$NON-NLS-1$
// NOTE: The code below is for tracking resource renaming and deleting. This is needed to keep
// ResourceConfiguration elements up to date. It may also be needed by AdditionalInput
// elements
-
+
private static ResourceChangeHandler2 listener;
// private DiscoveredPathManager fDiscoveryPathManager;
@@ -72,7 +72,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
}
return getDefault().getBundle().getSymbolicName();
}
-
+
/**
* @return the shared instance.
*/
@@ -88,23 +88,23 @@ public class ManagedBuilderCorePlugin extends Plugin {
// Turn on logging for plugin when debugging
super.start(context);
configurePluginDebugOptions();
-
-
+
+
// NOTE: The code below is for tracking resource renaming and deleting. This is needed to keep
// ResourceConfiguration elements up to date. It may also be needed by AdditionalInput
// elements
-
+
// IJobManager jobManager = Platform.getJobManager();
// IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
listener = new ResourceChangeHandler2();
ResourcesPlugin.getWorkspace().addResourceChangeListener(
- listener,
- IResourceChangeEvent.POST_CHANGE
+ listener,
+ IResourceChangeEvent.POST_CHANGE
| IResourceChangeEvent.PRE_DELETE
| IResourceChangeEvent.PRE_CLOSE
/*| IResourceChangeEvent.POST_BUILD*/);
-
+
BuildStateManager.getInstance().startup();
/* try {
jobManager.beginRule(root, null);
@@ -115,7 +115,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
//or core exception is thrown by the startResourceChangeHandling()
//in any case, schedule a job with the root rule
//that will perform the resource change handling initialization
-*/
+*/
//The startResourceChangeHandling() might result in throwing an error
//see bug# 132001
//Always schedule a job
@@ -135,7 +135,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
// null);
// }
// };
-//
+//
// rcJob.setRule(root);
// rcJob.setPriority(Job.INTERACTIVE);
// rcJob.setSystem(true);
@@ -146,7 +146,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
}
*/
}
-
+
/*
* This method adds a save participant and resource change listener
* Throws CoreException if the methods fails to add a save participant.
@@ -159,8 +159,8 @@ public class ManagedBuilderCorePlugin extends Plugin {
// ResourcesPlugin.getWorkspace().addSaveParticipant(ManagedBuilderCorePlugin.this, listener);
//
// ResourcesPlugin.getWorkspace().addResourceChangeListener(
-// listener,
-// IResourceChangeEvent.POST_CHANGE
+// listener,
+// IResourceChangeEvent.POST_CHANGE
// | IResourceChangeEvent.PRE_DELETE
// | IResourceChangeEvent.PRE_CLOSE
// /*| IResourceChangeEvent.POST_BUILD*/);
@@ -184,7 +184,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
// }
-
+
// NOTE: The code below is for tracking resource renaming and deleting. This is needed to keep
// ResourceConfiguration elements up to date. It may also be needed by AdditionalInput
// elements
@@ -196,7 +196,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
listener = null;
super.stop(context);
}
-
+
private static final String PATH_ENTRY = ManagedBuilderCorePlugin.getUniqueIdentifier() + "/debug/pathEntry"; //$NON-NLS-1$
private static final String PATH_ENTRY_INIT = ManagedBuilderCorePlugin.getUniqueIdentifier() + "/debug/pathEntryInit"; //$NON-NLS-1$
private static final String BUILDER = ManagedBuilderCorePlugin.getUniqueIdentifier() + "/debug/builder"; //$NON-NLS-1$
@@ -236,7 +236,7 @@ public class ManagedBuilderCorePlugin extends Plugin {
}
/**
- *
+ *
*/
private void configurePluginDebugOptions() {
if (isDebugging()) {
@@ -258,23 +258,23 @@ public class ManagedBuilderCorePlugin extends Plugin {
}
}
}
-
+
public static IBuilder[] createBuilders(IProject project, Map<String, String> args){
return BuilderFactory.createBuilders(project, args);
}
-
+
public static IBuilder createCustomBuilder(IConfiguration cfg, String builderId) throws CoreException{
return BuilderFactory.createCustomBuilder(cfg, builderId);
}
-
+
public static IBuilder createCustomBuilder(IConfiguration cfg, IBuilder base){
return BuilderFactory.createCustomBuilder(cfg, base);
}
-
+
public static IBuilder createBuilderForEclipseBuilder(IConfiguration cfg, String eclipseBuilderID) throws CoreException {
return BuilderFactory.createBuilderForEclipseBuilder(cfg, eclipseBuilderID);
}
-
+
public boolean isOldStyleMakeProject(IProject project){
return ProjectConverter.isOldStyleMakeProject(project);
}
@@ -283,12 +283,4 @@ public class ManagedBuilderCorePlugin extends Plugin {
ProjectConverter.convertOldStdMakeToNewStyle(project, monitor);
}
-
-// public IDiscoveredPathManager getDiscoveryManager() {
-// if ( fDiscoveryPathManager == null) {
-// fDiscoveryPathManager = new DiscoveredPathManager();
-// fDiscoveryPathManager.startup();
-// }
-// return fDiscoveryPathManager;
-// }
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/PluginResources.properties b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/PluginResources.properties
index 83ee8b40fa..20bc65cd8d 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/PluginResources.properties
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/PluginResources.properties
@@ -169,3 +169,14 @@ MultiResourceInfo.MultiResourceInfo.UnhandledIHoldsOptionsType=Unhandled parent
ResourceChangeHandler2.0=project build settings update job
ToolInfo.0=conversion failure
ToolInfo.1=the tool is removed
+
+#Language settings providers messages
+AbstractBuiltinSpecsDetector.AddScannerDiscoveryMarkers=Adding Scanner Discovery markers
+AbstractBuiltinSpecsDetector.ClearingMarkers=Clearing markers for {0}
+AbstractBuiltinSpecsDetector.DiscoverBuiltInSettingsJobName=Discover compiler built-in language settings
+AbstractBuiltinSpecsDetector.RunningScannerDiscovery=Running scanner discovery: {0}
+AbstractBuiltinSpecsDetector.ScannerDiscoveryMarkerLocationPreferences=Preferences, C++/Build/Settings/Discovery, [{0}] options
+AbstractBuiltinSpecsDetector.ScannerDiscoveryMarkerLocationProperties=Project Properties, C++ Preprocessor Include.../Providers, [{0}] options
+AbstractBuiltinSpecsDetector.ScannerDiscoveryTaskTitle=CDT Scanner Discovery
+AbstractBuiltinSpecsDetector.SerializingResults=Serializing results
+
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/MBSLanguageSettingsProvider.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/MBSLanguageSettingsProvider.java
new file mode 100644
index 0000000000..1026f2e5f5
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/MBSLanguageSettingsProvider.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.language.settings.providers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.AbstractExecutableExtensionBase;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsBroadcastingProvider;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsStorage;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICFileDescription;
+import org.eclipse.cdt.core.settings.model.ICFolderDescription;
+import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICResourceDescription;
+import org.eclipse.cdt.core.settings.model.ICSettingBase;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Implementation of language settings provider for CDT Managed Build System.
+ */
+public class MBSLanguageSettingsProvider extends AbstractExecutableExtensionBase implements ILanguageSettingsBroadcastingProvider {
+ @Override
+ public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) {
+
+ IPath projectPath = rc.getProjectRelativePath();
+ ICLanguageSetting[] languageSettings = null;
+
+ if (rc instanceof IFile) {
+ ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(projectPath, true);
+ if (ls != null) {
+ languageSettings = new ICLanguageSetting[] { ls };
+ } else {
+ return getSettingEntries(cfgDescription, rc.getParent(), languageId);
+ }
+ } else {
+ ICResourceDescription rcDescription = cfgDescription.getResourceDescription(projectPath, false);
+ languageSettings = getLanguageSettings(rcDescription);
+ }
+
+ List<ICLanguageSettingEntry> list = new ArrayList<ICLanguageSettingEntry>();
+
+ if (languageSettings != null) {
+ for (ICLanguageSetting langSetting : languageSettings) {
+ if (langSetting != null) {
+ String id = langSetting.getLanguageId();
+ if (id != null && id.equals(languageId)) {
+ int kindsBits = langSetting.getSupportedEntryKinds();
+ for (int kind=1; kind <= kindsBits; kind <<= 1) {
+ if ((kindsBits & kind) != 0) {
+ list.addAll(langSetting.getSettingEntriesList(kind));
+ }
+ }
+ }
+ }
+ }
+ }
+ return LanguageSettingsStorage.getPooledList(list);
+ }
+
+ /**
+ * Get language settings for resource description.
+ */
+ private ICLanguageSetting[] getLanguageSettings(ICResourceDescription rcDescription) {
+ ICLanguageSetting[] array = null;
+ switch (rcDescription.getType()) {
+ case ICSettingBase.SETTING_PROJECT:
+ case ICSettingBase.SETTING_CONFIGURATION:
+ case ICSettingBase.SETTING_FOLDER:
+ ICFolderDescription foDes = (ICFolderDescription)rcDescription;
+ array = foDes.getLanguageSettings();
+ break;
+ case ICSettingBase.SETTING_FILE:
+ ICFileDescription fiDes = (ICFileDescription)rcDescription;
+ ICLanguageSetting ls = fiDes.getLanguageSetting();
+ if (ls != null) {
+ array = new ICLanguageSetting[] { ls };
+ }
+ }
+ if (array == null) {
+ array = new ICLanguageSetting[0];
+ }
+ return array;
+ }
+
+ @Override
+ public LanguageSettingsStorage copyStorage() {
+ class PretendStorage extends LanguageSettingsStorage {
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+ @Override
+ public LanguageSettingsStorage clone() throws CloneNotSupportedException {
+ return this;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ // Note that this always triggers change event even if nothing changed in MBS
+ return false;
+ }
+ }
+ return new PretendStorage();
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java
new file mode 100644
index 0000000000..e927462383
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuildCommandParser.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.IErrorParser2;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
+import org.eclipse.cdt.core.errorparsers.RegexErrorPattern;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+/**
+ * Abstract class for providers parsing compiler option from build command when present in build output.
+ *
+ * @since 8.1
+ */
+public abstract class AbstractBuildCommandParser extends AbstractLanguageSettingsOutputScanner {
+ public static final Object JOB_FAMILY_BUILD_COMMAND_PARSER = "org.eclipse.cdt.managedbuilder.AbstractBuildCommandParser"; //$NON-NLS-1$
+
+ private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$
+ private static final String ATTR_RESOURCE_SCOPE = "resource-scope"; //$NON-NLS-1$
+ private static final String VALUE_FILE_SCOPE = "per-file"; //$NON-NLS-1$
+ private static final String VALUE_FOLDER_SCOPE = "per-folder"; //$NON-NLS-1$
+ private static final String VALUE_PROJECT_SCOPE = "per-project"; //$NON-NLS-1$
+
+
+ private static final String LEADING_PATH_PATTERN = "\\S+[/\\\\]"; //$NON-NLS-1$
+ private static final Pattern OPTIONS_PATTERN = Pattern.compile("-[^\\s\"']*(\\s*((\".*?\")|('.*?')|([^-\\s][^\\s]+)))?"); //$NON-NLS-1$
+ private static final int OPTION_GROUP = 0;
+
+ public enum ResourceScope {
+ FILE,
+ FOLDER,
+ PROJECT,
+ }
+
+ /**
+ * Note: design patterns to keep file group the same and matching {@link #FILE_GROUP}
+ */
+ @SuppressWarnings("nls")
+ private static final String[] COMPILER_COMMAND_PATTERN_TEMPLATES = {
+ "${COMPILER_PATTERN}.*\\s" + "()([^'\"\\s]*\\.${EXTENSIONS_PATTERN})(\\s.*)?[\r\n]*", // compiling unquoted file
+ "${COMPILER_PATTERN}.*\\s" + "(['\"])(.*\\.${EXTENSIONS_PATTERN})\\${COMPILER_GROUPS+1}(\\s.*)?[\r\n]*" // compiling quoted file
+ };
+ private static final int FILE_GROUP = 2;
+
+ // cached value from properties, do not need to use in equals() and hashCode()
+ private ResourceScope resourceScope = null;
+
+ /**
+ * The compiler command pattern without specifying compiler options.
+ * The options are intended to be handled with option parsers,
+ * see {@link #getOptionParsers()}.
+ * This is regular expression pattern.
+ *
+ * @return the compiler command pattern.
+ */
+ public String getCompilerPattern() {
+ return getProperty(ATTR_PARAMETER);
+ }
+
+ /**
+ * Set compiler command pattern for the provider. See {@link #getCompilerPattern()}.
+ * @param commandPattern - value of the command pattern to set.
+ * This is regular expression pattern.
+ */
+ public void setCompilerPattern(String commandPattern) {
+ setProperty(ATTR_PARAMETER, commandPattern);
+ }
+
+ /**
+ * Sub-expression for compiler command pattern accounting for spaces, quotes etc.
+ */
+ @SuppressWarnings("nls")
+ private String getCompilerPatternExtended() {
+ String compilerPattern = getCompilerPattern();
+ return "\\s*\"?("+LEADING_PATH_PATTERN+")?(" + compilerPattern + ")\"?";
+ }
+
+ /**
+ * @return resource scope of the entries, i.e. level in resource hierarchy where language settings entries
+ * will be applied by the provider. Resource scope can be one of the following:
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.FILE} - apply entries to the file being parsed.
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.FOLDER} - apply entries to the enclosing folder.
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.PROJECT} - apply entries to the project level.
+ */
+ public ResourceScope getResourceScope() {
+ if (resourceScope == null) {
+ String scopeStr = getProperty(ATTR_RESOURCE_SCOPE);
+ if (scopeStr.equals(VALUE_FILE_SCOPE)) {
+ resourceScope = ResourceScope.FILE;
+ } else if (scopeStr.equals(VALUE_FOLDER_SCOPE)) {
+ resourceScope = ResourceScope.FOLDER;
+ } else if (scopeStr.equals(VALUE_PROJECT_SCOPE)) {
+ resourceScope = ResourceScope.PROJECT;
+ } else {
+ resourceScope = ResourceScope.FILE;
+ }
+ }
+ return resourceScope;
+ }
+
+ /**
+ * Set resource scope of the entries, i.e. level in resource hierarchy where language settings entries
+ * will be applied by the provider.
+ *
+ * @param rcScope - resource scope can be one of the following:
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.FILE} - apply entries to the file being parsed.
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.FOLDER} - apply entries to the enclosing folder.
+ * <br>- {@code AbstractBuildCommandParser.ResourceScope.PROJECT} - apply entries to the project level.
+ */
+ public void setResourceScope(ResourceScope rcScope) {
+ resourceScope = rcScope;
+ switch (rcScope) {
+ case FILE:
+ setProperty(ATTR_RESOURCE_SCOPE, VALUE_FILE_SCOPE);
+ break;
+ case FOLDER:
+ setProperty(ATTR_RESOURCE_SCOPE, VALUE_FOLDER_SCOPE);
+ break;
+ case PROJECT:
+ setProperty(ATTR_RESOURCE_SCOPE, VALUE_PROJECT_SCOPE);
+ break;
+ default:
+ setProperty(ATTR_RESOURCE_SCOPE, VALUE_FILE_SCOPE);
+ break;
+ }
+ }
+
+ @Override
+ protected void setSettingEntries(List<ICLanguageSettingEntry> entries) {
+ IResource rc = null;
+ switch (getResourceScope()) {
+ case FILE:
+ rc = currentResource;
+ break;
+ case FOLDER:
+ if (currentResource instanceof IFile) {
+ rc = currentResource.getParent();
+ }
+ break;
+ case PROJECT:
+ if (currentResource != null) {
+ rc = currentResource.getProject();
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ setSettingEntries(currentCfgDescription, rc, currentLanguageId, entries);
+ }
+
+ /**
+ * Adjust count for file group taking into consideration extra groups added by {@link #getCompilerPatternExtended()}.
+ */
+ private int adjustFileGroup() {
+ return countGroups(getCompilerPatternExtended()) + FILE_GROUP;
+ }
+
+ /**
+ * Make search pattern for compiler command based on template.
+ */
+ private String makePattern(String template) {
+ @SuppressWarnings("nls")
+ String pattern = template
+ .replace("${COMPILER_PATTERN}", getCompilerPatternExtended())
+ .replace("${EXTENSIONS_PATTERN}", getPatternFileExtensions())
+ .replace("${COMPILER_GROUPS+1}", new Integer(countGroups(getCompilerPatternExtended()) + 1).toString());
+ return pattern;
+ }
+
+ @Override
+ protected String parseResourceName(String line) {
+ if (line == null) {
+ return null;
+ }
+
+ for (String template : COMPILER_COMMAND_PATTERN_TEMPLATES) {
+ String pattern = makePattern(template);
+ Matcher fileMatcher = Pattern.compile(pattern).matcher(line);
+ if (fileMatcher.matches()) {
+ int fileGroup = adjustFileGroup();
+ String sourceFileName = fileMatcher.group(fileGroup);
+ return sourceFileName;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected List<String> parseOptions(String line) {
+ if (line == null || currentResource == null) {
+ return null;
+ }
+
+ List<String> options = new ArrayList<String>();
+ Matcher optionMatcher = OPTIONS_PATTERN.matcher(line);
+ while (optionMatcher.find()) {
+ String option = optionMatcher.group(OPTION_GROUP);
+ if (option!=null) {
+ options.add(option);
+ }
+ }
+ return options;
+ }
+
+ private void serializeLanguageSettingsInBackground() {
+ ILanguageSettingsProvider wspProvider = LanguageSettingsManager.getWorkspaceProvider(getId());
+ ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(wspProvider);
+ if (rawProvider == this) {
+ // this is workspace provider
+ serializeLanguageSettingsInBackground(null);
+ } else {
+ serializeLanguageSettingsInBackground(currentCfgDescription);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ serializeLanguageSettingsInBackground();
+ super.shutdown();
+ }
+
+ /**
+ * Trivial Error Parser which allows highlighting of output lines matching the patterns
+ * of this parser. Intended for better troubleshooting experience.
+ * Implementers are supposed to add the error parser via extension point {@code org.eclipse.cdt.core.ErrorParser}.
+ */
+ protected static abstract class AbstractBuildCommandPatternHighlighter extends RegexErrorParser implements IErrorParser2 {
+ /**
+ * Constructor.
+ * @param parserId - build command parser ID specified in the extension {@code org.eclipse.cdt.core.LanguageSettingsProvider}.
+ */
+ public AbstractBuildCommandPatternHighlighter(String parserId) {
+ init(parserId);
+ }
+
+ /**
+ * Initialize the error parser.
+ * @param parserId - language settings provider (the build command parser) ID.
+ */
+ protected void init(String parserId) {
+ AbstractBuildCommandParser buildCommandParser = (AbstractBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(parserId, false);
+ if (buildCommandParser != null) {
+ for (String template : COMPILER_COMMAND_PATTERN_TEMPLATES) {
+ String pattern = buildCommandParser.makePattern(template);
+ String fileExpr = "$"+buildCommandParser.adjustFileGroup(); //$NON-NLS-1$
+ String descExpr = "$0"; //$NON-NLS-1$
+ addPattern(new RegexErrorPattern(pattern, fileExpr, null, descExpr, null, IMarkerGenerator.SEVERITY_WARNING, true));
+ }
+ }
+ }
+
+ @Override
+ public int getProcessLineBehaviour() {
+ return KEEP_LONGLINES;
+ }
+ }
+
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java
new file mode 100644
index 0000000000..0ad1dd0ded
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractBuiltinSpecsDetector.java
@@ -0,0 +1,745 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.CommandLauncher;
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.ICommandLauncher;
+import org.eclipse.cdt.core.IConsoleParser;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.ProblemMarkerInfo;
+import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser;
+import org.eclipse.cdt.core.language.settings.providers.ICListenerAgent;
+import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.ILanguageDescriptor;
+import org.eclipse.cdt.core.model.LanguageManager;
+import org.eclipse.cdt.core.resources.IConsole;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICProjectDescription;
+import org.eclipse.cdt.internal.core.BuildRunnerHelper;
+import org.eclipse.cdt.internal.core.XmlUtil;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
+import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages;
+import org.eclipse.cdt.utils.CommandLineUtil;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.jobs.Job;
+import org.w3c.dom.Element;
+
+/**
+ * Abstract parser capable to execute compiler command printing built-in compiler
+ * specs and parse built-in language settings out of it.
+ *
+ * @since 8.1
+ */
+public abstract class AbstractBuiltinSpecsDetector extends AbstractLanguageSettingsOutputScanner implements ICListenerAgent {
+ public static final String JOB_FAMILY_BUILTIN_SPECS_DETECTOR = "org.eclipse.cdt.managedbuilder.AbstractBuiltinSpecsDetector"; //$NON-NLS-1$
+
+ protected static final String COMPILER_MACRO = "${COMMAND}"; //$NON-NLS-1$
+ protected static final String SPEC_FILE_MACRO = "${INPUTS}"; //$NON-NLS-1$
+ protected static final String SPEC_EXT_MACRO = "${EXT}"; //$NON-NLS-1$
+ protected static final String SPEC_FILE_BASE = "spec"; //$NON-NLS-1$
+
+ private static final String CDT_MANAGEDBUILDER_UI_PLUGIN_ID = "org.eclipse.cdt.managedbuilder.ui"; //$NON-NLS-1$
+ private static final String SCANNER_DISCOVERY_CONSOLE = "org.eclipse.cdt.managedbuilder.ScannerDiscoveryConsole"; //$NON-NLS-1$
+ private static final String SCANNER_DISCOVERY_GLOBAL_CONSOLE = "org.eclipse.cdt.managedbuilder.ScannerDiscoveryGlobalConsole"; //$NON-NLS-1$
+ private static final String DEFAULT_CONSOLE_ICON = "icons/obj16/inspect_system.gif"; //$NON-NLS-1$
+ private static final String GMAKE_ERROR_PARSER_ID = "org.eclipse.cdt.core.GmakeErrorParser"; //$NON-NLS-1$
+
+ private static final String ATTR_PARAMETER = "parameter"; //$NON-NLS-1$
+ private static final String ATTR_CONSOLE = "console"; //$NON-NLS-1$
+
+ private static final int MONITOR_SCALE = 100;
+ private static final int TICKS_REMOVE_MARKERS = 1 * MONITOR_SCALE;
+ private static final int TICKS_RUN_FOR_ONE_LANGUAGE = 10 * MONITOR_SCALE;
+ private static final int TICKS_SERIALIZATION = 1 * MONITOR_SCALE;
+ private static final int TICKS_OUTPUT_PARSING = 1 * MONITOR_SCALE;
+ private static final int TICKS_EXECUTE_COMMAND = 1 * MONITOR_SCALE;
+
+ protected URI mappedRootURI = null;
+ protected URI buildDirURI = null;
+ protected java.io.File specFile = null;
+ protected boolean preserveSpecFile = false;
+ protected List<ICLanguageSettingEntry> detectedSettingEntries = null;
+ protected int collected = 0;
+ protected boolean isExecuted = false;
+
+ private BuildRunnerHelper buildRunnerHelper;
+ private SDMarkerGenerator markerGenerator = new SDMarkerGenerator();
+ private boolean isConsoleEnabled = false;
+ private String currentCommandResolved = null;
+
+ private class SDMarkerGenerator implements IMarkerGenerator {
+ // Reuse scanner discovery markers defined in org.eclipse.cdt.managedbuilder.core plugin.xml
+ protected static final String SCANNER_DISCOVERY_PROBLEM_MARKER = "org.eclipse.cdt.managedbuilder.core.scanner.discovery.problem"; //$NON-NLS-1$
+ protected static final String ATTR_PROVIDER = "provider"; //$NON-NLS-1$
+
+ @Override
+ public void addMarker(IResource rc, int lineNumber, String errorDesc, int severity, String errorVar) {
+ ProblemMarkerInfo info = new ProblemMarkerInfo(rc, lineNumber, errorDesc, severity, errorVar);
+ addMarker(info);
+ }
+
+ @Override
+ public void addMarker(final ProblemMarkerInfo problemMarkerInfo) {
+ final String providerName = getName();
+ final String providerId = getId();
+ // Add markers in a job to avoid deadlocks
+ Job markerJob = new Job(ManagedMakeMessages.getResourceString("AbstractBuiltinSpecsDetector.AddScannerDiscoveryMarkers")) { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ // Avoid duplicates as different languages can generate identical errors
+ try {
+ IMarker[] markers = problemMarkerInfo.file.findMarkers(SDMarkerGenerator.SCANNER_DISCOVERY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+ for (IMarker marker : markers) {
+ int sev = ((Integer) marker.getAttribute(IMarker.SEVERITY)).intValue();
+ if (sev == problemMarkerInfo.severity) {
+ String msg = (String) marker.getAttribute(IMarker.MESSAGE);
+ if (msg != null && msg.equals(problemMarkerInfo.description)) {
+ return Status.OK_STATUS;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ return new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Error checking markers.", e); //$NON-NLS-1$
+ }
+
+ try {
+ IMarker marker = problemMarkerInfo.file.createMarker(SDMarkerGenerator.SCANNER_DISCOVERY_PROBLEM_MARKER);
+ marker.setAttribute(IMarker.MESSAGE, problemMarkerInfo.description);
+ marker.setAttribute(IMarker.SEVERITY, problemMarkerInfo.severity);
+ marker.setAttribute(SDMarkerGenerator.ATTR_PROVIDER, providerId);
+
+ if (problemMarkerInfo.file instanceof IWorkspaceRoot) {
+ String msgPreferences = ManagedMakeMessages.getFormattedString("AbstractBuiltinSpecsDetector.ScannerDiscoveryMarkerLocationPreferences", providerName); //$NON-NLS-1$
+ marker.setAttribute(IMarker.LOCATION, msgPreferences);
+ } else {
+ String msgProperties = ManagedMakeMessages.getFormattedString("AbstractBuiltinSpecsDetector.ScannerDiscoveryMarkerLocationProperties", providerName); //$NON-NLS-1$
+ marker.setAttribute(IMarker.LOCATION, msgProperties);
+ }
+ } catch (CoreException e) {
+ return new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Error adding markers.", e); //$NON-NLS-1$
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ markerJob.setRule(problemMarkerInfo.file);
+ markerJob.schedule();
+ }
+
+ /**
+ * Delete markers previously set by this provider for the resource.
+ *
+ * @param rc - resource to check markers.
+ */
+ public void deleteMarkers(IResource rc) {
+ String providerId = getId();
+ try {
+ IMarker[] markers = rc.findMarkers(SCANNER_DISCOVERY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+ for (IMarker marker : markers) {
+ if (providerId.equals(marker.getAttribute(ATTR_PROVIDER))) {
+ marker.delete();
+ }
+ }
+ } catch (CoreException e) {
+ ManagedBuilderCorePlugin.log(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Error deleting markers.", e)); //$NON-NLS-1$
+ }
+ }
+
+ }
+
+ /**
+ * Internal ICConsoleParser to handle individual run for one language.
+ */
+ private class ConsoleParserAdapter implements ICBuildOutputParser {
+ @Override
+ public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker) throws CoreException {
+ AbstractBuiltinSpecsDetector.this.cwdTracker = cwdTracker;
+ }
+ @Override
+ public boolean processLine(String line) {
+ return AbstractBuiltinSpecsDetector.this.processLine(line);
+ }
+ @Override
+ public void shutdown() {
+ AbstractBuiltinSpecsDetector.this.cwdTracker = null;
+ }
+ }
+
+ /**
+ * Compiler command without arguments. This value is used to replace macro ${COMMAND}.
+ * In particular, this method is implemented in {@link ToolchainBuiltinSpecsDetector}
+ * which retrieves the command from tool-chain.
+ *
+ * @param languageId - language ID.
+ * @return compiler command without arguments, i.e. compiler program.
+ */
+ protected abstract String getCompilerCommand(String languageId);
+
+ /**
+ * The command to run. Some macros could be specified in there:
+ * <ul>
+ * <b>${COMMAND}</b> - compiler command without arguments (compiler program).
+ * Normally would come from the tool-chain.<br>
+ * <b>${INPUTS}</b> - path to spec file which will be placed in workspace area.<br>
+ * <b>${EXT}</b> - file extension calculated from language ID.
+ * </ul>
+ * The parameter could be taken from the extension
+ * in {@code plugin.xml} or from property file.
+ *
+ * @return the command to run or empty string if command is not defined.
+ */
+ public String getCommand() {
+ return getProperty(ATTR_PARAMETER);
+ }
+
+ /**
+ * Set custom command for the provider. See {@link #getCommand()}.
+ * @param command - value of custom command to set.
+ */
+ public void setCommand(String command) {
+ setProperty(ATTR_PARAMETER, command);
+ }
+
+ /**
+ * @return {@code true} if console output is enabled for this provider, {@code false} otherwise.
+ */
+ public boolean isConsoleEnabled() {
+ return isConsoleEnabled;
+ }
+
+ /**
+ * Enable or disable console output for this provider.
+ *
+ * @param enable - {@code true} to enable console output or {@code false} to disable.
+ */
+ public void setConsoleEnabled(boolean enable) {
+ isConsoleEnabled = enable;
+ }
+
+ /**
+ * Expand macros specified in the compiler command. See {@link #getCommand()} for
+ * the recognized list of macros.
+ *
+ * @param languageId - language ID.
+ * @return - resolved command to run.
+ * @throws CoreException if something goes wrong.
+ */
+ protected String resolveCommand(String languageId) throws CoreException {
+ String cmd = getCommand();
+ if (cmd != null) {
+ if (cmd.contains(COMPILER_MACRO)) {
+ String compiler = getCompilerCommand(languageId);
+ if (compiler != null)
+ cmd = cmd.replace(COMPILER_MACRO, compiler);
+ }
+ if (cmd.contains(SPEC_FILE_MACRO)) {
+ String specFileName = getSpecFile(languageId);
+ if (specFileName != null)
+ cmd = cmd.replace(SPEC_FILE_MACRO, specFileName);
+ }
+ if (cmd.contains(SPEC_EXT_MACRO)) {
+ String specFileExt = getSpecFileExtension(languageId);
+ if (specFileExt != null)
+ cmd = cmd.replace(SPEC_EXT_MACRO, specFileExt);
+ }
+ }
+ return cmd;
+ }
+
+ @Override
+ protected String parseResourceName(String line) {
+ // Normally built-in specs detectors are per-language and the result applies for the whole workspace.
+ // Returning null works workspace-wide here.
+ return null;
+ }
+
+ @Override
+ protected String determineLanguage() {
+ // language id is supposed to be set by run(), just return it
+ return currentLanguageId;
+ }
+
+ @Override
+ protected URI getMappedRootURI(IResource sourceFile, String parsedResourceName) {
+ // Do not calculate mappedRootURI for each line
+ if (mappedRootURI == null) {
+ mappedRootURI = super.getMappedRootURI(sourceFile, parsedResourceName);
+ }
+ return mappedRootURI;
+ }
+
+ @Override
+ protected URI getBuildDirURI(URI mappedRootURI) {
+ // Do not calculate buildDirURI for each line
+ if (buildDirURI == null) {
+ buildDirURI = super.getBuildDirURI(mappedRootURI);
+ }
+ return buildDirURI;
+ }
+
+ @Override
+ public void registerListener(ICConfigurationDescription cfgDescription) {
+ currentCfgDescription = cfgDescription;
+ execute();
+ }
+
+ @Override
+ public void unregisterListener() {
+ }
+
+ @Override
+ public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker) throws CoreException {
+ super.startup(cfgDescription, cwdTracker);
+
+ mappedRootURI = null;
+ buildDirURI = super.getBuildDirURI(mappedRootURI);
+ }
+
+ @Override
+ public void shutdown() {
+ mappedRootURI = null;
+ buildDirURI = null;
+
+ super.shutdown();
+ }
+
+ /**
+ * Execute provider's command which is expected to print built-in compiler options (specs) to build output.
+ * The parser will parse output and generate language settings for corresponding resources.
+ */
+ protected void execute() {
+ if (isExecuted) {
+ return;
+ }
+ isExecuted = true;
+
+ Job job = new Job(ManagedMakeMessages.getResourceString("AbstractBuiltinSpecsDetector.DiscoverBuiltInSettingsJobNam")) { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ IStatus status;
+ try {
+ startup(currentCfgDescription, null);
+ status = runForEachLanguage(monitor);
+ } catch (CoreException e) {
+ ManagedBuilderCorePlugin.log(e);
+ status = new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, IStatus.ERROR, "Error running Builtin Specs Detector", e); //$NON-NLS-1$
+ } finally {
+ shutdown();
+ }
+
+ return status;
+ }
+ @Override
+ public boolean belongsTo(Object family) {
+ return family == JOB_FAMILY_BUILTIN_SPECS_DETECTOR;
+ }
+ };
+
+ IProject project = null;
+ if (currentCfgDescription != null) {
+ ICProjectDescription prjDescription = currentCfgDescription.getProjectDescription();
+ if (prjDescription != null) {
+ project = prjDescription.getProject();
+ }
+ }
+ job.setRule(project);
+ job.schedule();
+ }
+
+ /**
+ * Run built-in specs command for each language.
+ *
+ * @param monitor - progress monitor in the initial state where {@link IProgressMonitor#beginTask(String, int)}
+ * has not been called yet.
+ * @return status of operation.
+ */
+ protected IStatus runForEachLanguage(IProgressMonitor monitor) {
+ MultiStatus status = new MultiStatus(ManagedBuilderCorePlugin.PLUGIN_ID, IStatus.OK, "Problem running CDT Scanner Discovery provider " + getId(), null); //$NON-NLS-1$
+
+ if (monitor == null) {
+ monitor = new NullProgressMonitor();
+ }
+
+ try {
+ boolean isChanged = false;
+
+ List<String> languageIds = getLanguageScope();
+ if (languageIds != null) {
+ monitor.beginTask(ManagedMakeMessages.getResourceString("AbstractBuiltinSpecsDetector.ScannerDiscoveryTaskTitle"), //$NON-NLS-1$
+ TICKS_REMOVE_MARKERS + languageIds.size()*TICKS_RUN_FOR_ONE_LANGUAGE + TICKS_SERIALIZATION);
+
+ IResource markersResource = currentProject != null ? currentProject : ResourcesPlugin.getWorkspace().getRoot();
+
+ monitor.subTask(ManagedMakeMessages.getFormattedString("AbstractBuiltinSpecsDetector.ClearingMarkers", markersResource.getFullPath().toString())); //$NON-NLS-1$
+ markerGenerator.deleteMarkers(markersResource);
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+
+ monitor.worked(TICKS_REMOVE_MARKERS);
+
+ for (String languageId : languageIds) {
+ List<ICLanguageSettingEntry> oldEntries = getSettingEntries(currentCfgDescription, null, languageId);
+ try {
+ startupForLanguage(languageId);
+ runForLanguage(new SubProgressMonitor(monitor, TICKS_RUN_FOR_ONE_LANGUAGE));
+ } catch (Exception e) {
+ IStatus s = new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, IStatus.ERROR, "Error running Builtin Specs Detector", e); //$NON-NLS-1$
+ ManagedBuilderCorePlugin.log(s);
+ status.merge(s);
+ } finally {
+ shutdownForLanguage();
+ }
+ if (!isChanged) {
+ List<ICLanguageSettingEntry> newEntries = getSettingEntries(currentCfgDescription, null, languageId);
+ isChanged = newEntries != oldEntries;
+ }
+
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+ }
+ }
+
+ monitor.subTask(ManagedMakeMessages.getResourceString("AbstractBuiltinSpecsDetector.SerializingResults")); //$NON-NLS-1$
+ if (isChanged) { // avoids resource and settings change notifications
+ IStatus s = serializeLanguageSettings(currentCfgDescription);
+ status.merge(s);
+ }
+ monitor.worked(TICKS_SERIALIZATION);
+
+ } catch (OperationCanceledException e) {
+ // user chose to cancel operation, do not threaten them with red error signs
+ } catch (Exception e) {
+ status.merge(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, IStatus.ERROR, "Error running Builtin Specs Detector", e)); //$NON-NLS-1$
+ ManagedBuilderCorePlugin.log(status);
+ } finally {
+ monitor.done();
+ }
+
+ return status;
+ }
+
+ /**
+ * Initialize provider before running for a language.
+ *
+ * @param languageId - language ID.
+ * @throws CoreException if something goes wrong.
+ */
+ protected void startupForLanguage(String languageId) throws CoreException {
+ currentLanguageId = languageId;
+
+ specFile = null; // init specFile *before* calling resolveCommand(), can be changed in there
+ currentCommandResolved = resolveCommand(currentLanguageId);
+
+ detectedSettingEntries = new ArrayList<ICLanguageSettingEntry>();
+ collected = 0;
+ }
+
+ /**
+ * Save collected entries and dispose temporary data used during run for the language.
+ */
+ protected void shutdownForLanguage() {
+ if (detectedSettingEntries != null && detectedSettingEntries.size() > 0) {
+ collected = detectedSettingEntries.size();
+ setSettingEntries(currentCfgDescription, currentResource, currentLanguageId, detectedSettingEntries);
+ }
+ detectedSettingEntries = null;
+
+ currentCommandResolved = null;
+ if (specFile!=null && !preserveSpecFile) {
+ specFile.delete();
+ specFile = null;
+ }
+
+ currentLanguageId = null;
+ }
+
+ /**
+ * Run built-in specs command for one language.
+ *
+ * @param monitor - progress monitor in the initial state where {@link IProgressMonitor#beginTask(String, int)}
+ * has not been called yet.
+ */
+ private void runForLanguage(IProgressMonitor monitor) throws CoreException {
+ buildRunnerHelper = new BuildRunnerHelper(currentProject);
+
+ if (monitor == null) {
+ monitor = new NullProgressMonitor();
+ }
+ try {
+ monitor.beginTask(ManagedMakeMessages.getFormattedString("AbstractBuiltinSpecsDetector.RunningScannerDiscovery", getName()), //$NON-NLS-1$
+ TICKS_EXECUTE_COMMAND + TICKS_OUTPUT_PARSING);
+
+ IConsole console;
+ if (isConsoleEnabled) {
+ console = startProviderConsole();
+ } else {
+ // that looks in extension points registry and won't find the id, this console is not shown
+ console = CCorePlugin.getDefault().getConsole(ManagedBuilderCorePlugin.PLUGIN_ID + ".console.hidden"); //$NON-NLS-1$
+ }
+ console.start(currentProject);
+
+ ICommandLauncher launcher = new CommandLauncher();
+ launcher.setProject(currentProject);
+
+ IPath program = new Path(""); //$NON-NLS-1$
+ String[] args = new String[0];
+ String[] cmdArray = CommandLineUtil.argumentsToArray(currentCommandResolved);
+ if (cmdArray != null && cmdArray.length > 0) {
+ program = new Path(cmdArray[0]);
+ if (cmdArray.length > 1) {
+ args = new String[cmdArray.length-1];
+ System.arraycopy(cmdArray, 1, args, 0, args.length);
+ }
+ }
+
+ String[] envp = BuildRunnerHelper.getEnvp(currentCfgDescription);
+
+ // Using GMAKE_ERROR_PARSER_ID as it can handle generated error messages
+ ErrorParserManager epm = new ErrorParserManager(currentProject, buildDirURI, markerGenerator, new String[] {GMAKE_ERROR_PARSER_ID});
+ ConsoleParserAdapter consoleParser = new ConsoleParserAdapter();
+ consoleParser.startup(currentCfgDescription, epm);
+ List<IConsoleParser> parsers = new ArrayList<IConsoleParser>();
+ parsers.add(consoleParser);
+
+ buildRunnerHelper.setLaunchParameters(launcher, program, args, buildDirURI, envp);
+ buildRunnerHelper.prepareStreams(epm, parsers, console, new SubProgressMonitor(monitor, TICKS_OUTPUT_PARSING));
+
+ buildRunnerHelper.greeting(ManagedMakeMessages.getFormattedString("AbstractBuiltinSpecsDetector.RunningScannerDiscovery", getName())); //$NON-NLS-1$
+
+ OutputStream outStream = buildRunnerHelper.getOutputStream();
+ OutputStream errStream = buildRunnerHelper.getErrorStream();
+ runProgramForLanguage(currentLanguageId, currentCommandResolved, envp, buildDirURI, outStream, errStream,
+ new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
+
+ buildRunnerHelper.close();
+ buildRunnerHelper.goodbye();
+
+ } catch (Exception e) {
+ ManagedBuilderCorePlugin.log(new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Error running Builtin Specs Detector" , e))); //$NON-NLS-1$
+ } finally {
+ try {
+ buildRunnerHelper.close();
+ } catch (IOException e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ monitor.done();
+ }
+ }
+
+ protected int runProgramForLanguage(String languageId, String command, String[] envp, URI workingDirectoryURI, OutputStream consoleOut, OutputStream consoleErr, IProgressMonitor monitor) throws CoreException, IOException {
+ return buildRunnerHelper.build(monitor);
+ }
+
+ @Override
+ protected void setSettingEntries(List<ICLanguageSettingEntry> entries) {
+ // Built-in specs detectors collect entries not per line but for the whole output
+ // so collect them to save later when output finishes
+ if (entries != null) {
+ detectedSettingEntries.addAll(entries);
+ }
+ }
+
+ /**
+ * Create and start the provider console.
+ * @return CDT console.
+ */
+ private IConsole startProviderConsole() {
+ IConsole console = null;
+
+ if (isConsoleEnabled && currentLanguageId != null) {
+ String extConsoleId;
+ if (currentProject != null) {
+ extConsoleId = SCANNER_DISCOVERY_CONSOLE;
+ } else {
+ extConsoleId = SCANNER_DISCOVERY_GLOBAL_CONSOLE;
+ }
+ ILanguage ld = LanguageManager.getInstance().getLanguage(currentLanguageId);
+ if (ld != null) {
+ String consoleId = ManagedBuilderCorePlugin.PLUGIN_ID + '.' + getId() + '.' + currentLanguageId;
+ String consoleName = getName() + ", " + ld.getName(); //$NON-NLS-1$
+ URL defaultIcon = Platform.getBundle(CDT_MANAGEDBUILDER_UI_PLUGIN_ID).getEntry(DEFAULT_CONSOLE_ICON);
+ if (defaultIcon == null) {
+ @SuppressWarnings("nls")
+ String msg = "Unable to find icon " + DEFAULT_CONSOLE_ICON + " in plugin " + CDT_MANAGEDBUILDER_UI_PLUGIN_ID;
+ ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg));
+ }
+
+ console = CCorePlugin.getDefault().getConsole(extConsoleId, consoleId, consoleName, defaultIcon);
+ }
+ }
+
+ if (console == null) {
+ // that looks in extension points registry and won't find the id, this console is not shown
+ console = CCorePlugin.getDefault().getConsole(ManagedBuilderCorePlugin.PLUGIN_ID + ".console.hidden"); //$NON-NLS-1$
+ }
+
+ return console;
+ }
+
+ /**
+ * Get path to spec file which normally would be placed in workspace area.
+ * This value is used to replace macro ${INPUTS}.
+ *
+ * @param languageId - language ID.
+ * @return full path to the specs file.
+ */
+ protected String getSpecFile(String languageId) {
+ String specExt = getSpecFileExtension(languageId);
+ String ext = ""; //$NON-NLS-1$
+ if (specExt != null) {
+ ext = '.' + specExt;
+ }
+
+ String specFileName = SPEC_FILE_BASE + ext;
+ IPath workingLocation = ManagedBuilderCorePlugin.getDefault().getStateLocation();
+ IPath fileLocation = workingLocation.append(specFileName);
+
+ specFile = new java.io.File(fileLocation.toOSString());
+ // will preserve spec file if it was already there otherwise will delete upon finishing
+ preserveSpecFile = specFile.exists();
+ if (!preserveSpecFile) {
+ try {
+ // In the typical case it is sufficient to have an empty file.
+ specFile.createNewFile();
+ } catch (IOException e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ }
+
+ return fileLocation.toString();
+ }
+
+ /**
+ * Determine file extension by language id. This implementation retrieves first extension
+ * from the list as there could be multiple extensions associated with the given language.
+ * This value is used to replace macro ${EXT}.
+ *
+ * @param languageId - given language ID.
+ * @return file extension associated with the language or {@code null} if not found.
+ */
+ protected String getSpecFileExtension(String languageId) {
+ String ext = null;
+ ILanguageDescriptor langDescriptor = LanguageManager.getInstance().getLanguageDescriptor(languageId);
+ if (langDescriptor != null) {
+ IContentType[] contentTypes = langDescriptor.getContentTypes();
+ if (contentTypes != null && contentTypes.length > 0) {
+ String[] fileExtensions = contentTypes[0].getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
+ if (fileExtensions != null && fileExtensions.length > 0) {
+ ext = fileExtensions[0];
+ }
+ }
+ }
+
+ if (ext == null) {
+ ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, "Unable to find file extension for language " + languageId)); //$NON-NLS-1$
+ }
+ return ext;
+ }
+
+ @Override
+ public Element serializeAttributes(Element parentElement) {
+ Element elementProvider = super.serializeAttributes(parentElement);
+ elementProvider.setAttribute(ATTR_CONSOLE, Boolean.toString(isConsoleEnabled));
+ return elementProvider;
+ }
+
+ @Override
+ public void loadAttributes(Element providerNode) {
+ super.loadAttributes(providerNode);
+
+ String consoleValue = XmlUtil.determineAttributeValue(providerNode, ATTR_CONSOLE);
+ if (consoleValue != null) {
+ isConsoleEnabled = Boolean.parseBoolean(consoleValue);
+ }
+ }
+
+ @Override
+ public void loadEntries(Element providerNode) {
+ super.loadEntries(providerNode);
+ if (!isEmpty()) {
+ isExecuted = true;
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ // treat provider that has been executed as not empty
+ // to let "Clear" button to restart the provider
+ return !isExecuted && super.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ isExecuted = false;
+ }
+
+ @Override
+ protected AbstractBuiltinSpecsDetector cloneShallow() throws CloneNotSupportedException {
+ AbstractBuiltinSpecsDetector clone = (AbstractBuiltinSpecsDetector) super.cloneShallow();
+ clone.isExecuted = false;
+ return clone;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (isConsoleEnabled ? 1231 : 1237);
+ result = prime * result + (isExecuted ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof AbstractBuiltinSpecsDetector))
+ return false;
+ AbstractBuiltinSpecsDetector other = (AbstractBuiltinSpecsDetector) obj;
+ if (isConsoleEnabled != other.isConsoleEnabled)
+ return false;
+ if (isExecuted != other.isExecuted)
+ return false;
+ return true;
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java
new file mode 100644
index 0000000000..c3e480fdff
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java
@@ -0,0 +1,1073 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
+import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
+import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser;
+import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.cdt.core.settings.model.util.CDataUtil;
+import org.eclipse.cdt.internal.core.XmlUtil;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
+import org.eclipse.cdt.utils.EFSExtensionManager;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.w3c.dom.Element;
+
+/**
+ * Abstract class for language settings providers capable to parse build output.
+ *
+ * @since 8.1
+ */
+public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSettingsSerializableProvider implements ICBuildOutputParser {
+ protected static final String ATTR_KEEP_RELATIVE_PATHS = "keep-relative-paths"; //$NON-NLS-1$
+
+ protected ICConfigurationDescription currentCfgDescription = null;
+ protected IWorkingDirectoryTracker cwdTracker = null;
+ protected IProject currentProject = null;
+ protected IResource currentResource = null;
+ protected String currentLanguageId = null;
+
+ protected String parsedResourceName = null;
+ protected boolean isResolvingPaths = true;
+
+ /**
+ * Abstract class defining common functionality for option parsers.
+ * The purpose of this parser is to parse a portion of string representing
+ * a single option and create a language settings entry out of it.
+ *
+ * See {@link GCCBuildCommandParser} for an example how to define the parsers.
+ */
+ protected static abstract class AbstractOptionParser {
+ private final int kind;
+ private final String patternStr;
+ private final Pattern pattern;
+ private final String nameExpression;
+ private final String valueExpression;
+ private final int extraFlag;
+
+ private String parsedName;
+ private String parsedValue;
+
+ /**
+ * Constructor.
+ *
+ * @param kind - kind of language settings entries being parsed by the parser.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param valueExpression - capturing group expression defining value of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public AbstractOptionParser(int kind, String pattern, String nameExpression, String valueExpression, int extraFlag) {
+ this.kind = kind;
+ this.patternStr = pattern;
+ this.nameExpression = nameExpression;
+ this.valueExpression = valueExpression;
+ this.extraFlag = extraFlag;
+
+ this.pattern = Pattern.compile(pattern);
+ }
+
+ /**
+ * Create language settings entry of appropriate kind and considering extra-flag passed in constructor.
+ *
+ * @param name - name of language settings entry.
+ * @param value - value of language settings entry.
+ * @param flag - flag to set. Note that the flag will be amended with the extra-flag defined in constructor.
+ * @return new language settings entry.
+ */
+ public ICLanguageSettingEntry createEntry(String name, String value, int flag) {
+ return (ICLanguageSettingEntry) CDataUtil.createEntry(kind, name, value, null, flag | extraFlag);
+ }
+
+ /**
+ * Check if the king of option parsed by parser is "file".
+ *
+ * @return {@code true} if the kind is file, {@code false} otherwise.
+ */
+ public boolean isForFile() {
+ return kind == ICSettingEntry.INCLUDE_FILE || kind == ICSettingEntry.MACRO_FILE;
+ }
+
+ /**
+ * Check if the king of option parsed by parser is "folder".
+ *
+ * @return {@code true} if the kind is folder, {@code false} otherwise.
+ */
+ public boolean isForFolder() {
+ return kind == ICSettingEntry.INCLUDE_PATH || kind == ICSettingEntry.LIBRARY_PATH;
+ }
+
+ /**
+ * Return value represented by the capturing group expression.
+ */
+ private String parseStr(Matcher matcher, String str) {
+ if (str != null)
+ return matcher.replaceAll(str);
+ return null;
+ }
+
+ /**
+ * Test for a match and parse a portion of input string representing a single option
+ * to retrieve name and value.
+ *
+ * @param optionString - an option to test and parse, possibly with an argument.
+ * @return {@code true} if the option is a match to parser's regular expression
+ * or {@code false} otherwise.
+ */
+ public boolean parseOption(String optionString) {
+ // get rid of extra text at the end (for example file name could be confused for an argument)
+ @SuppressWarnings("nls")
+ String option = optionString.replaceFirst("(" + patternStr + ").*", "$1");
+
+ Matcher matcher = pattern.matcher(option);
+ boolean isMatch = matcher.matches();
+ if (isMatch) {
+ parsedName = parseStr(matcher, nameExpression);
+ parsedValue = parseStr(matcher, valueExpression);
+ }
+ return isMatch;
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for include path options parsing.
+ */
+ protected static class IncludePathOptionParser extends AbstractOptionParser {
+ public IncludePathOptionParser(String pattern, String nameExpression) {
+ super(ICLanguageSettingEntry.INCLUDE_PATH, pattern, nameExpression, nameExpression, 0);
+ }
+ public IncludePathOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.INCLUDE_PATH, pattern, nameExpression, nameExpression, extraFlag);
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for include file options parsing.
+ */
+ protected static class IncludeFileOptionParser extends AbstractOptionParser {
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ */
+ public IncludeFileOptionParser(String pattern, String nameExpression) {
+ super(ICLanguageSettingEntry.INCLUDE_FILE, pattern, nameExpression, nameExpression, 0);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public IncludeFileOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.INCLUDE_FILE, pattern, nameExpression, nameExpression, extraFlag);
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for macro options parsing.
+ */
+ protected static class MacroOptionParser extends AbstractOptionParser {
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param valueExpression - capturing group expression defining value of an entry.
+ */
+ public MacroOptionParser(String pattern, String nameExpression, String valueExpression) {
+ super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, valueExpression, 0);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param valueExpression - capturing group expression defining value of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public MacroOptionParser(String pattern, String nameExpression, String valueExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, valueExpression, extraFlag);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public MacroOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.MACRO, pattern, nameExpression, null, extraFlag);
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for macro file options parsing.
+ */
+ protected static class MacroFileOptionParser extends AbstractOptionParser {
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ */
+ public MacroFileOptionParser(String pattern, String nameExpression) {
+ super(ICLanguageSettingEntry.MACRO_FILE, pattern, nameExpression, nameExpression, 0);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public MacroFileOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.MACRO_FILE, pattern, nameExpression, nameExpression, extraFlag);
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for library path options parsing.
+ */
+ protected static class LibraryPathOptionParser extends AbstractOptionParser {
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ */
+ public LibraryPathOptionParser(String pattern, String nameExpression) {
+ super(ICLanguageSettingEntry.LIBRARY_PATH, pattern, nameExpression, nameExpression, 0);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public LibraryPathOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.LIBRARY_PATH, pattern, nameExpression, nameExpression, extraFlag);
+ }
+ }
+
+ /**
+ * Implementation of {@link AbstractOptionParser} for library file options parsing.
+ */
+ protected static class LibraryFileOptionParser extends AbstractOptionParser {
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ */
+ public LibraryFileOptionParser(String pattern, String nameExpression) {
+ super(ICLanguageSettingEntry.LIBRARY_FILE, pattern, nameExpression, nameExpression, 0);
+ }
+ /**
+ * Constructor.
+ * @param pattern - regular expression pattern being parsed by the parser.
+ * @param nameExpression - capturing group expression defining name of an entry.
+ * @param extraFlag - extra-flag to add while creating language settings entry.
+ */
+ public LibraryFileOptionParser(String pattern, String nameExpression, int extraFlag) {
+ super(ICLanguageSettingEntry.LIBRARY_FILE, pattern, nameExpression, nameExpression, extraFlag);
+ }
+ }
+
+ /**
+ * Parse the line returning the resource name as appears in the output.
+ * This is the resource where {@link ICLanguageSettingEntry} list is being added.
+ *
+ * @param line - one input line from the output stripped from end of line characters.
+ * @return the resource name as appears in the output or {@code null}.
+ * Note that {@code null} can have different semantics and can mean "no resource found"
+ * or "applicable to any resource". By default "no resource found" is used in this
+ * abstract class but extenders can handle otherwise.
+ */
+ protected abstract String parseResourceName(String line);
+
+ /**
+ * Parse the line returning the list of substrings to be treated each as input to
+ * the option parsers. It is assumed that each substring presents one
+ * {@link ICLanguageSettingEntry} (for example compiler options {@code -I/path} or
+ * {@code -DMACRO=1}).
+ *
+ * @param line - one input line from the output stripped from end of line characters.
+ * @return list of substrings representing language settings entries.
+ */
+ protected abstract List<String> parseOptions(String line);
+
+ /**
+ * @return array of option parsers defining how to parse a string to
+ * {@link ICLanguageSettingEntry}.
+ * See {@link AbstractOptionParser} and its specific extenders.
+ */
+ protected abstract AbstractOptionParser[] getOptionParsers();
+
+ /**
+ * @return {@code true} when the provider tries to resolve relative or remote paths
+ * to the existing paths in the workspace or local file-system using certain heuristics.
+ */
+ public boolean isResolvingPaths() {
+ return isResolvingPaths;
+ }
+
+ /**
+ * Enable or disable resolving relative or remote paths to the existing paths
+ * in the workspace or local file-system.
+ *
+ * @param resolvePaths - set {@code true} to enable or {@code false} to disable
+ * resolving paths. When this parameter is set to {@code false} the paths will
+ * be kept as they appear in the build output.
+ */
+ public void setResolvingPaths(boolean resolvePaths) {
+ this.isResolvingPaths = resolvePaths;
+ }
+
+
+ @Override
+ public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker) throws CoreException {
+ this.currentCfgDescription = cfgDescription;
+ this.currentProject = cfgDescription != null ? cfgDescription.getProjectDescription().getProject() : null;
+ this.cwdTracker = cwdTracker;
+ }
+
+ @Override
+ public void shutdown() {
+ // release resources for garbage collector
+ // but keep currentCfgDescription for AbstractBuiltinSpecsDetector flow
+ parsedResourceName = null;
+ currentLanguageId = null;
+ currentResource = null;
+ cwdTracker = null;
+ }
+
+ @Override
+ public boolean processLine(String line) {
+ parsedResourceName = parseResourceName(line);
+ currentResource = findResource(parsedResourceName);
+
+ currentLanguageId = determineLanguage();
+ if (!isLanguageInScope(currentLanguageId)) {
+ return false;
+ }
+
+ /**
+ * URI of directory where the build is happening. This URI could point to a remote file-system
+ * for remote builds. Most often it is the same file-system as for currentResource but
+ * it can be different file-system (and different URI schema).
+ */
+ URI buildDirURI = null;
+
+ /**
+ * Where source tree starts if mapped. This kind of mapping is useful for example in cases when
+ * the absolute path to the source file on the remote system is simulated inside a project in the
+ * workspace.
+ * This URI is rooted on the same file-system where currentResource resides. In general this file-system
+ * (or even URI schema) does not have to match that of buildDirURI.
+ */
+ URI mappedRootURI = null;
+
+ if (isResolvingPaths) {
+ mappedRootURI = getMappedRootURI(currentResource, parsedResourceName);
+ buildDirURI = getBuildDirURI(mappedRootURI);
+ }
+
+ List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>();
+
+ List<String> options = parseOptions(line);
+ if (options != null) {
+ AbstractOptionParser[] optionParsers = getOptionParsers();
+ for (String option : options) {
+ for (AbstractOptionParser optionParser : optionParsers) {
+ try {
+ if (optionParser.parseOption(option)) {
+ ICLanguageSettingEntry entry = null;
+ if (isResolvingPaths && (optionParser.isForFile() || optionParser.isForFolder())) {
+ URI baseURI = mappedRootURI;
+ if (buildDirURI != null && !new Path(optionParser.parsedName).isAbsolute()) {
+ baseURI = EFSExtensionManager.getDefault().append(mappedRootURI, buildDirURI.getPath());
+ }
+ entry = createResolvedPathEntry(optionParser, optionParser.parsedName, 0, baseURI);
+ } else {
+ entry = optionParser.createEntry(optionParser.parsedName, optionParser.parsedValue, 0);
+ }
+
+ if (entry != null && !entries.contains(entry)) {
+ entries.add(entry);
+ break;
+ }
+ }
+ } catch (Throwable e) {
+ @SuppressWarnings("nls")
+ String msg = "Exception trying to parse option [" + option + "], class " + getClass().getSimpleName();
+ ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, e));
+ }
+ }
+ }
+ if (entries.size() > 0) {
+ setSettingEntries(entries);
+ } else {
+ setSettingEntries(null);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * In case when absolute path is mapped to the source tree in a project
+ * this function will try to figure mapping and return "mapped root",
+ * i.e URI where the root path would be mapped. The mapped root will be
+ * used to prepend to other "absolute" paths where appropriate.
+ *
+ * @param resource - a resource referred by parsed path
+ * @param parsedResourceName - path as appears in the output
+ * @return mapped path as URI
+ */
+ protected URI getMappedRootURI(IResource resource, String parsedResourceName) {
+ if (resource == null) {
+ return null;
+ }
+
+ URI resourceURI = resource.getLocationURI();
+ String mappedRoot = "/"; //$NON-NLS-1$
+
+ if (parsedResourceName != null) {
+ IPath parsedSrcPath = new Path(parsedResourceName);
+ if (parsedSrcPath.isAbsolute()) {
+ IPath absResourcePath = resource.getLocation();
+ int absSegmentsCount = absResourcePath.segmentCount();
+ int relSegmentsCount = parsedSrcPath.segmentCount();
+ if (absSegmentsCount >= relSegmentsCount) {
+ IPath ending = absResourcePath.removeFirstSegments(absSegmentsCount - relSegmentsCount);
+ ending = ending.setDevice(parsedSrcPath.getDevice()).makeAbsolute();
+ if (ending.equals(parsedSrcPath.makeAbsolute())) {
+ // mappedRoot here is parsedSrcPath with removed parsedResourceName trailing segments,
+ // i.e. if absResourcePath="/path/workspace/project/file.c" and parsedResourceName="project/file.c"
+ // then mappedRoot="/path/workspace/"
+ mappedRoot = absResourcePath.removeLastSegments(relSegmentsCount).toString();
+ }
+ }
+ }
+ }
+ // this creates URI with schema and other components from resourceURI but path as mappedRoot
+ URI uri = EFSExtensionManager.getDefault().createNewURIFromPath(resourceURI, mappedRoot);
+ return uri;
+ }
+
+ /**
+ * Determine current build directory considering currentResource (resource being compiled),
+ * parsedResourceName and mappedRootURI.
+ *
+ * @param mappedRootURI - root of the source tree when mapped to remote file-system.
+ * @return {@link URI} of current build directory
+ */
+ protected URI getBuildDirURI(URI mappedRootURI) {
+ URI buildDirURI = null;
+
+ // try to deduce build directory from full path of currentResource and partial path of parsedResourceName
+ URI cwdURI = null;
+ if (currentResource != null && parsedResourceName != null && !new Path(parsedResourceName).isAbsolute()) {
+ cwdURI = findBaseLocationURI(currentResource.getLocationURI(), parsedResourceName);
+ }
+ String cwdPath = cwdURI != null ? EFSExtensionManager.getDefault().getPathFromURI(cwdURI) : null;
+ if (cwdPath != null && mappedRootURI != null) {
+ buildDirURI = EFSExtensionManager.getDefault().append(mappedRootURI, cwdPath);
+ } else {
+ buildDirURI = cwdURI;
+ }
+
+ // try IWorkingDirectoryTracker
+ if (buildDirURI == null && cwdTracker != null) {
+ buildDirURI = cwdTracker.getWorkingDirectoryURI();
+ }
+
+ // try builder working directory
+ if (buildDirURI == null && currentCfgDescription != null) {
+ IPath pathBuilderCWD = currentCfgDescription.getBuildSetting().getBuilderCWD();
+ if (pathBuilderCWD != null) {
+ String builderCWD = pathBuilderCWD.toString();
+ try {
+ // here is a hack to overcome ${workspace_loc:/prj-name} returned by builder
+ // where "/" is treated as path separator by pathBuilderCWD
+ ICdtVariableManager vmanager = CCorePlugin.getDefault().getCdtVariableManager();
+ builderCWD = vmanager.resolveValue(builderCWD, "", null, currentCfgDescription); //$NON-NLS-1$
+ } catch (CdtVariableException e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ if (builderCWD != null && !builderCWD.isEmpty()) {
+ buildDirURI = org.eclipse.core.filesystem.URIUtil.toURI(builderCWD);
+ }
+ }
+ }
+
+ // try directory of the current project
+ if (buildDirURI == null && currentProject != null) {
+ buildDirURI = currentProject.getLocationURI();
+ }
+
+ // try parent folder of the resource
+ if (buildDirURI == null && currentResource != null) {
+ IContainer container;
+ if (currentResource instanceof IContainer) {
+ container = (IContainer) currentResource;
+ } else {
+ container = currentResource.getParent();
+ }
+ buildDirURI = container.getLocationURI();
+ }
+ return buildDirURI;
+ }
+
+ /**
+ * Sets language settings entries for current configuration description, current resource
+ * and current language ID.
+ *
+ * @param entries - language settings entries to set.
+ */
+ protected void setSettingEntries(List<ICLanguageSettingEntry> entries) {
+ setSettingEntries(currentCfgDescription, currentResource, currentLanguageId, entries);
+ }
+
+ /**
+ * Determine a language associated with the resource.
+ *
+ * @return language ID for the resource.
+ */
+ protected String determineLanguage() {
+ IResource rc = currentResource;
+ if (rc == null && currentProject != null && parsedResourceName != null) {
+ String fileName = new Path(parsedResourceName).lastSegment().toString();
+ // use handle; resource does not need to exist
+ rc = currentProject.getFile("__" + fileName); //$NON-NLS-1$
+ }
+
+ if (rc == null)
+ return null;
+
+ List<String> languageIds = LanguageSettingsManager.getLanguages(rc, currentCfgDescription);
+ if (languageIds.isEmpty())
+ return null;
+
+ return languageIds.get(0);
+ }
+
+ /**
+ * Determine if the language is in scope of the provider.
+ *
+ * @param languageId - language ID.
+ * @return {@code true} if the language is in scope, {@code false } otherwise.
+ */
+ protected boolean isLanguageInScope(String languageId) {
+ List<String> languageIds = getLanguageScope();
+ return languageIds == null || languageIds.contains(languageId);
+ }
+
+ /**
+ * Find resource in the workspace for a given URI with a preference for the resource
+ * to reside in the given project.
+ */
+ private static IResource findFileForLocationURI(URI uri, IProject preferredProject) {
+ IResource sourceFile = null;
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IResource[] resources = root.findFilesForLocationURI(uri);
+ if (resources.length > 0) {
+ sourceFile = resources[0];
+ if (preferredProject != null) {
+ for (IResource rc : resources) {
+ if (rc.getProject().equals(preferredProject)) {
+ sourceFile = rc;
+ break;
+ }
+ }
+ }
+ }
+ return sourceFile;
+ }
+
+ /**
+ * Return a resource in workspace corresponding the given folder {@link URI} preferable residing in
+ * the provided project.
+ */
+ private static IResource findContainerForLocationURI(URI uri, IProject preferredProject) {
+ IResource resource = null;
+ IResource[] resources = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(uri);
+ for (IResource rc : resources) {
+ if ((rc instanceof IProject || rc instanceof IFolder)) { // treat IWorkspaceRoot as non-workspace path
+ if (rc.getProject().equals(preferredProject)) {
+ resource = rc;
+ break;
+ }
+ if (resource == null) {
+ resource = rc; // to be deterministic the first qualified resource has preference
+ }
+ }
+ }
+ return resource;
+ }
+
+ /**
+ * Determine resource in the workspace corresponding to the parsed resource name.
+ */
+ private IResource findResource(String parsedResourceName) {
+ if (parsedResourceName == null || parsedResourceName.isEmpty()) {
+ return null;
+ }
+
+ IResource sourceFile = null;
+
+ // try ErrorParserManager
+ if (cwdTracker instanceof ErrorParserManager) {
+ sourceFile = ((ErrorParserManager) cwdTracker).findFileName(parsedResourceName);
+ }
+
+ // try to find absolute path in the workspace
+ if (sourceFile == null && new Path(parsedResourceName).isAbsolute()) {
+ URI uri = org.eclipse.core.filesystem.URIUtil.toURI(parsedResourceName);
+ sourceFile = findFileForLocationURI(uri, currentProject);
+ }
+
+ // try last known current working directory from build output
+ if (sourceFile == null && cwdTracker != null) {
+ URI cwdURI = cwdTracker.getWorkingDirectoryURI();
+ if (cwdURI != null) {
+ URI uri = EFSExtensionManager.getDefault().append(cwdURI, parsedResourceName);
+ sourceFile = findFileForLocationURI(uri, currentProject);
+ }
+ }
+
+ // try path relative to build dir from configuration
+ if (sourceFile == null && currentCfgDescription != null) {
+ IPath builderCWD = currentCfgDescription.getBuildSetting().getBuilderCWD();
+ if (builderCWD!=null) {
+ IPath path = builderCWD.append(parsedResourceName);
+ URI uri = org.eclipse.core.filesystem.URIUtil.toURI(path);
+ sourceFile = findFileForLocationURI(uri, currentProject);
+ }
+ }
+
+ // try path relative to the project
+ if (sourceFile == null && currentProject != null) {
+ sourceFile = currentProject.findMember(parsedResourceName);
+ }
+
+ return sourceFile;
+ }
+
+ /**
+ * Find base location of the file, i.e. location of the directory which
+ * results from removing trailing relativeFileName from fileURI or
+ * {@code null} if fileURI doesn't represent relativeFileName.
+ */
+ private static URI findBaseLocationURI(URI fileURI, String relativeFileName) {
+ URI cwdURI = null;
+ String path = fileURI.getPath();
+
+ String[] segments = relativeFileName.split("[/\\\\]"); //$NON-NLS-1$
+
+ // start removing segments from the end of the path
+ for (int i = segments.length - 1; i >= 0; i--) {
+ String lastSegment = segments[i];
+ if (lastSegment.length() > 0 && !lastSegment.equals(".")) { //$NON-NLS-1$
+ if (lastSegment.equals("..")) { //$NON-NLS-1$
+ // navigating ".." in the other direction is ambiguous, bailing out
+ return null;
+ } else {
+ if (path.endsWith("/" + lastSegment)) { //$NON-NLS-1$
+ int pos = path.lastIndexOf("/" + lastSegment); //$NON-NLS-1$
+ path = path.substring(0, pos);
+ continue;
+ } else {
+ // ouch, relativeFileName does not match fileURI, bailing out
+ return null;
+ }
+ }
+ }
+ }
+
+ try {
+ cwdURI = new URI(fileURI.getScheme(), fileURI.getUserInfo(), fileURI.getHost(),
+ fileURI.getPort(), path + '/', fileURI.getQuery(), fileURI.getFragment());
+ } catch (URISyntaxException e) {
+ // It should be valid URI here or something is really wrong
+ ManagedBuilderCorePlugin.log(e);
+ }
+
+ return cwdURI;
+ }
+
+ /**
+ * The manipulations here are done to resolve "../" navigation for symbolic links where "link/.." cannot
+ * be collapsed as it must follow the real file-system path. {@link java.io.File#getCanonicalPath()} deals
+ * with that correctly but {@link Path} or {@link URI} try to normalize the path which would be incorrect
+ * here.
+ */
+ private static URI resolvePathFromBaseLocation(String name, IPath baseLocation) {
+ String pathName = name;
+ if (baseLocation != null && !baseLocation.isEmpty()) {
+ pathName = pathName.replace(File.separatorChar, '/');
+ String device = new Path(pathName).getDevice();
+ if (device==null || device.equals(baseLocation.getDevice())) {
+ if (device != null && device.length() > 0) {
+ pathName = pathName.substring(device.length());
+ }
+
+ baseLocation = baseLocation.addTrailingSeparator();
+ if (pathName.startsWith("/")) { //$NON-NLS-1$
+ pathName = pathName.substring(1);
+ }
+ pathName = baseLocation.toString() + pathName;
+ }
+ }
+
+ try {
+ File file = new File(pathName);
+ file = file.getCanonicalFile();
+ return file.toURI();
+ } catch (IOException e) {
+ // if error just leave it as is
+ }
+
+ return org.eclipse.core.filesystem.URIUtil.toURI(pathName);
+ }
+
+ /**
+ * Determine URI on the local file-system considering possible mapping.
+ *
+ * @param pathStr - path to the resource, can be absolute or relative
+ * @param baseURI - base {@link URI} where path to the resource is rooted
+ * @return {@link URI} of the resource
+ */
+ private static URI determineMappedURI(String pathStr, URI baseURI) {
+ URI uri = null;
+
+ if (baseURI == null) {
+ if (new Path(pathStr).isAbsolute()) {
+ uri = resolvePathFromBaseLocation(pathStr, Path.ROOT);
+ }
+ } else if (baseURI.getScheme().equals(EFS.SCHEME_FILE)) {
+ // location on the local file-system
+ IPath baseLocation = org.eclipse.core.filesystem.URIUtil.toPath(baseURI);
+ // careful not to use Path here but 'pathStr' as String as we want to properly navigate symlinks
+ uri = resolvePathFromBaseLocation(pathStr, baseLocation);
+ } else {
+ // location on a remote file-system
+ IPath path = new Path(pathStr); // use canonicalized path here, in particular replace all '\' with '/' for Windows paths
+ URI remoteUri = EFSExtensionManager.getDefault().append(baseURI, path.toString());
+ if (remoteUri != null) {
+ String localPath = EFSExtensionManager.getDefault().getMappedPath(remoteUri);
+ if (localPath != null) {
+ uri = org.eclipse.core.filesystem.URIUtil.toURI(localPath);
+ }
+ }
+ }
+
+ if (uri == null) {
+ // if everything fails just wrap string to URI
+ uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
+ }
+ return uri;
+ }
+
+ /**
+ * Find all resources in the folder which might be represented by relative path passed.
+ */
+ private static List<IResource> findPathInFolder(IPath path, IContainer folder) {
+ List<IResource> paths = new ArrayList<IResource>();
+ IResource resource = folder.findMember(path);
+ if (resource != null) {
+ paths.add(resource);
+ }
+
+ try {
+ for (IResource res : folder.members()) {
+ if (res instanceof IContainer) {
+ paths.addAll(findPathInFolder(path, (IContainer) res));
+ }
+ }
+ } catch (CoreException e) {
+ // ignore
+ }
+
+ return paths;
+ }
+
+ /**
+ * Determine which resource in workspace is the best fit to parsedName passed.
+ */
+ private static IResource resolveResourceInWorkspace(String parsedName, IProject preferredProject, Set<String> referencedProjectsNames) {
+ IPath path = new Path(parsedName);
+ if (path.equals(new Path(".")) || path.equals(new Path(".."))) { //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ // prefer current project
+ if (preferredProject != null) {
+ List<IResource> result = findPathInFolder(path, preferredProject);
+ int size = result.size();
+ if (size == 1) { // found the one
+ return result.get(0);
+ } else if (size > 1) { // ambiguous
+ return null;
+ }
+ }
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ // then prefer referenced projects
+ if (referencedProjectsNames.size() > 0) {
+ IResource rc = null;
+ for (String prjName : referencedProjectsNames) {
+ IProject prj = root.getProject(prjName);
+ if (prj.isOpen()) {
+ List<IResource> result = findPathInFolder(path, prj);
+ int size = result.size();
+ if (size == 1 && rc == null) {
+ rc = result.get(0);
+ } else if (size > 0) {
+ // ambiguous
+ rc = null;
+ break;
+ }
+ }
+ }
+ if (rc != null) {
+ return rc;
+ }
+ }
+
+ // then check all other projects in workspace
+ IProject[] projects = root.getProjects();
+ if (projects.length > 0) {
+ IResource rc = null;
+ for (IProject prj : projects) {
+ if (!prj.equals(preferredProject) && !referencedProjectsNames.contains(prj.getName()) && prj.isOpen()) {
+ List<IResource> result = findPathInFolder(path, prj);
+ int size = result.size();
+ if (size == 1 && rc == null) {
+ rc = result.get(0);
+ } else if (size > 0) {
+ // ambiguous
+ rc = null;
+ break;
+ }
+ }
+ }
+ if (rc != null) {
+ return rc;
+ }
+ }
+
+ // not found or ambiguous
+ return null;
+ }
+
+ /**
+ * Get location on the local file-system considering possible mapping by {@link EFSExtensionManager}.
+ */
+ private static IPath getFilesystemLocation(URI uri) {
+ if (uri == null)
+ return null;
+
+ String pathStr = EFSExtensionManager.getDefault().getMappedPath(uri);
+ uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
+
+ try {
+ File file = new java.io.File(uri);
+ String canonicalPathStr = file.getCanonicalPath();
+ return new Path(canonicalPathStr);
+ } catch (Exception e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ return null;
+ }
+
+ /**
+ * Resolve and create language settings path entry.
+ */
+ private ICLanguageSettingEntry createResolvedPathEntry(AbstractOptionParser optionParser,
+ String parsedPath, int flag, URI baseURI) {
+
+ String resolvedPath = null;
+ int resolvedFlag = 0;
+
+ URI uri = determineMappedURI(parsedPath, baseURI);
+ IResource rc = null;
+
+ // Try to resolve in the workspace
+ if (uri != null && uri.isAbsolute()) {
+ if (optionParser.isForFolder()) {
+ rc = findContainerForLocationURI(uri, currentProject);
+ } else if (optionParser.isForFile()) {
+ rc = findFileForLocationURI(uri, currentProject);
+ }
+ if (rc != null) {
+ resolvedPath = rc.getFullPath().toString();
+ resolvedFlag = flag | ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED;
+ }
+ }
+
+ // Try to resolve on the file-system
+ if (resolvedPath == null) {
+ IPath path = getFilesystemLocation(uri);
+ if (path != null && new File(path.toString()).exists()) {
+ resolvedPath = path.toString();
+ resolvedFlag = flag;
+ }
+ if (resolvedPath == null) {
+ Set<String> referencedProjectsNames = new LinkedHashSet<String>();
+ if (currentCfgDescription!=null) {
+ Map<String,String> refs = currentCfgDescription.getReferenceInfo();
+ referencedProjectsNames.addAll(refs.keySet());
+ }
+ IResource resource = resolveResourceInWorkspace(parsedPath, currentProject, referencedProjectsNames);
+ if (resource != null) {
+ resolvedPath = resource.getFullPath().toString();
+ resolvedFlag = flag | ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED;
+ }
+ }
+ if (resolvedPath == null && path != null) {
+ resolvedPath = path.toString();
+ resolvedFlag = flag;
+ }
+ }
+
+ // if cannot resolve keep parsed path
+ if (resolvedPath == null) {
+ resolvedPath = parsedPath;
+ resolvedFlag = flag;
+ }
+
+ return optionParser.createEntry(resolvedPath, resolvedPath, resolvedFlag);
+ }
+
+ /**
+ * Count how many groups are present in regular expression.
+ * The implementation is simplistic but should be sufficient for the cause.
+ *
+ * @param str - regular expression to count the groups.
+ * @return number of the groups (groups are enclosed in round brackets) present.
+ */
+ protected static int countGroups(String str) {
+ @SuppressWarnings("nls")
+ int count = str.replaceAll("[^\\(]", "").length();
+ return count;
+ }
+
+ /**
+ * Helper method to construct logical "or" to be used inside regular expressions.
+ */
+ @SuppressWarnings("nls")
+ private static String expressionLogicalOr(Set<String> fileExts) {
+ String pattern = "(";
+ for (String ext : fileExts) {
+ if (pattern.length() != 1)
+ pattern += "|";
+ pattern += "(" + Pattern.quote(ext) + ")";
+ ext = ext.toUpperCase();
+ if (!fileExts.contains(ext)) {
+ pattern += "|(" + Pattern.quote(ext) + ")";
+ }
+ }
+ pattern += ")";
+ return pattern;
+ }
+
+ /**
+ * Construct regular expression to find any file extension for C or C++.
+ * Returns expression shaped in form of "((cpp)|(c++)|(c))".
+ *
+ * @return regular expression for searching C/C++ file extensions.
+ */
+ protected String getPatternFileExtensions() {
+ IContentTypeManager manager = Platform.getContentTypeManager();
+
+ Set<String> fileExts = new HashSet<String>();
+
+ IContentType contentTypeCpp = manager.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE);
+ fileExts.addAll(Arrays.asList(contentTypeCpp.getFileSpecs(IContentType.FILE_EXTENSION_SPEC)));
+
+ IContentType contentTypeC = manager.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE);
+ fileExts.addAll(Arrays.asList(contentTypeC.getFileSpecs(IContentType.FILE_EXTENSION_SPEC)));
+
+ String pattern = expressionLogicalOr(fileExts);
+
+ return pattern;
+ }
+
+ @Override
+ public Element serializeAttributes(Element parentElement) {
+ Element elementProvider = super.serializeAttributes(parentElement);
+ elementProvider.setAttribute(ATTR_KEEP_RELATIVE_PATHS, Boolean.toString( ! isResolvingPaths ));
+ return elementProvider;
+ }
+
+ @Override
+ public void loadAttributes(Element providerNode) {
+ super.loadAttributes(providerNode);
+
+ String expandRelativePathsValue = XmlUtil.determineAttributeValue(providerNode, ATTR_KEEP_RELATIVE_PATHS);
+ if (expandRelativePathsValue!=null)
+ isResolvingPaths = ! Boolean.parseBoolean(expandRelativePathsValue);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (isResolvingPaths ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AbstractLanguageSettingsOutputScanner other = (AbstractLanguageSettingsOutputScanner) obj;
+ if (isResolvingPaths != other.isResolvingPaths)
+ return false;
+ return true;
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuildCommandParser.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuildCommandParser.java
new file mode 100644
index 0000000000..93d0e20062
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuildCommandParser.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+
+import org.eclipse.cdt.core.errorparsers.RegexErrorPattern;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+
+/**
+ * Build command parser capable to parse gcc command in build output and generate
+ * language settings per file being compiled.
+ *
+ * @since 8.1
+ */
+public class GCCBuildCommandParser extends AbstractBuildCommandParser implements ILanguageSettingsEditableProvider {
+ @SuppressWarnings("nls")
+ static final AbstractOptionParser[] optionParsers = {
+ new IncludePathOptionParser("-I\\s*([\"'])(.*)\\1", "$2"),
+ new IncludePathOptionParser("-I\\s*([^\\s\"']*)", "$1"),
+ new IncludeFileOptionParser("-include\\s*([\"'])(.*)\\1", "$2"),
+ new IncludeFileOptionParser("-include\\s*([^\\s\"']*)", "$1"),
+ new MacroOptionParser("-D\\s*([\"'])([^=]*)(=(.*))?\\1", "$2", "$4"),
+ new MacroOptionParser("-D\\s*([^\\s=\"']*)=(\\\\([\"']))(.*?)\\2", "$1", "$3$4$3"),
+ new MacroOptionParser("-D\\s*([^\\s=\"']*)=([\"'])(.*?)\\2", "$1", "$3"),
+ new MacroOptionParser("-D\\s*([^\\s=\"']*)(=([^\\s\"']*))?", "$1", "$3"),
+ new MacroOptionParser("-U\\s*([^\\s=\"']*)", "$1", ICSettingEntry.UNDEFINED),
+ new MacroFileOptionParser("-macros\\s*([\"'])(.*)\\1", "$2"),
+ new MacroFileOptionParser("-macros\\s*([^\\s\"']*)", "$1"),
+ new LibraryPathOptionParser("-L\\s*([\"'])(.*)\\1", "$2"),
+ new LibraryPathOptionParser("-L\\s*([^\\s\"']*)", "$1"),
+ new LibraryFileOptionParser("-l\\s*([^\\s\"']*)", "lib$1.a"), };
+
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return optionParsers;
+ }
+
+ @Override
+ public GCCBuildCommandParser cloneShallow() throws CloneNotSupportedException {
+ return (GCCBuildCommandParser) super.cloneShallow();
+ }
+
+ @Override
+ public GCCBuildCommandParser clone() throws CloneNotSupportedException {
+ return (GCCBuildCommandParser) super.clone();
+ }
+
+ /**
+ * Error Parser which allows highlighting of output lines matching the patterns of this parser.
+ * Intended for better troubleshooting experience.
+ */
+ public static class GCCBuildCommandPatternHighlighter extends AbstractBuildCommandParser.AbstractBuildCommandPatternHighlighter {
+ // ID of the parser taken from the existing extension point
+ private static final String GCC_BUILD_COMMAND_PARSER_EXT = "org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"; //$NON-NLS-1$
+
+ /**
+ * Default constructor.
+ */
+ public GCCBuildCommandPatternHighlighter() {
+ super(GCC_BUILD_COMMAND_PARSER_EXT);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ GCCBuildCommandPatternHighlighter that = new GCCBuildCommandPatternHighlighter();
+ that.setId(getId());
+ that.setName(getName());
+ for (RegexErrorPattern pattern : getPatterns()) {
+ that.addPattern((RegexErrorPattern)pattern.clone());
+ }
+ return that;
+ }
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuiltinSpecsDetector.java
new file mode 100644
index 0000000000..865832c45c
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/GCCBuiltinSpecsDetector.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider;
+import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.core.settings.model.ICSettingEntry;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Language settings provider to detect built-in compiler settings for GCC compiler.
+ *
+ * @since 8.1
+ */
+public class GCCBuiltinSpecsDetector extends ToolchainBuiltinSpecsDetector implements ILanguageSettingsEditableProvider {
+ // ID must match the tool-chain definition in org.eclipse.cdt.managedbuilder.core.buildDefinitions extension point
+ private static final String GCC_TOOLCHAIN_ID = "cdt.managedbuild.toolchain.gnu.base"; //$NON-NLS-1$
+
+ private enum State {NONE, EXPECTING_LOCAL_INCLUDE, EXPECTING_SYSTEM_INCLUDE, EXPECTING_FRAMEWORKS}
+ private State state = State.NONE;
+
+ @SuppressWarnings("nls")
+ private static final AbstractOptionParser[] optionParsers = {
+ new IncludePathOptionParser("#include \"(\\S.*)\"", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.LOCAL),
+ new IncludePathOptionParser("#include <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY),
+ new IncludePathOptionParser("#framework <(\\S.*)>", "$1", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY | ICSettingEntry.FRAMEWORKS_MAC),
+ new MacroOptionParser("#define\\s+(\\S*\\(.*?\\))\\s*(.*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY),
+ new MacroOptionParser("#define\\s+(\\S*)\\s*(\\S*)", "$1", "$2", ICSettingEntry.BUILTIN | ICSettingEntry.READONLY),
+ };
+
+ @Override
+ protected String getToolchainId() {
+ return GCC_TOOLCHAIN_ID;
+ }
+
+ @Override
+ protected AbstractOptionParser[] getOptionParsers() {
+ return optionParsers;
+ }
+
+ /**
+ * Create a list from one item.
+ */
+ private List<String> makeList(String line) {
+ List<String> list = new ArrayList<String>();
+ list.add(line);
+ return list;
+ }
+
+ @SuppressWarnings("nls")
+ @Override
+ protected List<String> parseOptions(String line) {
+ line = line.trim();
+
+ // contribution of -dD option
+ if (line.startsWith("#define")) {
+ return makeList(line);
+ }
+
+ // contribution of includes
+ if (line.equals("#include \"...\" search starts here:")) {
+ state = State.EXPECTING_LOCAL_INCLUDE;
+ } else if (line.equals("#include <...> search starts here:")) {
+ state = State.EXPECTING_SYSTEM_INCLUDE;
+ } else if (line.startsWith("End of search list.")) {
+ state = State.NONE;
+ } else if (line.equals("Framework search starts here:")) {
+ state = State.EXPECTING_FRAMEWORKS;
+ } else if (line.startsWith("End of framework search list.")) {
+ state = State.NONE;
+ } else if (state==State.EXPECTING_LOCAL_INCLUDE) {
+ // making that up for the parser to figure out
+ line = "#include \""+line+"\"";
+ return makeList(line);
+ } else {
+ String frameworkIndicator = "(framework directory)";
+ if (state==State.EXPECTING_SYSTEM_INCLUDE) {
+ // making that up for the parser to figure out
+ if (line.contains(frameworkIndicator)) {
+ line = "#framework <"+line.replace(frameworkIndicator, "").trim()+">";
+ } else {
+ line = "#include <"+line+">";
+ }
+ return makeList(line);
+ } else if (state==State.EXPECTING_FRAMEWORKS) {
+ // making that up for the parser to figure out
+ line = "#framework <"+line.replace(frameworkIndicator, "").trim()+">";
+ return makeList(line);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker) throws CoreException {
+ super.startup(cfgDescription, cwdTracker);
+
+ state = State.NONE;
+ }
+
+ @Override
+ public void shutdown() {
+ state = State.NONE;
+
+ super.shutdown();
+ }
+
+ @Override
+ public GCCBuiltinSpecsDetector cloneShallow() throws CloneNotSupportedException {
+ return (GCCBuiltinSpecsDetector) super.cloneShallow();
+ }
+
+ @Override
+ public GCCBuiltinSpecsDetector clone() throws CloneNotSupportedException {
+ return (GCCBuiltinSpecsDetector) super.clone();
+ }
+
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/ToolchainBuiltinSpecsDetector.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/ToolchainBuiltinSpecsDetector.java
new file mode 100644
index 0000000000..e919180d5d
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/ToolchainBuiltinSpecsDetector.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Andrew Gvozdev 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:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.language.settings.providers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.managedbuilder.core.IInputType;
+import org.eclipse.cdt.managedbuilder.core.ITool;
+import org.eclipse.cdt.managedbuilder.core.IToolChain;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
+
+/**
+ * Abstract parser capable to execute compiler command printing built-in compiler
+ * specs and parse built-in language settings out of it. The compiler to be used
+ * is taken from MBS tool-chain definition.
+ *
+ * @since 8.1
+ */
+public abstract class ToolchainBuiltinSpecsDetector extends AbstractBuiltinSpecsDetector {
+ private Map<String, ITool> toolMap = new HashMap<String, ITool>();
+
+ /**
+ * Concrete compiler specs detectors need to supply tool-chain ID.
+ *
+ * Tool-chain id must be supplied for global providers where we don't
+ * have configuration description to figure that out programmatically.
+ */
+ protected abstract String getToolchainId();
+
+ /**
+ * Finds a tool handling given language in the tool-chain of the provider.
+ * This returns the first tool found.
+ */
+ private ITool getTool(String languageId) {
+ ITool langTool = toolMap.get(languageId);
+ if (langTool != null) {
+ return langTool;
+ }
+
+ String toolchainId = getToolchainId();
+ for (IToolChain toolchain = ManagedBuildManager.getExtensionToolChain(toolchainId);toolchain != null;toolchain = toolchain.getSuperClass()) {
+ ITool tool = getTool(languageId, toolchain);
+ if (tool != null) {
+ return tool;
+ }
+ }
+ ManagedBuilderCorePlugin.error("Unable to find tool in toolchain=" + toolchainId + " for language=" + languageId); //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ /**
+ * Finds a tool handling given language in the tool-chain.
+ * This returns the first tool found.
+ */
+ private ITool getTool(String languageId, IToolChain toolchain) {
+ ITool[] tools = toolchain.getTools();
+ for (ITool tool : tools) {
+ IInputType[] inputTypes = tool.getInputTypes();
+ for (IInputType inType : inputTypes) {
+ String lang = inType.getLanguageId(tool);
+ if (languageId.equals(lang)) {
+ toolMap.put(languageId, tool);
+ return tool;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected String getCompilerCommand(String languageId) {
+ ITool tool = getTool(languageId);
+ String compilerCommand = tool.getToolCommand();
+ if (compilerCommand.isEmpty()) {
+ ManagedBuilderCorePlugin.error("Unable to find compiler command in toolchain=" + getToolchainId()); //$NON-NLS-1$
+ }
+ return compilerCommand;
+ }
+
+ @Override
+ protected String getSpecFileExtension(String languageId) {
+ String ext = null;
+ ITool tool = getTool(languageId);
+ String[] srcFileExtensions = tool.getAllInputExtensions();
+ if (srcFileExtensions != null && srcFileExtensions.length > 0) {
+ ext = srcFileExtensions[0];
+ }
+ if (ext == null || ext.isEmpty()) {
+ ManagedBuilderCorePlugin.error("Unable to find file extension for language " + languageId); //$NON-NLS-1$
+ }
+ return ext;
+ }
+
+}

Back to the top