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