Skip to content

Commit c76a9af

Browse files
authored
[clang][Tooling] Choose header insertion ___location in global module fragment (llvm#151624)
Ensures that headers are inserted after `module;` declaration by updating minimum offset.
1 parent 8259be6 commit c76a9af

File tree

2 files changed

+173
-10
lines changed

2 files changed

+173
-10
lines changed

clang/lib/Tooling/Inclusions/HeaderIncludes.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,24 @@ void skipComments(Lexer &Lex, Token &Tok) {
7474
return;
7575
}
7676

77-
// Returns the offset after header guard directives and any comments
78-
// before/after header guards (e.g. #ifndef/#define pair, #pragma once). If no
79-
// header guard is present in the code, this will return the offset after
80-
// skipping all comments from the start of the code.
81-
unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
82-
StringRef Code,
83-
const IncludeStyle &Style) {
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+
86+
// Determines the minimum offset into the file where we want to insert header
87+
// includes. This will be put (when available):
88+
// - after `#pragma once`
89+
// - after header guards (`#ifdef` and `#define`)
90+
// - after opening global module (`module;`)
91+
// - after any comments at the start of the file or immediately following one of
92+
// the above constructs
93+
unsigned getMinHeaderInsertionOffset(StringRef FileName, StringRef Code,
94+
const IncludeStyle &Style) {
8495
// \p Consume returns ___location after header guard or 0 if no header guard is
8596
// found.
8697
auto ConsumeHeaderGuardAndComment =
@@ -95,7 +106,17 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
95106
return std::max(InitialOffset, Consume(SM, Lex, Tok));
96107
});
97108
};
98-
return std::max(
109+
110+
auto ModuleDecl = ConsumeHeaderGuardAndComment(
111+
[](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
112+
if (checkAndConsumeModuleDecl(SM, Lex, Tok)) {
113+
skipComments(Lex, Tok);
114+
return SM.getFileOffset(Tok.getLocation());
115+
}
116+
return 0;
117+
});
118+
119+
auto HeaderAndPPOffset = std::max(
99120
// #ifndef/#define
100121
ConsumeHeaderGuardAndComment(
101122
[](const SourceManager &SM, Lexer &Lex, Token Tok) -> unsigned {
@@ -115,6 +136,7 @@ unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
115136
return SM.getFileOffset(Tok.getLocation());
116137
return 0;
117138
}));
139+
return std::max(HeaderAndPPOffset, ModuleDecl);
118140
}
119141

120142
// Check if a sequence of tokens is like
@@ -280,8 +302,7 @@ const llvm::Regex HeaderIncludes::IncludeRegex(IncludeRegexPattern);
280302
HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
281303
const IncludeStyle &Style)
282304
: FileName(FileName), Code(Code), FirstIncludeOffset(-1),
283-
MinInsertOffset(
284-
getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style)),
305+
MinInsertOffset(getMinHeaderInsertionOffset(FileName, Code, Style)),
285306
MaxInsertOffset(MinInsertOffset +
286307
getMaxHeaderInsertionOffset(
287308
FileName, Code.drop_front(MinInsertOffset), Style)),

clang/unittests/Tooling/HeaderIncludesTest.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,148 @@ 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+
678+
TEST_F(HeaderIncludesTest, InsertInGlobalModuleFragmentWithPPIncludes) {
679+
// Ensure header insertions go only in the global module fragment
680+
std::string Code = R"cpp(// comments
681+
682+
// more comments
683+
684+
// some more comments
685+
686+
module;
687+
688+
#include "header.h"
689+
690+
#include <string>
691+
692+
#ifndef MACRO_NAME
693+
#define MACRO_NAME
694+
#endif
695+
696+
// comment
697+
698+
#ifndef MACRO_NAME
699+
#define MACRO_NAME
700+
#endif
701+
702+
// more comment
703+
704+
int main() {
705+
std::vector<int> ints {};
706+
})cpp";
707+
std::string Expected = R"cpp(// comments
708+
709+
// more comments
710+
711+
// some more comments
712+
713+
module;
714+
715+
#include "header.h"
716+
717+
#include <string>
718+
#include <vector>
719+
720+
#ifndef MACRO_NAME
721+
#define MACRO_NAME
722+
#endif
723+
724+
// comment
725+
726+
#ifndef MACRO_NAME
727+
#define MACRO_NAME
728+
#endif
729+
730+
// more comment
731+
732+
int main() {
733+
std::vector<int> ints {};
734+
})cpp";
735+
736+
EXPECT_EQ(Expected, insert(Code, "<vector>"));
737+
}
738+
597739
} // namespace
598740
} // namespace tooling
599741
} // namespace clang

0 commit comments

Comments
 (0)