Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-Andre Laperle2019-09-28 00:38:26 -0400
committerMarc-Andre Laperle2019-10-23 21:47:54 -0400
commit0c577f6e7e0726cf375ec9f774fdafde1762c0bc (patch)
tree155cf5266a250b10dbf4d6a3809365c4882150e3
parent6bd29843f2147e218e276e875642f85b774fa23e (diff)
downloadorg.eclipse.cdt-0c577f6e7e0726cf375ec9f774fdafde1762c0bc.tar.gz
org.eclipse.cdt-0c577f6e7e0726cf375ec9f774fdafde1762c0bc.tar.xz
org.eclipse.cdt-0c577f6e7e0726cf375ec9f774fdafde1762c0bc.zip
Bug 548730 - Compilation database (CDB) language settings provider
This language settings provider lets you specify the path to the compile_commands.json and reuses existing build output parsers to figure out all the language entries for each file to be used while indexing. With this, there is no need to do a full build and in fact no need to have a working build configured in CDT for indexing to work and be fully configured. This is especially useful for non-CMake build systems that have no existing integration in CDT but indexing would still works with little effort. The build output parser (GCC, MSVC, etc) is selectable as part of the configuration of the CDB provider. There is also an option to exclude any file that is not present in the CDB. This option is useful for large projects in order to speed up indexing but also to increase index accuracy (conflicting symbol names, etc). Change-Id: If21455ec529f9e162cdf3e5aff7a1bca83e362f6 Signed-off-by: Marc-Andre Laperle <malaperle@gmail.com>
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/META-INF/MANIFEST.MF2
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/AllLanguageSettingsProvidersMBSTests.java1
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/CompilationDatabaseParserTest.java924
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF5
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/plugin.properties1
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/plugin.xml6
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java460
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompileCommand.java34
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/Messages.java37
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/messages.properties21
-rw-r--r--build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF2
-rw-r--r--build/org.eclipse.cdt.managedbuilder.ui/plugin.xml7
-rw-r--r--build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/CompilationDatabaseParserOptionPage.java295
-rw-r--r--build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/Messages.java32
-rw-r--r--build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/messages.properties19
-rw-r--r--releng/CDT.setup4
-rw-r--r--releng/org.eclipse.cdt.target/cdt.target4
17 files changed, 1850 insertions, 4 deletions
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 af5e610101..1ba05c9894 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
@@ -14,6 +14,7 @@ Export-Package: org.eclipse.cdt.managedbuilder.core.tests,
org.eclipse.cdt.projectmodel.tests
Require-Bundle: org.eclipse.core.runtime,
org.junit,
+ org.junit.jupiter.api,
org.eclipse.core.resources,
org.eclipse.ui,
org.eclipse.ui.ide,
@@ -25,3 +26,4 @@ Require-Bundle: org.eclipse.core.runtime,
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Automatic-Module-Name: org.eclipse.cdt.managedbuilder.core.tests
+Import-Package: com.google.gson
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
index 2a13429717..e638ee210a 100644
--- 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
@@ -32,5 +32,6 @@ public class AllLanguageSettingsProvidersMBSTests extends TestSuite {
addTestSuite(GCCBuildCommandParserTest.class);
addTestSuite(BuiltinSpecsDetectorTest.class);
addTestSuite(GCCBuiltinSpecsDetectorTest.class);
+ addTestSuite(CompilationDatabaseParserTest.class);
}
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/CompilationDatabaseParserTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/CompilationDatabaseParserTest.java
new file mode 100644
index 0000000000..4a0490c26f
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/language/settings/providers/tests/CompilationDatabaseParserTest.java
@@ -0,0 +1,924 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Marc-Andre Laperle.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.language.settings.providers.tests;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.CCorePlugin;
+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.ILanguageSettingsProvidersKeeper;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
+import org.eclipse.cdt.core.settings.model.CMacroEntry;
+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.util.CDataUtil;
+import org.eclipse.cdt.core.testplugin.ResourceHelper;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsProvidersSerializer;
+import org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompilationDatabaseParser;
+import org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompileCommand;
+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.Path;
+import org.eclipse.core.runtime.jobs.Job;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * Test cases to test CompilationDatabaseParser (compile_commands.json).
+ */
+public class CompilationDatabaseParserTest extends BaseTestCase {
+ private static final String COMPILATION_DATABASE_PARSER_EXT = "org.eclipse.cdt.managedbuilder.core.CompilationDatabaseParser"; //$NON-NLS-1$
+ private static final String GCC_BUILD_COMMAND_PARSER_EXT = "org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"; //$NON-NLS-1$
+
+ private static final String ATTR_CDB_PATH = "cdb-path"; //$NON-NLS-1$
+ private static final String ATTR_BUILD_PARSER_ID = "build-parser-id"; //$NON-NLS-1$
+ private static final String ATTR_CDB_MODIFIED_TIME = "cdb-modified-time"; //$NON-NLS-1$
+ private static final String ATTR_EXCLUDE_FILES = "exclude-files"; //$NON-NLS-1$
+
+ private IFile fCdbFile;
+ private IFile fSourceFile;
+ private IFile fSourceFile2;
+ private IFile fOutsideCdbSourceFile;
+ private IProject fProject;
+ private IFolder fFolder;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ joingLanguageSettingsJobs();
+ } catch (Exception e) {
+ // ignore
+ }
+ super.tearDown();
+ }
+
+ private void createTestProject() throws Exception {
+ createTestProject(true, true, true, true, true);
+ }
+
+ private void createTestProject(boolean useAbsoluteSourcePath, boolean haveCommandDir, boolean validCommandDir,
+ boolean haveCommandLine, boolean validCommandLine) throws Exception {
+ fProject = ResourceHelper.createCDTProjectWithConfig(getName());
+ fFolder = ResourceHelper.createFolder(fProject, "folder");
+
+ IFile sourceFile = fFolder.getFile("test.cpp");
+ if (sourceFile.exists()) {
+ sourceFile.delete(true, null);
+ }
+
+ IFile sourceFile2 = fProject.getFile("test.cpp");
+ if (sourceFile2.exists()) {
+ sourceFile2.delete(true, null);
+ }
+
+ fSourceFile = ResourceHelper.createFile(sourceFile, "//comment");
+ fSourceFile2 = ResourceHelper.createFile(sourceFile2, "//comment2");
+
+ IFile outsideSourceFile = fFolder.getFile("outside.cpp");
+ if (outsideSourceFile.exists()) {
+ outsideSourceFile.delete(true, null);
+ }
+ fOutsideCdbSourceFile = ResourceHelper.createFile(outsideSourceFile, "//comment");
+
+ IFile file = fProject.getFile("compile_commands.json");
+ if (file.exists()) {
+ file.delete(true, null);
+ }
+
+ // Command for proj/folder/test.cpp
+ CompileCommand command = new CompileCommand();
+ if (haveCommandDir) {
+ if (validCommandDir)
+ command.directory = fSourceFile.getParent().getLocation().toOSString();
+ else
+ command.directory = "foo";
+ }
+ String sourceFilePath = fSourceFile.getLocation().toOSString();
+ if (!useAbsoluteSourcePath) {
+ sourceFilePath = fSourceFile.getLocation().makeRelativeTo(fSourceFile.getParent().getLocation())
+ .toOSString();
+ }
+ command.file = sourceFilePath;
+ if (haveCommandLine) {
+ if (validCommandLine)
+ command.command = "g++ -I" + fFolder.getLocation().toOSString() + " -DFOO=2 " + sourceFilePath;
+ else
+ command.command = "foo";
+ }
+
+ // Command for proj/test.cpp
+ CompileCommand command2 = new CompileCommand();
+ if (haveCommandDir) {
+ if (validCommandDir)
+ command2.directory = fSourceFile2.getParent().getLocation().toOSString();
+ else
+ command2.directory = "foo";
+ }
+ String sourceFilePath2 = fSourceFile2.getLocation().toOSString();
+ if (!useAbsoluteSourcePath) {
+ sourceFilePath2 = fSourceFile2.getLocation().makeRelativeTo(fSourceFile2.getParent().getLocation())
+ .toOSString();
+ }
+ command2.file = sourceFilePath2;
+ if (haveCommandLine) {
+ if (validCommandLine)
+ command2.command = "g++ -I" + fFolder.getLocation().toOSString() + " -DFOO=3 " + sourceFilePath2;
+ else
+ command2.command = "foo";
+ }
+
+ CompileCommand[] commands = new CompileCommand[2];
+ commands[0] = command;
+ commands[1] = command2;
+
+ String json = new Gson().toJson(commands);
+ fCdbFile = ResourceHelper.createFile(file, json);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+ GCCBuildCommandParser buildCommandParser = (GCCBuildCommandParser) LanguageSettingsManager
+ .getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
+ assertTrue(cfgDescription instanceof ILanguageSettingsProvidersKeeper);
+ List<ILanguageSettingsProvider> providers = new ArrayList<>();
+ providers.add(buildCommandParser);
+ ((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(providers);
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ }
+
+ private void joingLanguageSettingsJobs() throws InterruptedException {
+ Job.getJobManager().join(CompilationDatabaseParser.JOB_FAMILY_COMPILATION_DATABASE_PARSER, null);
+ Job.getJobManager().join(AbstractBuildCommandParser.JOB_FAMILY_BUILD_COMMAND_PARSER, null);
+ Job.getJobManager().join(LanguageSettingsProvidersSerializer.JOB_FAMILY_SERIALIZE_LANGUAGE_SETTINGS_PROJECT,
+ null);
+ Job.getJobManager().join(LanguageSettingsProvidersSerializer.JOB_FAMILY_SERIALIZE_LANGUAGE_SETTINGS_WORKSPACE,
+ null);
+ }
+
+ /**
+ * Helper method to fetch a configuration description.
+ */
+ private ICConfigurationDescription getConfigurationDescription(IProject project, boolean writable) {
+ CoreModel coreModel = CoreModel.getDefault();
+ ICProjectDescriptionManager mngr = coreModel.getProjectDescriptionManager();
+ // project description
+ ICProjectDescription projectDescription = mngr.getProjectDescription(project, writable);
+ assertNotNull(projectDescription);
+ assertEquals(1, projectDescription.getConfigurations().length);
+ // configuration description
+ ICConfigurationDescription[] cfgDescriptions = projectDescription.getConfigurations();
+ return cfgDescriptions[0];
+ }
+
+ private void addLanguageSettingsProvider(ILanguageSettingsProvider provider) throws CoreException {
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+ List<ILanguageSettingsProvider> providers = new ArrayList<>(
+ ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders());
+ providers.add(provider);
+ ((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(providers);
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ }
+
+ private CompilationDatabaseParser getCompilationDatabaseParser() throws CoreException {
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, false);
+ List<ILanguageSettingsProvider> settingProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription)
+ .getLanguageSettingProviders();
+ for (ILanguageSettingsProvider languageSettingsProvider : settingProviders) {
+ if (languageSettingsProvider instanceof CompilationDatabaseParser) {
+ return (CompilationDatabaseParser) languageSettingsProvider;
+ }
+ }
+
+ return null;
+ }
+
+ private void assertExpectedEntries(CompilationDatabaseParser parser) {
+ assertFalse(parser.isEmpty());
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID);
+
+ CIncludePathEntry expected = new CIncludePathEntry("/${ProjName}/folder",
+ CIncludePathEntry.VALUE_WORKSPACE_PATH);
+ 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);
+
+ assertEquals(new CMacroEntry("FOO", "2", 0), entries.get(1));
+
+ entries = parser.getSettingEntries(resCfgDescription, fSourceFile2, GPPLanguage.ID);
+
+ 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);
+
+ assertEquals(new CMacroEntry("FOO", "3", 0), entries.get(1));
+ }
+
+ public void testParseCDB_WritableConfigDesc() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertExpectedEntries(parser);
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_ReadonlyConfigDesc() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, false);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ // processCompileCommandsFile restarts itself in a WorkspaceJob with a writable config desc so we have to wait for the job.
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertExpectedEntries(getCompilationDatabaseParser());
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_WithExclusions() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ assertExpectedEntries(parser);
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertTrue(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_ReadonlyConfigDescWithExclusions() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, false);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ // processCompileCommandsFile restarts itself in a WorkspaceJob with a writable config desc so we have to wait for the job.
+ joingLanguageSettingsJobs();
+
+ assertExpectedEntries(getCompilationDatabaseParser());
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertTrue(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_NoBuildCommandParser() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_InvalidBuildCommandParser() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT + "foo");
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_NonExistantCDB() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(new Path("/testParseCDB_NonExistantCDB"));
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_EmptyCDBPath() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(new Path(""));
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_DirectoryCDBPath() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getParent().getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_InvalidJson() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ //Make the Json invalid
+ String cdbOsString = fCdbFile.getLocation().toOSString();
+ Files.write(Paths.get(cdbOsString), new byte[] { 'f', 'o', 'o' });
+ try (FileReader reader = new FileReader(cdbOsString)) {
+ Gson gson = new Gson();
+ CompileCommand[] compileCommands = gson.fromJson(reader, CompileCommand[].class);
+ assertTrue("Json should have been invalid and thrown an JsonSyntaxException", false);
+ } catch (JsonSyntaxException e) {
+
+ } catch (Exception e) {
+ assertTrue("Json should have been invalid and thrown an JsonSyntaxException", false);
+ }
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ parser.setExcludeFiles(true);
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ assertThrows(CoreException.class, () -> parser.processCompileCommandsFile(null, cfgDescription));
+
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ CompilationDatabaseParser resultParser = getCompilationDatabaseParser();
+ assertTrue(resultParser.isEmpty());
+ List<ICLanguageSettingEntry> entries = resultParser.getSettingEntries(resCfgDescription, fSourceFile,
+ GPPLanguage.ID);
+ assertTrue(entries == null);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_RelativePaths() throws Exception {
+ createTestProject(false, true, true, true, true);
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ assertExpectedEntries(parser);
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_InvalidCommandDir() throws Exception {
+ createTestProject(true, true, false, true, true);
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(resCfgDescription, fSourceFile2,
+ GPPLanguage.ID);
+
+ // Since the directory could not be used as working dir, both files CDB entries will match
+ // the same source file and only the last one will be recorder in language setting entries.
+ CIncludePathEntry expected = new CIncludePathEntry("/${ProjName}/folder",
+ CIncludePathEntry.VALUE_WORKSPACE_PATH);
+ 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);
+
+ assertEquals(new CMacroEntry("FOO", "3", 0), entries.get(1));
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_NoCommandDir() throws Exception {
+ createTestProject(true, false, true, true, true);
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(resCfgDescription, fSourceFile2,
+ GPPLanguage.ID);
+
+ // Since the directory could not be used as working dir, both files CDB entries will match
+ // the same source file and only the last one will be recorder in language setting entries.
+ CIncludePathEntry expected = new CIncludePathEntry("/${ProjName}/folder",
+ CIncludePathEntry.VALUE_WORKSPACE_PATH);
+ 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);
+
+ assertEquals(new CMacroEntry("FOO", "3", 0), entries.get(1));
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_InvalidCommandLine() throws Exception {
+ createTestProject(true, true, true, true, false);
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertNull(parser.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID));
+ assertNull(parser.getSettingEntries(resCfgDescription, fSourceFile2, GPPLanguage.ID));
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testParseCDB_NoCommandLine() throws Exception {
+ createTestProject(true, true, true, false, true);
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertNull(parser.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID));
+ assertNull(parser.getSettingEntries(resCfgDescription, fSourceFile2, GPPLanguage.ID));
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+ }
+
+ public void testClear() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+
+ parser.clear();
+ assertTrue(parser.isEmpty());
+ assertEquals(parser.getProperty(ATTR_CDB_MODIFIED_TIME), "");
+ }
+
+ public void testCloneShallow() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+
+ CompilationDatabaseParser clonedShallow = parser.cloneShallow();
+ assertEquals(clonedShallow.getProperty(ATTR_CDB_PATH), parser.getProperty(ATTR_CDB_PATH));
+ assertEquals(clonedShallow.getProperty(ATTR_BUILD_PARSER_ID), parser.getProperty(ATTR_BUILD_PARSER_ID));
+ assertEquals(clonedShallow.getProperty(ATTR_EXCLUDE_FILES), parser.getProperty(ATTR_EXCLUDE_FILES));
+ assertEquals(clonedShallow.getProperty(ATTR_CDB_MODIFIED_TIME), "");
+ }
+
+ public void testClone() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID);
+ assertExpectedEntries(parser);
+
+ CompilationDatabaseParser cloned = parser.clone();
+ entries = cloned.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID);
+ assertExpectedEntries(cloned);
+ assertEquals(cloned.getProperty(ATTR_CDB_MODIFIED_TIME), parser.getProperty(ATTR_CDB_MODIFIED_TIME));
+ }
+
+ public void testParseCDB_testUpdateWithModifiedCDB() throws Exception {
+ createTestProject();
+
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(fProject);
+ ICElement ce = CCorePlugin.getDefault().getCoreModel().create(fOutsideCdbSourceFile.getFullPath());
+ ITranslationUnit tu = (ITranslationUnit) ce;
+ assertFalse(
+ CDataUtil.isExcluded(tu.getPath(), getConfigurationDescription(fProject, false).getSourceEntries()));
+
+ CompilationDatabaseParser parser = (CompilationDatabaseParser) LanguageSettingsManager
+ .getExtensionProviderCopy(COMPILATION_DATABASE_PARSER_EXT, true);
+ assertTrue(parser.isEmpty());
+ parser.setBuildParserId(GCC_BUILD_COMMAND_PARSER_EXT);
+ parser.setCompilationDataBasePath(fCdbFile.getLocation());
+ addLanguageSettingsProvider(parser);
+
+ ICConfigurationDescription cfgDescription = getConfigurationDescription(fProject, true);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ ICConfigurationDescription resCfgDescription = getConfigurationDescription(fProject, false);
+ assertExpectedEntries(parser);
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+
+ // Modify the CDB, only to contain one file with different macro definition.
+ String sourceFilePath = fSourceFile.getLocation().toOSString();
+ CompileCommand command = new CompileCommand();
+ command.directory = fSourceFile.getParent().getLocation().toOSString();
+ command.file = sourceFilePath;
+ command.command = "g++ -I" + fFolder.getLocation().toOSString() + " -DFOO=200 " + sourceFilePath;
+ CompileCommand[] commands = new CompileCommand[1];
+ commands[0] = command;
+ String json = new Gson().toJson(commands);
+ InputStream inputStream = new ByteArrayInputStream(json.getBytes());
+ // Make sure the timestamp is different, in case the code runs fast and
+ // in case the system doesn't support milliseconds granularity.
+ while (fCdbFile.getLocalTimeStamp() / 1000 == System.currentTimeMillis() / 1000) {
+ Thread.sleep(5);
+ }
+ fCdbFile.setContents(inputStream, IFile.FORCE, null);
+
+ parser.processCompileCommandsFile(null, cfgDescription);
+ assertFalse(parser.isEmpty());
+ CoreModel.getDefault().setProjectDescription(cfgDescription.getProjectDescription().getProject(),
+ cfgDescription.getProjectDescription());
+ joingLanguageSettingsJobs();
+
+ resCfgDescription = getConfigurationDescription(fProject, false);
+
+ assertFalse(CDataUtil.isExcluded(tu.getPath(), resCfgDescription.getSourceEntries()));
+
+ assertFalse(parser.isEmpty());
+ List<ICLanguageSettingEntry> entries = parser.getSettingEntries(resCfgDescription, fSourceFile, GPPLanguage.ID);
+
+ CIncludePathEntry expected = new CIncludePathEntry("/${ProjName}/folder",
+ CIncludePathEntry.VALUE_WORKSPACE_PATH);
+ 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);
+
+ assertEquals(new CMacroEntry("FOO", "200", 0), entries.get(1));
+
+ entries = parser.getSettingEntries(resCfgDescription, fSourceFile2, GPPLanguage.ID);
+ assertNull(entries);
+ }
+}
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 12509538aa..7557234565 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
@@ -17,7 +17,7 @@ Export-Package: org.eclipse.cdt.build.core.scannerconfig,
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.language.settings.providers;x-friends:="org.eclipse.cdt.managedbuilder.ui",
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,
@@ -41,5 +41,6 @@ Require-Bundle: org.eclipse.cdt.core;bundle-version="[5.0.0,7.0.0)",
org.eclipse.core.filesystem;bundle-version="1.2.0"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: com.ibm.icu.text
+Import-Package: com.google.gson;version="2.8.0",
+ com.ibm.icu.text
Automatic-Module-Name: org.eclipse.cdt.managedbuilder.core
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.properties b/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
index 5112695a91..4c0da31292 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
@@ -84,6 +84,7 @@ GCCBuildOutputParser.name = CDT GCC Build Output Parser
GCCBuiltinCompilerSettings.name = CDT GCC Built-in Compiler Settings
GCCBuiltinCompilerSettingsMinGW.name = CDT GCC Built-in Compiler Settings MinGW
GCCBuiltinCompilerSettingsCygwin.name = CDT GCC Built-in Compiler Settings Cygwin
+CompilationDatabaseParser.name = Compilation Database Parser
ManagedBuildSettingEntries.name = CDT Managed Build Setting Entries
extension.name.8 = C/C++ Scanner Discovery Problem
extension.name.9 = HeadlessBuilder Additional Settings \ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
index 8a3c70c496..a9ebd32a79 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
@@ -645,6 +645,12 @@
parameter="(g?cc)|([gc]\+\+)|(clang)"
prefer-non-shared="true">
</provider>
+ <provider
+ class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompilationDatabaseParser"
+ id="org.eclipse.cdt.managedbuilder.core.CompilationDatabaseParser"
+ name="%CompilationDatabaseParser.name"
+ prefer-non-shared="true">
+ </provider>
</extension>
<extension
id="scanner.discovery.problem"
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
new file mode 100644
index 0000000000..e8c1e8a4a1
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Marc-Andre Laperle.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.language.settings.providers;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.language.settings.providers.ICListenerAgent;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider;
+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.LanguageSettingsSerializableProvider;
+import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsStorage;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICElementVisitor;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+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.ICSourceEntry;
+import org.eclipse.cdt.core.settings.model.util.CDataUtil;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.AbstractBuildCommandParser;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceProxy;
+import org.eclipse.core.resources.IResourceProxyVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+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.Path;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+
+import com.google.gson.Gson;
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * This language settings provider takes a compile_commands.json file as input (aka, Compilation Database or CDB) and parses the commands
+ * with a chosen build command parser. The command parser can be any implementation of AbstractBuildCommandParser like GCCBuildCommandParser,
+ * MSVCBuildCommandParser, etc.
+ *
+ * The file json file is re-parsed at startup through {@link #registerListener(ICConfigurationDescription)} but only if the timestamp changed.
+ * It it also parsed when the options are modified in the UI through {@link #processCompileCommandsFile(IProgressMonitor, ICConfigurationDescription)}
+ */
+public class CompilationDatabaseParser extends LanguageSettingsSerializableProvider
+ implements ICListenerAgent, ILanguageSettingsEditableProvider {
+
+ public static final String JOB_FAMILY_COMPILATION_DATABASE_PARSER = "org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompilationDatabaseParser"; //$NON-NLS-1$
+
+ private static final String ATTR_CDB_PATH = "cdb-path"; //$NON-NLS-1$
+ private static final String ATTR_BUILD_PARSER_ID = "build-parser-id"; //$NON-NLS-1$
+ private static final String ATTR_CDB_MODIFIED_TIME = "cdb-modified-time"; //$NON-NLS-1$
+ private static final String ATTR_EXCLUDE_FILES = "exclude-files"; //$NON-NLS-1$
+
+ public IPath getCompilationDataBasePath() {
+ return Path.fromOSString(getProperty(ATTR_CDB_PATH));
+ }
+
+ public void setCompilationDataBasePath(IPath compilationDataBasePath) {
+ setProperty(ATTR_CDB_PATH, compilationDataBasePath.toOSString());
+ }
+
+ public void setExcludeFiles(boolean selection) {
+ setPropertyBool(ATTR_EXCLUDE_FILES, selection);
+ }
+
+ public boolean getExcludeFiles() {
+ return getPropertyBool(ATTR_EXCLUDE_FILES);
+ }
+
+ public void setBuildParserId(String parserId) {
+ setProperty(ATTR_BUILD_PARSER_ID, parserId);
+ }
+
+ public String getBuildParserId() {
+ return getProperty(ATTR_BUILD_PARSER_ID);
+ }
+
+ public Long getCDBModifiedTime(String cdbPath) throws IOException {
+ FileTime lastModifiedTime = Files.getLastModifiedTime(Paths.get(cdbPath));
+ return lastModifiedTime.toMillis();
+ }
+
+ // Wanted to use this as a base to also count the number of translation unit
+ // for the progress monitor but it's too slow so only use it to exclude for now.
+ private abstract class SourceFilesVisitor implements ICElementVisitor {
+ @Override
+ public boolean visit(ICElement element) throws CoreException {
+ int elementType = element.getElementType();
+ if (elementType != ICElement.C_UNIT) {
+ return elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT;
+ }
+
+ ITranslationUnit tu = (ITranslationUnit) element;
+ if (tu.isSourceUnit()) {
+ handleTranslationUnit(tu);
+ }
+ return false;
+ }
+
+ abstract void handleTranslationUnit(ITranslationUnit tu) throws CoreException;
+ }
+
+ private final class ExcludeSourceFilesVisitor extends SourceFilesVisitor {
+ private final ICConfigurationDescription cfgDescription;
+ ICSourceEntry[] entries = null;
+ private final IProgressMonitor monitor;
+ private final int sourceFilesCount;
+ private int nbChecked = 0;
+
+ //Note: monitor already has ticks allocated for number of source files (not considering exclusions though)
+ private ExcludeSourceFilesVisitor(IProgressMonitor monitor, int sourceFilesCount,
+ ICConfigurationDescription cfgDescription) {
+ this.monitor = monitor;
+ this.sourceFilesCount = sourceFilesCount;
+ this.cfgDescription = cfgDescription;
+ }
+
+ public ICSourceEntry[] getSourceEntries() {
+ return entries;
+ }
+
+ @Override
+ void handleTranslationUnit(ITranslationUnit tu) throws CoreException {
+ boolean isExcluded = CDataUtil.isExcluded(tu.getPath(), cfgDescription.getSourceEntries());
+ if (!isExcluded) {
+ List<ICLanguageSettingEntry> list = getSettingEntries(cfgDescription, tu.getResource(),
+ tu.getLanguage().getId());
+ if (list == null) {
+ if (entries == null) {
+ entries = cfgDescription.getSourceEntries();
+ }
+ entries = CDataUtil.setExcluded(tu.getResource().getFullPath(), false, true, entries);
+ }
+ }
+ monitor.worked(1);
+ if (nbChecked % 100 == 0) {
+ monitor.subTask(String.format(Messages.CompilationDatabaseParser_ProgressExcludingFiles, nbChecked,
+ sourceFilesCount));
+ }
+ nbChecked++;
+ }
+ }
+
+ private static class CDBWorkingDirectoryTracker implements IWorkingDirectoryTracker {
+ URI currentDirectory = null;
+
+ @Override
+ public URI getWorkingDirectoryURI() {
+ return currentDirectory;
+ }
+
+ public void setCurrentDirectory(URI currentDirectory) {
+ this.currentDirectory = currentDirectory;
+ }
+ }
+
+ @Override
+ public void registerListener(ICConfigurationDescription cfgDescription) {
+ unregisterListener();
+ try {
+ processCompileCommandsFile(null, cfgDescription);
+ } catch (CoreException e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ }
+
+ @Override
+ public void unregisterListener() {
+ }
+
+ /**
+ * Processes the compilation database based on the attributes previously set.
+ * Parses the commands and sets the language setting entries. If cfgDescription is a writable configuration, it is assumed that the caller will call
+ * CoreModel#setProjectDescription. Otherwise if cfgDescription is read-only, the method will restart itself with a writable configuration description and call CoreModel#setProjectDescription.
+ */
+ public boolean processCompileCommandsFile(IProgressMonitor monitor, ICConfigurationDescription cfgDescription)
+ throws CoreException {
+ if (cfgDescription.isReadOnly()) {
+ scheduleOnWritableCfgDescription(cfgDescription);
+ return false;
+ }
+
+ if (getCompilationDataBasePath().isEmpty()) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_CDBNotConfigured));
+ }
+
+ if (!Files.exists(Paths.get(getCompilationDataBasePath().toOSString()))) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, MessageFormat.format(
+ Messages.CompilationDatabaseParser_CDBNotFound, getCompilationDataBasePath().toOSString())));
+ }
+
+ try {
+ if (!getProperty(ATTR_CDB_MODIFIED_TIME).isEmpty() && getProperty(ATTR_CDB_MODIFIED_TIME)
+ .equals(getCDBModifiedTime(getCompilationDataBasePath().toOSString()).toString())) {
+ return false;
+ }
+ } catch (IOException e) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_ErrorProcessingCompilationDatabase, e));
+ }
+
+ if (getBuildParserId().isEmpty()) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ MessageFormat.format(Messages.CompilationDatabaseParser_BuildCommandParserNotConfigured,
+ getCompilationDataBasePath().toOSString())));
+ }
+
+ if (!isEmpty()) {
+ clear();
+ }
+ String cdbPath = getCompilationDataBasePath().toOSString();
+ Long cdbModifiedTime;
+ try {
+ cdbModifiedTime = getCDBModifiedTime(cdbPath);
+ } catch (Exception e) {
+ //setProperty(ATTR_CDB_MODIFIED_TIME, Long.toString(0L));
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_ErrorProcessingCompilationDatabase, e));
+ }
+
+ int totalTicks = getExcludeFiles() ? 100 : 60;
+ SubMonitor subMonitor = SubMonitor.convert(monitor, totalTicks);
+ subMonitor.subTask(Messages.CompilationDatabaseParser_ProgressParsingJSONFile);
+ subMonitor.split(5);
+
+ CompileCommand[] compileCommands = null;
+ try (FileReader reader = new FileReader(cdbPath)) {
+ Gson gson = new Gson();
+ compileCommands = gson.fromJson(reader, CompileCommand[].class);
+ } catch (Exception e) {
+ //setProperty(ATTR_CDB_MODIFIED_TIME, Long.toString(0L));
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_ErrorProcessingCompilationDatabase, e));
+ }
+
+ AbstractBuildCommandParser outputParser;
+ try {
+ outputParser = getBuildCommandParser(cfgDescription, getBuildParserId());
+ } catch (Exception e) {
+ //setProperty(ATTR_CDB_MODIFIED_TIME, Long.toString(0L));
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_ErrorProcessingCompilationDatabase, e));
+ }
+
+ CDBWorkingDirectoryTracker workingDirectoryTracker = new CDBWorkingDirectoryTracker();
+
+ SubMonitor parseCmdsMonitor = SubMonitor.convert(subMonitor.split(50), compileCommands.length);
+ outputParser.startup(cfgDescription, workingDirectoryTracker);
+ for (int i = 0; i < compileCommands.length; i++) {
+ CompileCommand c = compileCommands[i];
+ // Don't spam the progress view too much
+ if (i % 100 == 0) {
+ parseCmdsMonitor.subTask(String.format(Messages.CompilationDatabaseParser_ProgressParsingBuildCommands,
+ i, compileCommands.length));
+ }
+ String dir = c.getDirectory();
+ workingDirectoryTracker.setCurrentDirectory(null);
+ if (dir != null) {
+ File file = new File(dir);
+ if (file.exists()) {
+ workingDirectoryTracker.setCurrentDirectory(file.toURI());
+ }
+ }
+
+ outputParser.processLine(c.getCommand());
+ parseCmdsMonitor.worked(1);
+ }
+ LanguageSettingsStorage storage = outputParser.copyStorage();
+ SubMonitor entriesMonitor = SubMonitor.convert(subMonitor.split(5), storage.getLanguages().size());
+ entriesMonitor.subTask(Messages.CompilationDatabaseParser_ProgressApplyingEntries);
+ for (String language : storage.getLanguages()) {
+ SubMonitor langMonitor = entriesMonitor.split(1);
+ Set<String> resourcePaths = storage.getResourcePaths(language);
+ SubMonitor langEntriesMonitor = SubMonitor.convert(langMonitor, resourcePaths.size());
+ for (String resourcePath : resourcePaths) {
+ IFile file = cfgDescription.getProjectDescription().getProject().getFile(new Path(resourcePath));
+ if (file.exists()) {
+ List<ICLanguageSettingEntry> settingEntries = storage.getSettingEntries(resourcePath, language);
+ setSettingEntries(cfgDescription, file, language, settingEntries);
+ }
+ langEntriesMonitor.worked(1);
+ }
+ }
+
+ if (getExcludeFiles()) {
+ excludeFiles(cfgDescription, subMonitor);
+ }
+
+ setProperty(ATTR_CDB_MODIFIED_TIME, cdbModifiedTime.toString());
+ touchProjectDes(cfgDescription.getProjectDescription());
+ return true;
+ }
+
+ private void scheduleOnWritableCfgDescription(ICConfigurationDescription cfgDescription) {
+ WorkspaceJob job = new WorkspaceJob(Messages.CompilationDatabaseParser_Job) {
+ @Override
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ // If the config description we have been given is read-only, we need to get a writable one instead in order to be able to set source entries (exclusions).
+ // The tricky thing is that in that situation, the CompilationDatabaseParser instance (this) came from the read-only project description so anything that is
+ // saved that is not stored in the project description (i.e. calls to setProperties) will be saved to the wrong instance so when we call setProjectDescription, our changes will be ignored.
+ // So instead, restart the whole thing with the corresponding CompilationDatabaseParser instance in the writable config.
+ IProject project = cfgDescription.getProjectDescription().getProject();
+ ICProjectDescription projectDescription = CCorePlugin.getDefault().getCoreModel()
+ .getProjectDescription(project.getProject(), true);
+ ICConfigurationDescription writableCfg = projectDescription
+ .getConfigurationById(cfgDescription.getId());
+ if (!(writableCfg instanceof ILanguageSettingsProvidersKeeper)) {
+ return Status.CANCEL_STATUS;
+ }
+
+ CompilationDatabaseParser parser = null;
+ List<ILanguageSettingsProvider> settingProviders = ((ILanguageSettingsProvidersKeeper) writableCfg)
+ .getLanguageSettingProviders();
+ for (ILanguageSettingsProvider languageSettingsProvider : settingProviders) {
+ if (languageSettingsProvider.getId().equals(CompilationDatabaseParser.this.getId())
+ && languageSettingsProvider instanceof CompilationDatabaseParser) {
+ parser = (CompilationDatabaseParser) languageSettingsProvider;
+ break;
+ }
+ }
+
+ if (parser == null) {
+ // Seems very unlikely to get here. This should mean that the provider was disabled before the job ran.
+ return Status.CANCEL_STATUS;
+ }
+
+ try {
+ if (parser.processCompileCommandsFile(monitor, writableCfg)) {
+ CoreModel.getDefault().setProjectDescription(project.getProject(), projectDescription);
+ }
+ } catch (CoreException e) {
+ // If we are running this in a WorkspaceJob it's because the CfgDescription was read-only so we are probably loading the project.
+ // We don't want to pop-up jarring error dialogs on start-up. Ideally, CDT would have problem markers for project setup issues.
+ ManagedBuilderCorePlugin.log(e);
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return family == JOB_FAMILY_COMPILATION_DATABASE_PARSER;
+ }
+ };
+
+ // Using root rule because of call to setProjectDescription above
+ job.setRule(ResourcesPlugin.getWorkspace().getRoot());
+ job.schedule();
+ }
+
+ private void excludeFiles(ICConfigurationDescription cfgDescription, SubMonitor subMonitor) throws CoreException {
+ ICProject cProject = CCorePlugin.getDefault().getCoreModel()
+ .create(cfgDescription.getProjectDescription().getProject());
+ // Getting a approximation of the number of source files we will have to visit based on file names.
+ // Much faster than going through the CElements. Then do the real work and report progress.
+ // It's possible that the approximation will be pretty wrong if there are a lot of already excluded files
+ // then we won't visit them in the ExcludeSourceFilesVisitor and the progress monitor won't be ticked for those.
+ int sourceFilesCount[] = new int[1];
+ cProject.getProject().accept(new IResourceProxyVisitor() {
+ @Override
+ public boolean visit(IResourceProxy proxy) throws CoreException {
+ if (CoreModel.isValidSourceUnitName(cProject.getProject(), proxy.getName()))
+ sourceFilesCount[0]++;
+ return true;
+ }
+ }, IResource.DEPTH_INFINITE, IResource.NONE);
+ SubMonitor sourceMonitor = SubMonitor.convert(subMonitor.split(35), sourceFilesCount[0]);
+
+ ExcludeSourceFilesVisitor sourceFileVisitor = new ExcludeSourceFilesVisitor(sourceMonitor, sourceFilesCount[0],
+ cfgDescription);
+ cProject.accept(sourceFileVisitor);
+ ICSourceEntry[] sourceEntries = sourceFileVisitor.getSourceEntries();
+
+ subMonitor.split(5);
+ if (sourceEntries != null) {
+ cfgDescription.setSourceEntries(sourceEntries);
+ }
+ }
+
+ private void touchProjectDes(ICProjectDescription desc) {
+ // Make sure the project description is marked as modified so that language settings serialization kicks in.
+ // We need to let the setProjectDescription do the serialization because we cannot do it on a writable description
+ // and we need a writable description because we need to call setSourceEntries!
+ final QualifiedName TOUCH_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, "touch-project"); //$NON-NLS-1$
+ desc.setSessionProperty(TOUCH_PROPERTY, ""); //$NON-NLS-1$
+ desc.setSessionProperty(TOUCH_PROPERTY, null);
+ }
+
+ private AbstractBuildCommandParser getBuildCommandParser(ICConfigurationDescription cfgDesc, String id)
+ throws CloneNotSupportedException {
+ ICConfigurationDescription configurationDescription = cfgDesc;
+ if (configurationDescription instanceof ILanguageSettingsProvidersKeeper) {
+ List<ILanguageSettingsProvider> settingProviders = ((ILanguageSettingsProvidersKeeper) configurationDescription)
+ .getLanguageSettingProviders();
+ for (ILanguageSettingsProvider languageSettingsProvider : settingProviders) {
+ if (languageSettingsProvider instanceof AbstractBuildCommandParser
+ && languageSettingsProvider instanceof ILanguageSettingsEditableProvider) {
+ AbstractBuildCommandParser buildParser = (AbstractBuildCommandParser) languageSettingsProvider;
+ if (buildParser.getId().equals(id))
+ return (AbstractBuildCommandParser) ((ILanguageSettingsEditableProvider) buildParser).clone();
+ }
+ }
+ }
+
+ throw new IllegalArgumentException(MessageFormat
+ .format(Messages.CompilationDatabaseParser_BuildCommandParserNotFound, id, cfgDesc.getName()));
+ }
+
+ @Override
+ public boolean isEmpty() {
+ // treat provider that has been executed as not empty
+ // to let "Clear" button to restart the provider
+ return getProperty(ATTR_CDB_MODIFIED_TIME).isEmpty() && super.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ setProperty(ATTR_CDB_MODIFIED_TIME, null);
+ }
+
+ @Override
+ public CompilationDatabaseParser cloneShallow() throws CloneNotSupportedException {
+ CompilationDatabaseParser clone = (CompilationDatabaseParser) super.cloneShallow();
+ clone.setProperty(ATTR_CDB_MODIFIED_TIME, null);
+ return clone;
+ }
+
+ @Override
+ public CompilationDatabaseParser clone() throws CloneNotSupportedException {
+ return (CompilationDatabaseParser) super.clone();
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompileCommand.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompileCommand.java
new file mode 100644
index 0000000000..3675d94dc0
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompileCommand.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2019 QNX Software Systems and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Marc-André Laperle - Moved to managed builder
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.language.settings.providers;
+
+public class CompileCommand {
+
+ public String directory;
+ public String command;
+ public String file;
+
+ public String getDirectory() {
+ return directory;
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+ public String getFile() {
+ return file;
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/Messages.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/Messages.java
new file mode 100644
index 0000000000..1a15eaff8f
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/Messages.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Marc-Andre Laperle.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.language.settings.providers;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.managedbuilder.internal.language.settings.providers.messages"; //$NON-NLS-1$
+
+ public static String CompilationDatabaseParser_BuildCommandParserNotConfigured;
+ public static String CompilationDatabaseParser_BuildCommandParserNotFound;
+ public static String CompilationDatabaseParser_CDBNotConfigured;
+ public static String CompilationDatabaseParser_CDBNotFound;
+ public static String CompilationDatabaseParser_ErrorProcessingCompilationDatabase;
+ public static String CompilationDatabaseParser_Job;
+ public static String CompilationDatabaseParser_ProgressApplyingEntries;
+ public static String CompilationDatabaseParser_ProgressExcludingFiles;
+ public static String CompilationDatabaseParser_ProgressParsingBuildCommands;
+ public static String CompilationDatabaseParser_ProgressParsingJSONFile;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/messages.properties b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/messages.properties
new file mode 100644
index 0000000000..f5b2a80d63
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/messages.properties
@@ -0,0 +1,21 @@
+################################################################################
+# Copyright (c) 2019 Marc-Andre Laperle.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+################################################################################
+
+CompilationDatabaseParser_BuildCommandParserNotConfigured=Compilation database parser does not have a build command parser configured.
+CompilationDatabaseParser_BuildCommandParserNotFound=Could not find '{0}' language settings provider in configuration '{1}'
+CompilationDatabaseParser_CDBNotConfigured=Compilation database (usually compile_commands.json) path not set.
+CompilationDatabaseParser_CDBNotFound=Compilation database (usually compile_commands.json) not found at location {0}.
+CompilationDatabaseParser_ErrorProcessingCompilationDatabase=Error processing compilation database.
+CompilationDatabaseParser_Job=Discover Compilation Database language settings
+CompilationDatabaseParser_ProgressApplyingEntries=Applying language setting entries
+CompilationDatabaseParser_ProgressExcludingFiles=Excluding files not in compilation database. Checking %d/%d (Estimate)
+CompilationDatabaseParser_ProgressParsingBuildCommands=Parsing build commands (%d/%d)
+CompilationDatabaseParser_ProgressParsingJSONFile=Parsing JSON file \ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
index ccd25f1019..f8f7c4b19b 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.ui; singleton:=true
-Bundle-Version: 9.1.300.qualifier
+Bundle-Version: 9.1.400.qualifier
Bundle-Activator: org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
index e9df66e8a4..198bcea804 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
@@ -884,6 +884,13 @@
ui-clear-entries="true"
ui-edit-entries="false">
</class-association>
+ <class-association
+ class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompilationDatabaseParser"
+ icon="icons/obj16/log_obj.gif"
+ page="org.eclipse.cdt.managedbuilder.internal.ui.language.settings.providers.CompilationDatabaseParserOptionPage"
+ ui-clear-entries="true"
+ ui-edit-entries="false">
+ </class-association>
</extension>
<extension
point="org.eclipse.cdt.core.CBuildConsole">
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/CompilationDatabaseParserOptionPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/CompilationDatabaseParserOptionPage.java
new file mode 100644
index 0000000000..391fe05fdc
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/CompilationDatabaseParserOptionPage.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Marc-Andre Laperle.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.language.settings.providers;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
+import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
+import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
+import org.eclipse.cdt.internal.ui.newui.StatusMessageLine;
+import org.eclipse.cdt.managedbuilder.internal.language.settings.providers.CompilationDatabaseParser;
+import org.eclipse.cdt.managedbuilder.language.settings.providers.AbstractBuildCommandParser;
+import org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin;
+import org.eclipse.cdt.ui.language.settings.providers.AbstractLanguageSettingProviderOptionPage;
+import org.eclipse.cdt.utils.ui.controls.ControlFactory;
+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.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Options page for {@link CompilationDatabaseParser}.
+ *
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public final class CompilationDatabaseParserOptionPage extends AbstractLanguageSettingProviderOptionPage {
+ private boolean fEditable;
+ private Text fCompileCommandsPath;
+
+ @SuppressWarnings("restriction")
+ private StatusMessageLine fStatusLine;
+ private Combo fBuildOutputParserCombo;
+
+ @Override
+ public void createControl(Composite parent) {
+ fEditable = parent.isEnabled();
+ CompilationDatabaseParser provider = (CompilationDatabaseParser) getProvider();
+
+ Composite composite = createCompositeForPageArea(parent);
+ createCompileCommandsPathInputControl(composite, provider);
+ createBrowseButton(composite);
+ createOutputParserCombo(composite);
+ createExclusionOptions(composite);
+ createStatusLine(composite, provider);
+
+ setControl(composite);
+ }
+
+ private Composite createCompositeForPageArea(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.marginWidth = 1;
+ layout.marginHeight = 1;
+ layout.marginRight = 1;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Dialog.applyDialogFont(composite);
+
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ composite.setLayoutData(gd);
+ return composite;
+ }
+
+ private void createCompileCommandsPathInputControl(Composite composite, CompilationDatabaseParser provider) {
+ Label label = ControlFactory.createLabel(composite,
+ Messages.CompilationDatabaseParserOptionPage_CompileCommandsPath);
+ GridData gd = new GridData();
+ gd.horizontalSpan = 2;
+ label.setLayoutData(gd);
+ label.setEnabled(fEditable);
+
+ fCompileCommandsPath = ControlFactory.createTextField(composite, SWT.SINGLE | SWT.BORDER);
+ String command = provider.getCompilationDataBasePath().toOSString();
+ fCompileCommandsPath.setText(command != null ? command : ""); //$NON-NLS-1$
+ fCompileCommandsPath.setEnabled(fEditable);
+ fCompileCommandsPath.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ String text = fCompileCommandsPath.getText();
+ CompilationDatabaseParser provider = (CompilationDatabaseParser) getProvider();
+ if (provider.getCompilationDataBasePath() == null
+ || !text.equals(provider.getCompilationDataBasePath().toOSString())) {
+ CompilationDatabaseParser selectedProvider = (CompilationDatabaseParser) getProviderWorkingCopy();
+ selectedProvider.setCompilationDataBasePath(Path.fromOSString(text));
+ refreshItem(selectedProvider);
+ validate();
+ }
+ }
+ });
+ }
+
+ private void createBrowseButton(Composite composite) {
+ Button button = ControlFactory.createPushButton(composite, Messages.CompilationDatabaseParserOptionPage_Browse);
+ button.setEnabled(fEditable);
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent evt) {
+ FileDialog dialog = new FileDialog(getShell(), SWT.NONE);
+ dialog.setText(Messages.CompilationDatabaseParserOptionPage_ChooseFile);
+ String fileName = fCompileCommandsPath.getText();
+ IPath folder = new Path(fileName).removeLastSegments(1);
+ dialog.setFilterPath(folder.toOSString());
+ String chosenFile = dialog.open();
+ if (chosenFile != null) {
+ fCompileCommandsPath.insert(chosenFile);
+ }
+ }
+ });
+ }
+
+ private void createOutputParserCombo(Composite composite) {
+ ICConfigurationDescription configurationDescription = getConfigurationDescription();
+ List<AbstractBuildCommandParser> buildParsers = new ArrayList<>();
+ if (configurationDescription instanceof ILanguageSettingsProvidersKeeper) {
+ List<ILanguageSettingsProvider> settingProviders = ((ILanguageSettingsProvidersKeeper) configurationDescription)
+ .getLanguageSettingProviders();
+ for (ILanguageSettingsProvider languageSettingsProvider : settingProviders) {
+ if (languageSettingsProvider instanceof AbstractBuildCommandParser) {
+ AbstractBuildCommandParser buildParser = (AbstractBuildCommandParser) languageSettingsProvider;
+ buildParsers.add(buildParser);
+ }
+ }
+ }
+
+ Label parserLabel = ControlFactory.createLabel(composite,
+ Messages.CompilationDatabaseParserOptionPage_BuildParser);
+ GridData gd = new GridData(SWT.BEGINNING);
+ gd.horizontalSpan = 2;
+ parserLabel.setLayoutData(gd);
+
+ fBuildOutputParserCombo = new Combo(composite, SWT.READ_ONLY);
+ fBuildOutputParserCombo.setEnabled(fEditable);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ fBuildOutputParserCombo.setLayoutData(gd);
+ if (buildParsers.isEmpty()) {
+ fBuildOutputParserCombo.add(Messages.CompilationDatabaseParserOptionPage_NoBuildOutputParserError);
+ fBuildOutputParserCombo.select(0);
+ fBuildOutputParserCombo.setEnabled(false);
+ // Can't call getProviderWorkingCopy().setBuildParserId() while creating the page since
+ // it will try to replace the selected provider in the table which
+ // doesn't have a proper selection index until one of them is clicked.
+ // Use combo.setData to encode invalid/valid data then set it on the working copy on setVisible(true)/validate.
+ fBuildOutputParserCombo.setData(null);
+ return;
+ }
+
+ for (int i = 0; i < buildParsers.size(); i++) {
+ AbstractBuildCommandParser buildParser = buildParsers.get(i);
+ fBuildOutputParserCombo.add(buildParser.getName());
+ fBuildOutputParserCombo.setData(buildParser.getName(), buildParser);
+ if (buildParser.getId().equals(((CompilationDatabaseParser) getProvider()).getBuildParserId())) {
+ fBuildOutputParserCombo.select(i);
+ fBuildOutputParserCombo.setData(buildParser.getId());
+ }
+ }
+
+ fBuildOutputParserCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ AbstractBuildCommandParser parser = (AbstractBuildCommandParser) fBuildOutputParserCombo
+ .getData(fBuildOutputParserCombo.getText());
+ CompilationDatabaseParser selectedProvider = (CompilationDatabaseParser) getProviderWorkingCopy();
+ String parserId = ""; //$NON-NLS-1$
+ if (parser != null) {
+ parserId = parser.getId();
+ }
+ selectedProvider.setBuildParserId(parserId);
+ fBuildOutputParserCombo.setData(parserId);
+ validate();
+ }
+ });
+
+ }
+
+ private void createExclusionOptions(Composite parent) {
+ Button keepExclusion = new Button(parent, SWT.CHECK);
+ keepExclusion.setText(Messages.CompilationDatabaseParserOptionPage_ExcludeFiles);
+ GridData gd = new GridData(SWT.BEGINNING);
+ gd.horizontalSpan = 2;
+ keepExclusion.setLayoutData(gd);
+
+ keepExclusion.setSelection(((CompilationDatabaseParser) getProvider()).getExcludeFiles());
+ keepExclusion.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ CompilationDatabaseParser selectedProvider = (CompilationDatabaseParser) getProviderWorkingCopy();
+ selectedProvider.setExcludeFiles(keepExclusion.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ }
+
+ @SuppressWarnings("restriction")
+ private void createStatusLine(Composite composite, CompilationDatabaseParser provider) {
+ fStatusLine = new StatusMessageLine(composite, SWT.LEFT, 2);
+ }
+
+ @SuppressWarnings("restriction")
+ @Override
+ public void performApply(IProgressMonitor monitor) throws CoreException {
+ ILanguageSettingsProvider provider = providerTab.getProvider(providerId);
+ if ((provider instanceof CompilationDatabaseParser)) { // basically check for working copy
+ CompilationDatabaseParser compilationDatabaseParser = (CompilationDatabaseParser) provider;
+ ILanguageSettingsProvider initialProvider = providerTab.getInitialProvider(providerId);
+ if (!(initialProvider instanceof CompilationDatabaseParser)
+ || !((CompilationDatabaseParser) initialProvider).getCompilationDataBasePath()
+ .equals(compilationDatabaseParser.getCompilationDataBasePath())
+ || !((CompilationDatabaseParser) initialProvider).getBuildParserId()
+ .equals(compilationDatabaseParser.getBuildParserId())
+ || ((CompilationDatabaseParser) initialProvider).getExcludeFiles() != compilationDatabaseParser
+ .getExcludeFiles()) {
+ compilationDatabaseParser.clear();
+ }
+ if (compilationDatabaseParser.isEmpty()) {
+ compilationDatabaseParser.processCompileCommandsFile(monitor, getConfigurationDescription());
+ }
+ }
+
+ super.performApply(monitor);
+ }
+
+ @SuppressWarnings("restriction")
+ private void validate() {
+ if (fBuildOutputParserCombo.getData() == null) {
+ ((CompilationDatabaseParser) getProviderWorkingCopy()).setBuildParserId(null);
+ }
+
+ CompilationDatabaseParser provider = (CompilationDatabaseParser) getProvider();
+ if (provider.getCompilationDataBasePath() == null || provider.getCompilationDataBasePath().isEmpty()
+ || !Files.exists(Paths.get(provider.getCompilationDataBasePath().toOSString()))) {
+ fStatusLine.setErrorStatus(new Status(IStatus.ERROR, ManagedBuilderUIPlugin.getUniqueIdentifier(),
+ Messages.CompilationDatabaseParserOptionPage_CompileCommandsPathError));
+ return;
+ }
+
+ if (provider.getBuildParserId() == null || provider.getBuildParserId().isEmpty()) {
+ fStatusLine.setErrorStatus(new Status(IStatus.ERROR, ManagedBuilderUIPlugin.getUniqueIdentifier(),
+ Messages.CompilationDatabaseParserOptionPage_BuildOutputParserError));
+ return;
+ }
+
+ fStatusLine.setErrorStatus(Status.OK_STATUS);
+ }
+
+ private ICConfigurationDescription getConfigurationDescription() {
+ if (providerTab.page.isForPrefs()) {
+ return null;
+ }
+
+ return providerTab.getResDesc().getConfiguration().getConfiguration();
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible) {
+ validate();
+ }
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/Messages.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/Messages.java
new file mode 100644
index 0000000000..1b0d061dc9
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/Messages.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Marc-Andre Laperle.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.language.settings.providers;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.managedbuilder.internal.ui.language.settings.providers.messages"; //$NON-NLS-1$
+ public static String CompilationDatabaseParserOptionPage_Browse;
+ public static String CompilationDatabaseParserOptionPage_BuildOutputParserError;
+ public static String CompilationDatabaseParserOptionPage_BuildParser;
+ public static String CompilationDatabaseParserOptionPage_ChooseFile;
+ public static String CompilationDatabaseParserOptionPage_CompileCommandsPath;
+ public static String CompilationDatabaseParserOptionPage_CompileCommandsPathError;
+ public static String CompilationDatabaseParserOptionPage_ExcludeFiles;
+ public static String CompilationDatabaseParserOptionPage_NoBuildOutputParserError;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/messages.properties b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/messages.properties
new file mode 100644
index 0000000000..c9657a7442
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/language/settings/providers/messages.properties
@@ -0,0 +1,19 @@
+################################################################################
+# Copyright (c) 2019 Marc-Andre Laperle.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+################################################################################
+
+CompilationDatabaseParserOptionPage_Browse=Browse...
+CompilationDatabaseParserOptionPage_BuildOutputParserError=Invalid build parser
+CompilationDatabaseParserOptionPage_BuildParser=Build parser:
+CompilationDatabaseParserOptionPage_ChooseFile=Choose File
+CompilationDatabaseParserOptionPage_CompileCommandsPath=Compilation Database path (compile_commands.json):
+CompilationDatabaseParserOptionPage_CompileCommandsPathError=Compilation Database path does not exist
+CompilationDatabaseParserOptionPage_ExcludeFiles=Exclude files not in the Compilation Database
+CompilationDatabaseParserOptionPage_NoBuildOutputParserError=No build output parser enabled in "Providers"
diff --git a/releng/CDT.setup b/releng/CDT.setup
index 9df0b1396f..9430d61d0b 100644
--- a/releng/CDT.setup
+++ b/releng/CDT.setup
@@ -123,6 +123,10 @@
<requirement
name="org.junit.source"/>
<requirement
+ name="org.junit.jupiter.api"/>
+ <requirement
+ name="org.junit.jupiter.api.source"/>
+ <requirement
name="org.mockito"/>
<requirement
name="org.hamcrest"/>
diff --git a/releng/org.eclipse.cdt.target/cdt.target b/releng/org.eclipse.cdt.target/cdt.target
index 3be416a720..c644ae0128 100644
--- a/releng/org.eclipse.cdt.target/cdt.target
+++ b/releng/org.eclipse.cdt.target/cdt.target
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?><?pde version="3.8"?><target name="cdt" sequenceNumber="62">
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><?pde version="3.8"?><target name="cdt" sequenceNumber="63">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="com.google.gson" version="0.0.0"/>
@@ -17,6 +17,8 @@
<unit id="org.hamcrest.core" version="0.0.0"/>
<unit id="org.junit" version="0.0.0"/>
<unit id="org.junit.source" version="0.0.0"/>
+<unit id="org.junit.jupiter.api" version="0.0.0"/>
+<unit id="org.junit.jupiter.api.source" version="0.0.0"/>
<unit id="org.mockito" version="0.0.0"/>
<unit id="org.slf4j.impl.log4j12" version="0.0.0"/>
<repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository/"/>

Back to the top