Skip to content

Commit 7dd2f1c

Browse files
authored
[clang-format] Add IndentPPDirectives Leave option (#139750)
Allow an option to leave preprocessor directive indenting as-is. This simplifies handling mixed styles of CPP directive indentation. Fixes #38511
1 parent 4338491 commit 7dd2f1c

File tree

10 files changed

+136
-25
lines changed

10 files changed

+136
-25
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4426,6 +4426,21 @@ the configuration (without a prefix: ``Auto``).
44264426
#endif
44274427
#endif
44284428

4429+
* ``PPDIS_Leave`` (in configuration: ``Leave``)
4430+
Leaves indentation of directives as-is.
4431+
4432+
.. note::
4433+
4434+
Ignores ``PPIndentWidth``.
4435+
4436+
.. code-block:: c++
4437+
4438+
#if FOO
4439+
#if BAR
4440+
#include <foo>
4441+
#endif
4442+
#endif
4443+
44294444

44304445

44314446
.. _IndentRequiresClause:

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ clang-format
475475
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
476476
- Add ``NumericLiteralCase`` option for enforcing character case in numeric
477477
literals.
478+
- Add ``Leave`` suboption to ``IndentPPDirectives``.
478479

479480
libclang
480481
--------

clang/include/clang/Format/Format.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2976,7 +2976,19 @@ struct FormatStyle {
29762976
/// #endif
29772977
/// #endif
29782978
/// \endcode
2979-
PPDIS_BeforeHash
2979+
PPDIS_BeforeHash,
2980+
/// Leaves indentation of directives as-is.
2981+
/// \note
2982+
/// Ignores ``PPIndentWidth``.
2983+
/// \endnote
2984+
/// \code
2985+
/// #if FOO
2986+
/// #if BAR
2987+
/// #include <foo>
2988+
/// #endif
2989+
/// #endif
2990+
/// \endcode
2991+
PPDIS_Leave
29802992
};
29812993

29822994
/// The preprocessor directive indenting style to use.

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -780,19 +780,21 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
780780

781781
// Indent preprocessor directives after the hash if required.
782782
int PPColumnCorrection = 0;
783-
if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash &&
784-
Previous.is(tok::hash) && State.FirstIndent > 0 &&
785-
&Previous == State.Line->First &&
783+
if (&Previous == State.Line->First && Previous.is(tok::hash) &&
786784
(State.Line->Type == LT_PreprocessorDirective ||
787785
State.Line->Type == LT_ImportStatement)) {
788-
Spaces += State.FirstIndent;
789-
790-
// For preprocessor indent with tabs, State.Column will be 1 because of the
791-
// hash. This causes second-level indents onward to have an extra space
792-
// after the tabs. We avoid this misalignment by subtracting 1 from the
793-
// column value passed to replaceWhitespace().
794-
if (Style.UseTab != FormatStyle::UT_Never)
795-
PPColumnCorrection = -1;
786+
if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) {
787+
Spaces += State.FirstIndent;
788+
789+
// For preprocessor indent with tabs, State.Column will be 1 because of
790+
// the hash. This causes second-level indents onward to have an extra
791+
// space after the tabs. We avoid this misalignment by subtracting 1 from
792+
// the column value passed to replaceWhitespace().
793+
if (Style.UseTab != FormatStyle::UT_Never)
794+
PPColumnCorrection = -1;
795+
} else if (Style.IndentPPDirectives == FormatStyle::PPDIS_Leave) {
796+
Spaces += Current.OriginalColumn - Previous.OriginalColumn - 1;
797+
}
796798
}
797799

798800
if (!DryRun) {

clang/lib/Format/Format.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
535535
IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
536536
IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
537537
IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash);
538+
IO.enumCase(Value, "Leave", FormatStyle::PPDIS_Leave);
538539
}
539540
};
540541

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3627,7 +3627,7 @@ void TokenAnnotator::setCommentLineLevels(
36273627
// Align comments for preprocessor lines with the # in column 0 if
36283628
// preprocessor lines are not indented. Otherwise, align with the next
36293629
// line.
3630-
Line->Level = Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
3630+
Line->Level = Style.IndentPPDirectives < FormatStyle::PPDIS_BeforeHash &&
36313631
PPDirectiveOrImportStmt
36323632
? 0
36333633
: NextNonCommentLine->Level;

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,16 @@ class LevelIndentTracker {
6262
// having the right size in adjustToUnmodifiedline.
6363
if (Line.Level >= IndentForLevel.size())
6464
IndentForLevel.resize(Line.Level + 1, -1);
65-
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
66-
(Line.InPPDirective ||
67-
(Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
68-
Line.Type == LT_CommentAbovePPDirective))) {
65+
if (Style.IndentPPDirectives == FormatStyle::PPDIS_Leave &&
66+
(Line.InPPDirective || Line.Type == LT_CommentAbovePPDirective)) {
67+
Indent = Line.InMacroBody
68+
? (Line.Level - Line.PPLevel) * Style.IndentWidth +
69+
AdditionalIndent
70+
: Line.First->OriginalColumn;
71+
} else if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
72+
(Line.InPPDirective ||
73+
(Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
74+
Line.Type == LT_CommentAbovePPDirective))) {
6975
unsigned PPIndentWidth =
7076
(Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
7177
Indent = Line.InMacroBody
@@ -1656,7 +1662,7 @@ void UnwrappedLineFormatter::formatFirstToken(
16561662
// Preprocessor directives get indented before the hash only if specified. In
16571663
// Javascript import statements are indented like normal statements.
16581664
if (!Style.isJavaScript() &&
1659-
Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
1665+
Style.IndentPPDirectives < FormatStyle::PPDIS_BeforeHash &&
16601666
(Line.Type == LT_PreprocessorDirective ||
16611667
Line.Type == LT_ImportStatement)) {
16621668
Indent = 0;

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,13 @@ UnwrappedLineParser::UnwrappedLineParser(
162162
LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords),
163163
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
164164
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
165-
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
166-
? IG_Rejected
167-
: IG_Inited),
165+
IncludeGuard(getIncludeGuardState(Style.IndentPPDirectives)),
168166
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn),
169167
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {}
170168

171169
void UnwrappedLineParser::reset() {
172170
PPBranchLevel = -1;
173-
IncludeGuard = Style.IndentPPDirectives == FormatStyle::PPDIS_None
174-
? IG_Rejected
175-
: IG_Inited;
171+
IncludeGuard = getIncludeGuardState(Style.IndentPPDirectives);
176172
IncludeGuardToken = nullptr;
177173
Line.reset(new UnwrappedLine);
178174
CommentsBeforeNextToken.clear();
@@ -1140,7 +1136,7 @@ void UnwrappedLineParser::parsePPEndIf() {
11401136
// If the #endif of a potential include guard is the last thing in the file,
11411137
// then we found an include guard.
11421138
if (IncludeGuard == IG_Defined && PPBranchLevel == -1 && Tokens->isEOF() &&
1143-
Style.IndentPPDirectives != FormatStyle::PPDIS_None) {
1139+
getIncludeGuardState(Style.IndentPPDirectives) == IG_Inited) {
11441140
IncludeGuard = IG_Found;
11451141
}
11461142
}

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,13 @@ class UnwrappedLineParser {
397397
// Current state of include guard search.
398398
IncludeGuardState IncludeGuard;
399399

400+
IncludeGuardState
401+
getIncludeGuardState(FormatStyle::PPDirectiveIndentStyle Style) const {
402+
return Style == FormatStyle::PPDIS_None || Style == FormatStyle::PPDIS_Leave
403+
? IG_Rejected
404+
: IG_Inited;
405+
}
406+
400407
// Points to the #ifndef condition for a potential include guard. Null unless
401408
// IncludeGuardState == IG_IfNdefed.
402409
FormatToken *IncludeGuardToken;

clang/unittests/Format/FormatTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5564,6 +5564,63 @@ TEST_F(FormatTest, IndentsPPDirectiveWithPPIndentWidth) {
55645564
" }",
55655565
style);
55665566

5567+
style.IndentPPDirectives = FormatStyle::PPDIS_Leave;
5568+
style.IndentWidth = 4;
5569+
verifyNoChange("#ifndef foo\n"
5570+
"#define foo\n"
5571+
"if (emacs) {\n"
5572+
"#ifdef is\n"
5573+
"#define lit \\\n"
5574+
" if (af) { \\\n"
5575+
" return duh(); \\\n"
5576+
" }\n"
5577+
"#endif\n"
5578+
"}\n"
5579+
"#endif",
5580+
style);
5581+
verifyNoChange("#ifndef foo\n"
5582+
" #define foo\n"
5583+
"if (emacs) {\n"
5584+
" #ifdef is\n"
5585+
"#define lit \\\n"
5586+
" if (af) { \\\n"
5587+
" return duh(); \\\n"
5588+
" }\n"
5589+
" #endif\n"
5590+
"}\n"
5591+
"#endif",
5592+
style);
5593+
verifyNoChange(" #ifndef foo\n"
5594+
"# define foo\n"
5595+
"if (emacs) {\n"
5596+
"#ifdef is\n"
5597+
" # define lit \\\n"
5598+
" if (af) { \\\n"
5599+
" return duh(); \\\n"
5600+
" }\n"
5601+
"#endif\n"
5602+
"}\n"
5603+
" #endif",
5604+
style);
5605+
verifyNoChange("#ifdef foo\n"
5606+
"#else\n"
5607+
"/* This is a comment */\n"
5608+
"#ifdef BAR\n"
5609+
"#endif\n"
5610+
"#endif",
5611+
style);
5612+
5613+
style.IndentWidth = 1;
5614+
style.PPIndentWidth = 4;
5615+
verifyNoChange("# if 1\n"
5616+
" #define X \\\n"
5617+
" { \\\n"
5618+
" x; \\\n"
5619+
" x; \\\n"
5620+
" }\n"
5621+
"# endif",
5622+
style);
5623+
55675624
style.IndentWidth = 4;
55685625
style.PPIndentWidth = 1;
55695626
style.IndentPPDirectives = FormatStyle::PPDIS_AfterHash;
@@ -25597,6 +25654,20 @@ TEST_F(FormatTest, SkipMacroDefinitionBody) {
2559725654
"a",
2559825655
Style);
2559925656

25657+
Style.IndentPPDirectives = FormatStyle::PPDIS_Leave;
25658+
verifyNoChange("#if A\n"
25659+
"#define A a\n"
25660+
"#endif",
25661+
Style);
25662+
verifyNoChange("#if A\n"
25663+
" #define A a\n"
25664+
"#endif",
25665+
Style);
25666+
verifyNoChange("#if A\n"
25667+
"# define A a\n"
25668+
"#endif",
25669+
Style);
25670+
2560025671
// Adjust indendations but don't change the definition.
2560125672
Style.IndentPPDirectives = FormatStyle::PPDIS_None;
2560225673
verifyNoChange("#if A\n"

0 commit comments

Comments
 (0)