diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h --- a/clang-tools-extra/clangd/Headers.h +++ b/clang-tools-extra/clangd/Headers.h @@ -52,11 +52,11 @@ // An #include directive that we found in the main file. struct Inclusion { - Range R; // Inclusion range. tok::PPKeywordKind Directive; // Directive used for inclusion, e.g. import std::string Written; // Inclusion name as written e.g. . Path Resolved; // Resolved path of included file. Empty if not resolved. unsigned HashOffset = 0; // Byte offset from start of file to #. + int HashLine = 0; // Line number containing the directive, 0-indexed. SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User; }; llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Inclusion &); 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 @@ -38,11 +38,12 @@ if (isInsideMainFile(HashLoc, SM)) { Out->MainFileIncludes.emplace_back(); auto &Inc = Out->MainFileIncludes.back(); - Inc.R = halfOpenToRange(SM, FilenameRange); Inc.Written = (IsAngled ? "<" + FileName + ">" : "\"" + FileName + "\"").str(); Inc.Resolved = std::string(File ? File->tryGetRealPathName() : ""); Inc.HashOffset = SM.getFileOffset(HashLoc); + Inc.HashLine = + SM.getLineNumber(SM.getFileID(HashLoc), Inc.HashOffset) - 1; Inc.FileKind = FileKind; Inc.Directive = IncludeTok.getIdentifierInfo()->getPPKeywordID(); } @@ -228,8 +229,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Inclusion &Inc) { return OS << Inc.Written << " = " - << (!Inc.Resolved.empty() ? Inc.Resolved : "[unresolved]") << " at " - << Inc.R; + << (!Inc.Resolved.empty() ? Inc.Resolved : "[unresolved]") + << " at line" << Inc.HashLine; } } // namespace clangd diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -187,7 +187,7 @@ ParsedAST &AST, llvm::StringRef MainFilePath) { for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { - if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) { + if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) { LocatedSymbol File; File.Name = std::string(llvm::sys::path::filename(Inc.Resolved)); File.PreferredDeclaration = { @@ -599,10 +599,23 @@ std::vector Result; for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { - if (!Inc.Resolved.empty()) { - Result.push_back(DocumentLink( - {Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)})); - } + if (Inc.Resolved.empty()) + continue; + auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset); + const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc); + assert(HashTok && "got inclusion at wrong offset"); + const auto *IncludeTok = std::next(HashTok); + const auto *FileTok = std::next(IncludeTok); + // FileTok->range is not sufficient here, as raw lexing wouldn't yield + // correct tokens for angled filenames. Hence we explicitly use + // Inc.Written's length. + auto FileRange = + syntax::FileRange(SM, FileTok->location(), Inc.Written.length()) + .toCharRange(SM); + + Result.push_back( + DocumentLink({halfOpenToRange(SM, FileRange), + URIForFile::canonicalize(Inc.Resolved, *MainFilePath)})); } return Result; 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 @@ -127,7 +127,7 @@ MATCHER_P(Written, Name, "") { return arg.Written == Name; } MATCHER_P(Resolved, Name, "") { return arg.Resolved == Name; } -MATCHER_P(IncludeLine, N, "") { return arg.R.start.line == N; } +MATCHER_P(IncludeLine, N, "") { return arg.HashLine == N; } MATCHER_P(Directive, D, "") { return arg.Directive == D; } MATCHER_P2(Distance, File, D, "") { diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1490,14 +1490,15 @@ TEST(DocumentLinks, All) { Annotations MainCpp(R"cpp( - #include $foo[["foo.h"]] + #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments int end_of_preamble = 0; - #include $bar[["bar.h"]] + #include $bar[[]] )cpp"); TestTU TU; TU.Code = std::string(MainCpp.code()); TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}}; + TU.ExtraArgs = {"-isystem."}; auto AST = TU.build(); EXPECT_THAT(