xref: /llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp (revision 3bd8b02aa0c5fcbb005f6d72f58f4a05421e7823)
12c9372e7SMyDeveloperDay //===--- QualifierAlignmentFixer.cpp ----------------------------*- C++--*-===//
2a44ab170Smydeveloperday //
3a44ab170Smydeveloperday // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a44ab170Smydeveloperday // See https://llvm.org/LICENSE.txt for license information.
5a44ab170Smydeveloperday // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a44ab170Smydeveloperday //
7a44ab170Smydeveloperday //===----------------------------------------------------------------------===//
8a44ab170Smydeveloperday ///
9a44ab170Smydeveloperday /// \file
102c9372e7SMyDeveloperDay /// This file implements QualifierAlignmentFixer, a TokenAnalyzer that
11a44ab170Smydeveloperday /// enforces either left or right const depending on the style.
12a44ab170Smydeveloperday ///
13a44ab170Smydeveloperday //===----------------------------------------------------------------------===//
14a44ab170Smydeveloperday 
15a44ab170Smydeveloperday #include "QualifierAlignmentFixer.h"
16b2082a98SOwen Pan #include "FormatToken.h"
17b2082a98SOwen Pan #include "llvm/Support/Debug.h"
18b2082a98SOwen Pan #include "llvm/Support/Regex.h"
19b2082a98SOwen Pan 
20b2082a98SOwen Pan #include <algorithm>
21b2082a98SOwen Pan #include <optional>
22a44ab170Smydeveloperday 
23a44ab170Smydeveloperday #define DEBUG_TYPE "format-qualifier-alignment-fixer"
24a44ab170Smydeveloperday 
25a44ab170Smydeveloperday namespace clang {
26a44ab170Smydeveloperday namespace format {
27a44ab170Smydeveloperday 
28899c8677SSedenion void addQualifierAlignmentFixerPasses(const FormatStyle &Style,
29899c8677SSedenion                                       SmallVectorImpl<AnalyzerPass> &Passes) {
30a44ab170Smydeveloperday   std::vector<std::string> LeftOrder;
31a44ab170Smydeveloperday   std::vector<std::string> RightOrder;
32a44ab170Smydeveloperday   std::vector<tok::TokenKind> ConfiguredQualifierTokens;
33899c8677SSedenion   prepareLeftRightOrderingForQualifierAlignmentFixer(
34899c8677SSedenion       Style.QualifierOrder, LeftOrder, RightOrder, ConfiguredQualifierTokens);
35a44ab170Smydeveloperday 
367d639734SMarek Kurdej   // Handle the left and right alignment separately.
37a44ab170Smydeveloperday   for (const auto &Qualifier : LeftOrder) {
38a44ab170Smydeveloperday     Passes.emplace_back(
39a44ab170Smydeveloperday         [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
40a44ab170Smydeveloperday           return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
41a44ab170Smydeveloperday                                                   ConfiguredQualifierTokens,
42a44ab170Smydeveloperday                                                   /*RightAlign=*/false)
43a44ab170Smydeveloperday               .process();
44a44ab170Smydeveloperday         });
45a44ab170Smydeveloperday   }
46a44ab170Smydeveloperday   for (const auto &Qualifier : RightOrder) {
47a44ab170Smydeveloperday     Passes.emplace_back(
48a44ab170Smydeveloperday         [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
49a44ab170Smydeveloperday           return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
50a44ab170Smydeveloperday                                                   ConfiguredQualifierTokens,
51a44ab170Smydeveloperday                                                   /*RightAlign=*/true)
52a44ab170Smydeveloperday               .process();
53a44ab170Smydeveloperday         });
54a44ab170Smydeveloperday   }
55a44ab170Smydeveloperday }
56a44ab170Smydeveloperday 
57a44ab170Smydeveloperday static void replaceToken(const SourceManager &SourceMgr,
58a44ab170Smydeveloperday                          tooling::Replacements &Fixes,
59a44ab170Smydeveloperday                          const CharSourceRange &Range, std::string NewText) {
60a44ab170Smydeveloperday   auto Replacement = tooling::Replacement(SourceMgr, Range, NewText);
61a44ab170Smydeveloperday   auto Err = Fixes.add(Replacement);
62a44ab170Smydeveloperday 
63bebf7bdfSowenca   if (Err) {
64a44ab170Smydeveloperday     llvm::errs() << "Error while rearranging Qualifier : "
65a44ab170Smydeveloperday                  << llvm::toString(std::move(Err)) << "\n";
66a44ab170Smydeveloperday   }
67bebf7bdfSowenca }
68a44ab170Smydeveloperday 
69a44ab170Smydeveloperday static void removeToken(const SourceManager &SourceMgr,
70a44ab170Smydeveloperday                         tooling::Replacements &Fixes,
71a44ab170Smydeveloperday                         const FormatToken *First) {
72a44ab170Smydeveloperday   auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
73a44ab170Smydeveloperday                                              First->Tok.getEndLoc());
74a44ab170Smydeveloperday   replaceToken(SourceMgr, Fixes, Range, "");
75a44ab170Smydeveloperday }
76a44ab170Smydeveloperday 
77a44ab170Smydeveloperday static void insertQualifierAfter(const SourceManager &SourceMgr,
78a44ab170Smydeveloperday                                  tooling::Replacements &Fixes,
79a44ab170Smydeveloperday                                  const FormatToken *First,
80a44ab170Smydeveloperday                                  const std::string &Qualifier) {
81cd7ab4b5SAlexander Hederstaf   auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(),
82cd7ab4b5SAlexander Hederstaf                                              First->Tok.getEndLoc());
83a44ab170Smydeveloperday 
84cd7ab4b5SAlexander Hederstaf   std::string NewText{};
85cd7ab4b5SAlexander Hederstaf   NewText += First->TokenText;
86cd7ab4b5SAlexander Hederstaf   NewText += " " + Qualifier;
87a44ab170Smydeveloperday   replaceToken(SourceMgr, Fixes, Range, NewText);
88a44ab170Smydeveloperday }
89a44ab170Smydeveloperday 
90a44ab170Smydeveloperday static void insertQualifierBefore(const SourceManager &SourceMgr,
91a44ab170Smydeveloperday                                   tooling::Replacements &Fixes,
92a44ab170Smydeveloperday                                   const FormatToken *First,
93a44ab170Smydeveloperday                                   const std::string &Qualifier) {
94a44ab170Smydeveloperday   auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
95a44ab170Smydeveloperday                                              First->Tok.getEndLoc());
96a44ab170Smydeveloperday 
97a44ab170Smydeveloperday   std::string NewText = " " + Qualifier + " ";
98a44ab170Smydeveloperday   NewText += First->TokenText;
99a44ab170Smydeveloperday 
100a44ab170Smydeveloperday   replaceToken(SourceMgr, Fixes, Range, NewText);
101a44ab170Smydeveloperday }
102a44ab170Smydeveloperday 
103a44ab170Smydeveloperday static bool endsWithSpace(const std::string &s) {
104d079995dSMarek Kurdej   if (s.empty())
105a44ab170Smydeveloperday     return false;
106a44ab170Smydeveloperday   return isspace(s.back());
107a44ab170Smydeveloperday }
108a44ab170Smydeveloperday 
109a44ab170Smydeveloperday static bool startsWithSpace(const std::string &s) {
110d079995dSMarek Kurdej   if (s.empty())
111a44ab170Smydeveloperday     return false;
112a44ab170Smydeveloperday   return isspace(s.front());
113a44ab170Smydeveloperday }
114a44ab170Smydeveloperday 
115a44ab170Smydeveloperday static void rotateTokens(const SourceManager &SourceMgr,
116a44ab170Smydeveloperday                          tooling::Replacements &Fixes, const FormatToken *First,
117a44ab170Smydeveloperday                          const FormatToken *Last, bool Left) {
118a44ab170Smydeveloperday   auto *End = Last;
119a44ab170Smydeveloperday   auto *Begin = First;
120a44ab170Smydeveloperday   if (!Left) {
121a44ab170Smydeveloperday     End = Last->Next;
122a44ab170Smydeveloperday     Begin = First->Next;
123a44ab170Smydeveloperday   }
124a44ab170Smydeveloperday 
125a44ab170Smydeveloperday   std::string NewText;
126a44ab170Smydeveloperday   // If we are rotating to the left we move the Last token to the front.
127a44ab170Smydeveloperday   if (Left) {
128a44ab170Smydeveloperday     NewText += Last->TokenText;
129a44ab170Smydeveloperday     NewText += " ";
130a44ab170Smydeveloperday   }
131a44ab170Smydeveloperday 
132a44ab170Smydeveloperday   // Then move through the other tokens.
133a44ab170Smydeveloperday   auto *Tok = Begin;
134a44ab170Smydeveloperday   while (Tok != End) {
135d079995dSMarek Kurdej     if (!NewText.empty() && !endsWithSpace(NewText))
136a44ab170Smydeveloperday       NewText += " ";
137a44ab170Smydeveloperday 
138a44ab170Smydeveloperday     NewText += Tok->TokenText;
139a44ab170Smydeveloperday     Tok = Tok->Next;
140a44ab170Smydeveloperday   }
141a44ab170Smydeveloperday 
142a44ab170Smydeveloperday   // If we are rotating to the right we move the first token to the back.
143a44ab170Smydeveloperday   if (!Left) {
144d079995dSMarek Kurdej     if (!NewText.empty() && !startsWithSpace(NewText))
145a44ab170Smydeveloperday       NewText += " ";
146a44ab170Smydeveloperday     NewText += First->TokenText;
147a44ab170Smydeveloperday   }
148a44ab170Smydeveloperday 
149a44ab170Smydeveloperday   auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
150a44ab170Smydeveloperday                                              Last->Tok.getEndLoc());
151a44ab170Smydeveloperday 
152a44ab170Smydeveloperday   replaceToken(SourceMgr, Fixes, Range, NewText);
153a44ab170Smydeveloperday }
154a44ab170Smydeveloperday 
155cd7ab4b5SAlexander Hederstaf static bool
156cd7ab4b5SAlexander Hederstaf isConfiguredQualifier(const FormatToken *const Tok,
157cd7ab4b5SAlexander Hederstaf                       const std::vector<tok::TokenKind> &Qualifiers) {
158cd7ab4b5SAlexander Hederstaf   return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind());
159cd7ab4b5SAlexander Hederstaf }
160cd7ab4b5SAlexander Hederstaf 
161cd7ab4b5SAlexander Hederstaf static bool isQualifier(const FormatToken *const Tok) {
162cd7ab4b5SAlexander Hederstaf   if (!Tok)
163cd7ab4b5SAlexander Hederstaf     return false;
164cd7ab4b5SAlexander Hederstaf 
165cd7ab4b5SAlexander Hederstaf   switch (Tok->Tok.getKind()) {
166cd7ab4b5SAlexander Hederstaf   case tok::kw_const:
167cd7ab4b5SAlexander Hederstaf   case tok::kw_volatile:
168cd7ab4b5SAlexander Hederstaf   case tok::kw_static:
169cd7ab4b5SAlexander Hederstaf   case tok::kw_inline:
170cd7ab4b5SAlexander Hederstaf   case tok::kw_constexpr:
171cd7ab4b5SAlexander Hederstaf   case tok::kw_restrict:
172cd7ab4b5SAlexander Hederstaf   case tok::kw_friend:
173cd7ab4b5SAlexander Hederstaf     return true;
174cd7ab4b5SAlexander Hederstaf   default:
175cd7ab4b5SAlexander Hederstaf     return false;
176cd7ab4b5SAlexander Hederstaf   }
177cd7ab4b5SAlexander Hederstaf }
178cd7ab4b5SAlexander Hederstaf 
179031d3eceSmydeveloperday const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
180a44ab170Smydeveloperday     const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
181cd7ab4b5SAlexander Hederstaf     tooling::Replacements &Fixes, const FormatToken *const Tok,
182a44ab170Smydeveloperday     const std::string &Qualifier, tok::TokenKind QualifierType) {
183a44ab170Smydeveloperday   // We only need to think about streams that begin with a qualifier.
18491c4db00SOwen Pan   if (Tok->isNot(QualifierType))
185a44ab170Smydeveloperday     return Tok;
186a44ab170Smydeveloperday   // Don't concern yourself if nothing follows the qualifier.
187a44ab170Smydeveloperday   if (!Tok->Next)
188a44ab170Smydeveloperday     return Tok;
189a44ab170Smydeveloperday 
190cd7ab4b5SAlexander Hederstaf   // Skip qualifiers to the left to find what preceeds the qualifiers.
191cd7ab4b5SAlexander Hederstaf   // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers.
192cd7ab4b5SAlexander Hederstaf   const FormatToken *PreviousCheck = Tok->getPreviousNonComment();
193cd7ab4b5SAlexander Hederstaf   while (isQualifier(PreviousCheck))
194cd7ab4b5SAlexander Hederstaf     PreviousCheck = PreviousCheck->getPreviousNonComment();
195d4d28f2aSMarek Kurdej 
196cd7ab4b5SAlexander Hederstaf   // Examples given in order of ['type', 'const', 'volatile']
197cd7ab4b5SAlexander Hederstaf   const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() {
198cd7ab4b5SAlexander Hederstaf     // The cases:
199cd7ab4b5SAlexander Hederstaf     // `Foo() const` -> `Foo() const`
200cd7ab4b5SAlexander Hederstaf     // `Foo() const final` -> `Foo() const final`
201cd7ab4b5SAlexander Hederstaf     // `Foo() const override` -> `Foo() const final`
202cd7ab4b5SAlexander Hederstaf     // `Foo() const volatile override` -> `Foo() const volatile override`
203cd7ab4b5SAlexander Hederstaf     // `Foo() volatile const final` -> `Foo() const volatile final`
204cd7ab4b5SAlexander Hederstaf     if (PreviousCheck->is(tok::r_paren))
205cd7ab4b5SAlexander Hederstaf       return true;
206cd7ab4b5SAlexander Hederstaf 
207cd7ab4b5SAlexander Hederstaf     // The cases:
208cd7ab4b5SAlexander Hederstaf     // `struct {} volatile const a;` -> `struct {} const volatile a;`
209cd7ab4b5SAlexander Hederstaf     // `class {} volatile const a;` -> `class {} const volatile a;`
210cd7ab4b5SAlexander Hederstaf     if (PreviousCheck->is(tok::r_brace))
211cd7ab4b5SAlexander Hederstaf       return true;
212cd7ab4b5SAlexander Hederstaf 
213cd7ab4b5SAlexander Hederstaf     // The case:
214cd7ab4b5SAlexander Hederstaf     // `template <class T> const Bar Foo()` ->
215cd7ab4b5SAlexander Hederstaf     // `template <class T> Bar const Foo()`
216cd7ab4b5SAlexander Hederstaf     // The cases:
217cd7ab4b5SAlexander Hederstaf     // `Foo<int> const foo` -> `Foo<int> const foo`
218cd7ab4b5SAlexander Hederstaf     // `Foo<int> volatile const` -> `Foo<int> const volatile`
219cd7ab4b5SAlexander Hederstaf     // The case:
220cd7ab4b5SAlexander Hederstaf     // ```
221cd7ab4b5SAlexander Hederstaf     // template <class T>
222cd7ab4b5SAlexander Hederstaf     //   requires Concept1<T> && requires Concept2<T>
223cd7ab4b5SAlexander Hederstaf     // const Foo f();
224cd7ab4b5SAlexander Hederstaf     // ```
225cd7ab4b5SAlexander Hederstaf     // ->
226cd7ab4b5SAlexander Hederstaf     // ```
227cd7ab4b5SAlexander Hederstaf     // template <class T>
228cd7ab4b5SAlexander Hederstaf     //   requires Concept1<T> && requires Concept2<T>
229cd7ab4b5SAlexander Hederstaf     // Foo const f();
230cd7ab4b5SAlexander Hederstaf     // ```
231cd7ab4b5SAlexander Hederstaf     if (PreviousCheck->is(TT_TemplateCloser)) {
232cd7ab4b5SAlexander Hederstaf       // If the token closes a template<> or requires clause, then it is a left
233cd7ab4b5SAlexander Hederstaf       // qualifier and should be moved to the right.
234cd7ab4b5SAlexander Hederstaf       return !(PreviousCheck->ClosesTemplateDeclaration ||
235cd7ab4b5SAlexander Hederstaf                PreviousCheck->ClosesRequiresClause);
236a44ab170Smydeveloperday     }
237cd7ab4b5SAlexander Hederstaf 
238cd7ab4b5SAlexander Hederstaf     // The case  `Foo* const` -> `Foo* const`
239cd7ab4b5SAlexander Hederstaf     // The case  `Foo* volatile const` -> `Foo* const volatile`
240cd7ab4b5SAlexander Hederstaf     // The case  `int32_t const` -> `int32_t const`
241cd7ab4b5SAlexander Hederstaf     // The case  `auto volatile const` -> `auto const volatile`
242cd7ab4b5SAlexander Hederstaf     if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier,
243cd7ab4b5SAlexander Hederstaf                                tok::kw_auto)) {
244cd7ab4b5SAlexander Hederstaf       return true;
245cd7ab4b5SAlexander Hederstaf     }
246cd7ab4b5SAlexander Hederstaf 
247cd7ab4b5SAlexander Hederstaf     return false;
248cd7ab4b5SAlexander Hederstaf   }();
249cd7ab4b5SAlexander Hederstaf 
250cd7ab4b5SAlexander Hederstaf   // Find the last qualifier to the right.
251cd7ab4b5SAlexander Hederstaf   const FormatToken *LastQual = Tok;
252cd7ab4b5SAlexander Hederstaf   while (isQualifier(LastQual->getNextNonComment()))
253cd7ab4b5SAlexander Hederstaf     LastQual = LastQual->getNextNonComment();
254cd7ab4b5SAlexander Hederstaf 
255cd7ab4b5SAlexander Hederstaf   // If this qualifier is to the right of a type or pointer do a partial sort
256cd7ab4b5SAlexander Hederstaf   // and return.
257cd7ab4b5SAlexander Hederstaf   if (IsRightQualifier) {
258cd7ab4b5SAlexander Hederstaf     if (LastQual != Tok)
259a44ab170Smydeveloperday       rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
26028bb040dSmydeveloperday     return Tok;
261cd7ab4b5SAlexander Hederstaf   }
262cd7ab4b5SAlexander Hederstaf 
263cd7ab4b5SAlexander Hederstaf   const FormatToken *TypeToken = LastQual->getNextNonComment();
264cd7ab4b5SAlexander Hederstaf   if (!TypeToken)
265cd7ab4b5SAlexander Hederstaf     return Tok;
266cd7ab4b5SAlexander Hederstaf 
267cd7ab4b5SAlexander Hederstaf   // Stay safe and don't move past macros, also don't bother with sorting.
268cd7ab4b5SAlexander Hederstaf   if (isPossibleMacro(TypeToken))
269cd7ab4b5SAlexander Hederstaf     return Tok;
270cd7ab4b5SAlexander Hederstaf 
271cd7ab4b5SAlexander Hederstaf   // The case `const long long int volatile` -> `long long int const volatile`
272cd7ab4b5SAlexander Hederstaf   // The case `long const long int volatile` -> `long long int const volatile`
273cd7ab4b5SAlexander Hederstaf   // The case `long long volatile int const` -> `long long int const volatile`
274cd7ab4b5SAlexander Hederstaf   // The case `const long long volatile int` -> `long long int const volatile`
275364f988dSOwen Pan   if (TypeToken->isTypeName(LangOpts)) {
276cd7ab4b5SAlexander Hederstaf     // The case `const decltype(foo)` -> `const decltype(foo)`
277cd7ab4b5SAlexander Hederstaf     // The case `const typeof(foo)` -> `const typeof(foo)`
278cd7ab4b5SAlexander Hederstaf     // The case `const _Atomic(foo)` -> `const _Atomic(foo)`
279cd7ab4b5SAlexander Hederstaf     if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
280cd7ab4b5SAlexander Hederstaf       return Tok;
281cd7ab4b5SAlexander Hederstaf 
282cd7ab4b5SAlexander Hederstaf     const FormatToken *LastSimpleTypeSpecifier = TypeToken;
2836f31cf51SOwen Pan     while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
284364f988dSOwen Pan                              LangOpts)) {
285cd7ab4b5SAlexander Hederstaf       LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
2866f31cf51SOwen Pan     }
287cd7ab4b5SAlexander Hederstaf 
288cd7ab4b5SAlexander Hederstaf     rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
289cd7ab4b5SAlexander Hederstaf                  /*Left=*/false);
290cd7ab4b5SAlexander Hederstaf     return LastSimpleTypeSpecifier;
291cd7ab4b5SAlexander Hederstaf   }
292cd7ab4b5SAlexander Hederstaf 
293cd7ab4b5SAlexander Hederstaf   // The case  `unsigned short const` -> `unsigned short const`
294cd7ab4b5SAlexander Hederstaf   // The case:
295cd7ab4b5SAlexander Hederstaf   // `unsigned short volatile const` -> `unsigned short const volatile`
296364f988dSOwen Pan   if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) {
297cd7ab4b5SAlexander Hederstaf     if (LastQual != Tok)
298cd7ab4b5SAlexander Hederstaf       rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
299cd7ab4b5SAlexander Hederstaf     return Tok;
300cd7ab4b5SAlexander Hederstaf   }
301cd7ab4b5SAlexander Hederstaf 
302cd7ab4b5SAlexander Hederstaf   // Skip the typename keyword.
303cd7ab4b5SAlexander Hederstaf   // The case `const typename C::type` -> `typename C::type const`
304cd7ab4b5SAlexander Hederstaf   if (TypeToken->is(tok::kw_typename))
305cd7ab4b5SAlexander Hederstaf     TypeToken = TypeToken->getNextNonComment();
306cd7ab4b5SAlexander Hederstaf 
307cd7ab4b5SAlexander Hederstaf   // Skip the initial :: of a global-namespace type.
308cd7ab4b5SAlexander Hederstaf   // The case `const ::...` -> `::... const`
309cd7ab4b5SAlexander Hederstaf   if (TypeToken->is(tok::coloncolon)) {
310cd7ab4b5SAlexander Hederstaf     // The case `const ::template Foo...` -> `::template Foo... const`
311cd7ab4b5SAlexander Hederstaf     TypeToken = TypeToken->getNextNonComment();
312cd7ab4b5SAlexander Hederstaf     if (TypeToken && TypeToken->is(tok::kw_template))
313cd7ab4b5SAlexander Hederstaf       TypeToken = TypeToken->getNextNonComment();
314cd7ab4b5SAlexander Hederstaf   }
315cd7ab4b5SAlexander Hederstaf 
316cd7ab4b5SAlexander Hederstaf   // Don't change declarations such as
317cd7ab4b5SAlexander Hederstaf   // `foo(const struct Foo a);` -> `foo(const struct Foo a);`
318cd7ab4b5SAlexander Hederstaf   // as they would currently change code such as
319cd7ab4b5SAlexander Hederstaf   // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {}
320cd7ab4b5SAlexander Hederstaf   // my_struct;`
321cd7ab4b5SAlexander Hederstaf   if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class))
322cd7ab4b5SAlexander Hederstaf     return Tok;
323cd7ab4b5SAlexander Hederstaf 
324cd7ab4b5SAlexander Hederstaf   if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) {
325cd7ab4b5SAlexander Hederstaf     // The case  `const auto` -> `auto const`
326a44ab170Smydeveloperday     // The case  `const Foo` -> `Foo const`
327d4d28f2aSMarek Kurdej     // The case  `const ::Foo` -> `::Foo const`
328a44ab170Smydeveloperday     // The case  `const Foo *` -> `Foo const *`
329a44ab170Smydeveloperday     // The case  `const Foo &` -> `Foo const &`
330a44ab170Smydeveloperday     // The case  `const Foo &&` -> `Foo const &&`
331a44ab170Smydeveloperday     // The case  `const std::Foo &&` -> `std::Foo const &&`
332a44ab170Smydeveloperday     // The case  `const std::Foo<T> &&` -> `std::Foo<T> const &&`
333cd7ab4b5SAlexander Hederstaf     // The case  `const ::template Foo` -> `::template Foo const`
334cd7ab4b5SAlexander Hederstaf     // The case  `const T::template Foo` -> `T::template Foo const`
335cd7ab4b5SAlexander Hederstaf     const FormatToken *Next = nullptr;
336cd7ab4b5SAlexander Hederstaf     while ((Next = TypeToken->getNextNonComment()) &&
337cd7ab4b5SAlexander Hederstaf            (Next->is(TT_TemplateOpener) ||
338cd7ab4b5SAlexander Hederstaf             Next->startsSequence(tok::coloncolon, tok::identifier) ||
339cd7ab4b5SAlexander Hederstaf             Next->startsSequence(tok::coloncolon, tok::kw_template,
340cd7ab4b5SAlexander Hederstaf                                  tok::identifier))) {
341cd7ab4b5SAlexander Hederstaf       if (Next->is(TT_TemplateOpener)) {
342cd7ab4b5SAlexander Hederstaf         assert(Next->MatchingParen && "Missing template closer");
343cd7ab4b5SAlexander Hederstaf         TypeToken = Next->MatchingParen;
344cd7ab4b5SAlexander Hederstaf       } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) {
345cd7ab4b5SAlexander Hederstaf         TypeToken = Next->getNextNonComment();
346cd7ab4b5SAlexander Hederstaf       } else {
347cd7ab4b5SAlexander Hederstaf         TypeToken = Next->getNextNonComment()->getNextNonComment();
348393e197cSEmilia Dreamer       }
349bebf7bdfSowenca     }
350cd7ab4b5SAlexander Hederstaf 
35140acaa39SOwen Pan     if (Next && Next->is(tok::kw_auto))
352b04664beSOwen Pan       TypeToken = Next;
353b04664beSOwen Pan 
354cd7ab4b5SAlexander Hederstaf     // Place the Qualifier at the end of the list of qualifiers.
355cd7ab4b5SAlexander Hederstaf     while (isQualifier(TypeToken->getNextNonComment())) {
356cd7ab4b5SAlexander Hederstaf       // The case `volatile Foo::iter const` -> `Foo::iter const volatile`
357cd7ab4b5SAlexander Hederstaf       TypeToken = TypeToken->getNextNonComment();
358a44ab170Smydeveloperday     }
359cd7ab4b5SAlexander Hederstaf 
360cd7ab4b5SAlexander Hederstaf     insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier);
361cd7ab4b5SAlexander Hederstaf     // Remove token and following whitespace.
362cd7ab4b5SAlexander Hederstaf     auto Range = CharSourceRange::getCharRange(
363cd7ab4b5SAlexander Hederstaf         Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace());
364cd7ab4b5SAlexander Hederstaf     replaceToken(SourceMgr, Fixes, Range, "");
365a44ab170Smydeveloperday   }
366a44ab170Smydeveloperday 
367a44ab170Smydeveloperday   return Tok;
368a44ab170Smydeveloperday }
369a44ab170Smydeveloperday 
370031d3eceSmydeveloperday const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
371a44ab170Smydeveloperday     const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
372cd7ab4b5SAlexander Hederstaf     tooling::Replacements &Fixes, const FormatToken *const Tok,
373a44ab170Smydeveloperday     const std::string &Qualifier, tok::TokenKind QualifierType) {
374cd7ab4b5SAlexander Hederstaf   // We only need to think about streams that begin with a qualifier.
37591c4db00SOwen Pan   if (Tok->isNot(QualifierType))
376cd7ab4b5SAlexander Hederstaf     return Tok;
377cd7ab4b5SAlexander Hederstaf   // Don't concern yourself if nothing preceeds the qualifier.
378cd7ab4b5SAlexander Hederstaf   if (!Tok->getPreviousNonComment())
379a44ab170Smydeveloperday     return Tok;
380a44ab170Smydeveloperday 
381cd7ab4b5SAlexander Hederstaf   // Skip qualifiers to the left to find what preceeds the qualifiers.
382cd7ab4b5SAlexander Hederstaf   const FormatToken *TypeToken = Tok->getPreviousNonComment();
383cd7ab4b5SAlexander Hederstaf   while (isQualifier(TypeToken))
384cd7ab4b5SAlexander Hederstaf     TypeToken = TypeToken->getPreviousNonComment();
385cd7ab4b5SAlexander Hederstaf 
386cd7ab4b5SAlexander Hederstaf   // For left qualifiers preceeded by nothing, a template declaration, or *,&,&&
387cd7ab4b5SAlexander Hederstaf   // we only perform sorting.
388cc75e520SOwen Pan   if (!TypeToken || TypeToken->isPointerOrReference() ||
389*3bd8b02aSOwen Pan       TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration ||
390*3bd8b02aSOwen Pan       TypeToken->is(tok::r_square)) {
391cd7ab4b5SAlexander Hederstaf 
392cd7ab4b5SAlexander Hederstaf     // Don't sort past a non-configured qualifier token.
393cd7ab4b5SAlexander Hederstaf     const FormatToken *FirstQual = Tok;
394cd7ab4b5SAlexander Hederstaf     while (isConfiguredQualifier(FirstQual->getPreviousNonComment(),
395cd7ab4b5SAlexander Hederstaf                                  ConfiguredQualifierTokens)) {
396cd7ab4b5SAlexander Hederstaf       FirstQual = FirstQual->getPreviousNonComment();
397a44ab170Smydeveloperday     }
398a44ab170Smydeveloperday 
399cd7ab4b5SAlexander Hederstaf     if (FirstQual != Tok)
400cd7ab4b5SAlexander Hederstaf       rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true);
401a44ab170Smydeveloperday     return Tok;
402bebf7bdfSowenca   }
40328bb040dSmydeveloperday 
404cd7ab4b5SAlexander Hederstaf   // Stay safe and don't move past macros, also don't bother with sorting.
405cd7ab4b5SAlexander Hederstaf   if (isPossibleMacro(TypeToken))
406cd7ab4b5SAlexander Hederstaf     return Tok;
407a44ab170Smydeveloperday 
408cd7ab4b5SAlexander Hederstaf   // Examples given in order of ['const', 'volatile', 'type']
409cd7ab4b5SAlexander Hederstaf 
410cd7ab4b5SAlexander Hederstaf   // The case `volatile long long int const` -> `const volatile long long int`
411cd7ab4b5SAlexander Hederstaf   // The case `volatile long long const int` -> `const volatile long long int`
412cd7ab4b5SAlexander Hederstaf   // The case `const long long volatile int` -> `const volatile long long int`
413cd7ab4b5SAlexander Hederstaf   // The case `long volatile long int const` -> `const volatile long long int`
414364f988dSOwen Pan   if (TypeToken->isTypeName(LangOpts)) {
415cd7ab4b5SAlexander Hederstaf     const FormatToken *LastSimpleTypeSpecifier = TypeToken;
416cd7ab4b5SAlexander Hederstaf     while (isConfiguredQualifierOrType(
417cd7ab4b5SAlexander Hederstaf         LastSimpleTypeSpecifier->getPreviousNonComment(),
418364f988dSOwen Pan         ConfiguredQualifierTokens, LangOpts)) {
419cd7ab4b5SAlexander Hederstaf       LastSimpleTypeSpecifier =
420cd7ab4b5SAlexander Hederstaf           LastSimpleTypeSpecifier->getPreviousNonComment();
421a44ab170Smydeveloperday     }
422cd7ab4b5SAlexander Hederstaf 
423cd7ab4b5SAlexander Hederstaf     rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok,
424cd7ab4b5SAlexander Hederstaf                  /*Left=*/true);
425cd7ab4b5SAlexander Hederstaf     return Tok;
426a44ab170Smydeveloperday   }
427cd7ab4b5SAlexander Hederstaf 
428cd7ab4b5SAlexander Hederstaf   if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) {
429cd7ab4b5SAlexander Hederstaf     const auto IsStartOfType = [](const FormatToken *const Tok) -> bool {
430cd7ab4b5SAlexander Hederstaf       if (!Tok)
431cd7ab4b5SAlexander Hederstaf         return true;
432cd7ab4b5SAlexander Hederstaf 
433cd7ab4b5SAlexander Hederstaf       // A template closer is not the start of a type.
434cd7ab4b5SAlexander Hederstaf       // The case `?<> const` -> `const ?<>`
435cd7ab4b5SAlexander Hederstaf       if (Tok->is(TT_TemplateCloser))
436cd7ab4b5SAlexander Hederstaf         return false;
437cd7ab4b5SAlexander Hederstaf 
438cd7ab4b5SAlexander Hederstaf       const FormatToken *const Previous = Tok->getPreviousNonComment();
439cd7ab4b5SAlexander Hederstaf       if (!Previous)
440cd7ab4b5SAlexander Hederstaf         return true;
441cd7ab4b5SAlexander Hederstaf 
442cd7ab4b5SAlexander Hederstaf       // An identifier preceeded by :: is not the start of a type.
443cd7ab4b5SAlexander Hederstaf       // The case `?::Foo const` -> `const ?::Foo`
444cd7ab4b5SAlexander Hederstaf       if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon))
445cd7ab4b5SAlexander Hederstaf         return false;
446cd7ab4b5SAlexander Hederstaf 
447cd7ab4b5SAlexander Hederstaf       const FormatToken *const PrePrevious = Previous->getPreviousNonComment();
448cd7ab4b5SAlexander Hederstaf       // An identifier preceeded by ::template is not the start of a type.
449cd7ab4b5SAlexander Hederstaf       // The case `?::template Foo const` -> `const ?::template Foo`
450cd7ab4b5SAlexander Hederstaf       if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) &&
451cd7ab4b5SAlexander Hederstaf           PrePrevious && PrePrevious->is(tok::coloncolon)) {
452cd7ab4b5SAlexander Hederstaf         return false;
453cd7ab4b5SAlexander Hederstaf       }
454cd7ab4b5SAlexander Hederstaf 
455b04664beSOwen Pan       if (Tok->endsSequence(tok::kw_auto, tok::identifier))
456b04664beSOwen Pan         return false;
457b04664beSOwen Pan 
458cd7ab4b5SAlexander Hederstaf       return true;
459cd7ab4b5SAlexander Hederstaf     };
460cd7ab4b5SAlexander Hederstaf 
461cd7ab4b5SAlexander Hederstaf     while (!IsStartOfType(TypeToken)) {
462cd7ab4b5SAlexander Hederstaf       // The case `?<>`
463cd7ab4b5SAlexander Hederstaf       if (TypeToken->is(TT_TemplateCloser)) {
464cd7ab4b5SAlexander Hederstaf         assert(TypeToken->MatchingParen && "Missing template opener");
465cd7ab4b5SAlexander Hederstaf         TypeToken = TypeToken->MatchingParen->getPreviousNonComment();
466cd7ab4b5SAlexander Hederstaf       } else {
467cd7ab4b5SAlexander Hederstaf         // The cases
468cd7ab4b5SAlexander Hederstaf         // `::Foo`
469cd7ab4b5SAlexander Hederstaf         // `?>::Foo`
470cd7ab4b5SAlexander Hederstaf         // `?Bar::Foo`
471cd7ab4b5SAlexander Hederstaf         // `::template Foo`
472cd7ab4b5SAlexander Hederstaf         // `?>::template Foo`
473cd7ab4b5SAlexander Hederstaf         // `?Bar::template Foo`
474cd7ab4b5SAlexander Hederstaf         if (TypeToken->getPreviousNonComment()->is(tok::kw_template))
475cd7ab4b5SAlexander Hederstaf           TypeToken = TypeToken->getPreviousNonComment();
476cd7ab4b5SAlexander Hederstaf 
477cd7ab4b5SAlexander Hederstaf         const FormatToken *const ColonColon =
478cd7ab4b5SAlexander Hederstaf             TypeToken->getPreviousNonComment();
479cd7ab4b5SAlexander Hederstaf         const FormatToken *const PreColonColon =
480cd7ab4b5SAlexander Hederstaf             ColonColon->getPreviousNonComment();
481cd7ab4b5SAlexander Hederstaf         if (PreColonColon &&
482cd7ab4b5SAlexander Hederstaf             PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) {
483cd7ab4b5SAlexander Hederstaf           TypeToken = PreColonColon;
484cd7ab4b5SAlexander Hederstaf         } else {
485cd7ab4b5SAlexander Hederstaf           TypeToken = ColonColon;
486a44ab170Smydeveloperday         }
487a44ab170Smydeveloperday       }
488a44ab170Smydeveloperday     }
489cd7ab4b5SAlexander Hederstaf 
490cd7ab4b5SAlexander Hederstaf     assert(TypeToken && "Should be auto or identifier");
491cd7ab4b5SAlexander Hederstaf 
492cd7ab4b5SAlexander Hederstaf     // Place the Qualifier at the start of the list of qualifiers.
493cd7ab4b5SAlexander Hederstaf     const FormatToken *Previous = nullptr;
494cd7ab4b5SAlexander Hederstaf     while ((Previous = TypeToken->getPreviousNonComment()) &&
495cd7ab4b5SAlexander Hederstaf            (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) ||
496cd7ab4b5SAlexander Hederstaf             Previous->is(tok::kw_typename))) {
497cd7ab4b5SAlexander Hederstaf       // The case `volatile Foo::iter const` -> `const volatile Foo::iter`
498cd7ab4b5SAlexander Hederstaf       // The case `typename C::type const` -> `const typename C::type`
499cd7ab4b5SAlexander Hederstaf       TypeToken = Previous;
500cd7ab4b5SAlexander Hederstaf     }
501cd7ab4b5SAlexander Hederstaf 
502cd7ab4b5SAlexander Hederstaf     // Don't change declarations such as
503cd7ab4b5SAlexander Hederstaf     // `foo(struct Foo const a);` -> `foo(struct Foo const a);`
504cd7ab4b5SAlexander Hederstaf     if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) {
505cd7ab4b5SAlexander Hederstaf       insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier);
506cd7ab4b5SAlexander Hederstaf       removeToken(SourceMgr, Fixes, Tok);
507cd7ab4b5SAlexander Hederstaf     }
508cd7ab4b5SAlexander Hederstaf   }
509cd7ab4b5SAlexander Hederstaf 
510a44ab170Smydeveloperday   return Tok;
511a44ab170Smydeveloperday }
512a44ab170Smydeveloperday 
513a44ab170Smydeveloperday tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
514a44ab170Smydeveloperday     const std::string &Qualifier) {
5152c60cfc0SMarek Kurdej   // Don't let 'type' be an identifier, but steal typeof token.
516a44ab170Smydeveloperday   return llvm::StringSwitch<tok::TokenKind>(Qualifier)
517a44ab170Smydeveloperday       .Case("type", tok::kw_typeof)
518a44ab170Smydeveloperday       .Case("const", tok::kw_const)
519a44ab170Smydeveloperday       .Case("volatile", tok::kw_volatile)
520a44ab170Smydeveloperday       .Case("static", tok::kw_static)
521a44ab170Smydeveloperday       .Case("inline", tok::kw_inline)
522a44ab170Smydeveloperday       .Case("constexpr", tok::kw_constexpr)
523a44ab170Smydeveloperday       .Case("restrict", tok::kw_restrict)
5244cafc372SMicah Weston       .Case("friend", tok::kw_friend)
525a44ab170Smydeveloperday       .Default(tok::identifier);
526a44ab170Smydeveloperday }
527a44ab170Smydeveloperday 
528a44ab170Smydeveloperday LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer(
529a44ab170Smydeveloperday     const Environment &Env, const FormatStyle &Style,
530a44ab170Smydeveloperday     const std::string &Qualifier,
531a44ab170Smydeveloperday     const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
532a44ab170Smydeveloperday     : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
5336f31cf51SOwen Pan       ConfiguredQualifierTokens(QualifierTokens) {}
534a44ab170Smydeveloperday 
535a44ab170Smydeveloperday std::pair<tooling::Replacements, unsigned>
536a44ab170Smydeveloperday LeftRightQualifierAlignmentFixer::analyze(
53706e42590SMarek Kurdej     TokenAnnotator & /*Annotator*/,
53806e42590SMarek Kurdej     SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
539a44ab170Smydeveloperday     FormatTokenLexer &Tokens) {
540a44ab170Smydeveloperday   tooling::Replacements Fixes;
541f0ad9ea3SOwen Pan   AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
542f0ad9ea3SOwen Pan   fixQualifierAlignment(AnnotatedLines, Tokens, Fixes);
543f0ad9ea3SOwen Pan   return {Fixes, 0};
544f0ad9ea3SOwen Pan }
545f0ad9ea3SOwen Pan 
546f0ad9ea3SOwen Pan void LeftRightQualifierAlignmentFixer::fixQualifierAlignment(
547f0ad9ea3SOwen Pan     SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens,
548f0ad9ea3SOwen Pan     tooling::Replacements &Fixes) {
549a44ab170Smydeveloperday   const AdditionalKeywords &Keywords = Tokens.getKeywords();
550a44ab170Smydeveloperday   const SourceManager &SourceMgr = Env.getSourceManager();
551a44ab170Smydeveloperday   tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier);
552a44ab170Smydeveloperday   assert(QualifierToken != tok::identifier && "Unrecognised Qualifier");
553a44ab170Smydeveloperday 
5544681ae93SMarek Kurdej   for (AnnotatedLine *Line : AnnotatedLines) {
555f0ad9ea3SOwen Pan     fixQualifierAlignment(Line->Children, Tokens, Fixes);
556f3dcd3adSColin Ogilvie     if (!Line->Affected || Line->InPPDirective)
557eee536ddSowenca       continue;
5584681ae93SMarek Kurdej     FormatToken *First = Line->First;
559e329b586SMarek Kurdej     assert(First);
560e329b586SMarek Kurdej     if (First->Finalized)
561e329b586SMarek Kurdej       continue;
562e329b586SMarek Kurdej 
5634681ae93SMarek Kurdej     const auto *Last = Line->Last;
564a44ab170Smydeveloperday 
565031d3eceSmydeveloperday     for (const auto *Tok = First; Tok && Tok != Last && Tok->Next;
566031d3eceSmydeveloperday          Tok = Tok->Next) {
567ea16a3bbSOwen Pan       if (Tok->MustBreakBefore)
568ea16a3bbSOwen Pan         break;
569a44ab170Smydeveloperday       if (Tok->is(tok::comment))
570a44ab170Smydeveloperday         continue;
571bebf7bdfSowenca       if (RightAlign) {
572a44ab170Smydeveloperday         Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier,
573a44ab170Smydeveloperday                            QualifierToken);
574bebf7bdfSowenca       } else {
575a44ab170Smydeveloperday         Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier,
576a44ab170Smydeveloperday                           QualifierToken);
577a44ab170Smydeveloperday       }
578a44ab170Smydeveloperday     }
579bebf7bdfSowenca   }
580a44ab170Smydeveloperday }
581a44ab170Smydeveloperday 
582899c8677SSedenion void prepareLeftRightOrderingForQualifierAlignmentFixer(
583a44ab170Smydeveloperday     const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
584a44ab170Smydeveloperday     std::vector<std::string> &RightOrder,
585a44ab170Smydeveloperday     std::vector<tok::TokenKind> &Qualifiers) {
586a44ab170Smydeveloperday 
587a44ab170Smydeveloperday   // Depending on the position of type in the order you need
588a44ab170Smydeveloperday   // To iterate forward or backward through the order list as qualifier
589a44ab170Smydeveloperday   // can push through each other.
590a44ab170Smydeveloperday   // The Order list must define the position of "type" to signify
591e567f37dSKazu Hirata   assert(llvm::is_contained(Order, "type") &&
592efb284c0SDmitri Gribenko          "QualifierOrder must contain type");
593a44ab170Smydeveloperday   // Split the Order list by type and reverse the left side.
594a44ab170Smydeveloperday 
595a44ab170Smydeveloperday   bool left = true;
596a44ab170Smydeveloperday   for (const auto &s : Order) {
597a44ab170Smydeveloperday     if (s == "type") {
598a44ab170Smydeveloperday       left = false;
599a44ab170Smydeveloperday       continue;
600a44ab170Smydeveloperday     }
601a44ab170Smydeveloperday 
602a44ab170Smydeveloperday     tok::TokenKind QualifierToken =
603a44ab170Smydeveloperday         LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s);
604d079995dSMarek Kurdej     if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier)
605a44ab170Smydeveloperday       Qualifiers.push_back(QualifierToken);
606a44ab170Smydeveloperday 
607bebf7bdfSowenca     if (left) {
608a44ab170Smydeveloperday       // Reverse the order for left aligned items.
609a44ab170Smydeveloperday       LeftOrder.insert(LeftOrder.begin(), s);
610bebf7bdfSowenca     } else {
611a44ab170Smydeveloperday       RightOrder.push_back(s);
612a44ab170Smydeveloperday     }
613a44ab170Smydeveloperday   }
614bebf7bdfSowenca }
615a44ab170Smydeveloperday 
616364f988dSOwen Pan bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) {
617364f988dSOwen Pan   return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
618364f988dSOwen Pan                  isQualifier(Tok));
619cd7ab4b5SAlexander Hederstaf }
620cd7ab4b5SAlexander Hederstaf 
621c72e9438SOwen Pan bool isConfiguredQualifierOrType(const FormatToken *Tok,
622c72e9438SOwen Pan                                  const std::vector<tok::TokenKind> &Qualifiers,
623364f988dSOwen Pan                                  const LangOptions &LangOpts) {
624364f988dSOwen Pan   return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
625626025acSOwen Pan                  isConfiguredQualifier(Tok, Qualifiers));
626a44ab170Smydeveloperday }
627a44ab170Smydeveloperday 
628a44ab170Smydeveloperday // If a token is an identifier and it's upper case, it could
629a44ab170Smydeveloperday // be a macro and hence we need to be able to ignore it.
630c72e9438SOwen Pan bool isPossibleMacro(const FormatToken *Tok) {
631a44ab170Smydeveloperday   if (!Tok)
632a44ab170Smydeveloperday     return false;
63391c4db00SOwen Pan   if (Tok->isNot(tok::identifier))
634a44ab170Smydeveloperday     return false;
635bebf7bdfSowenca   if (Tok->TokenText.upper() == Tok->TokenText.str()) {
63628bb040dSmydeveloperday     // T,K,U,V likely could be template arguments
637875b8811SOwen Pan     return Tok->TokenText.size() != 1;
638bebf7bdfSowenca   }
639a44ab170Smydeveloperday   return false;
640a44ab170Smydeveloperday }
641a44ab170Smydeveloperday 
642a44ab170Smydeveloperday } // namespace format
643a44ab170Smydeveloperday } // namespace clang
644