Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java')
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java545
1 files changed, 545 insertions, 0 deletions
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 00000000000..c543ae5a19e
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
@@ -0,0 +1,545 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 Marc-Andre Laperle 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-Andre Laperle - Initial API and implementation
+ * Sergei Kovalchuk (NXP)
+ *******************************************************************************/
+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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
+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;
+
+/**
+ * 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 String getCompilationDataBasePathProperty() {
+ return getProperty(ATTR_CDB_PATH);
+ }
+
+ /**
+ * Resolve the compilation database path property by expanding variables (if any) and check that the file exists and is readable.
+ *
+ * @param cfgDescription the configuration description used to resolved variables that depend on it
+ * @return the resolved, readable path of the compilation database
+ * @throws CoreException On failure to resolve variables or non readable path
+ */
+ public String resolveCompilationDataBasePath(ICConfigurationDescription cfgDescription) throws CoreException {
+ ICdtVariableManager varManager = CCorePlugin.getDefault().getCdtVariableManager();
+ String compilationDataBasePath = varManager.resolveValue(getCompilationDataBasePathProperty(), "", null, //$NON-NLS-1$
+ cfgDescription);
+
+ if (Files.isDirectory(Paths.get(compilationDataBasePath))
+ || !Files.isReadable(Paths.get(compilationDataBasePath)))
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, MessageFormat
+ .format(Messages.CompilationDatabaseParser_CDBNotFound, getCompilationDataBasePathProperty())));
+
+ return compilationDataBasePath;
+ }
+
+ public void setCompilationDataBasePathProperty(String compilationDataBasePathProperty) {
+ setProperty(ATTR_CDB_PATH, compilationDataBasePathProperty);
+ }
+
+ 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();
+ }
+
+ /**
+ * Visit all folders and exclude all files that do not have entries coming from the CDB.
+ * The algorithm detects when whole folders can be excluded to prevent a large number of
+ * individual file exclusions.
+ */
+ private final class ExcludeSourceFilesVisitor implements ICElementVisitor {
+ private final ICConfigurationDescription cfgDescription;
+ ICSourceEntry[] entries = null;
+ private final IProgressMonitor monitor;
+ private final int sourceFilesCount;
+ private int nbChecked = 0;
+
+ // Keep track of excluded files and folders as we visit each folder in a depth-first manner.
+ private Stack<FolderExclusionInfo> folderExclusionInfos = new Stack<>();
+
+ private class FolderExclusionInfo {
+ // In case not all files are excluded in this folder, we need to keep track of which folders we'll exclude individually.
+ private ArrayList<IPath> childrenFoldersWithAllFilesExcluded = new ArrayList<>();
+ // In case not all files are excluded in this folder, we need to keep track of which files we'll exclude individually.
+ private ArrayList<IPath> excludedSourceFiles = new ArrayList<>();
+ // True if all children of the folder are excluded, recursively.
+ // Children folders can set this to false on their parent when non-excluded files are detected.
+ // Therefore, this value is reliable only when all children are visited.
+ private boolean allFilesExcluded = true;
+ }
+
+ //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;
+ this.entries = cfgDescription.getSourceEntries();
+ }
+
+ public ICSourceEntry[] getSourceEntries() {
+ return entries;
+ }
+
+ @Override
+ public boolean visit(ICElement element) throws CoreException {
+ int elementType = element.getElementType();
+ if (elementType != ICElement.C_UNIT) {
+ boolean isSourceContainer = elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT;
+ if (isSourceContainer) {
+ folderExclusionInfos.push(new FolderExclusionInfo());
+ }
+ return isSourceContainer;
+ }
+
+ ITranslationUnit tu = (ITranslationUnit) element;
+ if (tu.isSourceUnit()) {
+ handleTranslationUnit(tu);
+ }
+ return false;
+ }
+
+ private void handleTranslationUnit(ITranslationUnit tu) throws CoreException {
+ FolderExclusionInfo folderInfo = folderExclusionInfos.peek();
+ List<ICLanguageSettingEntry> list = getSettingEntries(cfgDescription, tu.getResource(),
+ tu.getLanguage().getId());
+ if (list == null) {
+ folderInfo.excludedSourceFiles.add(tu.getResource().getFullPath());
+ } else {
+ folderInfo.allFilesExcluded = false;
+ }
+
+ monitor.worked(1);
+ if (nbChecked % 100 == 0) {
+ monitor.subTask(String.format(Messages.CompilationDatabaseParser_ProgressExcludingFiles, nbChecked,
+ sourceFilesCount));
+ }
+ nbChecked++;
+ }
+
+ @Override
+ public void leave(ICElement element) throws CoreException {
+ int elementType = element.getElementType();
+ if (elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT) {
+
+ FolderExclusionInfo folderInfo = folderExclusionInfos.pop();
+
+ if (folderInfo.allFilesExcluded && !folderExclusionInfos.isEmpty()) {
+ // Consider this folder for exclusion later, maybe the parent will also be excluded
+ folderExclusionInfos.peek().childrenFoldersWithAllFilesExcluded.add(element.getPath());
+ } else {
+ if (!folderExclusionInfos.isEmpty()) {
+ folderExclusionInfos.peek().allFilesExcluded = false;
+ }
+
+ // Exclude all children folders previously considered for exclusion, since the parent
+ // (the currently visited element) cannot be excluded, we have to exclude them individually.
+ for (IPath excludedFolder : folderInfo.childrenFoldersWithAllFilesExcluded) {
+ entries = CDataUtil.setExcluded(excludedFolder, true, true, entries);
+ }
+
+ // Exclude all direct children files that need to be excluded.
+ for (IPath excludedFile : folderInfo.excludedSourceFiles) {
+ entries = CDataUtil.setExcluded(excludedFile, false, true, entries);
+ }
+ }
+ }
+ }
+ }
+
+ 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 (!cfgDescription.equals(cfgDescription.getProjectDescription().getDefaultSettingConfiguration()))
+ return false;
+
+ if (getCompilationDataBasePathProperty().isEmpty()) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_CDBNotConfigured));
+ }
+
+ String cdbPath = resolveCompilationDataBasePath(cfgDescription);
+
+ try {
+ if (!getProperty(ATTR_CDB_MODIFIED_TIME).isEmpty()
+ && getProperty(ATTR_CDB_MODIFIED_TIME).equals(getCDBModifiedTime(cdbPath).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, cdbPath)));
+ }
+
+ if (!isEmpty()) {
+ clear();
+ }
+ 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));
+ }
+
+ if (compileCommands == null) {
+ throw new CoreException(new Status(Status.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
+ Messages.CompilationDatabaseParser_ErrorProcessingCompilationDatabase,
+ new NullPointerException(Messages.CompilationDatabaseParser_StillNull)));
+ }
+
+ 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());
+ }
+ }
+
+ String command = c.getCommand();
+ if (command != null) {
+ outputParser.processLine(command);
+ } else if (c.getArguments() != null) {
+ outputParser.processLine(String.join(" ", c.getArguments())); //$NON-NLS-1$
+ }
+ 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();
+ if (!project.isAccessible()) {
+ // Project was probably closed while the job was waiting to start.
+ return Status.CANCEL_STATUS;
+ }
+
+ 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();
+ }
+}

Back to the top