Index: clang-tools-extra/clangd/QueryDriverDatabase.cpp =================================================================== --- clang-tools-extra/clangd/QueryDriverDatabase.cpp +++ clang-tools-extra/clangd/QueryDriverDatabase.cpp @@ -85,9 +85,10 @@ return SystemIncludes; } -std::vector extractSystemIncludes(PathRef Driver, - llvm::StringRef Lang, - llvm::Regex &QueryDriverRegex) { +std::vector +extractSystemIncludes(PathRef Driver, llvm::StringRef Lang, + llvm::ArrayRef CommandLine, + llvm::Regex &QueryDriverRegex) { trace::Span Tracer("Extract system includes"); SPAN_ATTACH(Tracer, "driver", Driver); SPAN_ATTACH(Tracer, "lang", Lang); @@ -120,14 +121,43 @@ llvm::Optional Redirects[] = { {""}, {""}, llvm::StringRef(StdErrPath)}; - // Should we also preserve flags like "-sysroot", "-nostdinc" ? - const llvm::StringRef Args[] = {Driver, "-E", "-x", Lang, "-", "-v"}; + llvm::SmallVector Args = {Driver, "-E", "-x", + Lang, "-", "-v"}; + + // These flags will be preserved + const llvm::StringRef FlagsToPreserve[] = { + "-nostdinc", "--no-standard-includes", "-nostdinc++", "-nobuiltininc"}; + // Preserves these flags and their values, either as separate args or with an + // equalsbetween them + const llvm::StringRef ArgsToPreserve[] = {"--sysroot", "-isysroot"}; + + for (size_t I = 0, E = CommandLine.size(); I < E; ++I) { + llvm::StringRef Arg = CommandLine[I]; + if (llvm::any_of(FlagsToPreserve, + [&Arg](llvm::StringRef S) { return S == Arg; })) { + Args.push_back(Arg); + } else { + const auto *Found = + llvm::find_if(ArgsToPreserve, [&Arg](llvm::StringRef S) { + return Arg.startswith(S); + }); + if (Found == std::end(ArgsToPreserve)) + continue; + Arg.consume_front(*Found); + if (Arg.empty() && I + 1 < E) { + Args.push_back(CommandLine[I]); + Args.push_back(CommandLine[++I]); + } else if (Arg.startswith("=")) { + Args.push_back(CommandLine[I]); + } + } + } if (int RC = llvm::sys::ExecuteAndWait(Driver, Args, /*Env=*/llvm::None, Redirects)) { elog("System include extraction: driver execution failed with return code: " - "{0}", - llvm::to_string(RC)); + "{0}. Args: ['{1}']", + llvm::to_string(RC), llvm::join(Args, "', '")); return {}; } @@ -247,8 +277,8 @@ if (It != DriverToIncludesCache.end()) SystemIncludes = It->second; else - DriverToIncludesCache[Key] = SystemIncludes = - extractSystemIncludes(Key.first, Key.second, QueryDriverRegex); + DriverToIncludesCache[Key] = SystemIncludes = extractSystemIncludes( + Key.first, Key.second, Cmd->CommandLine, QueryDriverRegex); } return addSystemIncludes(*Cmd, SystemIncludes); @@ -278,7 +308,7 @@ if (QueryDriverGlobs.empty()) return Base; return std::make_unique(QueryDriverGlobs, - std::move(Base)); + std::move(Base)); } } // namespace clangd Index: clang-tools-extra/clangd/test/system-include-extractor.test =================================================================== --- clang-tools-extra/clangd/test/system-include-extractor.test +++ clang-tools-extra/clangd/test/system-include-extractor.test @@ -5,8 +5,12 @@ # Generate a mock-driver that will print %temp_dir%/my/dir and # %temp_dir%/my/dir2 as include search paths. -# RUN: echo '#!/bin/bash' >> %t.dir/my_driver.sh +# RUN: echo '#!/bin/sh' >> %t.dir/my_driver.sh # RUN: echo '[ "$0" = "%t.dir/my_driver.sh" ] || exit' >> %t.dir/my_driver.sh +# RUN: echo 'args="$*"' >> %t.dir/my_driver.sh +# RUN: echo '[ -z "${args##*"-nostdinc"*}" ] || exit' >> %t.dir/my_driver.sh +# RUN: echo '[ -z "${args##*"-isysroot=/isysroot"*}" ] || exit' >> %t.dir/my_driver.sh +# RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/my_driver.sh # RUN: echo 'echo line to ignore >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo -e "#include <...> search starts here:\r" >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/my_driver.sh @@ -22,7 +26,7 @@ # Generate a compile_commands.json that will query the mock driver we've # created. Which should add a.h and b.h into include search path. -# RUN: echo '[{"directory": "%/t.dir", "command": "%/t.dir/my_driver.sh the-file.cpp", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json +# RUN: echo '[{"directory": "%/t.dir", "command": "%/t.dir/my_driver.sh the-file.cpp -nostdinc --sysroot /my/sysroot/path -isysroot=/isysroot", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json # RUN: sed -e "s|INPUT_DIR|%/t.dir|g" %s > %t.test.1 # On Windows, we need the URI in didOpen to look like "uri":"file:///C:/..."