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/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. @@ -2072,6 +2097,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,249 @@ +//===--- 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 = 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)); +} + +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) { + const 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) { + 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->Next; + continue; + } 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); + } + } + } + } else if (Style.ConstStyle == FormatStyle::CS_Left) { + 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->Next; + continue; + } 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); + } + } + } + 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" @@ -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); @@ -755,6 +771,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; @@ -930,6 +947,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; @@ -981,6 +999,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 = @@ -1042,6 +1061,7 @@ MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; MozillaStyle.SpaceAfterTemplateKeyword = false; + MozillaStyle.ConstStyle = FormatStyle::CS_Leave; return MozillaStyle; } @@ -1065,6 +1085,7 @@ Style.PointerAlignment = FormatStyle::PAS_Left; Style.SpaceBeforeCpp11BracedList = true; Style.SpaceInEmptyBlock = true; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1080,6 +1101,7 @@ Style.FixNamespaceComments = false; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; Style.Standard = FormatStyle::LS_Cpp03; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1107,6 +1129,7 @@ Style.AllowShortLoopsOnASingleLine = false; Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + Style.ConstStyle = FormatStyle::CS_Leave; return Style; } @@ -1115,6 +1138,7 @@ NoStyle.DisableFormat = true; NoStyle.SortIncludes = false; NoStyle.SortUsingDeclarations = false; + NoStyle.ConstStyle = FormatStyle::CS_Leave; return NoStyle; } @@ -2403,6 +2427,20 @@ }); } + 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.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,18 @@ "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 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)); @@ -415,6 +428,22 @@ 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); + + 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, @@ -12570,6 +12577,24 @@ 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.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); @@ -14843,6 +14868,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