1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

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>
This commit is contained in:
Marc-Andre Laperle 2019-09-28 00:38:26 -04:00
parent 6bd29843f2
commit 0c577f6e7e
17 changed files with 1850 additions and 4 deletions

View file

@ -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

View file

@ -32,5 +32,6 @@ public class AllLanguageSettingsProvidersMBSTests extends TestSuite {
addTestSuite(GCCBuildCommandParserTest.class);
addTestSuite(BuiltinSpecsDetectorTest.class);
addTestSuite(GCCBuiltinSpecsDetectorTest.class);
addTestSuite(CompilationDatabaseParserTest.class);
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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() {
}
}

View file

@ -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

View file

@ -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

View file

@ -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">

View file

@ -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();
}
}
}

View file

@ -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() {
}
}

View file

@ -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"

View file

@ -122,6 +122,10 @@
name="org.junit"/>
<requirement
name="org.junit.source"/>
<requirement
name="org.junit.jupiter.api"/>
<requirement
name="org.junit.jupiter.api.source"/>
<requirement
name="org.mockito"/>
<requirement

View file

@ -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/"/>