https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/151624
>From f7e79ed934bcb05548b6a4d303d6ed6284648f35 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Fri, 1 Aug 2025 01:19:18 -0700 Subject: [PATCH] [libtooling] Insert headers in global module fragment --- .../lib/Tooling/Inclusions/HeaderIncludes.cpp | 22 ++++- .../unittests/Tooling/HeaderIncludesTest.cpp | 81 +++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp index 2b5a293b35841..2ad0c8b1ff135 100644 --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -74,6 +74,15 @@ void skipComments(Lexer &Lex, Token &Tok) { return; } +bool checkAndConsumeModuleDecl(const SourceManager &SM, Lexer &Lex, + Token &Tok) { + bool Matched = Tok.is(tok::raw_identifier) && + Tok.getRawIdentifier() == "module" && + !Lex.LexFromRawLexer(Tok) && Tok.is(tok::semi) && + !Lex.LexFromRawLexer(Tok); + return Matched; +} + // Returns the offset after header guard directives and any comments // before/after header guards (e.g. #ifndef/#define pair, #pragma once). If no // header guard is present in the code, this will return the offset after @@ -95,7 +104,17 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName, return std::max(InitialOffset, Consume(SM, Lex, Tok)); }); }; - return std::max( + + auto ModuleDecl = ConsumeHeaderGuardAndComment( + [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned { + if (checkAndConsumeModuleDecl(SM, Lex, Tok)) { + skipComments(Lex, Tok); + return SM.getFileOffset(Tok.getLocation()); + } + return 0; + }); + + auto HeaderAndPPOffset = std::max( // #ifndef/#define ConsumeHeaderGuardAndComment( [](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned { @@ -115,6 +134,7 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName, return SM.getFileOffset(Tok.getLocation()); return 0; })); + return std::max(HeaderAndPPOffset, ModuleDecl); } // Check if a sequence of tokens is like diff --git a/clang/unittests/Tooling/HeaderIncludesTest.cpp b/clang/unittests/Tooling/HeaderIncludesTest.cpp index 929156a11d0d9..9308513225d9a 100644 --- a/clang/unittests/Tooling/HeaderIncludesTest.cpp +++ b/clang/unittests/Tooling/HeaderIncludesTest.cpp @@ -594,6 +594,87 @@ TEST_F(HeaderIncludesTest, CanDeleteAfterCode) { EXPECT_EQ(Expected, remove(Code, "\"b.h\"")); } +TEST_F(HeaderIncludesTest, InsertInGlobalModuleFragment) { + // Ensure header insertions go only in the global module fragment + std::string Code = R"cpp(// comments + +// more comments + +module; +export module foo; + +int main() { + std::vector<int> ints {}; +})cpp"; + std::string Expected = R"cpp(// comments + +// more comments + +module; +#include <vector> +export module foo; + +int main() { + std::vector<int> ints {}; +})cpp"; + + auto InsertedCode = insert(Code, "<vector>"); + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + +TEST_F(HeaderIncludesTest, InsertInGlobalModuleFragmentWithPP) { + // Ensure header insertions go only in the global module fragment + std::string Code = R"cpp(// comments + +// more comments + +// some more comments + +module; + +#ifndef MACRO_NAME +#define MACRO_NAME +#endif + +// comment + +#ifndef MACRO_NAME +#define MACRO_NAME +#endif + +// more comment + +int main() { + std::vector<int> ints {}; +})cpp"; + std::string Expected = R"cpp(// comments + +// more comments + +// some more comments + +module; + +#include <vector> +#ifndef MACRO_NAME +#define MACRO_NAME +#endif + +// comment + +#ifndef MACRO_NAME +#define MACRO_NAME +#endif + +// more comment + +int main() { + std::vector<int> ints {}; +})cpp"; + + EXPECT_EQ(Expected, insert(Code, "<vector>")); +} + } // namespace } // namespace tooling } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits