diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java index 3a0435d654a..3d058dea1b9 100644 --- a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java @@ -16,6 +16,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.FileReader; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; import org.eclipse.cdt.managedbuilder.core.IBuilder; import org.eclipse.cdt.managedbuilder.core.IConfiguration; @@ -220,4 +223,27 @@ public void testMakeFileGenerationOff() throws Exception { app.build(IncrementalProjectBuilder.FULL_BUILD, null); assertFalse(app.getFile("Debug/compile_commands.json").exists()); } + + @Test + public void testGetCompilerArgsWithSpacesAndQuotes() { + String[] commandLine = { "gcc", "My file.c", "-o", "My file.o", "-DNAME=\"My Value\"", + "C:\\Program Files\\Lib" }; + List argsList = Arrays.asList(commandLine).subList(1, commandLine.length); + String result = escapeArgsForCompileCommand(argsList); + String expected = "\"My file.c\" -o \"My file.o\" \"-DNAME=\\\"My Value\\\"\" \"C:\\\\Program Files\\\\Lib\""; + + assertEquals(expected, result); + } + + private static String escapeArgsForCompileCommand(List args) { + return args.stream().map(arg -> { + if (arg.contains(" ") || arg.contains("\"") || arg.contains("\\")) { + String escaped = arg.replace("\\", "\\\\").replace("\"", "\\\""); + return "\"" + escaped + "\""; + } else { + return arg; + } + }).collect(Collectors.joining(" ")); + } + } diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java index 6c144d9c01f..243a8df3bd4 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java @@ -14,11 +14,13 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; @@ -69,8 +71,9 @@ public final class CompilationDatabaseGenerator { /** * Checked on each build * Used before we look up the environment + * Map of compiler name (as calculated by {@link #getCompilerName(String)}) to the absolute path of the compiler. */ - private Map toolMap = new HashMap<>(); + private Map toolMap = new HashMap<>(); private IProject project; private IConfiguration configuration; private ICSourceEntry[] srcEntries; @@ -229,18 +232,19 @@ private List populateObjList(IProject project, I outputLocation + "", inputStrings, sourceLocation, outputLocation); //$NON-NLS-1$ IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider(); - String compilerName = CompilationDatabaseGenerator.getCompilerName(tool); String commandLine = cmdLInfo.getCommandLine(); - commandLine = commandLine.replace(compilerName, "").trim(); //$NON-NLS-1$ - String compilerPath = findCompilerInPath(tool, config); + String compilerName = CompilationDatabaseGenerator.getCompilerName(commandLine); + String compilerArguments = getCompilerArgs(commandLine); + String compilerPath = findCompilerInPath(config, compilerName); String resolvedOptionFileContents; if (compilerPath != null && !compilerPath.isEmpty()) { - resolvedOptionFileContents = provider.resolveValueToMakefileFormat(compilerPath + " " + commandLine, //$NON-NLS-1$ + resolvedOptionFileContents = provider.resolveValueToMakefileFormat( + compilerPath + " " + compilerArguments, //$NON-NLS-1$ "", " ", //$NON-NLS-1$//$NON-NLS-2$ IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation, outputLocation, null, tool)); } else { - resolvedOptionFileContents = provider.resolveValueToMakefileFormat(commandLine, "", " ", //$NON-NLS-1$//$NON-NLS-2$ + resolvedOptionFileContents = provider.resolveValueToMakefileFormat(compilerArguments, "", " ", //$NON-NLS-1$//$NON-NLS-2$ IBuildMacroProvider.CONTEXT_FILE, new FileContextData(sourceLocation, outputLocation, null, tool)); @@ -438,15 +442,15 @@ public boolean visit(IResourceProxy proxy) throws CoreException { } - private String findCompilerInPath(ITool tool, IConfiguration config) { - if (toolMap.containsKey(tool)) { - return "\"" + toolMap.get(tool) + "\""; //$NON-NLS-1$//$NON-NLS-2$ + private String findCompilerInPath(IConfiguration config, String compilerName) { + String cacheKey = compilerName; + if (toolMap.containsKey(cacheKey)) { + return "\"" + toolMap.get(cacheKey) + "\""; //$NON-NLS-1$//$NON-NLS-2$ } - String compilerName = CompilationDatabaseGenerator.getCompilerName(tool); File pathToCompiler = new File(compilerName); if (pathToCompiler.isAbsolute()) { - toolMap.put(tool, compilerName); + toolMap.put(cacheKey, compilerName); return "\"" + compilerName + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } ICConfigurationDescription cfg = ManagedBuildManager.getDescriptionForConfiguration(config); @@ -458,7 +462,7 @@ private String findCompilerInPath(ITool tool, IConfiguration config) { IPath resolvedPath = PathUtil.findProgramLocation(compilerName, variable.getValue()); if (resolvedPath != null) { String path = resolvedPath.toString(); - toolMap.put(tool, path); + toolMap.put(cacheKey, path); return "\"" + path + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } else { return null; // Only one PATH so can exit early @@ -469,13 +473,32 @@ private String findCompilerInPath(ITool tool, IConfiguration config) { return null; } - private static String getCompilerName(ITool tool) { - String compilerCommand = tool.getToolCommand(); - String[] arguments = CommandLineUtil.argumentsToArray(compilerCommand); + private static String getCompilerName(String commandLine) { + String[] arguments = CommandLineUtil.argumentsToArray(commandLine); if (arguments.length == 0) { return ""; //$NON-NLS-1$ } return arguments[0]; } + private static String getCompilerArgs(String commandLine) { + String[] arguments = CommandLineUtil.argumentsToArray(commandLine); + if (arguments.length <= 1) { + return ""; //$NON-NLS-1$ + } + List argsList = Arrays.asList(arguments).subList(1, arguments.length); + return escArgsForCompileCommand(argsList); + } + + private static String escArgsForCompileCommand(final List args) { + return args.stream().map(arg -> { + if (arg.contains(" ") || arg.contains("\"") || arg.contains("\\")) { //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + String escaped = arg.replace("\\", "\\\\").replace("\"", "\\\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ + return "\"" + escaped + "\""; //$NON-NLS-1$//$NON-NLS-2$ + } else { + return arg; + } + }).collect(Collectors.joining(" ")); //$NON-NLS-1$ + } + }