Index: lib/Format/TokenAnnotator.h =================================================================== --- lib/Format/TokenAnnotator.h +++ lib/Format/TokenAnnotator.h @@ -38,7 +38,7 @@ class AnnotatedLine { public: AnnotatedLine(const UnwrappedLine &Line) - : First(Line.Tokens.front().Tok), Level(Line.Level), + : First(Line.Tokens.front().Tok), Level(Line.Level), LevelOffset(0), MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex), InPPDirective(Line.InPPDirective), MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), @@ -111,6 +111,12 @@ LineType Type; unsigned Level; + + /// Adjustment to Level based indent. When comments are aligned to the next + /// preprocessor line they must use the same offset as the directive, + /// typically 1 due to the leading #. + unsigned LevelOffset; + size_t MatchingOpeningBlockLineIndex; bool InPPDirective; bool MustBeDeclaration; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1707,6 +1707,33 @@ FormatToken *Current; }; +enum CommentAlignment { + CA_None, // Comment is not aligned with the next line. + CA_First, // Comment is aligned with the first token on the next line. + CA_Directive, // Comment is aligned with the indented preprocessor directive + // on the next line. +}; + +CommentAlignment getCommentAlignment(const AnnotatedLine &Comment, + const AnnotatedLine &NextNonComment) { + if (NextNonComment.First->NewlinesBefore > 1) + return CA_None; + // If the next line is an indented preprocessor line look at the directive, + // not the #. + if ((NextNonComment.Type == LT_PreprocessorDirective || + NextNonComment.Type == LT_ImportStatement) && + NextNonComment.Level > 0 && !Comment.InPPDirective) + return NextNonComment.First->Next && + (Comment.First->OriginalColumn == + NextNonComment.First->Next->OriginalColumn) + ? CA_Directive + : CA_None; + else + return Comment.First->OriginalColumn == NextNonComment.First->OriginalColumn + ? CA_First + : CA_None; +} + } // end anonymous namespace void TokenAnnotator::setCommentLineLevels( @@ -1723,15 +1750,15 @@ } } - if (NextNonCommentLine && CommentLine) { - // If the comment is currently aligned with the line immediately following - // it, that's probably intentional and we should keep it. - bool AlignedWithNextLine = - NextNonCommentLine->First->NewlinesBefore <= 1 && - NextNonCommentLine->First->OriginalColumn == - (*I)->First->OriginalColumn; - if (AlignedWithNextLine) + // If the comment is aligned with the line immediately following it, that's + // probably intentional and we should keep it. + if (CommentLine && NextNonCommentLine) { + CommentAlignment Alignment = + getCommentAlignment(**I, *NextNonCommentLine); + if (Alignment != CA_None) (*I)->Level = NextNonCommentLine->Level; + if (Alignment == CA_Directive) + (*I)->LevelOffset = 1; } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; } Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -52,6 +52,7 @@ /// next. void nextLine(const AnnotatedLine &Line) { Offset = getIndentOffset(*Line.First); + Offset += Line.LevelOffset; // Update the indent level cache size so that we can rely on it // having the right size in adjustToUnmodifiedline. while (IndentForLevel.size() <= Line.Level) Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -2497,7 +2497,6 @@ "code();\n" "#endif", Style); - // Include guards must cover the entire file. verifyFormat("code();\n" "code();\n" @@ -2593,21 +2592,97 @@ "code();\n" "#endif", Style)); - // FIXME: The comment indent corrector in TokenAnnotator gets thrown off by - // preprocessor indentation. - EXPECT_EQ("#if 1\n" - " // comment\n" - "# define A 0\n" - "// comment\n" - "# define B 0\n" - "#endif", - format("#if 1\n" - "// comment\n" - "# define A 0\n" - " // comment\n" - "# define B 0\n" - "#endif", - Style)); + // Comments aligned to macros stay aligned. This test is incompatible with + // verifyFormat() because messUp() removes the alignment. + { + const char *Expected = "" + "// Level 0 unaligned comment\n" + "// Level 0 unaligned continuation\n" + "#ifndef HEADER_H\n" + "// Level 0 aligned comment\n" + "// Level 0 aligned continuation\n" + "#define HEADER_H\n" + "#if 1\n" + " // aligned comment\n" + " // aligned continuation\n" + "# define A 0\n" + "// un-aligned comment\n" + "// un-aligned continuation\n" + "# define B 0\n" + "// Trailing aligned comment\n" + "#endif\n" + "#endif"; + const char *ToFormat = "" + " // Level 0 unaligned comment\n" + " // Level 0 unaligned continuation\n" + "#ifndef HEADER_H\n" + "// Level 0 aligned comment\n" + "// Level 0 aligned continuation\n" + "#define HEADER_H\n" + "#if 1\n" + " // aligned comment\n" + " // aligned continuation\n" + "# define A 0\n" + " // un-aligned comment\n" + " // un-aligned continuation\n" + "# define B 0\n" + " // Trailing aligned comment\n" + "#endif\n" + "#endif"; + EXPECT_EQ(Expected, format(ToFormat, Style)); + EXPECT_EQ(Expected, format(Expected, Style)); + } + // Same as above, but block comments. + { + const char *Expected = "" + "/*\n" + " * Level 0 unaligned block comment\n" + " */\n" + "#ifndef HEADER_H\n" + "/*\n" + " * Level 0 aligned comment\n" + " */\n" + "#define HEADER_H\n" + "#if 1\n" + " /*\n" + " * Aligned comment\n" + " */\n" + "# define A 0\n" + "/*\n" + " * Unaligned comment\n" + " */\n" + "# define B 0\n" + "/*\n" + " * Trailing aligned comment\n" + " */\n" + "#endif\n" + "#endif"; + const char *ToFormat = "" + " /*\n" + " * Level 0 unaligned block comment\n" + " */\n" + "#ifndef HEADER_H\n" + "/*\n" + " * Level 0 aligned comment\n" + " */\n" + "#define HEADER_H\n" + "#if 1\n" + " /*\n" + " * Aligned comment\n" + " */\n" + "# define A 0\n" + " /*\n" + " * Unaligned comment\n" + " */\n" + "# define B 0\n" + " /*\n" + " * Trailing aligned comment\n" + " */\n" + "#endif\n" + "#endif"; + EXPECT_EQ(Expected, format(ToFormat, Style)); + EXPECT_EQ(Expected, format(Expected, Style)); + } // Test with tabs. Style.UseTab = FormatStyle::UT_Always; Style.IndentWidth = 8;