Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -1408,6 +1408,37 @@ namespace Extra { }}} +**ConstStyle** (``ConstAlignmentStyle``) + Different ways to arrange const. + + Possible values: + + * ``CS_Leave`` (in configuration: ``Leave``) + Don't change const to either Right const or Left const. + + .. code-block:: c++ + + int const a; + const int *a; + + * ``CS_Left`` (in configuration: ``Left``) + Change type decorations to be Left const. + + .. code-block:: c++ + + const int a; + const int *a; + + * ``CS_Right`` (in configuration: ``Right``) + Change type decorations to be Right 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 @@ -297,6 +297,10 @@ bar(); }); +- Option ``ConstStyle`` has been added auto-arrange the positioning of const + in variable and parameter declarations to be ``Right`` const or ``Left`` + const . + libclang -------- Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1171,6 +1171,31 @@ /// \endcode std::string CommentPragmas; + /// Different const alignment styles. + enum ConstAlignmentStyle { + /// Don't change const to either Right const or Left const. + /// \code + /// int const a; + /// const int *a; + /// \endcode + CS_Leave, + /// Change type decorations to be Left const. + /// \code + /// const int a; + /// const int *a; + /// \endcode + CS_Left, + /// Change type decorations to be Right 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. @@ -1984,8 +2009,8 @@ /// \endcode SBPO_ControlStatements, /// Same as ``SBPO_ControlStatements`` except this option doesn't apply to - /// ForEach macros. This is useful in projects where ForEach macros are - /// treated as function calls instead of control statements. + /// ForEach macros. This is useful in projects where ForEach macros are + /// treated as function calls instead of control statements. /// \code /// void f() { /// Q_FOREACH(...) { @@ -2225,6 +2250,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/EastWestConstFixer.h =================================================================== --- /dev/null +++ clang/lib/Format/EastWestConstFixer.h @@ -0,0 +1,36 @@ +//===--- EastWwestConstFixer.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares EastWestConstFixer, a TokenAnalyzer that +/// enforces either east or west const depending on the style. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_EASTWESTCONSTFIXER_H +#define LLVM_CLANG_LIB_FORMAT_EASTWESTCONSTFIXER_H + +#include "TokenAnalyzer.h" + +namespace clang { +namespace format { + +class EastWestConstFixer : public TokenAnalyzer { +public: + EastWestConstFixer(const Environment &Env, const FormatStyle &Style); + + std::pair + analyze(TokenAnnotator &Annotator, + SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) override; +}; + +} // end namespace format +} // end namespace clang + +#endif Index: clang/lib/Format/EastWestConstFixer.cpp =================================================================== --- /dev/null +++ clang/lib/Format/EastWestConstFixer.cpp @@ -0,0 +1,261 @@ +//===--- EastWestConstFixer.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements EastWestConstFixer, a TokenAnalyzer that +/// enforces either east or west const depending on the style. +/// +//===----------------------------------------------------------------------===// + +#include "EastWestConstFixer.h" +#include "FormatToken.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Regex.h" + +#include + +#define DEBUG_TYPE "using-declarations-sorter" + +namespace clang { +namespace format { + +static void removeToken(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First) { + // Change `const int` to be `int const`. + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + First->Tok.getEndLoc()); + + auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, "")); + + if (Err) { + llvm::errs() << "Error while rearranging const : " + << llvm::toString(std::move(Err)) << "\n"; + } +} + +static void insertConstAfter(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First) { + FormatToken *Next = First->Next; + if (!Next) { + return; + } + // Change `const int` to be `int const`. + auto Range = CharSourceRange::getCharRange(First->Tok.getEndLoc(), + Next->getStartOfNonWhitespace()); + + auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, " const ")); + + if (Err) { + llvm::errs() << "Error while rearranging const : " + << llvm::toString(std::move(Err)) << "\n"; + } +} + +static void insertConstBefore(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First) { + // Change `const int` to be `int const`. + auto Range = CharSourceRange::getCharRange( + First->getStartOfNonWhitespace(), First->Next->getStartOfNonWhitespace()); + + std::string NewText = " const "; + NewText += First->TokenText; + + auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewText)); + + if (Err) { + llvm::errs() << "Error while rearranging const : " + << llvm::toString(std::move(Err)) << "\n"; + } +} + +static void swapFirstTwoTokens(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First, + const FormatToken *Second) { + // Change `const int` to be `int const`. + std::string NewType; + NewType += Second->TokenText; + NewType += " "; + NewType += First->TokenText; + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + Second->Tok.getEndLoc()); + + auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewType)); + + if (Err) { + llvm::errs() << "Error while rearranging const : " + << llvm::toString(std::move(Err)) << "\n"; + } +} + +static void swapFirstThreeTokens(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First, + const FormatToken *Second, + const FormatToken *Third, bool West) { + // Change `const unsigned char` to be `unsigned char const`. + std::string NewType; + if (West) { + NewType += Third->TokenText; + NewType += " "; + NewType += First->TokenText; + NewType += " "; + NewType += Second->TokenText; + } else { + NewType += Second->TokenText; + NewType += " "; + NewType += Third->TokenText; + NewType += " "; + NewType += First->TokenText; + } + + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + Third->Tok.getEndLoc()); + + auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewType)); + + if (Err) { + llvm::errs() << "Error while rearranging const : " + << llvm::toString(std::move(Err)) << "\n"; + } +} + +static bool IsCVQualifierOrType(const FormatToken *Tok) { + if (!Tok) + return false; + return (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_volatile)); +} + +static FormatToken *analyzeRight(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + FormatToken *Tok) { + if (Tok->is(tok::kw_const) && IsCVQualifierOrType(Tok->Next) && + Tok->Next->Next && IsCVQualifierOrType(Tok->Next->Next)) { + // The unsigned/signed case `const unsigned int` -> `unsigned int + // const` + swapFirstThreeTokens(SourceMgr, Fixes, Tok, Tok->Next, Tok->Next->Next, + /*West=*/false); + Tok = Tok->Next; + } else if (Tok->is(tok::kw_const) && Tok->Next->isSimpleTypeSpecifier()) { + // The basic case `const int` -> `int const` + swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next); + + } else if (Tok->startsSequence(tok::kw_const, tok::identifier)) { + // The case `const Foo` -> `Foo const` + // The case `const Foo *` -> `Foo const *` + if (Tok->Next->Next && + Tok->Next->Next->isOneOf(tok::identifier, tok::star, tok::amp, + tok::ampamp) && + !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) { + swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next); + } else if (Tok->startsSequence(tok::kw_const, tok::identifier, + TT_TemplateOpener)) { + // Read from to the end of the TemplateOpener to + // TemplateCloser const ArrayRef a; const ArrayRef &a; + FormatToken *EndTemplate = Tok->Next->Next->MatchingParen; + if (EndTemplate) { + // Move to the end of any template class members e.g. + // `Foo::iterator`. + if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon, + tok::identifier)) { + EndTemplate = EndTemplate->Next->Next; + } + // remove the const + removeToken(SourceMgr, Fixes, Tok); + insertConstAfter(SourceMgr, Fixes, EndTemplate); + } + } + } + return Tok; +} + +static FormatToken *analyzeLeft(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + FormatToken *Tok) { + if (IsCVQualifierOrType(Tok) && IsCVQualifierOrType(Tok->Next) && + Tok->Next->Next && Tok->Next->Next->is(tok::kw_const)) { + // The unsigned/signed case `unsigned int const` -> `const unsigned + // int` + swapFirstThreeTokens(SourceMgr, Fixes, Tok, Tok->Next, Tok->Next->Next, + /*West=*/true); + Tok = Tok->Next; + } else if (Tok->isSimpleTypeSpecifier() && Tok->Next->is(tok::kw_const)) { + // The basic case `int const` -> `const int` + swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next); + } else if (Tok->startsSequence(tok::identifier, tok::kw_const)) { + if (Tok->Next->Next && Tok->Next->Next->isOneOf(tok::identifier, tok::star, + tok::amp, tok::ampamp)) { + // Don't swap `::iterator const` to `::const iterator` + if (!Tok->Previous || + (Tok->Previous && !Tok->Previous->is(tok::coloncolon))) { + swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next); + } + } + } else if (Tok->startsSequence(tok::identifier, TT_TemplateOpener)) { + // Read from to the end of the TemplateOpener to + // TemplateCloser const ArrayRef a; const ArrayRef &a; + FormatToken *EndTemplate = Tok->Next->MatchingParen; + + // Move to the end of any template class members e.g. + // `Foo::iterator`. + if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon, + tok::identifier)) { + EndTemplate = EndTemplate->Next->Next; + } + + if (EndTemplate && EndTemplate->Next && + EndTemplate->Next->is(tok::kw_const)) { + // remove the const + removeToken(SourceMgr, Fixes, EndTemplate->Next); + insertConstBefore(SourceMgr, Fixes, Tok); + } + } + return Tok; +} + +EastWestConstFixer::EastWestConstFixer(const Environment &Env, + const FormatStyle &Style) + : TokenAnalyzer(Env, Style) {} + +std::pair +EastWestConstFixer::analyze(TokenAnnotator &Annotator, + SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) { + const AdditionalKeywords &Keywords = Tokens.getKeywords(); + const SourceManager &SourceMgr = Env.getSourceManager(); + AffectedRangeMgr.computeAffectedLines(AnnotatedLines); + tooling::Replacements Fixes; + for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { + auto *Tok = AnnotatedLines[I]->First; + const auto *Last = AnnotatedLines[I]->Last; + + while (Tok && Tok != Last) { + if (!Tok->Next) { + break; + } + if (Tok->is(tok::comment)) { + Tok = Tok->Next; + continue; + } + if (Style.ConstStyle == FormatStyle::CS_Right) { + Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok); + } else if (Style.ConstStyle == FormatStyle::CS_Left) { + Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok); + } + Tok = Tok->Next; + } + } + return {Fixes, 0}; +} +} // namespace format +} // namespace clang 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" @@ -115,6 +116,14 @@ } }; +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); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { IO.enumCase(Value, "None", FormatStyle::SFS_None); @@ -474,6 +483,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); @@ -786,6 +796,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; @@ -970,6 +981,7 @@ // taze:, triple slash directives (`/// <...`), tslint:, and @see, which is // commonly followed by overlong URLs. GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|tslint:|@see)"; + GoogleStyle.ConstStyle = FormatStyle::CS_Leave; // TODO: enable once decided, in particular re disabling bin packing. // https://google.github.io/styleguide/jsguide.html#features-arrays-trailing-comma // GoogleStyle.InsertTrailingCommas = FormatStyle::TCS_Wrapped; @@ -1024,6 +1036,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 = @@ -1085,6 +1098,7 @@ MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; MozillaStyle.SpaceAfterTemplateKeyword = false; + MozillaStyle.ConstStyle = FormatStyle::CS_Leave; return MozillaStyle; } @@ -1108,6 +1122,7 @@ Style.PointerAlignment = FormatStyle::PAS_Left; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBlock = true; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1123,6 +1138,7 @@ Style.FixNamespaceComments = false; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; Style.Standard = FormatStyle::LS_Cpp03; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1151,6 +1167,7 @@ Style.AllowShortLoopsOnASingleLine = false; Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1159,6 +1176,7 @@ NoStyle.DisableFormat = true; NoStyle.SortIncludes = false; NoStyle.SortUsingDeclarations = false; + NoStyle.ConstStyle = FormatStyle::CS_Leave; return NoStyle; } @@ -2526,6 +2544,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 @@ -13097,6 +13097,11 @@ 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: Right", ConstStyle, FormatStyle::CS_Right); + CHECK_PARSE("ConstStyle: Left", ConstStyle, FormatStyle::CS_Left); + Style.PointerAlignment = FormatStyle::PAS_Middle; CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PAS_Left); @@ -15849,6 +15854,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); + verifyFormat( + "template explicit Action(Action const &action);", + "template explicit Action(const Action& action);", + Style); + verifyFormat( + "template explicit Action(Action const &action);", + "template \nexplicit Action(const Action& action);", + Style); + + verifyFormat("int const a;", "const int a;", Style); + verifyFormat("int const *a;", "const int *a;", Style); + verifyFormat("int const &a;", "const int &a;", Style); + verifyFormat("foo(int const &a)", "foo(const int &a)", Style); + verifyFormat("unsigned char *a;", "unsigned char *a;", Style); + verifyFormat("unsigned char const *a;", "const unsigned char *a;", Style); + verifyFormat("vector args1", + "vector args1", Style); + verifyFormat("unsigned int const &get_nu() const", + "const unsigned int &get_nu() const", Style); + verifyFormat("Foo const &a", "const Foo &a", Style); + verifyFormat("Foo::iterator const &a", "const Foo::iterator &a", + Style); + + verifyFormat("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); + + verifyFormat("volatile int const;", "volatile const int;", Style); + verifyFormat("volatile int const;", "const volatile int;", Style); + verifyFormat("int volatile const;", "const int volatile;", Style); + verifyFormat("volatile int const *restrict;", "volatile const int *restrict;", + Style); + verifyFormat("volatile int const *restrict;", "const volatile int *restrict;", + Style); + verifyFormat("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); + verifyFormat("const unsigned char *a;", "unsigned char const *a;", Style); + verifyFormat("const Foo &a", "Foo const &a", Style); + verifyFormat("const Foo::iterator &a", "Foo::iterator const &a", + Style); + + verifyFormat("const int a;", "int const a;", Style); + verifyFormat("const int *a;", "int const *a;", Style); + verifyFormat("const int &a;", "int const &a;", Style); + verifyFormat("foo(const int &a)", "foo(int const &a)", Style); + verifyFormat("unsigned char *a;", "unsigned char *a;", Style); + verifyFormat("const unsigned int &get_nu() const", + "unsigned int const &get_nu() const", Style); + + verifyFormat("volatile const int;", "volatile const int;", Style); + verifyFormat("const volatile int;", "const volatile int;", Style); + verifyFormat("const int volatile;", "const int volatile;", Style); + + verifyFormat("volatile const int *restrict;", "volatile const int *restrict;", + Style); + verifyFormat("const volatile int *restrict;", "const volatile int *restrict;", + Style); + verifyFormat("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); + verifyFormat( + "template explicit Action(const Action &action);", + "template explicit Action(Action const &action);", + Style); +} + } // namespace } // namespace format } // namespace clang