diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -35,6 +35,27 @@ llvm::StringRef /*RelativePath*/, const Module * /*Imported*/, SrcMgr::CharacteristicKind FileKind) override { + if (!isInsideMainFile(HashLoc, SM)) { + auto PreLoc = SM.getPresumedLoc(HashLoc); + if (auto FE = SM.getFileManager().getFile(PreLoc.getFilename())) { + if (SM.getFileEntryForID(SM.getMainFileID()) == *FE) { + HashLoc = SM.translateLineCol(SM.getMainFileID(), PreLoc.getLine(), + PreLoc.getColumn()); + PreLoc = SM.getPresumedLoc(FilenameRange.getBegin()); + auto FileNameBegin = SM.translateLineCol( + SM.getMainFileID(), PreLoc.getLine(), PreLoc.getColumn()); + PreLoc = SM.getPresumedLoc(FilenameRange.getEnd()); + // translateLineCol doesn't allow offsetting into a line past its end. + // But FilenameRange can be a charrange and point past the line, as + // the endpoint is exclusive. + auto FileNameEnd = + SM.translateLineCol(SM.getMainFileID(), PreLoc.getLine(), 1) + .getLocWithOffset(PreLoc.getColumn() - 1); + FilenameRange = CharSourceRange({FileNameBegin, FileNameEnd}, + FilenameRange.isTokenRange()); + } + } + } if (isInsideMainFile(HashLoc, SM)) { Out->MainFileIncludes.emplace_back(); auto &Inc = Out->MainFileIncludes.back(); diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -16,6 +16,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/PreprocessorOptions.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -302,6 +303,29 @@ llvm::None); } +TEST_F(HeadersTest, PresumedLocations) { + FS.Files[MainFile] = R"cpp( +#include "a.h" +// #include "b.h" +// nothing on this line +// #include "c.h" +)cpp"; + std::string HeaderFile = testPath("a.h"); + std::string HeaderContents = llvm::formatv("#line 0 \"{0}\"", MainFile); + HeaderContents += R"cpp( +#line 3 +#include +#line 5 +#include +#include )cpp"; + FS.Files[HeaderFile] = HeaderContents; + + EXPECT_THAT(collectIncludes().MainFileIncludes, + UnorderedElementsAre(AllOf(IncludeLine(1), Written("\"a.h\"")), + AllOf(IncludeLine(2), Written("")), + AllOf(IncludeLine(4), Written("")), + AllOf(IncludeLine(5), Written("")))); +} } // namespace } // namespace clangd } // namespace clang