diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -38,6 +38,7 @@ public: AnnotatedLine(const UnwrappedLine &Line) : First(Line.Tokens.front().Tok), Level(Line.Level), + PPLevel(Line.PPLevel), MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex), MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex), InPPDirective(Line.InPPDirective), @@ -129,6 +130,7 @@ LineType Type; unsigned Level; + int PPLevel; size_t MatchingOpeningBlockLineIndex; size_t MatchingClosingBlockLineIndex; bool InPPDirective; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -63,9 +63,18 @@ if (Line.InPPDirective || (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && Line.Type == LT_CommentAbovePPDirective)) { - unsigned IndentWidth = + unsigned PPIndentWidth = (Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth; - Indent = Line.Level * IndentWidth + AdditionalIndent; + + if (Line.InMacroBody && Line.PPLevel > 0 && + static_cast(Line.PPLevel) <= Line.Level) { + + Indent = Line.PPLevel * PPIndentWidth; + Indent += (Line.Level - Line.PPLevel) * Style.IndentWidth; + } else { + Indent = Line.Level * PPIndentWidth; + } + Indent += AdditionalIndent; } else { Indent = getIndent(Line.Level); } @@ -78,9 +87,9 @@ /// Update the indent state given that \p Line indent should be /// skipped. void skipLine(const AnnotatedLine &Line, bool UnknownIndent = false) { - if (Line.Level >= IndentForLevel.size()) - IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent); - } + if (Line.Level >= IndentForLevel.size()) + IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent); +} /// Update the level indent to adapt to the given \p Line. /// diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -44,6 +44,9 @@ /// The indent level of the \c UnwrappedLine. unsigned Level; + /// The preprocessor indent level of the \c UnwrappedLine. + int PPLevel; + /// Whether this \c UnwrappedLine is part of a preprocessor directive. bool InPPDirective; /// Whether this \c UnwrappedLine is part of a pramga directive. diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -109,12 +109,14 @@ ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource, FormatToken *&ResetToken) : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken), - PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource), - Token(nullptr), PreviousToken(nullptr) { + PreviousLineLevel(Line.Level), PreviousLinePPLevel(Line.PPLevel), + PreviousTokenSource(TokenSource), Token(nullptr), + PreviousToken(nullptr) { FakeEOF.Tok.startToken(); FakeEOF.Tok.setKind(tok::eof); TokenSource = this; Line.Level = 0; + Line.PPLevel = 0; Line.InPPDirective = true; // InMacroBody gets set after the `#define x` part. } @@ -125,6 +127,7 @@ Line.InPPDirective = false; Line.InMacroBody = false; Line.Level = PreviousLineLevel; + Line.PPLevel = PreviousLinePPLevel; } FormatToken *getNextToken() override { @@ -177,6 +180,7 @@ FormatTokenSource *&TokenSource; FormatToken *&ResetToken; unsigned PreviousLineLevel; + unsigned PreviousLinePPLevel; FormatTokenSource *PreviousTokenSource; FormatToken *Token; @@ -197,6 +201,7 @@ PreBlockLine = std::move(Parser.Line); Parser.Line = std::make_unique(); Parser.Line->Level = PreBlockLine->Level; + Parser.Line->PPLevel = PreBlockLine->PPLevel; Parser.Line->InPPDirective = PreBlockLine->InPPDirective; Parser.Line->InMacroBody = PreBlockLine->InMacroBody; } @@ -364,8 +369,10 @@ // the guard) are over-indented by one. if (IncludeGuard == IG_Found) { for (auto &Line : Lines) - if (Line.InPPDirective && Line.Level > 0) + if (Line.InPPDirective && Line.Level > 0) { + --Line.PPLevel; --Line.Level; + } } // Create line with eof token. @@ -873,6 +880,7 @@ size_t PPStartHash = computePPHash(); const unsigned InitialLevel = Line->Level; + const int InitialPPLevel = Line->PPLevel; if (VerilogHierarchy) { AddLevels += parseVerilogHierarchyHeader(); } else { @@ -916,6 +924,7 @@ if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; + Line->PPLevel = InitialPPLevel; FormatTok->setBlockKind(BK_Block); return IfLBrace; } @@ -979,6 +988,7 @@ parseParens(); Line->Level = InitialLevel; + Line->PPLevel = InitialPPLevel; if (FormatTok->is(tok::kw_noexcept)) { // A noexcept in a requires expression. @@ -1269,10 +1279,13 @@ !FormatTok->hasWhitespaceBefore()) { parseParens(); } - if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) { Line->Level += PPBranchLevel + 1; + Line->PPLevel += PPBranchLevel + 1; + } addUnwrappedLine(); ++Line->Level; + ++Line->PPLevel; Line->InMacroBody = true; // Errors during a preprocessor directive can only affect the layout of the @@ -1292,8 +1305,10 @@ do { nextToken(); } while (!eof()); - if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) { Line->Level += PPBranchLevel + 1; + Line->PPLevel += PPBranchLevel + 1; + } addUnwrappedLine(); } @@ -3110,8 +3125,10 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { nextToken(); unsigned OldLineLevel = Line->Level; - if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) + unsigned OldLinePPLevel = Line->PPLevel; + if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) { --Line->Level; + } if (LeftAlignLabel) Line->Level = 0; @@ -3140,6 +3157,7 @@ addUnwrappedLine(); } Line->Level = OldLineLevel; + Line->PPLevel = OldLinePPLevel; if (FormatTok->isNot(tok::l_brace)) { parseStructuralElement(); addUnwrappedLine(); @@ -4297,10 +4315,11 @@ // don't know whether this colon is a label or a ternary expression at this // point. auto OrigLevel = Line->Level; + auto OrigPPLevel = Line->PPLevel; auto FirstLine = CurrentLines->size(); - if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1)) + if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1)) { ++Line->Level; - else if (!Style.IndentCaseBlocks && Keywords.isVerilogBegin(*FormatTok)) + } else if (!Style.IndentCaseBlocks && Keywords.isVerilogBegin(*FormatTok)) --Line->Level; parseStructuralElement(); // Restore the indentation in both the new line and the line that has the @@ -4308,6 +4327,7 @@ if (CurrentLines->size() > FirstLine) (*CurrentLines)[FirstLine].Level = OrigLevel; Line->Level = OrigLevel; + Line->PPLevel = OrigPPLevel; } LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, @@ -4632,6 +4652,7 @@ if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && PPBranchLevel > 0) { Line->Level += PPBranchLevel; + Line->PPLevel += PPBranchLevel; } flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -5040,6 +5040,189 @@ " int y = 0;\n" "}", style); + + style.IndentPPDirectives = FormatStyle::PPDIS_None; + verifyFormat("#ifdef X\n" + "#define Y \\\n" + " switch (Y) { \\\n" + " case 0: \\\n" + " break; \\\n" + " case 1: \\\n" + " break; \\\n" + " } \\\n" + " Z();\n" + "#endif", + style); + verifyFormat("#ifdef foo\n" + "#define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + verifyFormat("if (emacs) {\n" + "#ifdef is\n" + "#define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}", + style); + verifyFormat("#if abc\n" + "#ifdef foo\n" + "#define bar() \\\n" + " if (A) { \\\n" + " if (B) { \\\n" + " C(); \\\n" + " } \\\n" + " } \\\n" + " D();\n" + "#endif\n" + "#endif", + style); + verifyFormat("#ifndef foo\n" + "#define foo\n" + "if (emacs) {\n" + "#ifdef is\n" + "#define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}\n" + "#endif", + style); + + style.IndentPPDirectives = FormatStyle::PPDIS_AfterHash; + verifyFormat("#ifdef X\n" + "# define Y \\\n" + " switch (Y) { \\\n" + " case 0: \\\n" + " break; \\\n" + " case 1: \\\n" + " break; \\\n" + " } \\\n" + " Z();\n" + "#endif", + style); + verifyFormat("#ifdef foo\n" + "# define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + verifyFormat("if (emacs) {\n" + "#ifdef is\n" + "# define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}", + style); + verifyFormat("#if abc\n" + "# ifdef foo\n" + "# define bar() \\\n" + " if (A) { \\\n" + " if (B) { \\\n" + " C(); \\\n" + " } \\\n" + " } \\\n" + " D();\n" + "# endif\n" + "#endif", + style); + verifyFormat("#if abc\n" + "# ifdef foo\n" + "# define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "# endif\n" + "#endif", + style); + verifyFormat("#ifndef foo\n" + "#define foo\n" + "if (emacs) {\n" + "#ifdef is\n" + "# define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}\n" + "#endif", + style); + + style.IndentPPDirectives = FormatStyle::PPDIS_BeforeHash; + verifyFormat("#ifdef X\n" + " #define Y \\\n" + " switch (Y) { \\\n" + " case 0: \\\n" + " break; \\\n" + " case 1: \\\n" + " break; \\\n" + " } \\\n" + " Z();\n" + "#endif", + style); + verifyFormat("#ifdef foo\n" + " #define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + verifyFormat("if (emacs) {\n" + "#ifdef is\n" + " #define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}", + style); + verifyFormat("#if abc\n" + " #ifdef foo\n" + " #define bar() \\\n" + " if (A) { \\\n" + " if (B) { \\\n" + " C(); \\\n" + " } \\\n" + " } \\\n" + " D();\n" + " #endif\n" + "#endif", + style); + verifyFormat("#if abc\n" + " #ifdef foo\n" + " #define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + " #endif\n" + "#endif", + style); + verifyFormat("#ifndef foo\n" + "#define foo\n" + "if (emacs) {\n" + "#ifdef is\n" + " #define lit \\\n" + " if (af) { \\\n" + " return duh(); \\\n" + " }\n" + "#endif\n" + "}\n" + "#endif", + style); + } TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {