https://github.com/turgu1 updated https://github.com/llvm/llvm-project/pull/186686
>From c25fdac05571a44bb9c7e7ec297f7d50afe549c6 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sat, 14 Mar 2026 21:07:36 -0400 Subject: [PATCH 01/14] A new IndentPPDirectives style: BeforeHashWithCode --- clang/include/clang/Format/Format.h | 13 ++++ clang/lib/Format/Format.cpp | 1 + clang/lib/Format/FormatTokenSource.h | 5 +- clang/lib/Format/UnwrappedLineFormatter.cpp | 13 +++- clang/lib/Format/UnwrappedLineFormatter.h | 3 +- clang/lib/Format/UnwrappedLineParser.cpp | 68 +++++++++++++++++---- 6 files changed, 86 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index aea18a836328f..cb25b3a82cd5c 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3247,6 +3247,19 @@ struct FormatStyle { /// #endif /// \endcode PPDIS_BeforeHash, + /// Indents directives before the hash with the current code indentation + /// level. + /// \code + /// if (foo) + /// { + /// #if FOO + /// #if BAR + /// #include <foo> + /// #endif + /// #endif + /// } + /// \endcode + PPDIS_BeforeHashWithCode, /// Leaves indentation of directives as-is. /// \note /// Ignores ``PPIndentWidth``. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b98a9086811cd..563c9ba03adf2 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -622,6 +622,7 @@ struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { IO.enumCase(Value, "None", FormatStyle::PPDIS_None); IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash); + IO.enumCase(Value, "BeforeHashWithCode", FormatStyle::PPDIS_BeforeHashWithCode); IO.enumCase(Value, "Leave", FormatStyle::PPDIS_Leave); } }; diff --git a/clang/lib/Format/FormatTokenSource.h b/clang/lib/Format/FormatTokenSource.h index 8f00e5f4582c6..7ab49542ef099 100644 --- a/clang/lib/Format/FormatTokenSource.h +++ b/clang/lib/Format/FormatTokenSource.h @@ -191,14 +191,15 @@ class IndexedTokenSource : public FormatTokenSource { class ScopedMacroState : public FormatTokenSource { public: ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource, - FormatToken *&ResetToken) + FormatToken *&ResetToken, bool PreserveLevel = false) : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken), PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource), Token(nullptr), PreviousToken(nullptr) { FakeEOF.Tok.startToken(); FakeEOF.Tok.setKind(tok::eof); TokenSource = this; - Line.Level = 0; + if (!PreserveLevel) + Line.Level = 0; Line.InPPDirective = true; // InMacroBody gets set after the `#define x` part. } diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 74c0f4bf75721..f3b1510e3f687 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -68,6 +68,12 @@ class LevelIndentTracker { ? (Line.Level - Line.PPLevel) * Style.IndentWidth + AdditionalIndent : Line.First->OriginalColumn; + } else if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && + Line.InPPDirective && !Line.InMacroBody) { + // For BeforeHashWithCode, PP directives are indented at the surrounding + // code level, using the same indentation as regular code (not PPIndentWidth). + Indent = getIndent(Line.Level); + Indent += AdditionalIndent; } else if (Style.IndentPPDirectives != FormatStyle::PPDIS_None && (Line.InPPDirective || (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && @@ -1467,7 +1473,8 @@ unsigned UnwrappedLineFormatter::format( if (!DryRun) { bool LastLine = TheLine.First->is(tok::eof); formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent, - LastLine ? LastStartColumn : NextStartColumn + Indent); + LastLine ? LastStartColumn : NextStartColumn + Indent, + 0); } NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker); @@ -1516,7 +1523,7 @@ unsigned UnwrappedLineFormatter::format( if (ReformatLeadingWhitespace) { formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, TheLine.First->OriginalColumn, - TheLine.First->OriginalColumn); + TheLine.First->OriginalColumn, 0); } else { Whitespaces->addUntouchableToken(*TheLine.First, TheLine.InPPDirective); @@ -1649,7 +1656,7 @@ void UnwrappedLineFormatter::formatFirstToken( const AnnotatedLine &Line, const AnnotatedLine *PreviousLine, const AnnotatedLine *PrevPrevLine, const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent, - unsigned NewlineIndent) { + unsigned NewlineIndent, unsigned PPNestingLevel) { FormatToken &RootToken = *Line.First; if (RootToken.is(tok::eof)) { unsigned Newlines = std::min( diff --git a/clang/lib/Format/UnwrappedLineFormatter.h b/clang/lib/Format/UnwrappedLineFormatter.h index 9b8acf427a2a0..17889d03644b6 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.h +++ b/clang/lib/Format/UnwrappedLineFormatter.h @@ -47,7 +47,8 @@ class UnwrappedLineFormatter { const AnnotatedLine *PreviousLine, const AnnotatedLine *PrevPrevLine, const SmallVectorImpl<AnnotatedLine *> &Lines, - unsigned Indent, unsigned NewlineIndent); + unsigned Indent, unsigned NewlineIndent, + unsigned PPNestingLevel = 0); /// Returns the column limit for a line, taking into account whether we /// need an escaped newline due to a continued preprocessor directive. diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index ddf584c6ed818..c3ad21cf5291e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -998,7 +998,12 @@ void UnwrappedLineParser::parseChildBlock() { void UnwrappedLineParser::parsePPDirective() { assert(FormatTok->is(tok::hash) && "'#' expected"); - ScopedMacroState MacroState(*Line, Tokens, FormatTok); + // For BeforeHashWithCode, PP directives are indented at the surrounding code + // level. Preserving Line->Level allows ScopedMacroState to keep the code + // context level instead of resetting it to 0. + const bool PreserveLevel = + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; + ScopedMacroState MacroState(*Line, Tokens, FormatTok, PreserveLevel); nextToken(); @@ -4639,7 +4644,27 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { // At the top level we only get here when no unexpansion is going on, or // when conditional formatting led to unfinished macro reconstructions. assert(!Reconstruct || (CurrentLines != &Lines) || !PPStack.empty()); + // For BeforeHashWithCode, code lines inside PP conditional blocks must be + // indented by the PP nesting depth so that code appears more indented than + // its enclosing PP directive (mirroring how C++ block content is indented + // relative to the opening brace). PP directive lines already have + // PPBranchLevel+1 added in parsePPUnknown; code lines need the same + // treatment. We temporarily adjust Level here and restore it afterwards so + // that the next line still starts from the correct C++ brace level. + // For BeforeHashWithCode, code lines inside PP blocks need their level + // raised to match the enclosing PP directive's nesting depth. Using + // Line->PPLevel (set at first-token push time) instead of the current + // PPBranchLevel, which may have been altered by later PP directives that + // readToken processed after the code tokens but before addUnwrappedLine. + const bool BWHCCodeLine = + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && + !Line->InPPDirective && Line->PPLevel > 0; + const unsigned PPAdj = BWHCCodeLine ? Line->PPLevel : 0; + if (BWHCCodeLine) + Line->Level += PPAdj; CurrentLines->push_back(std::move(*Line)); + if (BWHCCodeLine) + Line->Level -= PPAdj; } Line->Tokens.clear(); Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex; @@ -4926,16 +4951,28 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // directives only after that unwrapped line was finished later. bool SwitchToPreprocessorLines = !Line->Tokens.empty(); ScopedLineState BlockState(*this, SwitchToPreprocessorLines); - assert((LevelDifference >= 0 || - static_cast<unsigned>(-LevelDifference) <= Line->Level) && - "LevelDifference makes Line->Level negative"); - Line->Level += LevelDifference; - // Comments stored before the preprocessor directive need to be output - // before the preprocessor directive, at the same level as the - // preprocessor directive, as we consider them to apply to the directive. - if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && - PPBranchLevel > 0) { - Line->Level += PPBranchLevel; + // For BeforeHashWithCode, the PP directive is indented at the surrounding + // code level. Apply LevelDifference to get the correct code context level + // (e.g. leaving a block), but do NOT apply PPBranchLevel since PP + // directives should align with the code rather than nesting PP levels. + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) { + assert((LevelDifference >= 0 || + static_cast<unsigned>(-LevelDifference) <= Line->Level) && + "LevelDifference makes Line->Level negative"); + Line->Level += LevelDifference; + } else { + assert((LevelDifference >= 0 || + static_cast<unsigned>(-LevelDifference) <= Line->Level) && + "LevelDifference makes Line->Level negative"); + Line->Level += LevelDifference; + // Comments stored before the preprocessor directive need to be output + // before the preprocessor directive, at the same level as the + // preprocessor directive, as we consider them to apply to the + // directive. + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && + PPBranchLevel > 0) { + Line->Level += PPBranchLevel; + } } assert(Line->Level >= Line->UnbracedBodyLevel); Line->Level -= Line->UnbracedBodyLevel; @@ -5111,6 +5148,15 @@ UnwrappedLineParser::parseMacroCall() { } void UnwrappedLineParser::pushToken(FormatToken *Tok) { + // For BeforeHashWithCode style, record the actual PP nesting depth when the + // first token of a code (non-PP) line is pushed. This captures the true PP + // context at line-start time, before readToken may subsequently process + // more PP directives and change PPBranchLevel before addUnwrappedLine. + if (Line->Tokens.empty() && !Line->InPPDirective && + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) { + Line->PPLevel = + PPBranchLevel >= 0 ? static_cast<unsigned>(PPBranchLevel + 1) : 0; + } Line->Tokens.push_back(UnwrappedLineNode(Tok)); if (AtEndOfPPLine) { auto &Tok = *Line->Tokens.back().Tok; >From 43a5fe4b85a2c30096722ea92d683fa75df54b2f Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 13:23:36 -0400 Subject: [PATCH 02/14] Some correction --- clang/lib/Format/UnwrappedLineFormatter.cpp | 6 +- clang/lib/Format/UnwrappedLineParser.cpp | 67 ++++++++++++++++++++- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index f3b1510e3f687..ad55a9ee678ea 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -68,10 +68,12 @@ class LevelIndentTracker { ? (Line.Level - Line.PPLevel) * Style.IndentWidth + AdditionalIndent : Line.First->OriginalColumn; - } else if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && + } else if (Style.IndentPPDirectives == + FormatStyle::PPDIS_BeforeHashWithCode && Line.InPPDirective && !Line.InMacroBody) { // For BeforeHashWithCode, PP directives are indented at the surrounding - // code level, using the same indentation as regular code (not PPIndentWidth). + // code level, using the same indentation as regular code (not + // PPIndentWidth). Indent = getIndent(Line.Level); Indent += AdditionalIndent; } else if (Style.IndentPPDirectives != FormatStyle::PPDIS_None && diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index c3ad21cf5291e..34aa92b31f79b 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1237,6 +1237,18 @@ void UnwrappedLineParser::parsePPUnknown() { nextToken(); if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; + // For BeforeHashWithCode, PP directives inside unreachable branches must + // not be emitted: in multi-pass formatting the surrounding C++ braces may + // have been skipped (PP_Unreachable code is not parsed), leaving + // Line->Level too low. The resulting incorrect replacement would conflict + // with the correct one produced by the reachable pass, causing an + // "overlapping replacement" error and an empty output. Simply discard the + // accumulated tokens so the reachable pass wins. + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && + !PPStack.empty() && PPStack.back().Kind == PP_Unreachable) { + Line->Tokens.clear(); + return; + } addUnwrappedLine(); } @@ -2524,11 +2536,30 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { parseChildBlock(); } } + // For BeforeHashWithCode enum bodies: whenever readToken just processed a + // PP directive and returned the first post-PP token (AtEndOfPPLine=true), + // flush the accumulated pre-PP body tokens as their own UnwrappedLine. + // This gives each PP-separated segment its own line so the BWHCCodeLine + // level-boost in addUnwrappedLine can apply the correct indentation. + if (IsEnum && !IsAngleBracket && + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && + Style.AllowShortEnumsOnASingleLine && AtEndOfPPLine && + !Line->Tokens.empty()) { + addUnwrappedLine(); + } if (FormatTok->is(IsAngleBracket ? tok::greater : tok::r_brace)) { if (IsEnum) { FormatTok->setBlockKind(BK_Block); - if (!Style.AllowShortEnumsOnASingleLine) + if (!Style.AllowShortEnumsOnASingleLine) { + addUnwrappedLine(); + } else if (Style.IndentPPDirectives == + FormatStyle::PPDIS_BeforeHashWithCode && + !Line->Tokens.empty()) { + // For BeforeHashWithCode, flush any remaining enum body tokens + // before the closing brace so they get their own UnwrappedLine + // with the correct indentation level. addUnwrappedLine(); + } } nextToken(); return !HasError; @@ -3885,10 +3916,20 @@ bool UnwrappedLineParser::parseEnum() { if (!Style.AllowShortEnumsOnASingleLine) { addUnwrappedLine(); Line->Level += 1; + } else if (Style.IndentPPDirectives == + FormatStyle::PPDIS_BeforeHashWithCode) { + // For BeforeHashWithCode, flush the enum declaration as its own + // UnwrappedLine (like AllowShortEnumsOnASingleLine=false does) so that + // body tokens start in a fresh line. Each PP-separated segment of the + // body can then be emitted at its correct indentation via BWHCCodeLine. + addUnwrappedLine(); + ++Line->Level; } bool HasError = !parseBracedList(/*IsAngleBracket=*/false, /*IsEnum=*/true); if (!Style.AllowShortEnumsOnASingleLine) Line->Level -= 1; + else if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) + --Line->Level; if (HasError) { if (FormatTok->is(tok::semi)) nextToken(); @@ -4950,6 +4991,9 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // If there is an unfinished unwrapped line, we flush the preprocessor // directives only after that unwrapped line was finished later. bool SwitchToPreprocessorLines = !Line->Tokens.empty(); + // Save CurrentLines before ScopedLineState may switch it to + // PreprocessorDirectives, so we can detect child-block contexts later. + const auto *OrigCurrentLines = CurrentLines; ScopedLineState BlockState(*this, SwitchToPreprocessorLines); // For BeforeHashWithCode, the PP directive is indented at the surrounding // code level. Apply LevelDifference to get the correct code context level @@ -4960,16 +5004,33 @@ void UnwrappedLineParser::readToken(int LevelDifference) { static_cast<unsigned>(-LevelDifference) <= Line->Level) && "LevelDifference makes Line->Level negative"); Line->Level += LevelDifference; + // When this PP directive is being deferred to PreprocessorDirectives + // (SwitchToPreprocessorLines=true), it may be encountered at a deeper + // C++ brace nesting than the opening PP directive of the same + // conditional block. This happens inside child-block contexts (e.g. + // lambda bodies): the opening #if is processed by readToken() before + // parseChildBlock()'s ScopedLineState adds +1 to Line->Level, while + // the closing #endif is processed after, giving it a Level one higher + // than the #if. Detect child-block context by checking OrigCurrentLines + // (saved before ScopedLineState may switch CurrentLines): inside a + // child block it points to the parent's token children list rather than + // the top-level Lines vector. Use the level recorded for the first + // deferred directive (the opening #if) so that all directives of the + // same conditional block share the same C++ level. + if (SwitchToPreprocessorLines && !PreprocessorDirectives.empty() && + OrigCurrentLines != &Lines) { + Line->Level = PreprocessorDirectives.front().Level; + } } else { assert((LevelDifference >= 0 || static_cast<unsigned>(-LevelDifference) <= Line->Level) && - "LevelDifference makes Line->Level negative"); + "LevelDifference makes Line->Level negative"); Line->Level += LevelDifference; // Comments stored before the preprocessor directive need to be output // before the preprocessor directive, at the same level as the // preprocessor directive, as we consider them to apply to the // directive. - if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && PPBranchLevel > 0) { Line->Level += PPBranchLevel; } >From 637767a97641209727b19cca8d6affc1585e96f5 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 15:38:42 -0400 Subject: [PATCH 03/14] Corrected line formatting. --- clang/lib/Format/Format.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 8dedab081a55c..787b469f9ccd5 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -622,7 +622,8 @@ struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { IO.enumCase(Value, "None", FormatStyle::PPDIS_None); IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash); - IO.enumCase(Value, "BeforeHashWithCode", FormatStyle::PPDIS_BeforeHashWithCode); + IO.enumCase(Value, "BeforeHashWithCode", + FormatStyle::PPDIS_BeforeHashWithCode); IO.enumCase(Value, "Leave", FormatStyle::PPDIS_Leave); } }; >From 0615fd3b7e1ab7cf098b411b64618da5698aa05c Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 15:46:10 -0400 Subject: [PATCH 04/14] Update clang/lib/Format/UnwrappedLineFormatter.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Björn Schäpers <[email protected]> --- clang/lib/Format/UnwrappedLineFormatter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index e282b0e27da07..15255e0b06d96 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1565,7 +1565,7 @@ unsigned UnwrappedLineFormatter::format( bool LastLine = TheLine.First->is(tok::eof); formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent, LastLine ? LastStartColumn : NextStartColumn + Indent, - 0); + /*PPNestingLevel=*/0); } NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker); >From 9c2e33016a4ac8cef9e6c840dd66294a68eef04a Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 15:46:31 -0400 Subject: [PATCH 05/14] Update clang/lib/Format/UnwrappedLineParser.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Björn Schäpers <[email protected]> --- clang/lib/Format/UnwrappedLineParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index d4af259a54832..db886a5cbc8d0 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2543,7 +2543,7 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { } } // For BeforeHashWithCode enum bodies: whenever readToken just processed a - // PP directive and returned the first post-PP token (AtEndOfPPLine=true), + // PP directive and returned the first post-PP token (AtEndOfPPLine == true), // flush the accumulated pre-PP body tokens as their own UnwrappedLine. // This gives each PP-separated segment its own line so the BWHCCodeLine // level-boost in addUnwrappedLine can apply the correct indentation. >From 9e1a991c167fbe7b2cf8530b9d1849f2370a3d82 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 16:29:09 -0400 Subject: [PATCH 06/14] Corrective actions as requested --- clang/docs/ClangFormatStyleOptions.rst | 18 +++++++++ clang/lib/Format/UnwrappedLineFormatter.cpp | 3 +- clang/lib/Format/UnwrappedLineParser.cpp | 44 ++++++++------------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 342eb0bdb1279..59b0105296211 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4810,6 +4810,24 @@ the configuration (without a prefix: ``Auto``). #endif #endif + * ``PPDIS_BeforeHashWithCode`` (in configuration: ``BeforeHashWithCode``) + Indents directives before the hash and align with the surrounding + C++ indentation level. Code inside a PP conditional block is indented + one further level relative to the directive that guards it. + + .. code-block:: c++ + + enum class Feature { + none, + #if PLATFORM_FULL + wifi, + #ifdef HAS_BLE + ble, + #endif + #endif + basic + }; + * ``PPDIS_Leave`` (in configuration: ``Leave``) Leaves indentation of directives as-is. diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 15255e0b06d96..1a6ecdb680674 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1614,7 +1614,8 @@ unsigned UnwrappedLineFormatter::format( if (ReformatLeadingWhitespace) { formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, TheLine.First->OriginalColumn, - TheLine.First->OriginalColumn, 0); + TheLine.First->OriginalColumn, + /*PPNestingLevel=*/0); } else { Whitespaces->addUntouchableToken(*TheLine.First, TheLine.InPPDirective); diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index db886a5cbc8d0..540eac61e035e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1243,15 +1243,15 @@ void UnwrappedLineParser::parsePPUnknown() { nextToken(); if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; - // For BeforeHashWithCode, PP directives inside unreachable branches must - // not be emitted: in multi-pass formatting the surrounding C++ braces may - // have been skipped (PP_Unreachable code is not parsed), leaving - // Line->Level too low. The resulting incorrect replacement would conflict - // with the correct one produced by the reachable pass, causing an - // "overlapping replacement" error and an empty output. Simply discard the - // accumulated tokens so the reachable pass wins. if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && !PPStack.empty() && PPStack.back().Kind == PP_Unreachable) { + // PP directives inside unreachable branches must + // not be emitted: in multi-pass formatting the surrounding C++ braces may + // have been skipped (PP_Unreachable code is not parsed), leaving + // Line->Level too low. The resulting incorrect replacement would conflict + // with the correct one produced by the reachable pass, causing an + // "overlapping replacement" error and an empty output. Simply discard the + // accumulated tokens so the reachable pass wins. Line->Tokens.clear(); return; } @@ -3922,23 +3922,15 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. nextToken(); - if (!Style.AllowShortEnumsOnASingleLine) { + bool updateLevel = !Style.AllowShortEnumsOnASingleLine || + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; + if (updateLevel) { addUnwrappedLine(); Line->Level += 1; - } else if (Style.IndentPPDirectives == - FormatStyle::PPDIS_BeforeHashWithCode) { - // For BeforeHashWithCode, flush the enum declaration as its own - // UnwrappedLine (like AllowShortEnumsOnASingleLine=false does) so that - // body tokens start in a fresh line. Each PP-separated segment of the - // body can then be emitted at its correct indentation via BWHCCodeLine. - addUnwrappedLine(); - ++Line->Level; } bool HasError = !parseBracedList(/*IsAngleBracket=*/false, /*IsEnum=*/true); - if (!Style.AllowShortEnumsOnASingleLine) + if (updateLevel) Line->Level -= 1; - else if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) - --Line->Level; if (HasError) { if (FormatTok->is(tok::semi)) nextToken(); @@ -4887,9 +4879,9 @@ void UnwrappedLineParser::nextToken(int LevelDifference) { if (Style.isVerilog()) { // Blocks in Verilog can have `begin` and `end` instead of braces. For // keywords like `begin`, we can't treat them the same as left braces - // because some contexts require one of them. For example structs use + // because some contexts require one of them. For example structs use // braces and if blocks use keywords, and a left brace can occur in an if - // statement, but it is not a block. For keywords like `end`, we simply + // statement, but it is not a block. For keywords like `end`, we simply // treat them the same as right braces. if (Keywords.isVerilogEnd(*FormatTok)) FormatTok->Tok.setKind(tok::r_brace); @@ -5011,11 +5003,11 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // code level. Apply LevelDifference to get the correct code context level // (e.g. leaving a block), but do NOT apply PPBranchLevel since PP // directives should align with the code rather than nesting PP levels. - if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) { - assert((LevelDifference >= 0 || + assert((LevelDifference >= 0 || static_cast<unsigned>(-LevelDifference) <= Line->Level) && "LevelDifference makes Line->Level negative"); - Line->Level += LevelDifference; + Line->Level += LevelDifference; + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) { // When this PP directive is being deferred to PreprocessorDirectives // (SwitchToPreprocessorLines=true), it may be encountered at a deeper // C++ brace nesting than the opening PP directive of the same @@ -5034,10 +5026,6 @@ void UnwrappedLineParser::readToken(int LevelDifference) { Line->Level = PreprocessorDirectives.front().Level; } } else { - assert((LevelDifference >= 0 || - static_cast<unsigned>(-LevelDifference) <= Line->Level) && - "LevelDifference makes Line->Level negative"); - Line->Level += LevelDifference; // Comments stored before the preprocessor directive need to be output // before the preprocessor directive, at the same level as the // preprocessor directive, as we consider them to apply to the >From 17b91b627655057c178edfe36d674b78be095d36 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 17:37:46 -0400 Subject: [PATCH 07/14] Code formatting update --- clang/lib/Format/UnwrappedLineFormatter.cpp | 2 +- clang/lib/Format/UnwrappedLineParser.cpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 1a6ecdb680674..df049a525f4d8 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1614,7 +1614,7 @@ unsigned UnwrappedLineFormatter::format( if (ReformatLeadingWhitespace) { formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, TheLine.First->OriginalColumn, - TheLine.First->OriginalColumn, + TheLine.First->OriginalColumn, /*PPNestingLevel=*/0); } else { Whitespaces->addUntouchableToken(*TheLine.First, diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 540eac61e035e..b68af35b59c14 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2543,10 +2543,11 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { } } // For BeforeHashWithCode enum bodies: whenever readToken just processed a - // PP directive and returned the first post-PP token (AtEndOfPPLine == true), - // flush the accumulated pre-PP body tokens as their own UnwrappedLine. - // This gives each PP-separated segment its own line so the BWHCCodeLine - // level-boost in addUnwrappedLine can apply the correct indentation. + // PP directive and returned the first post-PP token (AtEndOfPPLine == + // true), flush the accumulated pre-PP body tokens as their own + // UnwrappedLine. This gives each PP-separated segment its own line so the + // BWHCCodeLine level-boost in addUnwrappedLine can apply the correct + // indentation. if (IsEnum && !IsAngleBracket && Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && Style.AllowShortEnumsOnASingleLine && AtEndOfPPLine && @@ -3922,8 +3923,9 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. nextToken(); - bool updateLevel = !Style.AllowShortEnumsOnASingleLine || - Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; + bool updateLevel = + !Style.AllowShortEnumsOnASingleLine || + Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; if (updateLevel) { addUnwrappedLine(); Line->Level += 1; @@ -5004,8 +5006,8 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // (e.g. leaving a block), but do NOT apply PPBranchLevel since PP // directives should align with the code rather than nesting PP levels. assert((LevelDifference >= 0 || - static_cast<unsigned>(-LevelDifference) <= Line->Level) && - "LevelDifference makes Line->Level negative"); + static_cast<unsigned>(-LevelDifference) <= Line->Level) && + "LevelDifference makes Line->Level negative"); Line->Level += LevelDifference; if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode) { // When this PP directive is being deferred to PreprocessorDirectives >From 360c304e8e8aba0ec2aef17493318213e3abaeee Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 18:14:20 -0400 Subject: [PATCH 08/14] Update format documentation --- clang/include/clang/Format/Format.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index b9e432d560bc5..4b453112caa43 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3356,14 +3356,16 @@ struct FormatStyle { /// Indents directives before the hash with the current code indentation /// level. /// \code - /// if (foo) - /// { - /// #if FOO - /// #if BAR - /// #include <foo> - /// #endif - /// #endif - /// } + /// enum class Feature { + /// none, + /// #if PLATFORM_FULL + /// wifi, + /// #ifdef HAS_BLE + /// ble, + /// #endif + /// #endif + /// basic + /// }; /// \endcode PPDIS_BeforeHashWithCode, /// Leaves indentation of directives as-is. >From 4e37dd08020641be9a20bb7ba9ca22a5d1e68ff7 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 19:48:22 -0400 Subject: [PATCH 09/14] Documentation adjustment --- clang/include/clang/Format/Format.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 4b453112caa43..cd3798eea7596 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3353,8 +3353,9 @@ struct FormatStyle { /// #endif /// \endcode PPDIS_BeforeHash, - /// Indents directives before the hash with the current code indentation - /// level. + /// Indents directives before the hash and align with the surrounding + /// C++ indentation level. Code inside a PP conditional block is indented + /// one further level relative to the directive that guards it. /// \code /// enum class Feature { /// none, >From 81111d6107bf840816799fecc759a5151b286015 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 19:56:02 -0400 Subject: [PATCH 10/14] Renamed BWHCCodeLine to IsACodeLineInsidePPBlock --- clang/lib/Format/UnwrappedLineParser.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index b68af35b59c14..3f9fe40b2e56c 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2546,8 +2546,8 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { // PP directive and returned the first post-PP token (AtEndOfPPLine == // true), flush the accumulated pre-PP body tokens as their own // UnwrappedLine. This gives each PP-separated segment its own line so the - // BWHCCodeLine level-boost in addUnwrappedLine can apply the correct - // indentation. + // IsACodeLineInsidePPBlock level-boost in addUnwrappedLine can apply the + // correct indentation. if (IsEnum && !IsAngleBracket && Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && Style.AllowShortEnumsOnASingleLine && AtEndOfPPLine && @@ -4703,14 +4703,14 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { // Line->PPLevel (set at first-token push time) instead of the current // PPBranchLevel, which may have been altered by later PP directives that // readToken processed after the code tokens but before addUnwrappedLine. - const bool BWHCCodeLine = + const bool IsACodeLineInsidePPBlock = Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && !Line->InPPDirective && Line->PPLevel > 0; - const unsigned PPAdj = BWHCCodeLine ? Line->PPLevel : 0; - if (BWHCCodeLine) + const unsigned PPAdj = IsACodeLineInsidePPBlock ? Line->PPLevel : 0; + if (IsACodeLineInsidePPBlock) Line->Level += PPAdj; CurrentLines->push_back(std::move(*Line)); - if (BWHCCodeLine) + if (IsACodeLineInsidePPBlock) Line->Level -= PPAdj; } Line->Tokens.clear(); >From a41919e570751a1da343b226f63a2a9614a00b23 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Sun, 15 Mar 2026 20:41:57 -0400 Subject: [PATCH 11/14] Blank spaces removal --- clang/include/clang/Format/Format.h | 4 ++-- clang/lib/Format/UnwrappedLineParser.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index cd3798eea7596..e6c8e2170cc74 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3353,8 +3353,8 @@ struct FormatStyle { /// #endif /// \endcode PPDIS_BeforeHash, - /// Indents directives before the hash and align with the surrounding - /// C++ indentation level. Code inside a PP conditional block is indented + /// Indents directives before the hash and align with the surrounding + /// C++ indentation level. Code inside a PP conditional block is indented /// one further level relative to the directive that guards it. /// \code /// enum class Feature { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 3f9fe40b2e56c..d69747a09c542 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2546,7 +2546,7 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { // PP directive and returned the first post-PP token (AtEndOfPPLine == // true), flush the accumulated pre-PP body tokens as their own // UnwrappedLine. This gives each PP-separated segment its own line so the - // IsACodeLineInsidePPBlock level-boost in addUnwrappedLine can apply the + // IsACodeLineInsidePPBlock level-boost in addUnwrappedLine can apply the // correct indentation. if (IsEnum && !IsAngleBracket && Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && >From 1ec3df75ac5a8e849eac577518ce1ea8a18ecdd6 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Mon, 16 Mar 2026 03:29:30 -0400 Subject: [PATCH 12/14] End of line spaces removal --- clang/docs/ClangFormatStyleOptions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 59b0105296211..29a15d4fe31c2 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4811,8 +4811,8 @@ the configuration (without a prefix: ``Auto``). #endif * ``PPDIS_BeforeHashWithCode`` (in configuration: ``BeforeHashWithCode``) - Indents directives before the hash and align with the surrounding - C++ indentation level. Code inside a PP conditional block is indented + Indents directives before the hash and align with the surrounding + C++ indentation level. Code inside a PP conditional block is indented one further level relative to the directive that guards it. .. code-block:: c++ >From 43d7496d37843b69633c075e79765bc380ac956c Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Mon, 16 Mar 2026 03:49:52 -0400 Subject: [PATCH 13/14] Comments update --- clang/lib/Format/UnwrappedLineParser.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index d69747a09c542..e987b3c5d4f22 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1004,9 +1004,9 @@ void UnwrappedLineParser::parseChildBlock() { void UnwrappedLineParser::parsePPDirective() { assert(FormatTok->is(tok::hash) && "'#' expected"); - // For BeforeHashWithCode, PP directives are indented at the surrounding code - // level. Preserving Line->Level allows ScopedMacroState to keep the code - // context level instead of resetting it to 0. + // PP directives are indented at the surrounding code level. Preserving + // Line->Level allows ScopedMacroState to keep the code context level + // instead of resetting it to 0. const bool PreserveLevel = Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; ScopedMacroState MacroState(*Line, Tokens, FormatTok, PreserveLevel); @@ -1245,13 +1245,13 @@ void UnwrappedLineParser::parsePPUnknown() { Line->Level += PPBranchLevel + 1; if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode && !PPStack.empty() && PPStack.back().Kind == PP_Unreachable) { - // PP directives inside unreachable branches must - // not be emitted: in multi-pass formatting the surrounding C++ braces may - // have been skipped (PP_Unreachable code is not parsed), leaving - // Line->Level too low. The resulting incorrect replacement would conflict - // with the correct one produced by the reachable pass, causing an - // "overlapping replacement" error and an empty output. Simply discard the - // accumulated tokens so the reachable pass wins. + // PP directives inside unreachable branches must not be emitted: in + // multi-pass formatting the surrounding C++ braces may have been skipped + // (PP_Unreachable code is not parsed), leaving Line->Level too low. The + // resulting incorrect replacement would conflict with the correct one + // produced by the reachable pass, causing an "overlapping replacement" + // error and an empty output. Simply discard the accumulated tokens so + // the reachable pass wins. Line->Tokens.clear(); return; } >From 87a2600e3001c8114991b059dc85334e0ef394c1 Mon Sep 17 00:00:00 2001 From: Guy Turcotte <[email protected]> Date: Mon, 16 Mar 2026 15:59:34 -0400 Subject: [PATCH 14/14] Update clang/lib/Format/UnwrappedLineParser.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Björn Schäpers <[email protected]> --- clang/lib/Format/UnwrappedLineParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index e987b3c5d4f22..e475f199fd53e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3923,7 +3923,7 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. nextToken(); - bool updateLevel = + const bool UpdateLevel = !Style.AllowShortEnumsOnASingleLine || Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHashWithCode; if (updateLevel) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
