From cd7ab4b5c1684dcc60de027700177adfa096b98c Mon Sep 17 00:00:00 2001 From: Alexander Hederstaf Date: Mon, 27 Mar 2023 15:16:11 +0100 Subject: [PATCH] [clang-format] Improve QualifierAlignment Qualifiers were not moved for non-pointer non-simple types. Add additional support for many special cases such as templates, requires clauses, long qualified names. Fixes https://github.com/llvm/llvm-project/issues/57154 and https://github.com/llvm/llvm-project/issues/60898 Reviewed By: MyDeveloperDay, HazardyKnusperkeks Differential Revision: https://reviews.llvm.org/D144709 --- clang/docs/ReleaseNotes.rst | 2 + clang/lib/Format/QualifierAlignmentFixer.cpp | 480 +++++++++++++++-------- clang/lib/Format/QualifierAlignmentFixer.h | 10 +- clang/lib/Format/TokenAnnotator.cpp | 1 + clang/unittests/Format/QualifierFixerTest.cpp | 524 ++++++++++++++++++++++++-- 5 files changed, 814 insertions(+), 203 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 16dbe8e..b2efa99 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -363,6 +363,8 @@ clang-format Compared to ``NextLine`` style, ``NextLineOnly`` style will not try to put the initializers on the current line first, instead, it will try to put the initializers on the next line only. +- Add additional Qualifier Ordering support for special cases such + as templates, requires clauses, long qualified names. libclang -------- diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 609b412..5142a83 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -128,14 +128,12 @@ static void insertQualifierAfter(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const FormatToken *First, const std::string &Qualifier) { - FormatToken *Next = First->Next; - if (!Next) - return; - auto Range = CharSourceRange::getCharRange(Next->getStartOfNonWhitespace(), - Next->Tok.getEndLoc()); + auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(), + First->Tok.getEndLoc()); - std::string NewText = " " + Qualifier + " "; - NewText += Next->TokenText; + std::string NewText{}; + NewText += First->TokenText; + NewText += " " + Qualifier; replaceToken(SourceMgr, Fixes, Range, NewText); } @@ -204,9 +202,33 @@ static void rotateTokens(const SourceManager &SourceMgr, replaceToken(SourceMgr, Fixes, Range, NewText); } +static bool +isConfiguredQualifier(const FormatToken *const Tok, + const std::vector &Qualifiers) { + return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind()); +} + +static bool isQualifier(const FormatToken *const Tok) { + if (!Tok) + return false; + + switch (Tok->Tok.getKind()) { + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_static: + case tok::kw_inline: + case tok::kw_constexpr: + case tok::kw_restrict: + case tok::kw_friend: + return true; + default: + return false; + } +} + const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, const FormatToken *Tok, + tooling::Replacements &Fixes, const FormatToken *const Tok, const std::string &Qualifier, tok::TokenKind QualifierType) { // We only need to think about streams that begin with a qualifier. if (!Tok->is(QualifierType)) @@ -214,65 +236,141 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // Don't concern yourself if nothing follows the qualifier. if (!Tok->Next) return Tok; - if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next)) - return Tok; - auto AnalyzeTemplate = - [&](const FormatToken *Tok, - const FormatToken *StartTemplate) -> const FormatToken * { - // Read from the TemplateOpener to TemplateCloser. - FormatToken *EndTemplate = StartTemplate->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; - } + // Skip qualifiers to the left to find what preceeds the qualifiers. + // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers. + const FormatToken *PreviousCheck = Tok->getPreviousNonComment(); + while (isQualifier(PreviousCheck)) + PreviousCheck = PreviousCheck->getPreviousNonComment(); + + // Examples given in order of ['type', 'const', 'volatile'] + const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() { + // The cases: + // `Foo() const` -> `Foo() const` + // `Foo() const final` -> `Foo() const final` + // `Foo() const override` -> `Foo() const final` + // `Foo() const volatile override` -> `Foo() const volatile override` + // `Foo() volatile const final` -> `Foo() const volatile final` + if (PreviousCheck->is(tok::r_paren)) + return true; + + // The cases: + // `struct {} volatile const a;` -> `struct {} const volatile a;` + // `class {} volatile const a;` -> `class {} const volatile a;` + if (PreviousCheck->is(tok::r_brace)) + return true; + + // The case: + // `template const Bar Foo()` -> + // `template Bar const Foo()` + // The cases: + // `Foo const foo` -> `Foo const foo` + // `Foo volatile const` -> `Foo const volatile` + // The case: + // ``` + // template + // requires Concept1 && requires Concept2 + // const Foo f(); + // ``` + // -> + // ``` + // template + // requires Concept1 && requires Concept2 + // Foo const f(); + // ``` + if (PreviousCheck->is(TT_TemplateCloser)) { + // If the token closes a template<> or requires clause, then it is a left + // qualifier and should be moved to the right. + return !(PreviousCheck->ClosesTemplateDeclaration || + PreviousCheck->ClosesRequiresClause); } - if (EndTemplate && EndTemplate->Next && - !EndTemplate->Next->isOneOf(tok::equal, tok::l_paren)) { - insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier); - // Remove the qualifier. - removeToken(SourceMgr, Fixes, Tok); - return Tok; + + // The case `Foo* const` -> `Foo* const` + // The case `Foo* volatile const` -> `Foo* const volatile` + // The case `int32_t const` -> `int32_t const` + // The case `auto volatile const` -> `auto const volatile` + if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier, + tok::kw_auto)) { + return true; } - return nullptr; - }; - - FormatToken *Qual = Tok->Next; - FormatToken *LastQual = Qual; - while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { - LastQual = Qual; - Qual = Qual->Next; + + return false; + }(); + + // Find the last qualifier to the right. + const FormatToken *LastQual = Tok; + while (isQualifier(LastQual->getNextNonComment())) + LastQual = LastQual->getNextNonComment(); + + // If this qualifier is to the right of a type or pointer do a partial sort + // and return. + if (IsRightQualifier) { + if (LastQual != Tok) + rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); + return Tok; } - if (LastQual && Qual != LastQual) { - rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); - Tok = LastQual; - } else if (Tok->startsSequence(QualifierType, tok::identifier, - TT_TemplateCloser)) { - FormatToken *Closer = Tok->Next->Next; - rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/false); - Tok = Closer; + + const FormatToken *TypeToken = LastQual->getNextNonComment(); + if (!TypeToken) + return Tok; + + // Stay safe and don't move past macros, also don't bother with sorting. + if (isPossibleMacro(TypeToken)) + return Tok; + + // The case `const long long int volatile` -> `long long int const volatile` + // The case `long const long int volatile` -> `long long int const volatile` + // The case `long long volatile int const` -> `long long int const volatile` + // The case `const long long volatile int` -> `long long int const volatile` + if (TypeToken->isSimpleTypeSpecifier()) { + // The case `const decltype(foo)` -> `const decltype(foo)` + // The case `const typeof(foo)` -> `const typeof(foo)` + // The case `const _Atomic(foo)` -> `const _Atomic(foo)` + if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic)) + return Tok; + + const FormatToken *LastSimpleTypeSpecifier = TypeToken; + while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment())) + LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment(); + + rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier, + /*Left=*/false); + return LastSimpleTypeSpecifier; + } + + // The case `unsigned short const` -> `unsigned short const` + // The case: + // `unsigned short volatile const` -> `unsigned short const volatile` + if (PreviousCheck && PreviousCheck->isSimpleTypeSpecifier()) { + if (LastQual != Tok) + rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); + return Tok; + } + + // Skip the typename keyword. + // The case `const typename C::type` -> `typename C::type const` + if (TypeToken->is(tok::kw_typename)) + TypeToken = TypeToken->getNextNonComment(); + + // Skip the initial :: of a global-namespace type. + // The case `const ::...` -> `::... const` + if (TypeToken->is(tok::coloncolon)) { + // The case `const ::template Foo...` -> `::template Foo... const` + TypeToken = TypeToken->getNextNonComment(); + if (TypeToken && TypeToken->is(tok::kw_template)) + TypeToken = TypeToken->getNextNonComment(); + } + + // Don't change declarations such as + // `foo(const struct Foo a);` -> `foo(const struct Foo a);` + // as they would currently change code such as + // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {} + // my_struct;` + if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class)) return Tok; - } else if (Tok->startsSequence(QualifierType, tok::identifier, - TT_TemplateOpener)) { - // `const ArrayRef a;` - // `const ArrayRef &a;` - const FormatToken *NewTok = AnalyzeTemplate(Tok, Tok->Next->Next); - if (NewTok) - return NewTok; - } else if (Tok->startsSequence(QualifierType, tok::coloncolon, - tok::identifier, TT_TemplateOpener)) { - // `const ::ArrayRef a;` - // `const ::ArrayRef &a;` - const FormatToken *NewTok = AnalyzeTemplate(Tok, Tok->Next->Next->Next); - if (NewTok) - return NewTok; - } else if (Tok->startsSequence(QualifierType, tok::identifier) || - Tok->startsSequence(QualifierType, tok::coloncolon, - tok::identifier)) { - FormatToken *Next = Tok->Next; + + if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) { + // The case `const auto` -> `auto const` // The case `const Foo` -> `Foo const` // The case `const ::Foo` -> `::Foo const` // The case `const Foo *` -> `Foo const *` @@ -280,30 +378,35 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // The case `const Foo &&` -> `Foo const &&` // The case `const std::Foo &&` -> `std::Foo const &&` // The case `const std::Foo &&` -> `std::Foo const &&` - // However, `const Bar::*` remains the same. - while (Next && Next->isOneOf(tok::identifier, tok::coloncolon) && - !Next->startsSequence(tok::coloncolon, tok::star)) { - Next = Next->Next; - } - if (Next && Next->is(TT_TemplateOpener)) { - Next = Next->MatchingParen; - // Move to the end of any template class members e.g. - // `Foo::iterator`. - if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon, - tok::identifier)) { - return Tok; + // The case `const ::template Foo` -> `::template Foo const` + // The case `const T::template Foo` -> `T::template Foo const` + const FormatToken *Next = nullptr; + while ((Next = TypeToken->getNextNonComment()) && + (Next->is(TT_TemplateOpener) || + Next->startsSequence(tok::coloncolon, tok::identifier) || + Next->startsSequence(tok::coloncolon, tok::kw_template, + tok::identifier))) { + if (Next->is(TT_TemplateOpener)) { + assert(Next->MatchingParen && "Missing template closer"); + TypeToken = Next->MatchingParen; + } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) { + TypeToken = Next->getNextNonComment(); + } else { + TypeToken = Next->getNextNonComment()->getNextNonComment(); } - assert(Next && "Missing template opener"); - Next = Next->Next; } - if (Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) && - !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) { - if (Next->Previous && !Next->Previous->is(QualifierType)) { - insertQualifierAfter(SourceMgr, Fixes, Next->Previous, Qualifier); - removeToken(SourceMgr, Fixes, Tok); - } - return Next; + + // Place the Qualifier at the end of the list of qualifiers. + while (isQualifier(TypeToken->getNextNonComment())) { + // The case `volatile Foo::iter const` -> `Foo::iter const volatile` + TypeToken = TypeToken->getNextNonComment(); } + + insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier); + // Remove token and following whitespace. + auto Range = CharSourceRange::getCharRange( + Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace()); + replaceToken(SourceMgr, Fixes, Range, ""); } return Tok; @@ -311,98 +414,140 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, const FormatToken *Tok, + tooling::Replacements &Fixes, const FormatToken *const Tok, const std::string &Qualifier, tok::TokenKind QualifierType) { - // if Tok is an identifier and possibly a macro then don't convert. - if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok)) + // We only need to think about streams that begin with a qualifier. + if (!Tok->is(QualifierType)) + return Tok; + // Don't concern yourself if nothing preceeds the qualifier. + if (!Tok->getPreviousNonComment()) return Tok; - const FormatToken *Qual = Tok; - const FormatToken *LastQual = Qual; - while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { - LastQual = Qual; - Qual = Qual->Next; - if (Qual && Qual->is(QualifierType)) - break; + // Skip qualifiers to the left to find what preceeds the qualifiers. + const FormatToken *TypeToken = Tok->getPreviousNonComment(); + while (isQualifier(TypeToken)) + TypeToken = TypeToken->getPreviousNonComment(); + + // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& + // we only perform sorting. + if (!TypeToken || TypeToken->isOneOf(tok::star, tok::amp, tok::ampamp) || + TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) { + + // Don't sort past a non-configured qualifier token. + const FormatToken *FirstQual = Tok; + while (isConfiguredQualifier(FirstQual->getPreviousNonComment(), + ConfiguredQualifierTokens)) { + FirstQual = FirstQual->getPreviousNonComment(); + } + + if (FirstQual != Tok) + rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true); + return Tok; } - if (!Qual) + // Stay safe and don't move past macros, also don't bother with sorting. + if (isPossibleMacro(TypeToken)) return Tok; - if (LastQual && Qual != LastQual && Qual->is(QualifierType)) { - rotateTokens(SourceMgr, Fixes, Tok, Qual, /*Left=*/true); - if (!Qual->Next) - return Tok; - Tok = Qual->Next; - } else if (Tok->startsSequence(tok::identifier, QualifierType)) { - 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))) { - rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true); - Tok = Tok->Next; - } - } else if (Tok->startsSequence(tok::identifier, QualifierType, - TT_TemplateCloser)) { - FormatToken *Closer = Tok->Next->Next; - rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true); - Tok = Closer; + // Examples given in order of ['const', 'volatile', 'type'] + + // The case `volatile long long int const` -> `const volatile long long int` + // The case `volatile long long const int` -> `const volatile long long int` + // The case `const long long volatile int` -> `const volatile long long int` + // The case `long volatile long int const` -> `const volatile long long int` + if (TypeToken->isSimpleTypeSpecifier()) { + const FormatToken *LastSimpleTypeSpecifier = TypeToken; + while (isConfiguredQualifierOrType( + LastSimpleTypeSpecifier->getPreviousNonComment(), + ConfiguredQualifierTokens)) { + LastSimpleTypeSpecifier = + LastSimpleTypeSpecifier->getPreviousNonComment(); } + + rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok, + /*Left=*/true); + return Tok; } - if (Tok->is(TT_TemplateOpener) && Tok->Next && - (Tok->Next->is(tok::identifier) || Tok->Next->isSimpleTypeSpecifier()) && - Tok->Next->Next && Tok->Next->Next->is(QualifierType)) { - rotateTokens(SourceMgr, Fixes, Tok->Next, Tok->Next->Next, /*Left=*/true); - } - if ((Tok->startsSequence(tok::coloncolon, tok::identifier) || - Tok->is(tok::identifier)) && - Tok->Next) { - if (Tok->Previous && - Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { - return Tok; - } - const FormatToken *Next = Tok->Next; - // The case `std::Foo const` -> `const std::Foo &&` - while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) - Next = Next->Next; - if (Next && Next->Previous && - Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) { - // Read from to the end of the TemplateOpener to - // TemplateCloser const ArrayRef a; const ArrayRef &a; - if (Next->is(tok::comment) && Next->getNextNonComment()) - Next = Next->getNextNonComment(); - assert(Next->MatchingParen && "Missing template closer"); - Next = Next->MatchingParen; - - // If the template closer is closing the requires clause, - // then stop and go back to the TemplateOpener and do whatever is - // inside the <>. - if (Next->ClosesRequiresClause) - return Next->MatchingParen; - Next = Next->Next; - - // Move to the end of any template class members e.g. - // `Foo::iterator`. - if (Next && Next->startsSequence(tok::coloncolon, tok::identifier)) - Next = Next->Next->Next; - if (Next && Next->is(QualifierType)) { - // Move the qualifier. - insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); - removeToken(SourceMgr, Fixes, Next); - return Next; + + if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) { + const auto IsStartOfType = [](const FormatToken *const Tok) -> bool { + if (!Tok) + return true; + + // A template closer is not the start of a type. + // The case `?<> const` -> `const ?<>` + if (Tok->is(TT_TemplateCloser)) + return false; + + const FormatToken *const Previous = Tok->getPreviousNonComment(); + if (!Previous) + return true; + + // An identifier preceeded by :: is not the start of a type. + // The case `?::Foo const` -> `const ?::Foo` + if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon)) + return false; + + const FormatToken *const PrePrevious = Previous->getPreviousNonComment(); + // An identifier preceeded by ::template is not the start of a type. + // The case `?::template Foo const` -> `const ?::template Foo` + if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) && + PrePrevious && PrePrevious->is(tok::coloncolon)) { + return false; } - } - if (Next && Next->Next && - Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) { - if (Next->is(QualifierType)) { - // Move the qualifier. - insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); - removeToken(SourceMgr, Fixes, Next); - return Next; + + return true; + }; + + while (!IsStartOfType(TypeToken)) { + // The case `?<>` + if (TypeToken->is(TT_TemplateCloser)) { + assert(TypeToken->MatchingParen && "Missing template opener"); + TypeToken = TypeToken->MatchingParen->getPreviousNonComment(); + } else { + // The cases + // `::Foo` + // `?>::Foo` + // `?Bar::Foo` + // `::template Foo` + // `?>::template Foo` + // `?Bar::template Foo` + if (TypeToken->getPreviousNonComment()->is(tok::kw_template)) + TypeToken = TypeToken->getPreviousNonComment(); + + const FormatToken *const ColonColon = + TypeToken->getPreviousNonComment(); + const FormatToken *const PreColonColon = + ColonColon->getPreviousNonComment(); + if (PreColonColon && + PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) { + TypeToken = PreColonColon; + } else { + TypeToken = ColonColon; + } } } + + assert(TypeToken && "Should be auto or identifier"); + + // Place the Qualifier at the start of the list of qualifiers. + const FormatToken *Previous = nullptr; + while ((Previous = TypeToken->getPreviousNonComment()) && + (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) || + Previous->is(tok::kw_typename))) { + // The case `volatile Foo::iter const` -> `const volatile Foo::iter` + // The case `typename C::type const` -> `const typename C::type` + TypeToken = Previous; + } + + // Don't change declarations such as + // `foo(struct Foo const a);` -> `foo(struct Foo const a);` + if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) { + insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier); + removeToken(SourceMgr, Fixes, Tok); + } } + return Tok; } @@ -502,9 +647,16 @@ void QualifierAlignmentFixer::PrepareLeftRightOrdering( } bool LeftRightQualifierAlignmentFixer::isQualifierOrType( - const FormatToken *Tok, const std::vector &specifiedTypes) { + const FormatToken *const Tok) { + return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || + isQualifier(Tok)); +} + +bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( + const FormatToken *const Tok, + const std::vector &Qualifiers) { return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || - llvm::is_contained(specifiedTypes, Tok->Tok.getKind())); + isConfiguredQualifier(Tok, Qualifiers)); } // If a token is an identifier and it's upper case, it could diff --git a/clang/lib/Format/QualifierAlignmentFixer.h b/clang/lib/Format/QualifierAlignmentFixer.h index 30ef96b..3c90831 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.h +++ b/clang/lib/Format/QualifierAlignmentFixer.h @@ -86,11 +86,13 @@ public: const std::string &Qualifier, tok::TokenKind QualifierType); - // is the Token a simple or qualifier type - static bool isQualifierOrType(const FormatToken *Tok, - const std::vector &Qualifiers); + // Is the Token a simple or qualifier type + static bool isQualifierOrType(const FormatToken *Tok); + static bool + isConfiguredQualifierOrType(const FormatToken *Tok, + const std::vector &Qualifiers); - // is the Token likely a Macro + // Is the Token likely a Macro static bool isPossibleMacro(const FormatToken *Tok); }; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 5da5dc9..826cf81 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -199,6 +199,7 @@ private: CurrentToken->setType(TT_DictLiteral); } else { CurrentToken->setType(TT_TemplateCloser); + CurrentToken->Tok.setLength(1); } if (CurrentToken->Next && CurrentToken->Next->Tok.isLiteral()) return false; diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp index b244733..76800b3 100755 --- a/clang/unittests/Format/QualifierFixerTest.cpp +++ b/clang/unittests/Format/QualifierFixerTest.cpp @@ -156,7 +156,7 @@ TEST_F(QualifierFixerTest, LeftRightQualifier) { verifyFormat("int const *b;", Style); verifyFormat("int const &b;", Style); verifyFormat("int const &&b;", Style); - verifyFormat("int const *b const;", Style); + verifyFormat("int const *const b;", Style); verifyFormat("int *const c;", Style); verifyFormat("const Foo a;", Style); @@ -167,7 +167,7 @@ TEST_F(QualifierFixerTest, LeftRightQualifier) { verifyFormat("Foo const *b;", Style); verifyFormat("Foo const &b;", Style); verifyFormat("Foo const &&b;", Style); - verifyFormat("Foo const *b const;", Style); + verifyFormat("Foo const *const b;", Style); verifyFormat("LLVM_NODISCARD const int &Foo();", Style); verifyFormat("LLVM_NODISCARD int const &Foo();", Style); @@ -190,7 +190,7 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("int const *b;", Style); verifyFormat("int const &b;", Style); verifyFormat("int const &&b;", Style); - verifyFormat("int const *b const;", Style); + verifyFormat("int const *const b;", Style); verifyFormat("int *const c;", Style); verifyFormat("Foo const a;", Style); @@ -201,7 +201,7 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("Foo const *b;", Style); verifyFormat("Foo const &b;", Style); verifyFormat("Foo const &&b;", Style); - verifyFormat("Foo const *b const;", Style); + verifyFormat("Foo const *const b;", Style); verifyFormat("Foo *const b;", Style); verifyFormat("Foo const *const b;", Style); verifyFormat("auto const v = get_value();", Style); @@ -218,6 +218,11 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("void foo() const final;", Style); verifyFormat("void foo() const final LLVM_READONLY;", Style); verifyFormat("void foo() const LLVM_READONLY;", Style); + verifyFormat("void foo() const volatile override;", Style); + verifyFormat("void foo() const volatile override LLVM_READONLY;", Style); + verifyFormat("void foo() const volatile final;", Style); + verifyFormat("void foo() const volatile final LLVM_READONLY;", Style); + verifyFormat("void foo() const volatile LLVM_READONLY;", Style); verifyFormat( "template explicit Action(Action const &action);", @@ -258,6 +263,7 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("int const volatile;", "volatile const int;", Style); verifyFormat("int const volatile;", "const volatile int;", Style); verifyFormat("int const volatile;", "const int volatile;", Style); + verifyFormat("int const volatile *restrict;", "volatile const int *restrict;", Style); verifyFormat("int const volatile *restrict;", "const volatile int *restrict;", @@ -265,9 +271,44 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("int const volatile *restrict;", "const int volatile *restrict;", Style); + verifyFormat("long long int const volatile;", "const long long int volatile;", + Style); + verifyFormat("long long int const volatile;", "long const long int volatile;", + Style); + verifyFormat("long long int const volatile;", "long long volatile int const;", + Style); + verifyFormat("long long int const volatile;", "long volatile long const int;", + Style); + verifyFormat("long long int const volatile;", "const long long volatile int;", + Style); + verifyFormat("static int const bat;", "static const int bat;", Style); verifyFormat("static int const bat;", "static int const bat;", Style); + // static is not configured, unchanged on the left of the right hand + // qualifiers. + verifyFormat("int static const volatile;", "volatile const int static;", + Style); + verifyFormat("int static const volatile;", "const volatile int static;", + Style); + verifyFormat("int static const volatile;", "const int volatile static;", + Style); + verifyFormat("Foo static const volatile;", "volatile const Foo static;", + Style); + verifyFormat("Foo static const volatile;", "const volatile Foo static;", + Style); + verifyFormat("Foo static const volatile;", "const Foo volatile static;", + Style); + + verifyFormat("Foo inline static const;", "const Foo inline static;", Style); + verifyFormat("Foo inline static const;", "Foo const inline static;", Style); + verifyFormat("Foo inline static const;", "Foo inline const static;", Style); + verifyFormat("Foo inline static const;", "Foo inline static const;", Style); + + verifyFormat("Foo::Bar const volatile A::*;", + "volatile const Foo::Bar A::*;", + Style); + verifyFormat("int const Foo::bat = 0;", "const int Foo::bat = 0;", Style); verifyFormat("int const Foo::bat = 0;", "int const Foo::bat = 0;", @@ -333,7 +374,157 @@ TEST_F(QualifierFixerTest, RightQualifier) { verifyFormat("unsigned long long const a;", "const unsigned long long a;", Style); - // don't adjust macros + // Multiple template parameters. + verifyFormat("Bar", "Bar", Style); + // Variable declaration based on template type. + verifyFormat("Bar bar", "Bar bar", Style); + + // Using typename for a nested dependent type name. + verifyFormat("typename Foo::iterator const;", "const typename Foo::iterator;", + Style); + + // Don't move past C-style struct/class. + verifyFormat("void foo(const struct A a);", "void foo(const struct A a);", + Style); + verifyFormat("void foo(const class A a);", "void foo(const class A a);", + Style); + + // Don't move past struct/class combined declaration and variable + // definition. + verifyFormat("const struct {\n} var;", "const struct {\n} var;", Style); + verifyFormat("struct {\n} const var;", "struct {\n} const var;", Style); + verifyFormat("const class {\n} var;", "const class {\n} var;", Style); + verifyFormat("class {\n} const var;", "class {\n} const var;", Style); + + // Leave left qualifers unchanged for combined declaration and variable + // definition. + verifyFormat("volatile const class {\n} var;", + "volatile const class {\n} var;", Style); + verifyFormat("const volatile class {\n} var;", + "const volatile class {\n} var;", Style); + // Also do no sorting with respect to not-configured tokens. + verifyFormat("const static volatile class {\n} var;", + "const static volatile class {\n} var;", Style); + // Sort right qualifiers for combined declaration and variable definition. + verifyFormat("class {\n} const volatile var;", + "class {\n} const volatile var;", Style); + verifyFormat("class {\n} const volatile var;", + "class {\n} volatile const var;", Style); + // Static keyword is not configured, should end up on the left of the right + // side. + verifyFormat("class {\n} static const volatile var;", + "class {\n} static const volatile var;", Style); + verifyFormat("class {\n} static const volatile var;", + "class {\n} volatile static const var;", Style); + + // ::template for dependent names + verifyFormat("::template Foo const volatile var;", + "const volatile ::template Foo var;", Style); + verifyFormat("typename ::template Foo const volatile var;", + "const volatile typename ::template Foo var;", Style); + verifyFormat("typename Bar::template Foo::T const;", + "const typename Bar::template Foo::T;", Style); + verifyFormat("typename Bar::template Foo::T const volatile;", + "const volatile typename Bar::template Foo::T;", Style); + + // typename :: + verifyFormat("typename ::Bar const;", "const typename ::Bar;", + Style); + // typename ::template + verifyFormat("typename ::template Bar const;", + "const typename ::template Bar;", Style); + + verifyFormat("foo const>();", "foo>();", Style); + verifyFormat("foo const>();", "foo >();", Style); + verifyFormat("Bar<32, Foo<25> const>;", "Bar<32, const Foo<25>>;", Style); + verifyFormat("A const> const>;", "A>>;", Style); + verifyFormat("A const> const>;", "A>>;", + Style); + + // Don't move past decltype, typeof, or _Atomic. + verifyFormat("const decltype(foo)", "const decltype(foo)", Style); + verifyFormat("const typeof(foo)", "const typeof(foo)", Style); + verifyFormat("const _Atomic(foo)", "const _Atomic(foo)", Style); + + // Comments + const int ColumnLimit = Style.ColumnLimit; + Style.ColumnLimit = 200; + verifyFormat("/*c*/ Foo const *foo;", "const /*c*/ Foo *foo;", Style); + verifyFormat("Foo const /*c*/ *foo;", "const Foo /*c*/ *foo;", Style); + verifyFormat("Foo const * /*c*/ foo;", "const Foo * /*c*/ foo;", Style); + + verifyFormat("/*comment*/ std::vector const v;", + "const /*comment*/ std::vector v;", Style); + verifyFormat("std /*comment*/ ::vector const v;", + "const std /*comment*/ ::vector v;", Style); + verifyFormat("std::/*comment*/ vector const v;", + "const std::/*comment*/ vector v;", Style); + verifyFormat("std::vector /*comment*/ const v;", + "const std::vector /*comment*/ v;", Style); + verifyFormat("std::vector const v;", + "const std::vector v;", Style); + verifyFormat("std::vector const v;", + "const std::vector v;", Style); + verifyFormat("std::vector const /*comment*/ v;", + "const std::vector /*comment*/ v;", Style); + + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + + verifyFormat("typename C::template B const;", + "const typename C::template B;", Style); + verifyFormat("/*c*/ typename C::template B const;", + "const /*c*/ typename C::template B;", Style); + verifyFormat("typename /*c*/ C::template B const;", + "const typename /*c*/ C::template B;", Style); + verifyFormat("typename C /*c*/::template B const;", + "const typename C /*c*/::template B;", Style); + verifyFormat("typename C /*c*/ ::template B const;", + "const typename C /*c*/ ::template B;", Style); + verifyFormat("typename C::/*c*/ template B const;", + "const typename C::/*c*/ template B;", Style); + verifyFormat("typename C::template /*c*/ B const;", + "const typename C::template /*c*/B;", Style); + verifyFormat("typename C::template B const /*c*/;", + "const typename C::template B/*c*/;", Style); + + verifyFormat("/*c*/ /*c*/ typename /*c*/ C /*c*/ /*c*/ ::/*c*/ template " + "/*c*/ B /*c*/ const /*c*/ v;", + "/*c*/ const /*c*/ typename /*c*/ C /*c*/ /*c*/ " + "::/*c*/template /*c*/ B /*c*/ /*c*/ v;", + Style); + + verifyFormat("/*c*/ unsigned /*c*/ long const /*c*/ a;", + "const /*c*/ unsigned /*c*/ long /*c*/ a;", Style); + verifyFormat("unsigned /*c*/ long /*c*/ long const a;", + "const unsigned /*c*/ long /*c*/ long a;", Style); + + // Not changed + verifyFormat("foo() /*c*/ const", "foo() /*c*/ const", Style); + verifyFormat("const /*c*/ struct a;", "const /*c*/ struct a;", Style); + verifyFormat("const /*c*/ class a;", "const /*c*/ class a;", Style); + verifyFormat("const /*c*/ decltype(v) a;", "const /*c*/ decltype(v) a;", + Style); + verifyFormat("const /*c*/ typeof(v) a;", "const /*c*/ typeof(v) a;", Style); + verifyFormat("const /*c*/ _Atomic(v) a;", "const /*c*/ _Atomic(v) a;", Style); + verifyFormat("const decltype /*c*/ (v) a;", "const decltype /*c*/ (v) a;", + Style); + verifyFormat("const /*c*/ class {\n} volatile /*c*/ foo = {};", + "const /*c*/ class {\n} volatile /*c*/ foo = {};", Style); + + Style.ColumnLimit = ColumnLimit; + + // Don't adjust macros verifyFormat("const INTPTR a;", "const INTPTR a;", Style); // Pointers to members @@ -360,7 +551,7 @@ TEST_F(QualifierFixerTest, LeftQualifier) { verifyFormat("const int *b;", Style); verifyFormat("const int &b;", Style); verifyFormat("const int &&b;", Style); - verifyFormat("const int *b const;", Style); + verifyFormat("const int *const b;", Style); verifyFormat("int *const c;", Style); verifyFormat("const Foo a;", Style); @@ -371,7 +562,7 @@ TEST_F(QualifierFixerTest, LeftQualifier) { verifyFormat("const Foo *b;", Style); verifyFormat("const Foo &b;", Style); verifyFormat("const Foo &&b;", Style); - verifyFormat("const Foo *b const;", Style); + verifyFormat("const Foo *const b;", Style); verifyFormat("Foo *const b;", Style); verifyFormat("const Foo *const b;", Style); @@ -407,6 +598,17 @@ TEST_F(QualifierFixerTest, LeftQualifier) { verifyFormat("const volatile int *restrict;", "const int volatile *restrict;", Style); + verifyFormat("const volatile long long int;", "volatile long long int const;", + Style); + verifyFormat("const volatile long long int;", "volatile long long const int;", + Style); + verifyFormat("const volatile long long int;", "long long volatile int const;", + Style); + verifyFormat("const volatile long long int;", "long volatile long int const;", + Style); + verifyFormat("const volatile long long int;", "const long long volatile int;", + Style); + verifyFormat("SourceRange getSourceRange() const override LLVM_READONLY;", Style); @@ -488,7 +690,151 @@ TEST_F(QualifierFixerTest, LeftQualifier) { verifyFormat("const std::Foo < int", "const std::Foo", "const std::Foo", Style); - // don't adjust macros + // Multiple template parameters. + verifyFormat("Bar;", "Bar;", Style); + + // Variable declaration based on template type. + verifyFormat("Bar bar;", "Bar bar;", Style); + + // Using typename for a dependent name. + verifyFormat("const typename Foo::iterator;", "typename Foo::iterator const;", + Style); + + // Don't move past C-style struct/class. + verifyFormat("void foo(struct A const a);", "void foo(struct A const a);", + Style); + verifyFormat("void foo(class A const a);", "void foo(class A const a);", + Style); + + // Don't move past struct/class combined declaration and variable + // definition. + verifyFormat("const struct {\n} var;", "const struct {\n} var;", Style); + verifyFormat("struct {\n} const var;", "struct {\n} const var;", Style); + verifyFormat("const class {\n} var;", "const class {\n} var;", Style); + verifyFormat("class {\n} const var;", "class {\n} const var;", Style); + + // Sort left qualifiers for struct/class combined declaration and variable + // definition. + verifyFormat("const volatile class {\n} var;", + "const volatile class {\n} var;", Style); + verifyFormat("const volatile class {\n} var;", + "volatile const class {\n} var;", Style); + // Leave right qualifers unchanged for struct/class combined declaration and + // variable definition. + verifyFormat("class {\n} const volatile var;", + "class {\n} const volatile var;", Style); + verifyFormat("class {\n} volatile const var;", + "class {\n} volatile const var;", Style); + + verifyFormat("foo>>();", "foo> const>();", Style); + verifyFormat("foo>>();", "foo > const>();", + Style); + verifyFormat("Bar<32, const Foo<25>>;", "Bar<32, Foo<25> const>;", Style); + verifyFormat("A>>;", "A const> const>;", Style); + verifyFormat("A>>;", "A const> const>;", + Style); + + // Don't move past decltype, typeof, or _Atomic. + verifyFormat("decltype(foo) const", "decltype(foo) const", Style); + verifyFormat("typeof(foo) const", "typeof(foo) const", Style); + verifyFormat("_Atomic(foo) const", "_Atomic(foo) const", Style); + + // ::template for dependent names + verifyFormat("const volatile ::template Foo var;", + "::template Foo const volatile var;", Style); + verifyFormat("const volatile typename ::template Foo var;", + "typename ::template Foo const volatile var;", Style); + verifyFormat("const typename Bar::template Foo::T;", + "typename Bar::template Foo::T const;", Style); + verifyFormat("const volatile typename Bar::template Foo::T;", + "typename Bar::template Foo::T const volatile;", Style); + + // typename :: + verifyFormat("const typename ::Bar;", "typename ::Bar const;", + Style); + // typename ::template + verifyFormat("const typename ::template Bar;", + "typename ::template Bar const;", Style); + + // Comments + const int ColumnLimit = Style.ColumnLimit; + Style.ColumnLimit = 200; + verifyFormat("/*c*/ const Foo *foo;", "/*c*/ Foo const *foo;", Style); + verifyFormat("const Foo /*c*/ *foo;", "Foo const /*c*/ *foo;", Style); + verifyFormat("const Foo * /*c*/ foo;", "Foo const * /*c*/ foo;", Style); + + verifyFormat("/*comment*/ const std::vector v;", + "/*comment*/ std::vector const v;", Style); + verifyFormat("const std /*comment*/ ::vector v;", + "std /*comment*/ ::vector const v;", Style); + verifyFormat("const std::/*comment*/ vector v;", + "std::/*comment*/ vector const v;", Style); + verifyFormat("const std::vector /*comment*/ v;", + "std::vector /*comment*/ const v;", Style); + verifyFormat("const std::vector v;", + "std::vector const v;", Style); + verifyFormat("const std::vector v;", + "std::vector const v;", Style); + verifyFormat("const std::vector /*comment*/ v;", + "std::vector /*comment*/ const v;", Style); + + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + verifyFormat("std::vector v;", + "std::vector v;", Style); + + verifyFormat("const typename C::template B;", + "typename C::template B const;", Style); + verifyFormat("/*c*/ const typename C::template B;", + "/*c*/ typename C::template B const;", Style); + verifyFormat("const typename /*c*/ C::template B;", + "typename /*c*/ C::template B const;", Style); + verifyFormat("const typename C /*c*/::template B;", + "typename C /*c*/::template B const;", Style); + verifyFormat("const typename C /*c*/ ::template B;", + "typename C /*c*/ ::template B const;", Style); + verifyFormat("const typename C::/*c*/ template B;", + "typename C::/*c*/ template B const;", Style); + verifyFormat("const typename C::template /*c*/ B;", + "typename C::template /*c*/ B const;", Style); + verifyFormat("const typename C::template B /*c*/;", + "typename C::template B /*c*/ const;", Style); + + verifyFormat("/*c*/ const typename /*c*/ C /*c*/ /*c*/ ::/*c*/ template " + "/*c*/ B /*c*/ /*c*/ v;", + "/*c*/ typename /*c*/ C /*c*/ /*c*/ ::/*c*/ template /*c*/ B " + "/*c*/ /*c*/ const v;", + Style); + + verifyFormat("const unsigned /*c*/ long /*c*/ a;", + "unsigned /*c*/ long /*c*/ const a;", Style); + verifyFormat("const unsigned /*c*/ long /*c*/ long a;", + "unsigned /*c*/ long /*c*/ long const a;", Style); + + // Not changed + verifyFormat("foo() /*c*/ const", "foo() /*c*/ const", Style); + verifyFormat("struct /*c*/ const a;", "struct /*c*/ const a;", Style); + verifyFormat("class /*c*/ const a;", "class /*c*/ const a;", Style); + verifyFormat("decltype(v) /*c*/ const a;", "decltype(v) /*c*/ const a;", + Style); + verifyFormat("typeof(v) /*c*/ const a;", "typeof(v) /*c*/ const a;", Style); + verifyFormat("_Atomic(v) /*c*/ const a;", "_Atomic(v) /*c*/ const a;", Style); + verifyFormat("decltype /*c*/ (v) const a;", "decltype /*c*/ (v) const a;", + Style); + verifyFormat("const /*c*/ class {\n} /*c*/ volatile /*c*/ foo = {};", + "const /*c*/ class {\n} /*c*/ volatile /*c*/ foo = {};", Style); + + Style.ColumnLimit = ColumnLimit; + + // Don't adjust macros verifyFormat("INTPTR const a;", "INTPTR const a;", Style); // Pointers to members @@ -516,6 +862,12 @@ TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) { verifyFormat("const volatile int a;", "int volatile const a;", Style); verifyFormat("const volatile int a;", "const int volatile a;", Style); + verifyFormat("const volatile Foo a;", "const volatile Foo a;", Style); + verifyFormat("const volatile Foo a;", "volatile const Foo a;", Style); + verifyFormat("const volatile Foo a;", "Foo const volatile a;", Style); + verifyFormat("const volatile Foo a;", "Foo volatile const a;", Style); + verifyFormat("const volatile Foo a;", "const Foo volatile a;", Style); + Style.QualifierAlignment = FormatStyle::QAS_Right; Style.QualifierOrder = {"type", "const", "volatile"}; @@ -525,6 +877,12 @@ TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) { verifyFormat("int const volatile a;", "int volatile const a;", Style); verifyFormat("int const volatile a;", "const int volatile a;", Style); + verifyFormat("Foo const volatile a;", "const volatile Foo a;", Style); + verifyFormat("Foo const volatile a;", "volatile const Foo a;", Style); + verifyFormat("Foo const volatile a;", "Foo const volatile a;", Style); + verifyFormat("Foo const volatile a;", "Foo volatile const a;", Style); + verifyFormat("Foo const volatile a;", "const Foo volatile a;", Style); + Style.QualifierAlignment = FormatStyle::QAS_Left; Style.QualifierOrder = {"volatile", "const", "type"}; @@ -534,6 +892,12 @@ TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) { verifyFormat("volatile const int a;", "int volatile const a;", Style); verifyFormat("volatile const int a;", "const int volatile a;", Style); + verifyFormat("volatile const Foo a;", "const volatile Foo a;", Style); + verifyFormat("volatile const Foo a;", "volatile const Foo a;", Style); + verifyFormat("volatile const Foo a;", "Foo const volatile a;", Style); + verifyFormat("volatile const Foo a;", "Foo volatile const a;", Style); + verifyFormat("volatile const Foo a;", "const Foo volatile a;", Style); + Style.QualifierAlignment = FormatStyle::QAS_Right; Style.QualifierOrder = {"type", "volatile", "const"}; @@ -543,6 +907,12 @@ TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) { verifyFormat("int volatile const a;", "int volatile const a;", Style); verifyFormat("int volatile const a;", "const int volatile a;", Style); + verifyFormat("Foo volatile const a;", "const volatile Foo a;", Style); + verifyFormat("Foo volatile const a;", "volatile const Foo a;", Style); + verifyFormat("Foo volatile const a;", "Foo const volatile a;", Style); + verifyFormat("Foo volatile const a;", "Foo volatile const a;", Style); + verifyFormat("Foo volatile const a;", "const Foo volatile a;", Style); + Style.QualifierAlignment = FormatStyle::QAS_Custom; Style.QualifierOrder = {"type", "volatile", "const"}; @@ -551,6 +921,12 @@ TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) { verifyFormat("int volatile const a;", "int const volatile a;", Style); verifyFormat("int volatile const a;", "int volatile const a;", Style); verifyFormat("int volatile const a;", "const int volatile a;", Style); + + verifyFormat("Foo volatile const a;", "const volatile Foo a;", Style); + verifyFormat("Foo volatile const a;", "volatile const Foo a;", Style); + verifyFormat("Foo volatile const a;", "Foo const volatile a;", Style); + verifyFormat("Foo volatile const a;", "Foo volatile const a;", Style); + verifyFormat("Foo volatile const a;", "const Foo volatile a;", Style); } TEST_F(QualifierFixerTest, InlineStatics) { @@ -606,16 +982,16 @@ TEST_F(QualifierFixerTest, MoveConstBeforeTypeSmall) { verifyFormat("const int a;", "int const a;", Style); verifyFormat("const int *a;", "int const *a;", Style); - verifyFormat("const int *a const;", "int const *a const;", Style); + verifyFormat("const int *const a;", "int const *const a;", Style); verifyFormat("const int a = foo();", "int const a = foo();", Style); verifyFormat("const int *a = foo();", "int const *a = foo();", Style); - verifyFormat("const int *a const = foo();", "int const *a const = foo();", + verifyFormat("const int *const a = foo();", "int const *const a = foo();", Style); verifyFormat("const auto a = foo();", "auto const a = foo();", Style); verifyFormat("const auto *a = foo();", "auto const *a = foo();", Style); - verifyFormat("const auto *a const = foo();", "auto const *a const = foo();", + verifyFormat("const auto *const a = foo();", "auto const *const a = foo();", Style); } @@ -637,8 +1013,22 @@ TEST_F(QualifierFixerTest, MoveConstBeyondType) { verifyFormat("static inline int const volatile a;", "const int inline static volatile a;", Style); - verifyFormat("static inline int const volatile *a const;", - "const int inline static volatile *a const;", Style); + verifyFormat("static inline int const volatile *const a;", + "const int inline static volatile *const a;", Style); + + verifyFormat("static inline Foo const volatile a;", + "const inline static volatile Foo a;", Style); + verifyFormat("static inline Foo const volatile a;", + "volatile inline static const Foo a;", Style); + verifyFormat("static inline Foo const volatile a;", + "Foo const inline static volatile a;", Style); + verifyFormat("static inline Foo const volatile a;", + "Foo volatile inline static const a;", Style); + verifyFormat("static inline Foo const volatile a;", + "const Foo inline static volatile a;", Style); + + verifyFormat("static inline Foo const volatile *const a;", + "const Foo inline static volatile *const a;", Style); } TEST_F(QualifierFixerTest, PrepareLeftRightOrdering) { @@ -674,41 +1064,65 @@ TEST_F(QualifierFixerTest, IsQualifierType) { auto Tokens = annotate( "const static inline auto restrict int double long constexpr friend"); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[0], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[1], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[2], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[3], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[4], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[5], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[6], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[7], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[8], ConfiguredTokens)); - EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( Tokens[9], ConfiguredTokens)); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[0])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[1])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[2])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[3])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[4])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[5])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[6])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[7])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[8])); + EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[9])); + auto NotTokens = annotate("for while do Foo Bar "); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[0], ConfiguredTokens)); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[1], ConfiguredTokens)); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[2], ConfiguredTokens)); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[3], ConfiguredTokens)); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[4], ConfiguredTokens)); - EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType( + EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( NotTokens[5], ConfiguredTokens)); + + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[0])); + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[1])); + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[2])); + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[3])); + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[4])); + EXPECT_FALSE( + LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[5])); } TEST_F(QualifierFixerTest, IsMacro) { @@ -734,7 +1148,7 @@ TEST_F(QualifierFixerTest, DontPushQualifierThroughNonSpecifiedTypes) { FormatStyle Style = getLLVMStyle(); Style.QualifierAlignment = FormatStyle::QAS_Left; - Style.QualifierOrder = {"const", "type"}; + Style.QualifierOrder = {"const", "volatile", "type"}; verifyFormat("inline static const int a;", Style); @@ -745,6 +1159,28 @@ TEST_F(QualifierFixerTest, DontPushQualifierThroughNonSpecifiedTypes) { Style); verifyFormat("static const int a;", "const static int a;", Style); + + Style.QualifierOrder = {"const", "volatile", "type"}; + // static is not configured, unchanged at right hand qualifiers. + verifyFormat("const volatile int static;", "int volatile static const;", + Style); + verifyFormat("const volatile int static;", "int const static volatile;", + Style); + verifyFormat("const volatile int static;", "const int static volatile;", + Style); + verifyFormat("const volatile Foo static;", "Foo volatile static const;", + Style); + verifyFormat("const volatile Foo static;", "Foo const static volatile;", + Style); + verifyFormat("const volatile Foo static;", "const Foo static volatile;", + Style); + + verifyFormat("inline static const Foo;", "inline static Foo const;", Style); + verifyFormat("inline static const Foo;", "inline static const Foo;", Style); + + // Don't move qualifiers to the right for aestethics only. + verifyFormat("inline const static Foo;", "inline const static Foo;", Style); + verifyFormat("const inline static Foo;", "const inline static Foo;", Style); } TEST_F(QualifierFixerTest, UnsignedQualifier) { @@ -859,12 +1295,18 @@ TEST_F(QualifierFixerTest, TemplatesRight) { Style.QualifierAlignment = FormatStyle::QAS_Custom; Style.QualifierOrder = {"type", "const"}; + verifyFormat("template Foo const f();", + "template const Foo f();", Style); + verifyFormat("template int const f();", + "template const int f();", Style); + + verifyFormat("template t;", "template t;", Style); verifyFormat("template \n" " requires Concept\n" - "void f();", + "Foo const f();", "template \n" " requires Concept\n" - "void f();", + "const Foo f();", Style); verifyFormat("TemplateType t;", "TemplateType t;", Style); verifyFormat("TemplateType t;", @@ -874,15 +1316,27 @@ TEST_F(QualifierFixerTest, TemplatesRight) { TEST_F(QualifierFixerTest, TemplatesLeft) { FormatStyle Style = getLLVMStyle(); Style.QualifierAlignment = FormatStyle::QAS_Custom; - Style.QualifierOrder = {"const", "type"}; + Style.QualifierOrder = {"const", "volatile", "type"}; + + verifyFormat("template const Foo f();", + "template Foo const f();", Style); + verifyFormat("template const int f();", + "template int const f();", Style); verifyFormat("template t;", "template t;", Style); verifyFormat("template \n" " requires Concept\n" - "void f();", + "const Foo f();", + "template \n" + " requires Concept\n" + "Foo const f();", + Style); + verifyFormat("template \n" + " requires Concept\n" + "const volatile Foo f();", "template \n" " requires Concept\n" - "void f();", + "volatile const Foo f();", Style); verifyFormat("TemplateType t;", "TemplateType t;", Style); verifyFormat("TemplateType t;", -- 2.7.4