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/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5071,8 +5071,9 @@ } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { - llvm::errs() << "AnnotatedTokens(L=" << Line.Level << ", T=" << Line.Type - << ", C=" << Line.IsContinuation << "):\n"; + llvm::errs() << "AnnotatedTokens(L=" << Line.Level << ", P=" << Line.PPLevel + << ", T=" << Line.Type << ", C=" << Line.IsContinuation + << "):\n"; const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore 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,17 @@ // 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; + Indent = Line.InMacroBody + ? Line.PPLevel * PPIndentWidth + + (Line.Level - Line.PPLevel) * Style.IndentWidth + : 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,10 @@ /// The indent level of the \c UnwrappedLine. unsigned Level; + /// The \c PPBranchLevel (adjusted for header guards) if this line is a + /// \c InMacroBody line, and 0 otherwise. + 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 +362,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; } @@ -833,6 +834,8 @@ delete SavedToken.Tok; } + // If this changes PPLevel needs to be used for get correct indentation. + assert(!Line.InMacroBody && !InPPDirective); return Line.Level * Style.IndentWidth + Length <= ColumnLimit; } @@ -1273,6 +1276,8 @@ Line->Level += PPBranchLevel + 1; addUnwrappedLine(); ++Line->Level; + + 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,344 @@ " 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); + verifyFormat("#if 1\n" + "#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + 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 = 1; + style.PPIndentWidth = 4; + verifyFormat("#if 1\n" + "#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + 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); + verifyFormat("#if 1\n" + "# define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + 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 = 1; + style.PPIndentWidth = 4; + verifyFormat("#if 1\n" + "# define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + 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); + verifyFormat("#if 1\n" + " #define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + 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 = 1; + style.PPIndentWidth = 4; + verifyFormat("#if 1\n" + " #define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n" + "#endif", + style); + verifyFormat("#define X \\\n" + " { \\\n" + " x; \\\n" + " x; \\\n" + " }\n", + style); } TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {