1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-01 21:35:40 +02:00

Bug 559674: Migrating from a ILanguageSettingsProvider implementation to IIndexerInfoConsumer (2)

This is piece two of change https://git.eclipse.org/r/c/159828 being split into pieces.
Splitting is done for code reviewing reasons.

Change-Id: I9db46388046c57f2aaad88730636950d3271ae20
Signed-off-by: Martin Weber <fifteenknots505@gmail.com>
This commit is contained in:
Martin Weber 2020-05-06 21:48:28 +02:00 committed by Alexander Fedorov
parent c0ffeb6474
commit 9bf029721a
10 changed files with 276 additions and 541 deletions

View file

@ -13,6 +13,7 @@ import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
@ -37,7 +38,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor {
new OutputLineProcessor(" *(\\S.*)", 1, -1, true, 0) };
@SuppressWarnings("nls")
private static final OutputLineProcessor[] framewotks = {
private static final OutputLineProcessor[] frameworks = {
new OutputLineProcessor(" *(\\S.*)", 1, -1, true, ICSettingEntry.FRAMEWORKS_MAC) };
private State state = State.NONE;
@ -49,7 +50,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor {
@SuppressWarnings("nls")
@Override
public void processLine(String line, IProcessingContext processingContext) {
public void processLine(String line, IRawIndexerInfoCollector infoCollector) {
// include paths
if (line.equals("#include \"...\" search starts here:")) {
@ -74,7 +75,7 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor {
for (OutputLineProcessor processor : localIncludes) {
Optional<ICLanguageSettingEntry> result = processor.process(line);
if (result.isPresent()) {
processingContext.addSettingEntry(result.get());
infoCollector.addIncludePath(result.get().getName());
return; // line matched
}
}
@ -82,15 +83,16 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor {
for (OutputLineProcessor processor : systemIncludes) {
Optional<ICLanguageSettingEntry> result = processor.process(line);
if (result.isPresent()) {
processingContext.addSettingEntry(result.get());
infoCollector.addSystemIncludePath(result.get().getName());
return; // line matched
}
}
} else if (state == State.EXPECTING_FRAMEWORK) {
for (OutputLineProcessor processor : framewotks) {
for (OutputLineProcessor processor : frameworks) {
Optional<ICLanguageSettingEntry> result = processor.process(line);
if (result.isPresent()) {
processingContext.addSettingEntry(result.get());
// IExtendedScannerInfo has no mean to specify ICSettingEntry.FRAMEWORKS_MAC
// infoCollector.addSettingEntry(result.get());
return; // line matched
}
}
@ -99,11 +101,12 @@ public class GccOutputProcessor implements IBuiltinsOutputProcessor {
for (OutputLineProcessor processor : macros) {
Optional<ICLanguageSettingEntry> result = processor.process(line);
if (result.isPresent()) {
processingContext.addSettingEntry(result.get());
ICLanguageSettingEntry settingEntry = result.get();
infoCollector.addDefine(settingEntry.getName(), settingEntry.getValue());
return; // line matched
}
}
// System.err.println("NO MATCH ON LINE: '" + line + "'");
// System.err.println("NO MATCH ON LINE: '" + line + "'");
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019 Martin Weber.
* Copyright (c) 2019-2020 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
@ -36,15 +36,4 @@ public interface IBuiltinsDetectionBehavior {
* cases, most implementations, should return {@code false} here.
*/
boolean suppressErrormessage();
/**
* Gets the filename extension for the input file. An empty input file will be
* created and its name will be given on the command-line when the compiler is
* invoked for built-ins detection.
*
* @param languageID the language ID
* @return the filename extension or {@code null} if no filename argument needs
* to be given for built-ins detection
*/
String getInputFileExtension(String languageID);
}

View file

@ -9,9 +9,7 @@
package org.eclipse.cdt.cmake.is.core.builtins;
import java.util.List;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector;
/**
* Responsible for parsing the output that is produced when a compiler is
@ -23,39 +21,9 @@ public interface IBuiltinsOutputProcessor {
* Parsers the given line from the compiler output and places each
* ICLanguageSettingEntry found in the given {@code IProcessingContext}.
*
* @param line a line from the compiler output to parse
* @param processingContext the buffer that receives the new
* {@code LanguageSetting} entries
* @param line a line from the compiler output to parse
* @param infoCollector the buffer that receives the new {@code LanguageSetting}
* entries
*/
void processLine(String line, IProcessingContext processingContext);
/**
* Gathers the results of argument parsing.
*
* @author Martin Weber
*/
public interface IProcessingContext {
/**
* Adds a ICLanguageSettingEntry to the result list.
*
* @param entry the entry to add to the result list
*/
void addSettingEntry(ICLanguageSettingEntry entry);
} // IProcessingContext
/**
* The result of processing the complete compiler output.
*
* @author Martin Weber
*
* @see IBuiltinsOutputProcessor#processLine(String, IProcessingContext)
*/
public interface IResult {
/**
* Gets the language setting entries produced during processing.
*
* @return the language setting entries
*/
List<ICLanguageSettingEntry> getSettingEntries();
} // IResult
void processLine(String line, IRawIndexerInfoCollector infoCollector);
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018-2019 Martin Weber.
* Copyright (c) 2018-2020 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
@ -13,7 +13,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.Objects;
import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor.IProcessingContext;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector;
/**
* An OutputStream that passes each line written to it to a
@ -28,17 +28,18 @@ public class OutputSniffer extends OutputStream {
private static final String SEP = System.lineSeparator();
private final StringBuilder buffer;
private final IBuiltinsOutputProcessor processor;
private final IProcessingContext processingContext;
private final IRawIndexerInfoCollector infoCollector;
private final OutputStream os;
/**
* @param outputStream the OutputStream to write to or {@code null}
* @param processingContext the processing context
* @param outputStream the OutputStream to write to or {@code null}
* @param infoCollector collector for information about C preprocessor symbols
* and include paths
*/
public OutputSniffer(IBuiltinsOutputProcessor processor, OutputStream outputStream,
IProcessingContext processingContext) {
IRawIndexerInfoCollector infoCollector) {
this.processor = Objects.requireNonNull(processor, "processor"); //$NON-NLS-1$
this.processingContext = Objects.requireNonNull(processingContext, "processingContext"); //$NON-NLS-1$
this.infoCollector = Objects.requireNonNull(infoCollector, "infoCollector"); //$NON-NLS-1$
this.os = outputStream;
buffer = new StringBuilder(512);
}
@ -100,6 +101,6 @@ public class OutputSniffer extends OutputStream {
* @param line
*/
private void processLine(String line) {
processor.processLine(line, processingContext);
processor.processLine(line, infoCollector);
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018-2019 Martin Weber.
* Copyright (c) 2018-2020 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
@ -9,42 +9,38 @@
package org.eclipse.cdt.cmake.is.core.internal.builtins;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfo;
import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsDetectionBehavior;
import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor;
import org.eclipse.cdt.cmake.is.core.builtins.OutputSniffer;
import org.eclipse.cdt.cmake.is.core.internal.Plugin;
import org.eclipse.cdt.cmake.is.core.language.settings.providers.PreferenceConstants;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ConsoleOutputStream;
import org.eclipse.cdt.core.ICommandLauncher;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.model.LanguageManager;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.preference.IPreferenceStore;
/**
* Detects preprocessor macros and include paths that are built-in to a
@ -63,77 +59,66 @@ public class CompilerBuiltinsDetector {
@SuppressWarnings("nls")
private static final String MARKER_ID = Plugin.PLUGIN_ID + ".CompilerBuiltinsDetectorMarker";
private ICConfigurationDescription cfgDescription;
/** environment variables, lazily instantiated */
private String[] envp;
private final String languageId;
private final String sourceFileExtension;
private final String command;
private List<String> builtinsDetectionArgs;
private final List<String> builtinsDetectionArgs;
private final IBuiltinsDetectionBehavior builtinsDetectionBehavior;
private IBuildConfiguration buildConfiguration;
private java.nio.file.Path buildDirectory;
/**
* @param cfgDescription configuration description.
* @param languageId language id
* @param builtinsDetectionBehavior how compiler built-ins are to be detected
* @param command the compiler command (argument # 0)
* @param builtinsDetectionArgs the compiler arguments from the command-line
* that affect built-in detection. For the GNU
* compilers, these are options like
* {@code --sysroot} and options that specify
* the language's standard ({@code -std=c++17}.
* the language's standard (e.g.
* {@code -std=c++17}).
* @param sourceFileExtension the extension of the source file name
*/
@SuppressWarnings("nls")
public CompilerBuiltinsDetector(ICConfigurationDescription cfgDescription, String languageId,
IBuiltinsDetectionBehavior builtinsDetectionBehavior, String command, List<String> builtinsDetectionArgs) {
this.languageId = Objects.requireNonNull(languageId, "languageId");
public CompilerBuiltinsDetector(IBuiltinsDetectionBehavior builtinsDetectionBehavior, String command,
List<String> builtinsDetectionArgs, String sourceFileExtension) {
this.sourceFileExtension = Objects.requireNonNull(sourceFileExtension, "sourceFileExtension");
this.builtinsDetectionBehavior = Objects.requireNonNull(builtinsDetectionBehavior, "builtinsDetectionBehavior");
this.command = Objects.requireNonNull(command, "command");
this.builtinsDetectionArgs = Objects.requireNonNull(builtinsDetectionArgs, "builtinsDetectionArgs");
this.cfgDescription = Objects.requireNonNull(cfgDescription);
}
/**
* Gets the language ID of this detector.
*/
public String getLanguageId() {
return languageId;
}
/**
* Run built-in detection builtinsDetectionArgs.
*
* @param withConsole whether to show a console for the builtinsDetectionArgs
* output
* Runs built-in detection.
*
* @param buildConfiguration the project build configuration to use
* @param theBuildDirectory the build directory of the build configuration
* @param launcher the launcher that can run in docker container, if
* any
* @param console the console to print the compiler output to or
* <code>null</code> if a separate console is to be
* allocated.
* @throws CoreException
*/
public List<ICLanguageSettingEntry> run(boolean withConsole) throws CoreException {
ProcessingContext entries = new ProcessingContext();
public IRawIndexerInfo detectBuiltins(IBuildConfiguration buildConfiguration, java.nio.file.Path theBuildDirectory,
ICommandLauncher launcher, IConsole console, IProgressMonitor monitor) throws CoreException {
this.buildConfiguration = Objects.requireNonNull(buildConfiguration, "buildConfiguration"); //$NON-NLS-1$
this.buildDirectory = Objects.requireNonNull(theBuildDirectory, "buildDirectory"); //$NON-NLS-1$
final List<String> argList = getCompilerArguments(languageId);
argList.addAll(builtinsDetectionArgs);
IConsole console = null;
if (withConsole) {
console = startOutputConsole();
if (monitor == null) {
monitor = new NullProgressMonitor();
}
IProject project = cfgDescription.getProjectDescription().getProject();
// get the launcher that runs in docker container, if any
ICommandLauncher launcher = ManagedBuildManager.getConfigurationForDescription(cfgDescription)
.getEditableBuilder().getCommandLauncher();
launcher.setProject(project);
RawIndexerInfo result = new RawIndexerInfo();
final List<String> argList = getCompilerArguments();
argList.addAll(builtinsDetectionArgs);
console = startOutputConsole(console);
launcher.setProject(buildConfiguration.getProject());
launcher.showCommand(console != null);
final NullProgressMonitor monitor = new NullProgressMonitor();
final IPath builderCWD = cfgDescription.getBuildSetting().getBuilderCWD();
IPath buildRoot = ResourcesPlugin.getWorkspace().getRoot().getFolder(builderCWD).getLocation();
final Process proc = launcher.execute(new Path(command), argList.toArray(new String[argList.size()]), getEnvp(),
buildRoot, monitor);
new Path(this.buildDirectory.toString()), monitor);
if (proc != null) {
try {
// Close the input of the process since we will never write to it
@ -141,13 +126,22 @@ public class CompilerBuiltinsDetector {
} catch (IOException e) {
}
// NOTE: we need 2 of these, since the output streams are not synchronized,
// causing loss of
// the internal processor state
// causing loss of the output processors' internal state
final IBuiltinsOutputProcessor bopOut = builtinsDetectionBehavior.createCompilerOutputProcessor();
final IBuiltinsOutputProcessor bopErr = builtinsDetectionBehavior.createCompilerOutputProcessor();
long start = System.currentTimeMillis();
int state = launcher.waitAndRead(
new OutputSniffer(bopOut, console == null ? null : console.getOutputStream(), entries),
new OutputSniffer(bopErr, console == null ? null : console.getErrorStream(), entries), monitor);
new OutputSniffer(bopOut, console == null ? null : console.getOutputStream(), result),
new OutputSniffer(bopErr, console == null ? null : console.getErrorStream(), result), monitor);
if (console != null) {
final ConsoleOutputStream cis = console.getInfoStream();
try {
cis.write(String
.format("Detecting compiler built-ins took %d ms.\n", System.currentTimeMillis() - start)
.getBytes());
} catch (IOException ignore) {
}
}
if (state != ICommandLauncher.COMMAND_CANCELED) {
// check exit status
final int exitValue = proc.exitValue();
@ -161,154 +155,116 @@ public class CompilerBuiltinsDetector {
// process start failed
createMarker(launcher.getErrorMessage());
}
return entries.getSettingEntries();
return result;
}
/**
* Gets the compiler-arguments corresponding to the specified language ID and
* the builtinDetection.
* Gets the compiler-arguments corresponding to the builtinDetection.
*/
private List<String> getCompilerArguments(String languageId) {
private List<String> getCompilerArguments() {
List<String> args = new ArrayList<>();
args.addAll(builtinsDetectionBehavior.getBuiltinsOutputEnablingArgs());
String inputFile = getInputFile(languageId);
String inputFile = getInputFile();
if (inputFile != null) {
args.add(inputFile);
}
return args;
}
/**
* Get array of environment variables in format "var=value".
*/
@SuppressWarnings("nls")
private String[] getEnvp() {
if (envp == null) {
// On POSIX (Linux, UNIX) systems reset language variables to default
// (English)
// with UTF-8 encoding since GNU compilers can handle only UTF-8
// characters.
// Include paths with locale characters will be handled properly
// regardless
// of the language as long as the encoding is set to UTF-8.
// English language is set for parser because it relies on English
// messages
// in the output of the 'gcc -v' builtinsDetectionArgs.
List<String> env = new ArrayList<>(Arrays.asList(getEnvp(cfgDescription)));
for (Iterator<String> iterator = env.iterator(); iterator.hasNext();) {
String var = iterator.next();
if (var.startsWith("LANGUAGE" + '=') || var.startsWith("LC_ALL" + '=')) {
iterator.remove();
}
}
env.add("LANGUAGE" + "=en"); // override for GNU gettext //$NON-NLS-1$
env.add("LC_ALL" + "=C.UTF-8"); // for other parts of the //$NON-NLS-1$
// system libraries
envp = env.toArray(new String[env.size()]);
}
return envp;
}
/**
* Get environment variables from configuration as array of "var=value" suitable
* for using as "envp" with Runtime.exec(String[] cmdarray, String[] envp, File
* dir)
*
* @param cfgDescription configuration description.
* @return String array of environment variables in format "var=value". Does not
* return {@code null}.
*/
@SuppressWarnings("nls")
private static String[] getEnvp(ICConfigurationDescription cfgDescription) {
private String[] getEnvp() {
IEnvironmentVariableManager mngr = CCorePlugin.getDefault().getBuildEnvironmentManager();
IEnvironmentVariable[] vars = mngr.getVariables(cfgDescription, true);
IEnvironmentVariable[] vars = mngr.getVariables(buildConfiguration, true);
// Convert into envp strings
Set<String> strings = new HashSet<>(vars.length);
for (IEnvironmentVariable var : vars) {
if (var.getName().startsWith("LANGUAGE" + '=') || var.getName().startsWith("LC_ALL" + '='))
continue;
strings.add(var.getName() + '=' + var.getValue());
}
// On POSIX (Linux, UNIX) systems reset language variables to default
// (English)
// On POSIX (Linux, UNIX) systems reset language variables to default (English)
// with UTF-8 encoding since GNU compilers can handle only UTF-8 characters.
// Include paths with locale characters will be handled properly regardless
// of the language as long as the encoding is set to UTF-8.
// English language is set for parser because it relies on English messages
// in the output of the 'gcc -v' builtinsDetectionArgs.
strings.add("LANGUAGE" + "=en"); // override for GNU gettext
strings.add("LC_ALL" + "=C.UTF-8"); // for other parts of the system
// libraries
strings.add("LC_ALL" + "=C.UTF-8"); // for other parts of the system libraries
return strings.toArray(new String[strings.size()]);
}
/**
* Get path to source file which is the input for the compiler.
* Gets a path to the source file which is the input for the compiler. The file
* will be created with no content in the build directory.
*
* @param languageId the language ID.
* @return full path to the source file.
* @return the full file system path of the source file
*/
private String getInputFile(String languageId) {
String specExt = builtinsDetectionBehavior.getInputFileExtension(languageId);
if (specExt != null) {
String specFileName = "detect_compiler_builtins" + '.' + specExt; //$NON-NLS-1$
final IPath builderCWD = cfgDescription.getBuildSetting().getBuilderCWD();
IPath fileLocation = ResourcesPlugin.getWorkspace().getRoot().getFolder(builderCWD).getLocation()
.append(specFileName);
File specFile = new java.io.File(fileLocation.toOSString());
if (!specFile.exists()) {
try {
// In the typical case it is sufficient to have an empty file.
specFile.getParentFile().mkdirs(); // no build ran yet, must create dirs
specFile.createNewFile();
} catch (IOException e) {
Plugin.getDefault().getLog().log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "getInputFile()", e));
}
private String getInputFile() {
String specFileName = "detect_compiler_builtins" + '.' + sourceFileExtension; //$NON-NLS-1$
java.nio.file.Path specFile = buildDirectory.resolve(specFileName);
if (!Files.exists(specFile)) {
try {
// In the typical case it is sufficient to have an empty file.
Files.createDirectories(specFile.getParent()); // no build ran yet, must create dirs
Files.createFile(specFile);
} catch (IOException e) {
Plugin.getDefault().getLog().log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "getInputFile()", e)); //$NON-NLS-1$
}
return fileLocation.toString();
}
return null;
return specFile.toString();
}
private void createMarker(String message) throws CoreException {
IMarker marker = cfgDescription.getProjectDescription().getProject().createMarker(MARKER_ID);
IMarker marker = buildConfiguration.getProject().createMarker(MARKER_ID);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
marker.setAttribute(IMarker.MESSAGE, message);
}
/**
* Creates and starts the provider console.
* Creates and starts the output console.
*
* @return CDT console or <code>null</code>
*
* @throws CoreException
*/
private IConsole startOutputConsole() throws CoreException {
IConsole console = null;
@SuppressWarnings("nls")
private IConsole startOutputConsole(IConsole console) throws CoreException {
IPreferenceStore prefStore = Plugin.getDefault().getPreferenceStore();
if (!prefStore.getBoolean(PreferenceConstants.P_WITH_CONSOLE)) {
return null; // no console to allocate
} else {
IProject project = buildConfiguration.getProject();
if (console != null) {
String consoleId = CONSOLE_ID + "." + project.getName();
console = CCorePlugin.getDefault().getConsole(CONSOLE_ID, consoleId, null, null);
}
ILanguage ld = LanguageManager.getInstance().getLanguage(languageId);
if (ld != null) {
String consoleId = CONSOLE_ID + '.' + languageId;
console = CCorePlugin.getDefault().getConsole(CONSOLE_ID, consoleId, null, null);
final IProject project = cfgDescription.getProjectDescription().getProject();
console.start(project);
try {
final ConsoleOutputStream cis = console.getInfoStream();
cis.write(SimpleDateFormat.getTimeInstance().format(new Date()).getBytes());
cis.write(" Detecting compiler built-ins: ".getBytes());
cis.write(project.getName().getBytes());
cis.write("::".getBytes());
cis.write(cfgDescription.getConfiguration().getName().getBytes());
if (!buildConfiguration.getName().isEmpty()) {
cis.write("::".getBytes());
cis.write(buildConfiguration.getName().getBytes());
}
cis.write(" for ".getBytes());
cis.write(ld.getName().getBytes());
cis.write("\n".getBytes());
cis.write(sourceFileExtension.getBytes());
cis.write(" files\n".getBytes());
} catch (IOException ignore) {
}
}
return console;
}

View file

@ -46,16 +46,4 @@ public class MaybeGccBuiltinDetectionBehavior implements IBuiltinsDetectionBehav
// detection
return true;
}
@SuppressWarnings("nls")
@Override
public String getInputFileExtension(String languageId) {
if (languageId.equals("org.eclipse.cdt.core.gcc")) {
return "c";
}
if (languageId.equals("org.eclipse.cdt.core.g++")) {
return "cpp";
}
return null; // no input file required for built-in detection
}
}

View file

@ -1,49 +0,0 @@
/*******************************************************************************
* Copyright (c) 2019-2020 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.cmake.is.core.internal.builtins;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.cmake.is.core.builtins.IBuiltinsOutputProcessor;
import org.eclipse.cdt.cmake.is.core.internal.Plugin;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.core.runtime.Platform;
/**
* Default implementation of IProcessingContext.
*
* @author Martin Weber
*/
class ProcessingContext implements IBuiltinsOutputProcessor.IProcessingContext, IBuiltinsOutputProcessor.IResult {
@SuppressWarnings("nls")
private static final boolean DEBUG = Boolean
.parseBoolean(Platform.getDebugOption(Plugin.PLUGIN_ID + "/CECC/builtins/entries"));
private final List<ICLanguageSettingEntry> entries = Collections
.synchronizedList(new ArrayList<ICLanguageSettingEntry>());
public ProcessingContext() {
}
@Override
public void addSettingEntry(ICLanguageSettingEntry entry) {
if (DEBUG)
System.out.printf("Added builtin entry: %s%n", entry); //$NON-NLS-1$
entries.add(entry);
}
@Override
public List<ICLanguageSettingEntry> getSettingEntries() {
return entries;
}
}

View file

@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2020 Martin Weber.
*
* 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.cmake.is.core.internal.builtins;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfo;
import org.eclipse.cdt.cmake.is.core.IRawIndexerInfoCollector;
import org.eclipse.cdt.cmake.is.core.internal.Plugin;
import org.eclipse.core.runtime.Platform;
/**
* Default implementation of IRawIndexerInfo.
*
* @author weber
*/
public class RawIndexerInfo implements IRawIndexerInfo, IRawIndexerInfoCollector {
@SuppressWarnings("nls")
private static final boolean DEBUG = Boolean
.parseBoolean(Platform.getDebugOption(Plugin.PLUGIN_ID + "/debug/detected.entries"));
private final Map<String, String> defines = new HashMap<>();
private final List<String> undefines = new ArrayList<>();
private final List<String> includePaths = new ArrayList<>();
private final List<String> systemIncludePaths = new ArrayList<>();
@Override
public void addDefine(String name, String value) {
Objects.requireNonNull(name);
value = Objects.toString(value, ""); //$NON-NLS-1$
if (DEBUG)
System.out.printf(" Added define: %s=%s%n", name, value); //$NON-NLS-1$
defines.put(name, value);
}
@Override
public void addUndefine(String name) {
Objects.requireNonNull(name);
if (DEBUG)
System.out.printf(" Added undefine: %s%n", name); //$NON-NLS-1$
undefines.add(name);
// - The GCC man page states:
// '-U name Cancel any previous definition of name, either built in or provided
// with a -D option.'
// - The POSIX c99 man page states:
// '-U name Remove any initial definition of name.'
for (Iterator<Map.Entry<String, String>> iter = defines.entrySet().iterator(); iter.hasNext();) {
Entry<String, String> define = iter.next();
if (define.getKey().equals(name)) {
if (DEBUG)
System.out.printf(" Removed define: %s=%s%n", define.getKey(), define.getValue()); //$NON-NLS-1$
iter.remove();
}
}
}
@Override
public void addIncludePath(String path) {
Objects.requireNonNull(path);
if (DEBUG)
System.out.printf(" Added incl path: %s%n", path); //$NON-NLS-1$
includePaths.add(path);
}
@Override
public void addSystemIncludePath(String path) {
Objects.requireNonNull(path);
if (DEBUG)
System.out.printf(" Added sys incl path: %s%n", path); //$NON-NLS-1$
systemIncludePaths.add(path);
}
@Override
public Map<String, String> getDefines() {
return Collections.unmodifiableMap(defines);
}
@Override
public List<String> getUndefines() {
return Collections.unmodifiableList(undefines);
}
@Override
public List<String> getIncludePaths() {
return Collections.unmodifiableList(includePaths);
}
@Override
public List<String> getSystemIncludePaths() {
return Collections.unmodifiableList(systemIncludePaths);
}
}

View file

@ -1,273 +0,0 @@
/*******************************************************************************
* Copyright (c) 2018 Martin Weber.
*
* Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 "EPL".
* A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.cmake.is.core.language.settings.providers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import org.eclipse.cdt.build.core.scannerconfig.ScannerConfigNature;
import org.eclipse.cdt.cmake.is.core.internal.ParserDetection;
import org.eclipse.cdt.cmake.is.core.internal.Plugin;
import org.eclipse.cdt.cmake.is.core.internal.builtins.CompilerBuiltinsDetector;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.language.settings.providers.ICBuildOutputParser;
import org.eclipse.cdt.core.language.settings.providers.ICListenerAgent;
import org.eclipse.cdt.core.language.settings.providers.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.LanguageSettingsManager;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.widgets.Display;
import org.w3c.dom.Element;
/**
* A ILanguageSettingsProvider that detects the include paths and symbols
* built-in to the compilers found in the file 'compile_commands.json' produced
* by cmake.<br>
* NOTE: This class misuses interface ICBuildOutputParser to detect when a build
* did finish.<br>
* NOTE: This class misuses interface ICListenerAgent to populate the
* {@link #getSettingEntries setting entries} on workbench startup.
*
* @author Martin Weber
*/
/*
* TODO delete this after integration into core build
*/
public class BuiltinsCompileCommandsJsonParser extends LanguageSettingsSerializableProvider
implements ILanguageSettingsEditableProvider, ICListenerAgent, ICBuildOutputParser, Cloneable {
public static final String PROVIDER_ID = "org.eclipse.cdt.cmake.is.core.language.settings.providers.BuiltinsCompileCommandsJsonParser";
private static final ILog log = Plugin.getDefault().getLog();
/** storage key for with console */
@SuppressWarnings("nls")
private static final String ATTR_WITH_CONSOLE = "console";
private ICConfigurationDescription currentCfgDescription;
@Override
public void configureProvider(String id, String name, List<String> languages, List<ICLanguageSettingEntry> entries,
Map<String, String> properties) {
ArrayList<String> scope = new ArrayList<>();
scope.add("org.eclipse.cdt.core.gcc"); //$NON-NLS-1$
scope.add("org.eclipse.cdt.core.g++"); //$NON-NLS-1$
scope.addAll(ParserDetection.getCustomLanguages());
super.configureProvider(id, name, scope, entries, properties);
}
/**
* Detects the compiler built-in include paths and symbols. Uses
* {@link CompileCommandsJsonParser} for parsing of the json file and caching.
*
* @param initializingWorkbench {@code true} if the workbench is starting up. If
* {@code true}, this method will not trigger UI
* update to show newly detected include paths nor
* will it complain if a "compile_commands.json"
* file does not exist.
* @throws CoreException
*/
private void detectBuiltins(boolean initializingWorkbench) throws CoreException {
if (currentCfgDescription instanceof ILanguageSettingsProvidersKeeper) {
Iterable<CompilerBuiltinsDetector> detectors;
final List<ILanguageSettingsProvider> lsps = ((ILanguageSettingsProvidersKeeper) currentCfgDescription)
.getLanguageSettingProviders();
// get the CompileCommandsJsonParser object, if the settings provider is enabled
// on the configuration
final CompileCommandsJsonParser lsp;
Optional<ILanguageSettingsProvider> lspO = lsps.stream()
.filter(p -> CompileCommandsJsonParser.PROVIDER_ID.equals(p.getId())).findAny();
if (lspO.isPresent()) {
// CompileCommandsJsonParser is there, trigger it, regardless of provider order
lsp = (CompileCommandsJsonParser) LanguageSettingsManager.getRawProvider(lspO.get());
detectors = lsp.determineBuiltinDetectors(currentCfgDescription, true, initializingWorkbench);
} else {
// get a CompileCommandsJsonParser configured with the workspace default
// settings
lsp = (CompileCommandsJsonParser) LanguageSettingsManager
.getExtensionProviderCopy(CompileCommandsJsonParser.PROVIDER_ID, false);
detectors = lsp.determineBuiltinDetectors(currentCfgDescription, false, initializingWorkbench);
}
if (initializingWorkbench && detectors == null) {
// if initializing, always get the detectors
detectors = lsp.getBuiltinDetectors(currentCfgDescription);
}
if (detectors != null) {
// run each detector and gather the entries per language
HashMap<String, Set<ICLanguageSettingEntry>> langMap = new HashMap<>(2, 1.0f);
for (CompilerBuiltinsDetector detector : detectors) {
final String languageId = detector.getLanguageId();
// entries per language
List<ICLanguageSettingEntry> entries = detector.run(isWithConsole());
// use a Set here to avoid duplicates by name and kind ..
Set<ICLanguageSettingEntry> allEntries = langMap.get(languageId);
if (allEntries == null) {
allEntries = new HashSet<>();
langMap.put(languageId, allEntries);
}
allEntries.addAll(entries);
}
// store the entries per language
for (Entry<String, Set<ICLanguageSettingEntry>> entry : langMap.entrySet()) {
super.setSettingEntries(currentCfgDescription, null, entry.getKey(), Arrays
.asList(entry.getValue().toArray(new ICLanguageSettingEntry[entry.getValue().size()])));
}
}
}
}
/*-
* interface ICBuildOutputParser
*/
@Override
public void startup(ICConfigurationDescription cfgDescription, IWorkingDirectoryTracker cwdTracker)
throws CoreException {
currentCfgDescription = cfgDescription;
}
/**
* Invoked for each line in the build output.
*/
// interface ICBuildOutputParser
@Override
public boolean processLine(String line) {
// nothing to do
return false;
}
/*-
* interface ICBuildOutputParser
*/
@Override
public void shutdown() {
try {
detectBuiltins(false);
} catch (CoreException ex) {
log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "shutdown()", ex));
}
// release resources for garbage collector
currentCfgDescription = null;
}
@Override
public BuiltinsCompileCommandsJsonParser clone() throws CloneNotSupportedException {
return (BuiltinsCompileCommandsJsonParser) super.clone();
}
@Override
public BuiltinsCompileCommandsJsonParser cloneShallow() throws CloneNotSupportedException {
return (BuiltinsCompileCommandsJsonParser) super.cloneShallow();
}
/**
* Overridden to misuse this to populate the {@link #getSettingEntries setting
* entries} on startup.<br>
* {@inheritDoc}
*/
@Override
public void registerListener(ICConfigurationDescription cfgDescription) {
if (cfgDescription != null) {
// per-project or null if the user just added this provider on the provider tab
currentCfgDescription = cfgDescription;
try {
detectBuiltins(true);
} catch (CoreException ex) {
log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "registerListener()", ex));
}
} else {
// per workspace (to populate on startup)
Display.getDefault().asyncExec(() -> {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IProject[] projects = workspaceRoot.getProjects();
CCorePlugin ccp = CCorePlugin.getDefault();
// detect built-ins for any opened project that has a ScannerConfigNature...
for (IProject project : projects) {
try {
if (project.isOpen() && project.hasNature(ScannerConfigNature.NATURE_ID)) {
ICProjectDescription projectDescription = ccp.getProjectDescription(project, false);
if (projectDescription != null) {
ICConfigurationDescription activeConfiguration = projectDescription
.getActiveConfiguration();
if (activeConfiguration instanceof ILanguageSettingsProvidersKeeper) {
final List<ILanguageSettingsProvider> lsps = ((ILanguageSettingsProvidersKeeper) activeConfiguration)
.getLanguageSettingProviders();
for (ILanguageSettingsProvider lsp : lsps) {
if (PROVIDER_ID.equals(lsp.getId())) {
currentCfgDescription = activeConfiguration;
detectBuiltins(true);
break;
}
}
}
}
}
} catch (CoreException ex) {
log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, "registerListener()", ex));
}
}
});
}
// release resources for garbage collector
currentCfgDescription = null;
}
/*-
* @see org.eclipse.cdt.core.language.settings.providers.ICListenerAgent#unregisterListener()
*/
@Override
public void unregisterListener() {
}
/**
* Gets whether a console in the console view should be allocated during
* detection.
*/
public boolean isWithConsole() {
return getPropertyBool(ATTR_WITH_CONSOLE);
}
/**
* Sets whether a console in the console view should be allocated during
* detection.
*/
public void setWithConsole(boolean enabled) {
if (enabled) {
setPropertyBool(ATTR_WITH_CONSOLE, enabled);
} else {
properties.remove(ATTR_WITH_CONSOLE);
}
}
@Override
public void serializeEntries(Element elementProvider) {
// no language setting entries to serialize, since entries come from the
// compile_commands.json file
}
}

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2020 Martin Weber.
*
* 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.cmake.is.core.language.settings.providers;
/**
* Represents a parsed command entry of a compile_commands.json file.
* @author weber
*/
class CommandEntry {
private String directory;
private String command;
private String file;
/**
* Gets the build directory as a String.
*/
public String getDirectory() {
return directory;
}
/**
* Gets the command-line to compile the source file.
*/
public String getCommand() {
return command;
}
/**
* Gets the source file path as a String.
*/
public String getFile() {
return file;
}
}