From eff18b9b6f1218a6bbe4869989b08867823a4e75 Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Wed, 31 Jul 2013 23:16:02 +0000 Subject: [PATCH] clang-format: Add more options to namespace indentation. With this patch, clang-format can be configured to: * not indent in namespace at all (former behavior). * indent in namespace as in other blocks. * indent only in inner namespaces (as required by WebKit style). Also fix alignment of access specifiers in WebKit style. Patch started by Marek Kurdej. Thank you! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187540 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Format/Format.h | 10 ++++++ lib/Format/Format.cpp | 21 ++++++++++-- lib/Format/UnwrappedLineParser.cpp | 15 +++++---- lib/Format/UnwrappedLineParser.h | 2 +- unittests/Format/FormatTest.cpp | 52 ++++++++++++++++++++++++++++-- 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index d3f20b1054..7d5d66b7da 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -77,6 +77,15 @@ struct FormatStyle { /// Switch statement body is always indented one level more than case labels. bool IndentCaseLabels; + enum NamespaceIndentationKind { + NI_None, // Don't indent in namespaces. + NI_Inner, // Indent only in inner namespaces (nested in other namespaces). + NI_All // Indent in all namespaces. + }; + + /// \brief The indentation used for namespaces. + NamespaceIndentationKind NamespaceIndentation; + /// \brief The number of spaces to before trailing line comments. unsigned SpacesBeforeTrailingComments; @@ -198,6 +207,7 @@ struct FormatStyle { IndentCaseLabels == R.IndentCaseLabels && IndentWidth == R.IndentWidth && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && + NamespaceIndentation == R.NamespaceIndentation && ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && PenaltyBreakComment == R.PenaltyBreakComment && PenaltyBreakFirstLessLess == R.PenaltyBreakFirstLessLess && diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 008693619c..65b1a265e5 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -53,6 +53,18 @@ struct ScalarEnumerationTraits { } }; +template <> +struct ScalarEnumerationTraits< + clang::format::FormatStyle::NamespaceIndentationKind> { + static void + enumeration(IO &IO, + clang::format::FormatStyle::NamespaceIndentationKind &Value) { + IO.enumCase(Value, "None", clang::format::FormatStyle::NI_None); + IO.enumCase(Value, "Inner", clang::format::FormatStyle::NI_Inner); + IO.enumCase(Value, "All", clang::format::FormatStyle::NI_All); + } +}; + template <> struct MappingTraits { static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) { if (IO.outputting()) { @@ -102,6 +114,7 @@ template <> struct MappingTraits { Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); + IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); IO.mapOptional("ObjCSpaceBeforeProtocolList", Style.ObjCSpaceBeforeProtocolList); IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment); @@ -158,6 +171,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.IndentFunctionDeclarationAfterType = false; LLVMStyle.IndentWidth = 2; LLVMStyle.MaxEmptyLinesToKeep = 1; + LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerBindsToType = false; LLVMStyle.SpacesBeforeTrailingComments = 1; @@ -192,6 +206,7 @@ FormatStyle getGoogleStyle() { GoogleStyle.IndentFunctionDeclarationAfterType = true; GoogleStyle.IndentWidth = 2; GoogleStyle.MaxEmptyLinesToKeep = 1; + GoogleStyle.NamespaceIndentation = FormatStyle::NI_None; GoogleStyle.ObjCSpaceBeforeProtocolList = false; GoogleStyle.PointerBindsToType = true; GoogleStyle.SpacesBeforeTrailingComments = 2; @@ -229,11 +244,13 @@ FormatStyle getMozillaStyle() { FormatStyle getWebKitStyle() { FormatStyle Style = getLLVMStyle(); - Style.ColumnLimit = 0; - Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + Style.AccessModifierOffset = -4; Style.BreakBeforeBinaryOperators = true; + Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; Style.BreakConstructorInitializersBeforeComma = true; + Style.ColumnLimit = 0; Style.IndentWidth = 4; + Style.NamespaceIndentation = FormatStyle::NI_Inner; Style.PointerBindsToType = true; return Style; } diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 939a301e9d..94fbf078dc 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -319,8 +319,7 @@ void UnwrappedLineParser::calculateBraceTypes() { FormatTok = Tokens->setPosition(StoredPosition); } -void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, - unsigned AddLevels) { +void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel) { assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected"); unsigned InitialLevel = Line->Level; nextToken(); @@ -329,7 +328,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - Line->Level += AddLevels; + if (AddLevel) + ++Line->Level; parseLevel(/*HasOpeningBrace=*/true); if (!FormatTok->Tok.is(tok::r_brace)) { @@ -550,7 +550,7 @@ void UnwrappedLineParser::parseStructuralElement() { if (FormatTok->Tok.is(tok::string_literal)) { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - parseBlock(/*MustBeDeclaration=*/true, 0); + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false); addUnwrappedLine(); return; } @@ -794,7 +794,10 @@ void UnwrappedLineParser::parseNamespace() { if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/true, 0); + bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All || + (Style.NamespaceIndentation == FormatStyle::NI_Inner && + DeclarationScopeStack.size() > 1); + parseBlock(/*MustBeDeclaration=*/true, AddLevel); // Munch the semicolon after a namespace. This is more common than one would // think. Puttin the semicolon into its own line is very ugly. if (FormatTok->Tok.is(tok::semi)) @@ -874,7 +877,7 @@ void UnwrappedLineParser::parseSwitch() { if (FormatTok->Tok.is(tok::l_paren)) parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { - parseBlock(/*MustBeDeclaration=*/false, 1); + parseBlock(/*MustBeDeclaration=*/false); addUnwrappedLine(); } else { addUnwrappedLine(); diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 0624c4fd15..d23d157ccc 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -65,7 +65,7 @@ public: private: void parseFile(); void parseLevel(bool HasOpeningBrace); - void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); + void parseBlock(bool MustBeDeclaration, bool AddLevel = true); void parsePPDirective(); void parsePPDefine(); void parsePPIf(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 4a28cca222..61d0614595 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -842,10 +842,10 @@ TEST_F(FormatTest, AlignsBlockComments) { " 1.1.1. to keep the formatting.\n" " */")); EXPECT_EQ("/*\n" - "Don't try to outdent if there's not enough inentation.\n" + "Don't try to outdent if there's not enough indentation.\n" "*/", format(" /*\n" - " Don't try to outdent if there's not enough inentation.\n" + " Don't try to outdent if there's not enough indentation.\n" " */")); EXPECT_EQ("int i; /* Comment with empty...\n" @@ -1565,6 +1565,37 @@ TEST_F(FormatTest, FormatsNamespaces) { "int i;\n" "} // my_namespace\n" "#endif // HEADER_GUARD")); + + FormatStyle Style = getLLVMStyle(); + Style.NamespaceIndentation = FormatStyle::NI_All; + EXPECT_EQ("namespace out {\n" + " int i;\n" + " namespace in {\n" + " int i;\n" + " } // namespace\n" + "} // namespace", + format("namespace out {\n" + "int i;\n" + "namespace in {\n" + "int i;\n" + "} // namespace\n" + "} // namespace", + Style)); + + Style.NamespaceIndentation = FormatStyle::NI_Inner; + EXPECT_EQ("namespace out {\n" + "int i;\n" + "namespace in {\n" + " int i;\n" + "} // namespace\n" + "} // namespace", + format("namespace out {\n" + "int i;\n" + "namespace in {\n" + "int i;\n" + "} // namespace\n" + "} // namespace", + Style)); } TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); } @@ -5485,6 +5516,14 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces, FormatStyle::BS_Stroustrup); + Style.NamespaceIndentation = FormatStyle::NI_All; + CHECK_PARSE("NamespaceIndentation: None", NamespaceIndentation, + FormatStyle::NI_None); + CHECK_PARSE("NamespaceIndentation: Inner", NamespaceIndentation, + FormatStyle::NI_Inner); + CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation, + FormatStyle::NI_All); + #undef CHECK_PARSE #undef CHECK_PARSE_BOOL } @@ -5586,7 +5625,7 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) { verifyFormat("namespace outer {\n" "int i;\n" "namespace inner {\n" - "int i;\n" // FIXME: This should be indented. + " int i;\n" "} // namespace inner\n" "} // namespace outer\n" "namespace other_outer {\n" @@ -5632,6 +5671,13 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) { " , aaaaaaaaaaaaaaaaaaaaaaa()\n{\n}", Style); + // Access specifiers should be aligned left. + verifyFormat("class C {\n" + "public:\n" + " int i;\n" + "};", + Style); + // Do not align comments. // FIXME: Implement option to suppress comment alignment. // verifyFormat("int a; // Do not\n" -- 2.40.0