Skip to content

Commit f3a815a

Browse files
committed
[clangd] Map references from include'd files to directives
Differential Revision: https://reviews.llvm.org/D147139
1 parent c75e266 commit f3a815a

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

clang-tools-extra/clangd/IncludeCleaner.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@
5151
#include "llvm/Support/FormatVariadic.h"
5252
#include "llvm/Support/Path.h"
5353
#include "llvm/Support/Regex.h"
54+
#include <cassert>
5455
#include <iterator>
5556
#include <optional>
5657
#include <string>
58+
#include <utility>
5759
#include <vector>
5860

5961
namespace clang {
@@ -266,7 +268,6 @@ std::vector<Diag> generateUnusedIncludeDiagnostics(
266268
}
267269
} // namespace
268270

269-
270271
std::vector<include_cleaner::SymbolReference>
271272
collectMacroReferences(ParsedAST &AST) {
272273
const auto &SM = AST.getSourceManager();
@@ -398,6 +399,10 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
398399
// FIXME: Use presumed locations to map such usages back to patched
399400
// locations safely.
400401
auto Loc = SM.getFileLoc(Ref.RefLocation);
402+
// File locations can be outside of the main file if macro is expanded
403+
// through an #include.
404+
while (SM.getFileID(Loc) != SM.getMainFileID())
405+
Loc = SM.getIncludeLoc(SM.getFileID(Loc));
401406
const auto *Token = AST.getTokens().spelledTokenAt(Loc);
402407
MissingIncludeDiagInfo DiagInfo{Ref.Target, Token->range(SM),
403408
Providers};

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,35 @@ TEST(IncludeCleaner, UmbrellaUsesPrivate) {
384384
EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
385385
}
386386

387+
TEST(IncludeCleaner, MacroExpandedThroughIncludes) {
388+
Annotations MainFile(R"cpp(
389+
#include "all.h"
390+
#define FOO(X) const Foo *X
391+
void foo() {
392+
#include [["expander.inc"]]
393+
}
394+
)cpp");
395+
396+
TestTU TU;
397+
TU.AdditionalFiles["expander.inc"] = guard("FOO(f1);FOO(f2);");
398+
TU.AdditionalFiles["foo.h"] = guard("struct Foo {};");
399+
TU.AdditionalFiles["all.h"] = guard("#include \"foo.h\"");
400+
401+
TU.Code = MainFile.code();
402+
ParsedAST AST = TU.build();
403+
404+
auto Findings = computeIncludeCleanerFindings(AST).MissingIncludes;
405+
// FIXME: Deduplicate references resulting from expansion of the same macro in
406+
// multiple places.
407+
EXPECT_THAT(Findings, testing::SizeIs(2));
408+
auto RefRange = Findings.front().SymRefRange;
409+
auto &SM = AST.getSourceManager();
410+
EXPECT_EQ(RefRange.file(), SM.getMainFileID());
411+
// FIXME: Point at the spelling location, rather than the include.
412+
EXPECT_EQ(halfOpenToRange(SM, RefRange.toCharRange(SM)), MainFile.range());
413+
EXPECT_EQ(RefRange, Findings[1].SymRefRange);
414+
}
415+
387416
} // namespace
388417
} // namespace clangd
389418
} // namespace clang

0 commit comments

Comments
 (0)