Skip to content

Commit a8f46ea

Browse files
author
Adrien Garbani
committed
[clangd] textDocument/documentLink to support include statements with macro argument
1 parent 08beaa8 commit a8f46ea

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -859,17 +859,56 @@ 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+
// We can use the AST to get the macro expansion from the spelling
894+
// starting at FileTok and use the expansion to get all the spelled Tokens
895+
// that expanded to it
896+
897+
auto OptExpansion = AST.getTokens().expansionStartingAt(FileTok);
898+
if (OptExpansion && !OptExpansion->Spelled.empty()) {
899+
// If an expansion was found and has an non-empty spelling, return the
900+
// range from the start of the first Token to the end of the last Token
901+
const auto &LastTok = OptExpansion->Spelled.back();
902+
903+
FileRange = FileTok->range(SM).toCharRange(SM);
904+
const auto EndRange = LastTok.range(SM).toCharRange(SM);
905+
FileRange.setEnd(EndRange.getEnd());
906+
} else {
907+
// We failed to find a macro expansion from the spelling
908+
// fallback to FileTok->range
909+
FileRange = FileTok->range(SM).toCharRange(SM);
910+
}
911+
}
873912

874913
Result.push_back(
875914
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
@@ -2776,14 +2776,24 @@ TEST(GetNonLocalDeclRefs, All) {
27762776

27772777
TEST(DocumentLinks, All) {
27782778
Annotations MainCpp(R"cpp(
2779+
#define HEADER_AA "faa.h"
2780+
#define HEADER_BB "fbb.h"
2781+
#define GET_HEADER(X) HEADER_ ## X
2782+
27792783
#/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
27802784
int end_of_preamble = 0;
27812785
#include $bar[[<bar.h>]]
2786+
#include $AA[[GET_HEADER(AA)]] // Some comment !
2787+
# /* What about */ \
2788+
include /* multiple line */ \
2789+
$BB[[GET_HEADER( /* statements ? */ \
2790+
BB /* >>>> Hey ! Dont go further ! this ')' is the last token of the file ! >>>>*/ )]]
27822791
)cpp");
27832792

27842793
TestTU TU;
27852794
TU.Code = std::string(MainCpp.code());
2786-
TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}};
2795+
TU.AdditionalFiles = {
2796+
{"faa.h", ""}, {"fbb.h", ""}, {"foo.h", ""}, {"bar.h", ""}};
27872797
TU.ExtraArgs = {"-isystem."};
27882798
auto AST = TU.build();
27892799

@@ -2793,7 +2803,11 @@ TEST(DocumentLinks, All) {
27932803
DocumentLink({MainCpp.range("foo"),
27942804
URIForFile::canonicalize(testPath("foo.h"), "")}),
27952805
DocumentLink({MainCpp.range("bar"),
2796-
URIForFile::canonicalize(testPath("bar.h"), "")})));
2806+
URIForFile::canonicalize(testPath("bar.h"), "")}),
2807+
DocumentLink({MainCpp.range("AA"),
2808+
URIForFile::canonicalize(testPath("faa.h"), "")}),
2809+
DocumentLink({MainCpp.range("BB"),
2810+
URIForFile::canonicalize(testPath("fbb.h"), "")})));
27972811
}
27982812

27992813
} // namespace

0 commit comments

Comments
 (0)