Skip to content

Commit 147bce7

Browse files
frayienAdrien Garbani
andauthored
[clangd] textDocument/documentLink to support include statements with macro argument (#137550)
See issue clangd/clangd#2375 The clangd textDocument/documentLink request does not support include statements with macro argument and fails by returning an invalid range. This PR adds support for macro argument by detecting what form of include statement is currently being processed and returning a range accordingly First time contributing to LLVM, so if you have advice, questions or if I messed up procedure please tell me ! --------- Co-authored-by: Adrien Garbani <[email protected]>
1 parent f1ca88c commit 147bce7

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -859,17 +859,47 @@ std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
859859
for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
860860
if (Inc.Resolved.empty())
861861
continue;
862+
863+
// Get the ___location of the # symbole of the "#include ..." statement
862864
auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
865+
866+
// get the # Token itself, std::next to get the "include" token and the
867+
// first token after (aka "File Token")
863868
const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
864869
assert(HashTok && "got inclusion at wrong offset");
865870
const auto *IncludeTok = std::next(HashTok);
866871
const auto *FileTok = std::next(IncludeTok);
867-
// FileTok->range is not sufficient here, as raw lexing wouldn't yield
868-
// correct tokens for angled filenames. Hence we explicitly use
869-
// Inc.Written's length.
870-
auto FileRange =
871-
syntax::FileRange(SM, FileTok->___location(), Inc.Written.length())
872-
.toCharRange(SM);
872+
873+
// The File Token can either be of kind :
874+
// "less" if using the "#include <h-char-sequence> new-line" syntax
875+
// "string_literal" if using the "#include "q-char-sequence" new-line"
876+
// syntax something else (most likely "identifier") if using the "#include
877+
// pp-tokens new-line" syntax (#include with macro argument)
878+
879+
CharSourceRange FileRange;
880+
881+
if (FileTok->kind() == tok::TokenKind::less) {
882+
// FileTok->range would only include the '<' char. Hence we explicitly use
883+
// Inc.Written's length.
884+
FileRange =
885+
syntax::FileRange(SM, FileTok->___location(), Inc.Written.length())
886+
.toCharRange(SM);
887+
} else if (FileTok->kind() == tok::TokenKind::string_literal) {
888+
// FileTok->range includes the quotes for string literals so just return
889+
// it.
890+
FileRange = FileTok->range(SM).toCharRange(SM);
891+
} else {
892+
// FileTok is the first Token of a macro spelling
893+
894+
// Report the range of the first token (as it should be the macro
895+
// identifier)
896+
// We could use the AST to find the last spelled token of the macro and
897+
// report a range spanning the full macro expression, but it would require
898+
// using token-buffers that are deemed too unstable and crash-prone
899+
// due to optimizations in cland
900+
901+
FileRange = FileTok->range(SM).toCharRange(SM);
902+
}
873903

874904
Result.push_back(
875905
DocumentLink({halfOpenToRange(SM, FileRange),

clang-tools-extra/clangd/unittests/XRefsTests.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,14 +2784,24 @@ TEST(GetNonLocalDeclRefs, All) {
27842784

27852785
TEST(DocumentLinks, All) {
27862786
Annotations MainCpp(R"cpp(
2787+
#define HEADER_AA "faa.h"
2788+
#define HEADER_BB "fbb.h"
2789+
#define GET_HEADER(X) HEADER_ ## X
2790+
27872791
#/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
27882792
int end_of_preamble = 0;
27892793
#include $bar[[<bar.h>]]
2794+
#include $AA[[GET_HEADER]](AA) // Some comment !
2795+
# /* What about */ \
2796+
include /* multiple line */ \
2797+
$BB[[GET_HEADER]]( /* statements ? */ \
2798+
BB /* :) */ )
27902799
)cpp");
27912800

27922801
TestTU TU;
27932802
TU.Code = std::string(MainCpp.code());
2794-
TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}};
2803+
TU.AdditionalFiles = {
2804+
{"faa.h", ""}, {"fbb.h", ""}, {"foo.h", ""}, {"bar.h", ""}};
27952805
TU.ExtraArgs = {"-isystem."};
27962806
auto AST = TU.build();
27972807

@@ -2801,7 +2811,11 @@ TEST(DocumentLinks, All) {
28012811
DocumentLink({MainCpp.range("foo"),
28022812
URIForFile::canonicalize(testPath("foo.h"), "")}),
28032813
DocumentLink({MainCpp.range("bar"),
2804-
URIForFile::canonicalize(testPath("bar.h"), "")})));
2814+
URIForFile::canonicalize(testPath("bar.h"), "")}),
2815+
DocumentLink({MainCpp.range("AA"),
2816+
URIForFile::canonicalize(testPath("faa.h"), "")}),
2817+
DocumentLink({MainCpp.range("BB"),
2818+
URIForFile::canonicalize(testPath("fbb.h"), "")})));
28052819
}
28062820

28072821
} // namespace

0 commit comments

Comments
 (0)