[clang] cd7ab4b - [clang-format] Improve QualifierAlignment

via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 27 07:21:36 PDT 2023


Author: Alexander Hederstaf
Date: 2023-03-27T15:18:29+01:00
New Revision: cd7ab4b5c1684dcc60de027700177adfa096b98c

URL: https://github.com/llvm/llvm-project/commit/cd7ab4b5c1684dcc60de027700177adfa096b98c
DIFF: https://github.com/llvm/llvm-project/commit/cd7ab4b5c1684dcc60de027700177adfa096b98c.diff

LOG: [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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Format/QualifierAlignmentFixer.cpp
    clang/lib/Format/QualifierAlignmentFixer.h
    clang/lib/Format/TokenAnnotator.cpp
    clang/unittests/Format/QualifierFixerTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 16dbe8ec8d27..b2efa9931325 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 609b412380f8..5142a83efdd4 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<tok::TokenKind> &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<int>::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 <class T> const Bar Foo()` ->
+    // `template <class T> Bar const Foo()`
+    // The cases:
+    // `Foo<int> const foo` -> `Foo<int> const foo`
+    // `Foo<int> volatile const` -> `Foo<int> const volatile`
+    // The case:
+    // ```
+    // template <class T>
+    //   requires Concept1<T> && requires Concept2<T>
+    // const Foo f();
+    // ```
+    // ->
+    // ```
+    // template <class T>
+    //   requires Concept1<T> && requires Concept2<T>
+    // 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<int> a;`
-    // `const ArrayRef<int> &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<int> a;`
-    // `const ::ArrayRef<int> &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<T> &&` -> `std::Foo<T> 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<int>::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<T> const` -> `const std::Foo<T> &&`
-    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<int> a; const ArrayRef<int> &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<int>::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<tok::TokenKind> &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<tok::TokenKind> &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 30ef96b8b0a7..3c908316a303 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.h
+++ b/clang/lib/Format/QualifierAlignmentFixer.h
@@ -86,11 +86,13 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
                                  const std::string &Qualifier,
                                  tok::TokenKind QualifierType);
 
-  // is the Token a simple or qualifier type
-  static bool isQualifierOrType(const FormatToken *Tok,
-                                const std::vector<tok::TokenKind> &Qualifiers);
+  // Is the Token a simple or qualifier type
+  static bool isQualifierOrType(const FormatToken *Tok);
+  static bool
+  isConfiguredQualifierOrType(const FormatToken *Tok,
+                              const std::vector<tok::TokenKind> &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 5da5dc96032a..826cf8115a1e 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -199,6 +199,7 @@ class AnnotatingParser {
           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 b2447339a7d6..76800b3fc8e3 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 <typename Func> explicit Action(Action<Func> 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<T volatile>::Bar<Type const, 5> const volatile A::*;",
+               "volatile const Foo<volatile T>::Bar<const Type, 5> A::*;",
+               Style);
+
   verifyFormat("int const Foo<int>::bat = 0;", "const int Foo<int>::bat = 0;",
                Style);
   verifyFormat("int const Foo<int>::bat = 0;", "int const Foo<int>::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<std::Foo const, 32>", "Bar<const std::Foo, 32>", Style);
+  // Variable declaration based on template type.
+  verifyFormat("Bar<std::Foo const> bar", "Bar<const std::Foo> 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<T> const volatile var;",
+               "const volatile ::template Foo<T> var;", Style);
+  verifyFormat("typename ::template Foo<T> const volatile var;",
+               "const volatile typename ::template Foo<T> var;", Style);
+  verifyFormat("typename Bar::template Foo<T>::T const;",
+               "const typename Bar::template Foo<T>::T;", Style);
+  verifyFormat("typename Bar::template Foo<T>::T const volatile;",
+               "const volatile typename Bar::template Foo<T>::T;", Style);
+
+  // typename ::
+  verifyFormat("typename ::Bar<int> const;", "const typename ::Bar<int>;",
+               Style);
+  // typename ::template
+  verifyFormat("typename ::template Bar<int> const;",
+               "const typename ::template Bar<int>;", Style);
+
+  verifyFormat("foo<Bar<Baz> const>();", "foo<const Bar<Baz>>();", Style);
+  verifyFormat("foo<Bar<Baz> const>();", "foo<const Bar<Baz> >();", Style);
+  verifyFormat("Bar<32, Foo<25> const>;", "Bar<32, const Foo<25>>;", Style);
+  verifyFormat("A<B<C<D> const> const>;", "A<const B<const C<D>>>;", Style);
+  verifyFormat("A<B<C<D const> const> const>;", "A<const B<const C<const D>>>;",
+               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<int> const v;",
+               "const /*comment*/ std::vector<int> v;", Style);
+  verifyFormat("std /*comment*/ ::vector<int> const v;",
+               "const std /*comment*/ ::vector<int> v;", Style);
+  verifyFormat("std::/*comment*/ vector<int> const v;",
+               "const std::/*comment*/ vector<int> v;", Style);
+  verifyFormat("std::vector /*comment*/<int> const v;",
+               "const std::vector /*comment*/ <int> v;", Style);
+  verifyFormat("std::vector</*comment*/ int> const v;",
+               "const std::vector</*comment*/ int> v;", Style);
+  verifyFormat("std::vector<int /*comment*/> const v;",
+               "const std::vector<int /*comment*/> v;", Style);
+  verifyFormat("std::vector<int> const /*comment*/ v;",
+               "const std::vector<int> /*comment*/ v;", Style);
+
+  verifyFormat("std::vector</*comment*/ int const> v;",
+               "std::vector</*comment*/ const int> v;", Style);
+  verifyFormat("std::vector</*comment*/ int const> v;",
+               "std::vector<const /*comment*/ int> v;", Style);
+  verifyFormat("std::vector<int const /*comment*/> v;",
+               "std::vector<const int /*comment*/> v;", Style);
+  verifyFormat("std::vector</*comment*/ Foo const> v;",
+               "std::vector</*comment*/ const Foo> v;", Style);
+  verifyFormat("std::vector</*comment*/ Foo const> v;",
+               "std::vector<const /*comment*/ Foo> v;", Style);
+  verifyFormat("std::vector<Foo const /*comment*/> v;",
+               "std::vector<const Foo /*comment*/> v;", Style);
+
+  verifyFormat("typename C<T>::template B<T> const;",
+               "const typename C<T>::template B<T>;", Style);
+  verifyFormat("/*c*/ typename C<T>::template B<T> const;",
+               "const /*c*/ typename C<T>::template B<T>;", Style);
+  verifyFormat("typename /*c*/ C<T>::template B<T> const;",
+               "const typename /*c*/ C<T>::template B<T>;", Style);
+  verifyFormat("typename C /*c*/<T>::template B<T> const;",
+               "const typename C /*c*/<T>::template B<T>;", Style);
+  verifyFormat("typename C<T> /*c*/ ::template B<T> const;",
+               "const typename C<T> /*c*/ ::template B<T>;", Style);
+  verifyFormat("typename C<T>::/*c*/ template B<T> const;",
+               "const typename C<T>::/*c*/ template B<T>;", Style);
+  verifyFormat("typename C<T>::template /*c*/ B<T> const;",
+               "const typename C<T>::template /*c*/B<T>;", Style);
+  verifyFormat("typename C<T>::template B<T> const /*c*/;",
+               "const typename C<T>::template B<T>/*c*/;", Style);
+
+  verifyFormat("/*c*/ /*c*/ typename /*c*/ C /*c*/<T> /*c*/ ::/*c*/ template "
+               "/*c*/ B /*c*/<T> const /*c*/ v;",
+               "/*c*/ const /*c*/ typename /*c*/ C /*c*/<T> /*c*/ "
+               "::/*c*/template /*c*/ B /*c*/<T> /*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<int", Style);
   verifyFormat("const std::Foo<int>", "const std::Foo<int>", Style);
 
-  // don't adjust macros
+  // Multiple template parameters.
+  verifyFormat("Bar<const std::Foo, 32>;", "Bar<std::Foo const, 32>;", Style);
+
+  // Variable declaration based on template type.
+  verifyFormat("Bar<const std::Foo> bar;", "Bar<std::Foo const> 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<const Bar<Baz<T>>>();", "foo<Bar<Baz<T>> const>();", Style);
+  verifyFormat("foo<const Bar<Baz<T>>>();", "foo<Bar<Baz<T> > const>();",
+               Style);
+  verifyFormat("Bar<32, const Foo<25>>;", "Bar<32, Foo<25> const>;", Style);
+  verifyFormat("A<const B<const C<D>>>;", "A<B<C<D> const> const>;", Style);
+  verifyFormat("A<const B<const C<const D>>>;", "A<B<C<D const> 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<T> var;",
+               "::template Foo<T> const volatile var;", Style);
+  verifyFormat("const volatile typename ::template Foo<T> var;",
+               "typename ::template Foo<T> const volatile var;", Style);
+  verifyFormat("const typename Bar::template Foo<T>::T;",
+               "typename Bar::template Foo<T>::T const;", Style);
+  verifyFormat("const volatile typename Bar::template Foo<T>::T;",
+               "typename Bar::template Foo<T>::T const volatile;", Style);
+
+  // typename ::
+  verifyFormat("const typename ::Bar<int>;", "typename ::Bar<int> const;",
+               Style);
+  // typename ::template
+  verifyFormat("const typename ::template Bar<int>;",
+               "typename ::template Bar<int> 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<int> v;",
+               "/*comment*/ std::vector<int> const v;", Style);
+  verifyFormat("const std /*comment*/ ::vector<int> v;",
+               "std /*comment*/ ::vector<int> const v;", Style);
+  verifyFormat("const std::/*comment*/ vector<int> v;",
+               "std::/*comment*/ vector<int> const v;", Style);
+  verifyFormat("const std::vector /*comment*/<int> v;",
+               "std::vector /*comment*/<int> const v;", Style);
+  verifyFormat("const std::vector</*comment*/ int> v;",
+               "std::vector</*comment*/ int> const v;", Style);
+  verifyFormat("const std::vector<int /*comment*/> v;",
+               "std::vector<int /*comment*/> const v;", Style);
+  verifyFormat("const std::vector<int> /*comment*/ v;",
+               "std::vector<int> /*comment*/ const v;", Style);
+
+  verifyFormat("std::vector</*comment*/ const int> v;",
+               "std::vector</*comment*/ int const> v;", Style);
+  verifyFormat("std::vector<const int /*comment*/> v;",
+               "std::vector<int /*comment*/ const> v;", Style);
+  verifyFormat("std::vector<const int /*comment*/> v;",
+               "std::vector<int const /*comment*/> v;", Style);
+  verifyFormat("std::vector</*comment*/ const Foo> v;",
+               "std::vector</*comment*/ Foo const> v;", Style);
+  verifyFormat("std::vector<const Foo /*comment*/> v;",
+               "std::vector<Foo /*comment*/ const> v;", Style);
+  verifyFormat("std::vector<const Foo /*comment*/> v;",
+               "std::vector<Foo const /*comment*/> v;", Style);
+
+  verifyFormat("const typename C<T>::template B<T>;",
+               "typename C<T>::template B<T> const;", Style);
+  verifyFormat("/*c*/ const typename C<T>::template B<T>;",
+               "/*c*/ typename C<T>::template B<T> const;", Style);
+  verifyFormat("const typename /*c*/ C<T>::template B<T>;",
+               "typename /*c*/ C<T>::template B<T> const;", Style);
+  verifyFormat("const typename C /*c*/<T>::template B<T>;",
+               "typename C /*c*/<T>::template B<T> const;", Style);
+  verifyFormat("const typename C<T> /*c*/ ::template B<T>;",
+               "typename C<T> /*c*/ ::template B<T> const;", Style);
+  verifyFormat("const typename C<T>::/*c*/ template B<T>;",
+               "typename C<T>::/*c*/ template B<T> const;", Style);
+  verifyFormat("const typename C<T>::template /*c*/ B<T>;",
+               "typename C<T>::template /*c*/ B<T> const;", Style);
+  verifyFormat("const typename C<T>::template B<T> /*c*/;",
+               "typename C<T>::template B<T> /*c*/ const;", Style);
+
+  verifyFormat("/*c*/ const typename /*c*/ C /*c*/<T> /*c*/ ::/*c*/ template "
+               "/*c*/ B /*c*/<T> /*c*/ v;",
+               "/*c*/ typename /*c*/ C /*c*/<T> /*c*/ ::/*c*/ template /*c*/ B "
+               "/*c*/<T> /*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 <typename T> Foo const f();",
+               "template <typename T> const Foo f();", Style);
+  verifyFormat("template <typename T> int const f();",
+               "template <typename T> const int f();", Style);
+
+  verifyFormat("template <T const> t;", "template <const T> t;", Style);
   verifyFormat("template <typename T>\n"
                "  requires Concept<T const>\n"
-               "void f();",
+               "Foo const f();",
                "template <typename T>\n"
                "  requires Concept<const T>\n"
-               "void f();",
+               "const Foo f();",
                Style);
   verifyFormat("TemplateType<T const> t;", "TemplateType<const T> t;", Style);
   verifyFormat("TemplateType<Container const> 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 <typename T> const Foo f();",
+               "template <typename T> Foo const f();", Style);
+  verifyFormat("template <typename T> const int f();",
+               "template <typename T> int const f();", Style);
 
   verifyFormat("template <const T> t;", "template <T const> t;", Style);
   verifyFormat("template <typename T>\n"
                "  requires Concept<const T>\n"
-               "void f();",
+               "const Foo f();",
+               "template <typename T>\n"
+               "  requires Concept<T const>\n"
+               "Foo const f();",
+               Style);
+  verifyFormat("template <typename T>\n"
+               "  requires Concept<const T>\n"
+               "const volatile Foo f();",
                "template <typename T>\n"
                "  requires Concept<T const>\n"
-               "void f();",
+               "volatile const Foo f();",
                Style);
   verifyFormat("TemplateType<const T> t;", "TemplateType<T const> t;", Style);
   verifyFormat("TemplateType<const Container> t;",


        


More information about the cfe-commits mailing list