Skip to content

Commit 0dc13cd

Browse files
committedFeb 5, 2018
[clang-format] Fixup #include guard indents after parseFile()
Summary: When a preprocessor indent closes after the last line of normal code we do not correctly fixup include guard indents. For example: #ifndef HEADER_H #define HEADER_H #if 1 int i; # define A 0 #endif #endif incorrectly reformats to: #ifndef HEADER_H #define HEADER_H #if 1 int i; # define A 0 # endif #endif To resolve this issue we must fixup levels after parseFile(). Delaying the fixup introduces a new state, so consolidate include guard search state into an enum. Reviewers: krasimir, klimek Reviewed By: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D42035 llvm-svn: 324238
1 parent 0a1ff46 commit 0dc13cd

File tree

3 files changed

+66
-26
lines changed

3 files changed

+66
-26
lines changed
 

‎clang/lib/Format/UnwrappedLineParser.cpp

+35-22
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,15 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
234234
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
235235
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
236236
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
237-
IfNdefCondition(nullptr), FoundIncludeGuardStart(false),
238-
IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {}
237+
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
238+
? IG_Rejected
239+
: IG_Inited),
240+
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn) {}
239241

240242
void UnwrappedLineParser::reset() {
241243
PPBranchLevel = -1;
242-
IfNdefCondition = nullptr;
243-
FoundIncludeGuardStart = false;
244-
IncludeGuardRejected = false;
244+
IncludeGuard = IG_Inited;
245+
IncludeGuardToken = nullptr;
245246
Line.reset(new UnwrappedLine);
246247
CommentsBeforeNextToken.clear();
247248
FormatTok = nullptr;
@@ -264,6 +265,14 @@ void UnwrappedLineParser::parse() {
264265

265266
readToken();
266267
parseFile();
268+
269+
// If we found an include guard then all preprocessor directives (other than
270+
// the guard) are over-indented by one.
271+
if (IncludeGuard == IG_Found)
272+
for (auto &Line : Lines)
273+
if (Line.InPPDirective && Line.Level > 0)
274+
--Line.Level;
275+
267276
// Create line with eof token.
268277
pushToken(FormatTok);
269278
addUnwrappedLine();
@@ -724,26 +733,28 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
724733
// If there's a #ifndef on the first line, and the only lines before it are
725734
// comments, it could be an include guard.
726735
bool MaybeIncludeGuard = IfNDef;
727-
if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard) {
736+
if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
728737
for (auto &Line : Lines) {
729738
if (!Line.Tokens.front().Tok->is(tok::comment)) {
730739
MaybeIncludeGuard = false;
731-
IncludeGuardRejected = true;
740+
IncludeGuard = IG_Rejected;
732741
break;
733742
}
734743
}
735744
}
736745
--PPBranchLevel;
737746
parsePPUnknown();
738747
++PPBranchLevel;
739-
if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard)
740-
IfNdefCondition = IfCondition;
748+
if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
749+
IncludeGuard = IG_IfNdefed;
750+
IncludeGuardToken = IfCondition;
751+
}
741752
}
742753

743754
void UnwrappedLineParser::parsePPElse() {
744755
// If a potential include guard has an #else, it's not an include guard.
745-
if (FoundIncludeGuardStart && PPBranchLevel == 0)
746-
FoundIncludeGuardStart = false;
756+
if (IncludeGuard == IG_Defined && PPBranchLevel == 0)
757+
IncludeGuard = IG_Rejected;
747758
conditionalCompilationAlternative();
748759
if (PPBranchLevel > -1)
749760
--PPBranchLevel;
@@ -757,34 +768,37 @@ void UnwrappedLineParser::parsePPEndIf() {
757768
conditionalCompilationEnd();
758769
parsePPUnknown();
759770
// If the #endif of a potential include guard is the last thing in the file,
760-
// then we count it as a real include guard and subtract one from every
761-
// preprocessor indent.
771+
// then we found an include guard.
762772
unsigned TokenPosition = Tokens->getPosition();
763773
FormatToken *PeekNext = AllTokens[TokenPosition];
764-
if (FoundIncludeGuardStart && PPBranchLevel == -1 && PeekNext->is(tok::eof) &&
774+
if (IncludeGuard == IG_Defined && PPBranchLevel == -1 &&
775+
PeekNext->is(tok::eof) &&
765776
Style.IndentPPDirectives != FormatStyle::PPDIS_None)
766-
for (auto &Line : Lines)
767-
if (Line.InPPDirective && Line.Level > 0)
768-
--Line.Level;
777+
IncludeGuard = IG_Found;
769778
}
770779

771780
void UnwrappedLineParser::parsePPDefine() {
772781
nextToken();
773782

774783
if (FormatTok->Tok.getKind() != tok::identifier) {
784+
IncludeGuard = IG_Rejected;
785+
IncludeGuardToken = nullptr;
775786
parsePPUnknown();
776787
return;
777788
}
778-
if (IfNdefCondition && IfNdefCondition->TokenText == FormatTok->TokenText) {
779-
FoundIncludeGuardStart = true;
789+
790+
if (IncludeGuard == IG_IfNdefed &&
791+
IncludeGuardToken->TokenText == FormatTok->TokenText) {
792+
IncludeGuard = IG_Defined;
793+
IncludeGuardToken = nullptr;
780794
for (auto &Line : Lines) {
781795
if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) {
782-
FoundIncludeGuardStart = false;
796+
IncludeGuard = IG_Rejected;
783797
break;
784798
}
785799
}
786800
}
787-
IfNdefCondition = nullptr;
801+
788802
nextToken();
789803
if (FormatTok->Tok.getKind() == tok::l_paren &&
790804
FormatTok->WhitespaceRange.getBegin() ==
@@ -811,7 +825,6 @@ void UnwrappedLineParser::parsePPUnknown() {
811825
if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash)
812826
Line->Level += PPBranchLevel + 1;
813827
addUnwrappedLine();
814-
IfNdefCondition = nullptr;
815828
}
816829

817830
// Here we blacklist certain tokens that are not usually the first token in an

‎clang/lib/Format/UnwrappedLineParser.h

+17-4
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,23 @@ class UnwrappedLineParser {
248248
// sequence.
249249
std::stack<int> PPChainBranchIndex;
250250

251-
// Contains the #ifndef condition for a potential include guard.
252-
FormatToken *IfNdefCondition;
253-
bool FoundIncludeGuardStart;
254-
bool IncludeGuardRejected;
251+
// Include guard search state. Used to fixup preprocessor indent levels
252+
// so that include guards do not participate in indentation.
253+
enum IncludeGuardState {
254+
IG_Inited,
255+
IG_IfNdefed,
256+
IG_Defined,
257+
IG_Found,
258+
IG_Rejected,
259+
};
260+
261+
// Current state of include guard search.
262+
IncludeGuardState IncludeGuard;
263+
264+
// Points to the #ifndef condition for a potential include guard. Null unless
265+
// IncludeGuardState == IG_IfNdefed.
266+
FormatToken *IncludeGuardToken;
267+
255268
// Contains the first start column where the source begins. This is zero for
256269
// normal source code and may be nonzero when formatting a code fragment that
257270
// does not start at the beginning of the file.

‎clang/unittests/Format/FormatTest.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -2547,6 +2547,20 @@ TEST_F(FormatTest, IndentPreprocessorDirectives) {
25472547
"#elif FOO\n"
25482548
"#endif",
25492549
Style);
2550+
// Non-identifier #define after potential include guard.
2551+
verifyFormat("#ifndef FOO\n"
2552+
"# define 1\n"
2553+
"#endif\n",
2554+
Style);
2555+
// #if closes past last non-preprocessor line.
2556+
verifyFormat("#ifndef FOO\n"
2557+
"#define FOO\n"
2558+
"#if 1\n"
2559+
"int i;\n"
2560+
"# define A 0\n"
2561+
"#endif\n"
2562+
"#endif\n",
2563+
Style);
25502564
// FIXME: This doesn't handle the case where there's code between the
25512565
// #ifndef and #define but all other conditions hold. This is because when
25522566
// the #define line is parsed, UnwrappedLineParser::Lines doesn't hold the

0 commit comments

Comments
 (0)
Please sign in to comment.