Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -1375,6 +1375,37 @@ namespace Extra { }}} +**ConstStyle** (``ConstAlignmentStyle``) + Different ways to arrange const. + + Possible values: + + * ``CS_Leave`` (in configuration: ``Leave``) + Don't change const to either East const or West const. + + .. code-block:: c++ + + int const a; + const int *a; + + * ``CS_Left`` (in configuration: ``Left``) + Change type decorations to be Left/Before/West const. + + .. code-block:: c++ + + const int a; + const int *a; + + * ``CS_Right`` (in configuration: ``Right``) + Change type decorations to be Right/After/East const. + + .. code-block:: c++ + + int const a; + int const *a; + + + **ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``) If the constructor initializers don't fit on a line, put each initializer on its own line. Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -340,6 +340,10 @@ const x = foo ?? default; const z = foo?.bar?.baz; +- Option ``ConstStyle`` has been added auto-arrange the positioning of const + in variable and parameter declarations to be ``East`` const or ``West`` + const . + libclang -------- Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1106,6 +1106,31 @@ /// \endcode std::string CommentPragmas; + /// Different const alignment styles. + enum ConstAlignmentStyle { + /// Don't change const to either East const or West const. + /// \code + /// int const a; + /// const int *a; + /// \endcode + CS_Leave, + /// Change type decorations to be Left/Before/West const. + /// \code + /// const int a; + /// const int *a; + /// \endcode + CS_Left, + /// Change type decorations to be Right/After/East const. + /// \code + /// int const a; + /// int const *a; + /// \endcode + CS_Right + }; + + /// Different ways to arrange const. + ConstAlignmentStyle ConstStyle; + /// Different ways to break inheritance list. enum BreakInheritanceListStyle { /// Break inheritance list before the colon and after the commas. @@ -2089,6 +2114,7 @@ BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && + ConstStyle == R.ConstStyle && BreakInheritanceList == R.BreakInheritanceList && ConstructorInitializerAllOnOneLineOrOnePerLine == R.ConstructorInitializerAllOnOneLineOrOnePerLine && Index: clang/lib/Format/CMakeLists.txt =================================================================== --- clang/lib/Format/CMakeLists.txt +++ clang/lib/Format/CMakeLists.txt @@ -14,6 +14,7 @@ UnwrappedLineFormatter.cpp UnwrappedLineParser.cpp UsingDeclarationsSorter.cpp + EastWestConstFixer.cpp WhitespaceManager.cpp LINK_LIBS Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -15,6 +15,7 @@ #include "clang/Format/Format.h" #include "AffectedRangeManager.h" #include "ContinuationIndenter.h" +#include "EastWestConstFixer.h" #include "FormatInternal.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" @@ -114,6 +115,20 @@ } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::ConstAlignmentStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::CS_Leave); + IO.enumCase(Value, "Left", FormatStyle::CS_Left); + IO.enumCase(Value, "Right", FormatStyle::CS_Right); + + // Other allowed names following community conventions. + IO.enumCase(Value, "Before", FormatStyle::CS_Left); + IO.enumCase(Value, "After", FormatStyle::CS_Right); + IO.enumCase(Value, "East", FormatStyle::CS_Right); + IO.enumCase(Value, "West", FormatStyle::CS_Left); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { IO.enumCase(Value, "None", FormatStyle::SFS_None); @@ -460,6 +475,7 @@ IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); + IO.mapOptional("ConstStyle", Style.ConstStyle); IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", Style.ConstructorInitializerAllOnOneLineOrOnePerLine); @@ -761,6 +777,7 @@ LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; + LLVMStyle.ConstStyle = FormatStyle::CS_Leave; LLVMStyle.CompactNamespaces = false; LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; LLVMStyle.ConstructorInitializerIndentWidth = 4; @@ -939,6 +956,7 @@ // taze:, triple slash directives (`/// <...`), @see, which is commonly // followed by overlong URLs. GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|@see)"; + GoogleStyle.ConstStyle = FormatStyle::CS_Leave; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; @@ -990,6 +1008,7 @@ // _prepend that with a comment_ to prevent it" before changing behavior. ChromiumStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; + ChromiumStyle.ConstStyle = FormatStyle::CS_Leave; if (Language == FormatStyle::LK_Java) { ChromiumStyle.AllowShortIfStatementsOnASingleLine = @@ -1051,6 +1070,7 @@ MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; MozillaStyle.SpaceAfterTemplateKeyword = false; + MozillaStyle.ConstStyle = FormatStyle::CS_Leave; return MozillaStyle; } @@ -1074,6 +1094,7 @@ Style.PointerAlignment = FormatStyle::PAS_Left; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBlock = true; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1089,6 +1110,7 @@ Style.FixNamespaceComments = false; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; Style.Standard = FormatStyle::LS_Cpp03; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1116,6 +1138,7 @@ Style.AllowShortLoopsOnASingleLine = false; Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1124,6 +1147,7 @@ NoStyle.DisableFormat = true; NoStyle.SortIncludes = false; NoStyle.SortUsingDeclarations = false; + NoStyle.ConstStyle = FormatStyle::CS_Leave; return NoStyle; } @@ -2418,6 +2442,13 @@ }); } + if (Style.isCpp() || Style.Language == FormatStyle::LK_ObjC) { + if (Style.ConstStyle != FormatStyle::CS_Leave) + Passes.emplace_back([&](const Environment &Env) { + return EastWestConstFixer(Env, Expanded).process(); + }); + } + if (Style.Language == FormatStyle::LK_JavaScript && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) Passes.emplace_back([&](const Environment &Env) { Index: clang/tools/clang-format/ClangFormat.cpp =================================================================== --- clang/tools/clang-format/ClangFormat.cpp +++ clang/tools/clang-format/ClangFormat.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/Version.h" #include "clang/Format/Format.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" @@ -104,6 +105,12 @@ "SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt ConstStyle( + "const-style", + cl::desc("If set, overrides the const style behavior determined by the " + "ConstStyle style flag"), + cl::init(""), cl::cat(ClangFormatCategory)); + static cl::opt Verbose("verbose", cl::desc("If set, shows the list of processed files"), cl::cat(ClangFormatCategory)); @@ -384,6 +391,14 @@ return true; } + StringRef ConstAlignment = ConstStyle; + + FormatStyle->ConstStyle = + StringSwitch(ConstAlignment.lower()) + .Cases("right", "east", "after", FormatStyle::CS_Right) + .Cases("left", "west", "before", FormatStyle::CS_Left) + .Default(FormatStyle->ConstStyle); + if (SortIncludes.getNumOccurrences() != 0) FormatStyle->SortIncludes = SortIncludes; unsigned CursorPosition = Cursor; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -27,6 +27,10 @@ FormatStyle getGoogleStyle() { return getGoogleStyle(FormatStyle::LK_Cpp); } +#define VERIFYFORMAT(expect, style) verifyFormat(expect, style, __LINE__) +#define VERIFYFORMAT2(expect, actual, style) \ + verifyFormat(expect, actual, style, __LINE__) + class FormatTest : public ::testing::Test { protected: enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck }; @@ -66,10 +70,12 @@ } void verifyFormat(llvm::StringRef Expected, llvm::StringRef Code, - const FormatStyle &Style = getLLVMStyle()) { + const FormatStyle &Style = getLLVMStyle(), + int line = __LINE__) { EXPECT_EQ(Expected.str(), format(Expected, Style)) - << "Expected code is not stable"; - EXPECT_EQ(Expected.str(), format(Code, Style)); + << "Expected code is not stable at " << __FILE__ << ":" << line; + EXPECT_EQ(Expected.str(), format(Code, Style)) + << " at " << __FILE__ << ":" << line; if (Style.Language == FormatStyle::LK_Cpp) { // Objective-C++ is a superset of C++, so everything checked for C++ // needs to be checked for Objective-C++ as well. @@ -80,8 +86,9 @@ } void verifyFormat(llvm::StringRef Code, - const FormatStyle &Style = getLLVMStyle()) { - verifyFormat(Code, test::messUp(Code), Style); + const FormatStyle &Style = getLLVMStyle(), + int line = __LINE__) { + verifyFormat(Code, test::messUp(Code), Style, line); } void verifyIncompleteFormat(llvm::StringRef Code, @@ -12609,6 +12616,15 @@ CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u); CHECK_PARSE("CommentPragmas: '// abc$'", CommentPragmas, "// abc$"); + Style.ConstStyle = FormatStyle::CS_Left; + CHECK_PARSE("ConstStyle: Leave", ConstStyle, FormatStyle::CS_Leave); + CHECK_PARSE("ConstStyle: East", ConstStyle, FormatStyle::CS_Right); + CHECK_PARSE("ConstStyle: West", ConstStyle, FormatStyle::CS_Left); + CHECK_PARSE("ConstStyle: Right", ConstStyle, FormatStyle::CS_Right); + CHECK_PARSE("ConstStyle: Left", ConstStyle, FormatStyle::CS_Left); + CHECK_PARSE("ConstStyle: After", ConstStyle, FormatStyle::CS_Right); + CHECK_PARSE("ConstStyle: Before", ConstStyle, FormatStyle::CS_Left); + Style.PointerAlignment = FormatStyle::PAS_Middle; CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PAS_Left); @@ -14994,6 +15010,194 @@ verifyFormat("operator&&(int(&&)(), class Foo);", Style); } +TEST_F(FormatTest, EastWestConst) { + FormatStyle Style = getLLVMStyle(); + + // keep the const style unaltered + VERIFYFORMAT("const int a;", Style); + VERIFYFORMAT("const int *a;", Style); + VERIFYFORMAT("const int &a;", Style); + VERIFYFORMAT("const int &&a;", Style); + VERIFYFORMAT("int const b;", Style); + VERIFYFORMAT("int const *b;", Style); + VERIFYFORMAT("int const &b;", Style); + VERIFYFORMAT("int const &&b;", Style); + VERIFYFORMAT("int const *b const;", Style); + VERIFYFORMAT("int *const c;", Style); + + VERIFYFORMAT("const Foo a;", Style); + VERIFYFORMAT("const Foo *a;", Style); + VERIFYFORMAT("const Foo &a;", Style); + VERIFYFORMAT("const Foo &&a;", Style); + VERIFYFORMAT("Foo const b;", Style); + VERIFYFORMAT("Foo const *b;", Style); + VERIFYFORMAT("Foo const &b;", Style); + VERIFYFORMAT("Foo const &&b;", Style); + VERIFYFORMAT("Foo const *b const;", Style); + + VERIFYFORMAT("LLVM_NODISCARD const int &Foo();", Style); + VERIFYFORMAT("LLVM_NODISCARD int const &Foo();", Style); + + VERIFYFORMAT("volatile const int *restrict;", Style); + VERIFYFORMAT("const volatile int *restrict;", Style); + VERIFYFORMAT("const int volatile *restrict;", Style); + + Style.ConstStyle = FormatStyle::CS_Right; + + VERIFYFORMAT("int const a;", Style); + VERIFYFORMAT("int const *a;", Style); + VERIFYFORMAT("int const &a;", Style); + VERIFYFORMAT("int const &&a;", Style); + VERIFYFORMAT("int const b;", Style); + VERIFYFORMAT("int const *b;", Style); + VERIFYFORMAT("int const &b;", Style); + VERIFYFORMAT("int const &&b;", Style); + VERIFYFORMAT("int const *b const;", Style); + VERIFYFORMAT("int *const c;", Style); + + VERIFYFORMAT("Foo const a;", Style); + VERIFYFORMAT("Foo const *a;", Style); + VERIFYFORMAT("Foo const &a;", Style); + VERIFYFORMAT("Foo const &&a;", Style); + VERIFYFORMAT("Foo const b;", Style); + VERIFYFORMAT("Foo const *b;", Style); + VERIFYFORMAT("Foo const &b;", Style); + VERIFYFORMAT("Foo const &&b;", Style); + VERIFYFORMAT("Foo const *b const;", Style); + VERIFYFORMAT("Foo *const b;", Style); + VERIFYFORMAT("Foo const *const b;", Style); + VERIFYFORMAT("auto const v = get_value();", Style); + VERIFYFORMAT("long long const &a;", Style); + VERIFYFORMAT("unsigned char const *a;", Style); + VERIFYFORMAT("int main(int const argc, char const *const *const argv)", + Style); + + VERIFYFORMAT("LLVM_NODISCARD int const &Foo();", Style); + VERIFYFORMAT("SourceRange getSourceRange() const override LLVM_READONLY", + Style); + VERIFYFORMAT("void foo() const override;", Style); + VERIFYFORMAT("void foo() const override LLVM_READONLY;", Style); + VERIFYFORMAT("void foo() const final;", Style); + VERIFYFORMAT("void foo() const final LLVM_READONLY;", Style); + VERIFYFORMAT("void foo() const LLVM_READONLY;", Style); + + VERIFYFORMAT( + "template explicit Action(Action const &action);", + Style); + VERIFYFORMAT2( + "template explicit Action(Action const &action);", + "template explicit Action(const Action& action);", + Style); + VERIFYFORMAT2( + "template explicit Action(Action const &action);", + "template \nexplicit Action(const Action& action);", + Style); + + VERIFYFORMAT2("int const a;", "const int a;", Style); + VERIFYFORMAT2("int const *a;", "const int *a;", Style); + VERIFYFORMAT2("int const &a;", "const int &a;", Style); + VERIFYFORMAT2("foo(int const &a)", "foo(const int &a)", Style); + VERIFYFORMAT2("unsigned char *a;", "unsigned char *a;", Style); + VERIFYFORMAT2("unsigned char const *a;", "const unsigned char *a;", Style); + VERIFYFORMAT2("vector args1", + "vector args1", Style); + VERIFYFORMAT2("unsigned int const &get_nu() const", + "const unsigned int &get_nu() const", Style); + VERIFYFORMAT2("Foo const &a", "const Foo &a", Style); + VERIFYFORMAT2("Foo::iterator const &a", "const Foo::iterator &a", + Style); + + VERIFYFORMAT2("Foo(int a, " + "unsigned b, // c-style args\n" + " Bar const &c);", + "Foo(int a, " + "unsigned b, // c-style args\n" + " const Bar &c);", + Style); + + VERIFYFORMAT2("volatile int const;", "volatile const int;", Style); + VERIFYFORMAT2("volatile int const;", "const volatile int;", Style); + VERIFYFORMAT2("int volatile const;", "const int volatile;", Style); + VERIFYFORMAT2("volatile int const *restrict;", + "volatile const int *restrict;", Style); + VERIFYFORMAT2("volatile int const *restrict;", + "const volatile int *restrict;", Style); + VERIFYFORMAT2("int volatile const *restrict;", + "const int volatile *restrict;", Style); + + Style.ConstStyle = FormatStyle::CS_Left; + + VERIFYFORMAT("const int a;", Style); + VERIFYFORMAT("const int *a;", Style); + VERIFYFORMAT("const int &a;", Style); + VERIFYFORMAT("const int &&a;", Style); + VERIFYFORMAT("const int b;", Style); + VERIFYFORMAT("const int *b;", Style); + VERIFYFORMAT("const int &b;", Style); + VERIFYFORMAT("const int &&b;", Style); + VERIFYFORMAT("const int *b const;", Style); + VERIFYFORMAT("int *const c;", Style); + + VERIFYFORMAT("const Foo a;", Style); + VERIFYFORMAT("const Foo *a;", Style); + VERIFYFORMAT("const Foo &a;", Style); + VERIFYFORMAT("const Foo &&a;", Style); + VERIFYFORMAT("const Foo b;", Style); + VERIFYFORMAT("const Foo *b;", Style); + VERIFYFORMAT("const Foo &b;", Style); + VERIFYFORMAT("const Foo &&b;", Style); + VERIFYFORMAT("const Foo *b const;", Style); + VERIFYFORMAT("Foo *const b;", Style); + VERIFYFORMAT("const Foo *const b;", Style); + + VERIFYFORMAT("LLVM_NODISCARD const int &Foo();", Style); + + VERIFYFORMAT("const char a[];", Style); + VERIFYFORMAT("const auto v = get_value();", Style); + VERIFYFORMAT("const long long &a;", Style); + VERIFYFORMAT("const unsigned char *a;", Style); + VERIFYFORMAT2("const unsigned char *a;", "unsigned char const *a;", Style); + VERIFYFORMAT2("const Foo &a", "Foo const &a", Style); + VERIFYFORMAT2("const Foo::iterator &a", "Foo::iterator const &a", + Style); + + VERIFYFORMAT2("const int a;", "int const a;", Style); + VERIFYFORMAT2("const int *a;", "int const *a;", Style); + VERIFYFORMAT2("const int &a;", "int const &a;", Style); + VERIFYFORMAT2("foo(const int &a)", "foo(int const &a)", Style); + VERIFYFORMAT2("unsigned char *a;", "unsigned char *a;", Style); + VERIFYFORMAT2("const unsigned int &get_nu() const", + "unsigned int const &get_nu() const", Style); + + VERIFYFORMAT2("volatile const int;", "volatile const int;", Style); + VERIFYFORMAT2("const volatile int;", "const volatile int;", Style); + VERIFYFORMAT2("const int volatile;", "const int volatile;", Style); + + VERIFYFORMAT2("volatile const int *restrict;", + "volatile const int *restrict;", Style); + VERIFYFORMAT2("const volatile int *restrict;", + "const volatile int *restrict;", Style); + VERIFYFORMAT2("const int volatile *restrict;", + "const int volatile *restrict;", Style); + + VERIFYFORMAT("SourceRange getSourceRange() const override LLVM_READONLY;", + Style); + + VERIFYFORMAT("void foo() const override;", Style); + VERIFYFORMAT("void foo() const override LLVM_READONLY;", Style); + VERIFYFORMAT("void foo() const final;", Style); + VERIFYFORMAT("void foo() const final LLVM_READONLY;", Style); + VERIFYFORMAT("void foo() const LLVM_READONLY;", Style); + + VERIFYFORMAT( + "template explicit Action(const Action &action);", + Style); + VERIFYFORMAT2( + "template explicit Action(const Action &action);", + "template explicit Action(Action const &action);", + Style); +} + } // namespace } // namespace format } // namespace clang