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; + unsigned 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 @@ -60,12 +60,22 @@ // Update the indent level cache size so that we can rely on it // having the right size in adjustToUnmodifiedline. skipLine(Line, /*UnknownIndent=*/true); - if (Line.InPPDirective || - (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && - Line.Type == LT_CommentAbovePPDirective)) { - unsigned IndentWidth = + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None && + (Line.InPPDirective || + (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && + Line.Type == LT_CommentAbovePPDirective))) { + 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 + 1) * PPIndentWidth; + Indent += (Line.Level - Line.PPLevel - 1) * Style.IndentWidth; + if (PPIndentWidth < Style.IndentWidth) + Indent += Style.IndentWidth - PPIndentWidth; + } else { + Indent = Line.Level * PPIndentWidth; + } + Indent += AdditionalIndent; } else { Indent = getIndent(Line.Level); } 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,27 @@ /// The indent level of the \c UnwrappedLine. unsigned Level; + /// The nested preprocessor #if* level of the \c UnwrappedLine. This does not + /// include header-guards. + /// For example: + /// #ifndef foobar_h PPLevel still at : 0 (because header guard) + /// #define foobar_h PPLevel still at : 0 + /// #if A PPLevel from : 0 -> 1 + /// if (abc) { PPLevel still at : 1 (not preprocessor indent) + /// biz(); PPlevel still at : 1 + /// buz(); PPlevel still at : 1 + /// } PPLevel still at : 1 (not preprocessor indent) + /// #define B PPlevel still at : 1 + /// #ifdef foo PPLevel from : 1 -> 2 + /// #ifndef bar PPLevel from : 2 -> 3 + /// #else PPLevel still at : 3 + /// #endif PPLevel from : 3 -> 2 + /// #elif C PPLevel still at : 2 + /// #endif PPLevel from : 2 -> 1 + /// #endif PPLevel from : 1 -> 0 + /// #endif PPLevel still at : 0 + unsigned PPLevel; + /// Whether this \c UnwrappedLine is part of a preprocessor directive. bool InPPDirective; /// Whether this \c UnwrappedLine is part of a pramga directive. @@ -358,7 +379,7 @@ }; inline UnwrappedLine::UnwrappedLine() - : Level(0), InPPDirective(false), InPragmaDirective(false), + : Level(0), PPLevel(0), InPPDirective(false), InPragmaDirective(false), InMacroBody(false), MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {} 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 @@ -197,6 +197,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; } @@ -1273,6 +1274,10 @@ Line->Level += PPBranchLevel + 1; addUnwrappedLine(); ++Line->Level; + + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) + Line->PPLevel = PPBranchLevel + (IncludeGuard == IG_Defined ? 0 : 1); + Line->InMacroBody = true; // Errors during a preprocessor directive can only affect the layout of the 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,254 @@ " 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.PPIndentWidth = 2; + verifyFormat("#ifdef foo\n" + "#define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + style.IndentWidth = 8; + verifyFormat("#ifdef foo\n" + "#define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + + style.IndentWidth = 4; + style.PPIndentWidth = 1; + + 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.PPIndentWidth = 2; + verifyFormat("#ifdef foo\n" + "# define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + style.IndentWidth = 8; + verifyFormat("#ifdef foo\n" + "# define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + + style.IndentWidth = 4; + style.PPIndentWidth = 1; + + 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); + + style.PPIndentWidth = 2; + verifyFormat("#ifdef foo\n" + " #define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + style.IndentWidth = 8; + verifyFormat("#ifdef foo\n" + " #define bar() \\\n" + " if (A) { \\\n" + " B(); \\\n" + " } \\\n" + " C();\n" + "#endif", + style); + + style.IndentWidth = 4; + style.PPIndentWidth = 1; } TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {