Skip to content

Commit f7e79ed

Browse files
committed
[libtooling] Insert headers in global module fragment
1 parent 7d815c7 commit f7e79ed

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed

clang/lib/Tooling/Inclusions/HeaderIncludes.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ void skipComments(Lexer &Lex, Token &Tok) {
7474
return;
7575
}
7676

77+
bool checkAndConsumeModuleDecl(const SourceManager &SM, Lexer &Lex,
78+
Token &Tok) {
79+
bool Matched = Tok.is(tok::raw_identifier) &&
80+
Tok.getRawIdentifier() == "module" &&
81+
!Lex.LexFromRawLexer(Tok) && Tok.is(tok::semi) &&
82+
!Lex.LexFromRawLexer(Tok);
83+
return Matched;
84+
}
85+
7786
// Returns the offset after header guard directives and any comments
7887
// before/after header guards (e.g. #ifndef/#define pair, #pragma once). If no
7988
// header guard is present in the code, this will return the offset after
@@ -95,7 +104,17 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
95104
return std::max(InitialOffset, Consume(SM, Lex, Tok));
96105
});
97106
};
98-
return std::max(
107+
108+
auto ModuleDecl = ConsumeHeaderGuardAndComment(
109+
[](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
110+
if (checkAndConsumeModuleDecl(SM, Lex, Tok)) {
111+
skipComments(Lex, Tok);
112+
return SM.getFileOffset(Tok.getLocation());
113+
}
114+
return 0;
115+
});
116+
117+
auto HeaderAndPPOffset = std::max(
99118
// #ifndef/#define
100119
ConsumeHeaderGuardAndComment(
101120
[](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
@@ -115,6 +134,7 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
115134
return SM.getFileOffset(Tok.getLocation());
116135
return 0;
117136
}));
137+
return std::max(HeaderAndPPOffset, ModuleDecl);
118138
}
119139

120140
// Check if a sequence of tokens is like

clang/unittests/Tooling/HeaderIncludesTest.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,87 @@ TEST_F(HeaderIncludesTest, CanDeleteAfterCode) {
594594
EXPECT_EQ(Expected, remove(Code, "\"b.h\""));
595595
}
596596

597+
TEST_F(HeaderIncludesTest, InsertInGlobalModuleFragment) {
598+
// Ensure header insertions go only in the global module fragment
599+
std::string Code = R"cpp(// comments
600+
601+
// more comments
602+
603+
module;
604+
export module foo;
605+
606+
int main() {
607+
std::vector<int> ints {};
608+
})cpp";
609+
std::string Expected = R"cpp(// comments
610+
611+
// more comments
612+
613+
module;
614+
#include <vector>
615+
export module foo;
616+
617+
int main() {
618+
std::vector<int> ints {};
619+
})cpp";
620+
621+
auto InsertedCode = insert(Code, "<vector>");
622+
EXPECT_EQ(Expected, insert(Code, "<vector>"));
623+
}
624+
625+
TEST_F(HeaderIncludesTest, InsertInGlobalModuleFragmentWithPP) {
626+
// Ensure header insertions go only in the global module fragment
627+
std::string Code = R"cpp(// comments
628+
629+
// more comments
630+
631+
// some more comments
632+
633+
module;
634+
635+
#ifndef MACRO_NAME
636+
#define MACRO_NAME
637+
#endif
638+
639+
// comment
640+
641+
#ifndef MACRO_NAME
642+
#define MACRO_NAME
643+
#endif
644+
645+
// more comment
646+
647+
int main() {
648+
std::vector<int> ints {};
649+
})cpp";
650+
std::string Expected = R"cpp(// comments
651+
652+
// more comments
653+
654+
// some more comments
655+
656+
module;
657+
658+
#include <vector>
659+
#ifndef MACRO_NAME
660+
#define MACRO_NAME
661+
#endif
662+
663+
// comment
664+
665+
#ifndef MACRO_NAME
666+
#define MACRO_NAME
667+
#endif
668+
669+
// more comment
670+
671+
int main() {
672+
std::vector<int> ints {};
673+
})cpp";
674+
675+
EXPECT_EQ(Expected, insert(Code, "<vector>"));
676+
}
677+
597678
} // namespace
598679
} // namespace tooling
599680
} // namespace clang

0 commit comments

Comments
 (0)