diff --git a/clang-tools-extra/clangd/QueryDriverDatabase.cpp b/clang-tools-extra/clangd/QueryDriverDatabase.cpp --- a/clang-tools-extra/clangd/QueryDriverDatabase.cpp +++ b/clang-tools-extra/clangd/QueryDriverDatabase.cpp @@ -136,10 +136,26 @@ } llvm::Optional -extractSystemIncludesAndTarget(PathRef Driver, llvm::StringRef Lang, +extractSystemIncludesAndTarget(llvm::SmallString<128> Driver, + llvm::StringRef Lang, llvm::ArrayRef CommandLine, const llvm::Regex &QueryDriverRegex) { trace::Span Tracer("Extract system includes and target"); + + if (!llvm::sys::path::is_absolute(Driver)) { + assert(llvm::none_of( + Driver, [](char C) { return llvm::sys::path::is_separator(C); })); + auto DriverProgram = llvm::sys::findProgramByName(Driver); + if (DriverProgram) { + vlog("System include extraction: driver {0} expanded to {1}", Driver, + *DriverProgram); + Driver = *DriverProgram; + } else { + elog("System include extraction: driver {0} not found in PATH", Driver); + return llvm::None; + } + } + SPAN_ATTACH(Tracer, "driver", Driver); SPAN_ATTACH(Tracer, "lang", Lang); @@ -332,7 +348,11 @@ } llvm::SmallString<128> Driver(Cmd->CommandLine.front()); - llvm::sys::fs::make_absolute(Cmd->Directory, Driver); + if (llvm::any_of(Driver, + [](char C) { return llvm::sys::path::is_separator(C); })) + // Driver is a not a single executable name but instead a path (either + // relative or absolute). + llvm::sys::fs::make_absolute(Cmd->Directory, Driver); if (auto Info = QueriedDrivers.get(/*Key=*/(Driver + ":" + Lang).str(), [&] { diff --git a/clang-tools-extra/clangd/test/system-include-extractor.test b/clang-tools-extra/clangd/test/system-include-extractor.test --- a/clang-tools-extra/clangd/test/system-include-extractor.test +++ b/clang-tools-extra/clangd/test/system-include-extractor.test @@ -3,21 +3,24 @@ # The mock driver below is a shell script: # REQUIRES: shell +# Create a bin directory to store the mock-driver and add it to the path +# RUN: mkdir -p %t.dir/bin +# RUN: export PATH=%t.dir/bin:$PATH # Generate a mock-driver that will print %temp_dir%/my/dir and # %temp_dir%/my/dir2 as include search paths. -# 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 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/my_driver.sh -# RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/my_driver.sh -# RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/my_driver.sh -# RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/my_driver.sh -# RUN: echo 'printf "End of search list.\r\n" >&2' >> %t.dir/my_driver.sh -# RUN: chmod +x %t.dir/my_driver.sh +# RUN: echo '#!/bin/sh' >> %t.dir/bin/my_driver.sh +# RUN: echo '[ "$0" = "%t.dir/bin/my_driver.sh" ] || exit' >> %t.dir/bin/my_driver.sh +# RUN: echo 'args="$*"' >> %t.dir/bin/my_driver.sh +# RUN: echo '[ -z "${args##*"-nostdinc"*}" ] || exit' >> %t.dir/bin/my_driver.sh +# RUN: echo '[ -z "${args##*"-isysroot=/isysroot"*}" ] || exit' >> %t.dir/bin/my_driver.sh +# RUN: echo 'echo " $* " | grep " --sysroot /my/sysroot/path " || exit' >> %t.dir/bin/my_driver.sh +# RUN: echo 'echo line to ignore >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/bin/my_driver.sh +# RUN: echo 'printf "End of search list.\r\n" >&2' >> %t.dir/bin/my_driver.sh +# RUN: chmod +x %t.dir/bin/my_driver.sh # Create header files my/dir/a.h and my/dir2/b.h # RUN: mkdir -p %t.dir/my/dir @@ -27,7 +30,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 -nostdinc --sysroot /my/sysroot/path -isysroot=/isysroot", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json +# RUN: echo '[{"directory": "%/t.dir", "command": "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:/..."