diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -379,15 +379,13 @@ Ref.RT != include_cleaner::RefType::Explicit) return; - auto &Tokens = AST.getTokens(); - auto SpelledForExpanded = - Tokens.spelledForExpanded(Tokens.expandedTokens(Ref.RefLocation)); - if (!SpelledForExpanded) + auto ExpansionLoc = SM.getExpansionLoc(Ref.RefLocation); + const auto *Token = AST.getTokens().spelledTokenAt(ExpansionLoc); + if (!Token) return; - auto Range = syntax::Token::range(SM, SpelledForExpanded->front(), - SpelledForExpanded->back()); - MissingIncludeDiagInfo DiagInfo{Ref.Target, Range, Providers}; + MissingIncludeDiagInfo DiagInfo{Ref.Target, Token->range(SM), + Providers}; MissingIncludes.push_back(std::move(DiagInfo)); }); std::vector UnusedIncludes = diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -177,27 +177,34 @@ WithContextValue Ctx(Config::Key, std::move(Cfg)); Annotations MainFile(R"cpp( #include "a.h" +#include "all.h" $insert_b[[]]#include "baz.h" #include "dir/c.h" -$insert_d[[]]#include "fuzz.h" +$insert_d[[]]$insert_foo[[]]#include "fuzz.h" #include "header.h" $insert_foobar[[]]#include $insert_f[[]]$insert_vector[[]] - void foo() { - $b[[b]](); +#define DEF(X) const Foo *X; - ns::$bar[[Bar]] bar; - bar.d(); - $f[[f]](); + void foo() { + $b[[b]](); - // this should not be diagnosed, because it's ignored in the config - buzz(); + ns::$bar[[Bar]] bar; + bar.d(); + $f[[f]](); - $foobar[[foobar]](); + // this should not be diagnosed, because it's ignored in the config + buzz(); - std::$vector[[vector]] v; - })cpp"); + $foobar[[foobar]](); + + std::$vector[[vector]] v; + + int var = $FOO[[FOO]]; + + $DEF[[DEF]](a); +})cpp"); TestTU TU; TU.Filename = "foo.cpp"; @@ -224,6 +231,12 @@ namespace std { class vector {}; } )cpp"); + TU.AdditionalFiles["all.h"] = guard("#include \"foo.h\""); + TU.AdditionalFiles["foo.h"] = guard(R"cpp( + #define FOO 1 + struct Foo{}; + )cpp"); + TU.Code = MainFile.code(); ParsedAST AST = TU.build(); @@ -253,7 +266,15 @@ Diag(MainFile.range("vector"), "No header providing \"std::vector\" is directly included"), withFix(Fix(MainFile.range("insert_vector"), - "#include \n", "#include "))))); + "#include \n", "#include "))), + AllOf(Diag(MainFile.range("FOO"), + "No header providing \"FOO\" is directly included"), + withFix(Fix(MainFile.range("insert_foo"), + "#include \"foo.h\"\n", "#include \"foo.h\""))), + AllOf(Diag(MainFile.range("DEF"), + "No header providing \"Foo\" is directly included"), + withFix(Fix(MainFile.range("insert_foo"), + "#include \"foo.h\"\n", "#include \"foo.h\""))))); } TEST(IncludeCleaner, IWYUPragmas) { diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp --- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp +++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp @@ -33,9 +33,11 @@ tooling::stdlib::Recognizer Recognizer; for (auto *Root : ASTRoots) { walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND, RefType RT) { - if (!SM.isWrittenInMainFile(SM.getSpellingLoc(Loc))) + if (!SM.isWrittenInMainFile(SM.getSpellingLoc(Loc)) && + SM.getDecomposedLoc(SM.getSpellingLoc(Loc)).first != + SM.getPreambleFileID()) return; - // FIXME: Most of the work done here is repetative. It might be useful to + // FIXME: Most of the work done here is repetitive. It might be useful to // have a cache/batching. SymbolReference SymRef{Loc, ND, RT}; return CB(SymRef, headersForSymbol(ND, SM, PI));