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 @@ -121,7 +121,8 @@ if (!Macros.insert(FID).second) return; const auto &Exp = SM.getSLocEntry(FID).getExpansion(); - add(Exp.getSpellingLoc()); + if (!SM.isWrittenInScratchSpace(Exp.getSpellingLoc())) + add(Exp.getSpellingLoc()); add(Exp.getExpansionLocStart()); add(Exp.getExpansionLocEnd()); } 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 @@ -167,6 +167,29 @@ UnorderedElementsAre("\"unused.h\"", "\"dir/unused.h\"")); } +TEST(IncludeCleaner, ScratchBuffer) { + TestTU TU; + TU.Filename = "foo.cpp"; + TU.Code = R"cpp( + #include "macro_spelling_in_scratch_buffer.h" + + using flags::FLAGS_FOO; + )cpp"; + // The pasting operator in combination with DEFINE_FLAG will create + // ScratchBuffer with `flags::FLAGS_FOO` that will have FileID but not + // FileEntry. + TU.AdditionalFiles["macro_spelling_in_scratch_buffer.h"] = R"cpp( + #define DEFINE_FLAG(X) \ + namespace flags { \ + int FLAGS_##X; \ + } \ + + DEFINE_FLAG(FOO) + )cpp"; + ParsedAST AST = TU.build(); + EXPECT_THAT(computeUnusedIncludes(AST), testing::IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang