clang 24.0.0git
QualifierAlignmentFixer.cpp
Go to the documentation of this file.
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
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
22namespace clang {
23namespace format {
24
27 std::vector<std::string> LeftOrder;
28 std::vector<std::string> RightOrder;
29 std::vector<tok::TokenKind> ConfiguredQualifierTokens;
31 Style.QualifierOrder, LeftOrder, RightOrder, ConfiguredQualifierTokens);
32
33 const auto AddPass = [&](const std::string &Qualifier, bool RightAlign) {
34 Passes.emplace_back([&, Qualifier, ConfiguredQualifierTokens,
35 RightAlign](const Environment &Env) {
37 Env, Style, Qualifier, ConfiguredQualifierTokens, RightAlign)
38 .process();
39 });
40 };
41
42 // Handle the left and right alignment separately.
43 for (const auto &Qualifier : LeftOrder) {
44 AddPass(Qualifier, /*RightAlign=*/false);
45 // Unlike the other declaration specifiers, `long` can legally occur twice
46 // in the same sequence. A pass moves one occurrence across the type, so a
47 // second pass is needed for `long long` and is otherwise a no-op.
48 if (Qualifier == "long")
49 AddPass(Qualifier, /*RightAlign=*/false);
50 }
51 for (const auto &Qualifier : RightOrder) {
52 AddPass(Qualifier, /*RightAlign=*/true);
53 if (Qualifier == "long")
54 AddPass(Qualifier, /*RightAlign=*/true);
55 }
56}
57
58static void replaceToken(const SourceManager &SourceMgr,
60 const CharSourceRange &Range, std::string NewText) {
61 auto Replacement = tooling::Replacement(SourceMgr, Range, NewText);
62 auto Err = Fixes.add(Replacement);
63
64 if (Err) {
65 llvm::errs() << "Error while rearranging Qualifier : "
66 << llvm::toString(std::move(Err)) << "\n";
67 }
68}
69
70static void removeToken(const SourceManager &SourceMgr,
72 const FormatToken *First) {
73 auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
74 First->Tok.getEndLoc());
75 replaceToken(SourceMgr, Fixes, Range, "");
76}
77
78static void insertQualifierAfter(const SourceManager &SourceMgr,
80 const FormatToken *First,
81 const std::string &Qualifier) {
82 auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(),
83 First->Tok.getEndLoc());
84
85 std::string NewText{};
86 NewText += First->TokenText;
87 NewText += " " + Qualifier;
88 replaceToken(SourceMgr, Fixes, Range, NewText);
89}
90
91static void insertQualifierBefore(const SourceManager &SourceMgr,
93 const FormatToken *First,
94 const std::string &Qualifier) {
95 auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
96 First->Tok.getEndLoc());
97
98 std::string NewText = " " + Qualifier + " ";
99 NewText += First->TokenText;
100
101 replaceToken(SourceMgr, Fixes, Range, NewText);
102}
103
104static bool endsWithSpace(const std::string &s) {
105 if (s.empty())
106 return false;
107 return isspace(s.back());
108}
109
110static bool startsWithSpace(const std::string &s) {
111 if (s.empty())
112 return false;
113 return isspace(s.front());
114}
115
116static void rotateTokens(const SourceManager &SourceMgr,
118 const FormatToken *Last, bool Left) {
119 auto *End = Last;
120 auto *Begin = First;
121 if (!Left) {
122 End = Last->Next;
123 Begin = First->Next;
124 }
125
126 std::string NewText;
127 // If we are rotating to the left we move the Last token to the front.
128 if (Left) {
129 NewText += Last->TokenText;
130 NewText += " ";
131 }
132
133 // Then move through the other tokens.
134 auto *Tok = Begin;
135 while (Tok != End) {
136 if (!NewText.empty() && !endsWithSpace(NewText) &&
137 Tok->isNot(tok::coloncolon)) {
138 NewText += " ";
139 }
140
141 NewText += Tok->TokenText;
142 Tok = Tok->Next;
143 }
144
145 // If we are rotating to the right we move the first token to the back.
146 if (!Left) {
147 if (!NewText.empty() && !startsWithSpace(NewText))
148 NewText += " ";
149 NewText += First->TokenText;
150 }
151
152 auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
153 Last->Tok.getEndLoc());
154
155 replaceToken(SourceMgr, Fixes, Range, NewText);
156}
157
158static bool
160 const std::vector<tok::TokenKind> &Qualifiers) {
161 return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind());
162}
163
164static bool isQualifier(const FormatToken *const Tok) {
165 if (!Tok)
166 return false;
167
168 switch (Tok->Tok.getKind()) {
169 case tok::kw_const:
170 case tok::kw_volatile:
171 case tok::kw_static:
172 case tok::kw_inline:
173 case tok::kw_constexpr:
174 case tok::kw_restrict:
175 case tok::kw_friend:
176 case tok::kw__Nonnull:
177 case tok::kw__Nullable:
178 case tok::kw__Null_unspecified:
179 case tok::kw___ptr32:
180 case tok::kw___ptr64:
181 case tok::kw___funcref:
182 case tok::kw_typedef:
183 case tok::kw_consteval:
184 case tok::kw_constinit:
185 case tok::kw_thread_local:
186 case tok::kw_extern:
187 case tok::kw_mutable:
188 case tok::kw_explicit:
189 return true;
190 default:
191 return false;
192 }
193}
194
196 const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
197 tooling::Replacements &Fixes, const FormatToken *const Tok,
198 const std::string &Qualifier, tok::TokenKind QualifierType) {
199 // We only need to think about streams that begin with a qualifier.
200 if (Tok->isNot(QualifierType))
201 return Tok;
202
203 const auto *Next = Tok->getNextNonComment();
204
205 // Don't concern yourself if nothing follows the qualifier.
206 if (!Next)
207 return Tok;
208
209 // Skip qualifiers to the left to find what preceeds the qualifiers.
210 // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers.
211 const FormatToken *PreviousCheck = Tok->getPreviousNonComment();
212 while (isQualifier(PreviousCheck))
213 PreviousCheck = PreviousCheck->getPreviousNonComment();
214
215 // Examples given in order of ['type', 'const', 'volatile']
216 const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() {
217 // The cases:
218 // `Foo() const` -> `Foo() const`
219 // `Foo() const final` -> `Foo() const final`
220 // `Foo() const override` -> `Foo() const final`
221 // `Foo() const volatile override` -> `Foo() const volatile override`
222 // `Foo() volatile const final` -> `Foo() const volatile final`
223 if (PreviousCheck->is(tok::r_paren))
224 return true;
225
226 // The cases:
227 // `struct {} volatile const a;` -> `struct {} const volatile a;`
228 // `class {} volatile const a;` -> `class {} const volatile a;`
229 if (PreviousCheck->is(tok::r_brace))
230 return true;
231
232 // The case:
233 // `template <class T> const Bar Foo()` ->
234 // `template <class T> Bar const Foo()`
235 // The cases:
236 // `Foo<int> const foo` -> `Foo<int> const foo`
237 // `Foo<int> volatile const` -> `Foo<int> const volatile`
238 // The case:
239 // ```
240 // template <class T>
241 // requires Concept1<T> && requires Concept2<T>
242 // const Foo f();
243 // ```
244 // ->
245 // ```
246 // template <class T>
247 // requires Concept1<T> && requires Concept2<T>
248 // Foo const f();
249 // ```
250 if (PreviousCheck->is(TT_TemplateCloser)) {
251 // If the token closes a template<> or requires clause, then it is a left
252 // qualifier and should be moved to the right.
253 return !(PreviousCheck->ClosesTemplateDeclaration ||
254 PreviousCheck->ClosesRequiresClause);
255 }
256
257 // The case `Foo* const` -> `Foo* const`
258 // The case `Foo* volatile const` -> `Foo* const volatile`
259 // The case `int32_t const` -> `int32_t const`
260 // The case `auto volatile const` -> `auto const volatile`
261 if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier,
262 tok::kw_auto)) {
263 return true;
264 }
265
266 return false;
267 }();
268
269 // Find the last qualifier to the right.
270 const auto *LastQual = Tok;
271 for (; isQualifier(Next); Next = Next->getNextNonComment())
272 LastQual = Next;
273
274 if (!LastQual || !Next ||
275 (LastQual->isOneOf(tok::kw_const, tok::kw_volatile) &&
276 Next->isOneOf(Keywords.kw_override, Keywords.kw_final))) {
277 return Tok;
278 }
279
280 // If this qualifier is to the right of a type or pointer do a partial sort
281 // and return.
282 if (IsRightQualifier) {
283 if (LastQual != Tok)
284 rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
285 return Tok;
286 }
287
288 const FormatToken *TypeToken = LastQual->getNextNonComment();
289 if (!TypeToken)
290 return Tok;
291
292 // Stay safe and don't move past macros, also don't bother with sorting.
293 if (TypeToken->isPossibleMacro())
294 return Tok;
295
296 // The case `const long long int volatile` -> `long long int const volatile`
297 // The case `long const long int volatile` -> `long long int const volatile`
298 // The case `long long volatile int const` -> `long long int const volatile`
299 // The case `const long long volatile int` -> `long long int const volatile`
300 if (TypeToken->isTypeName(LangOpts)) {
301 // The case `const decltype(foo)` -> `const decltype(foo)`
302 // The case `const typeof(foo)` -> `const typeof(foo)`
303 // The case `const _Atomic(foo)` -> `const _Atomic(foo)`
304 if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
305 return Tok;
306
307 const FormatToken *LastSimpleTypeSpecifier = TypeToken;
308 while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
309 LangOpts)) {
310 LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
311 }
312
313 rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
314 /*Left=*/false);
315 return LastSimpleTypeSpecifier;
316 }
317
318 // The case `unsigned short const` -> `unsigned short const`
319 // The case:
320 // `unsigned short volatile const` -> `unsigned short const volatile`
321 if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) {
322 if (LastQual != Tok)
323 rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
324 return Tok;
325 }
326
327 // Skip the typename keyword.
328 // The case `const typename C::type` -> `typename C::type const`
329 if (TypeToken->is(tok::kw_typename))
330 TypeToken = TypeToken->getNextNonComment();
331
332 // Skip the initial :: of a global-namespace type.
333 // The case `const ::...` -> `::... const`
334 if (TypeToken->is(tok::coloncolon)) {
335 // The case `const ::template Foo...` -> `::template Foo... const`
336 TypeToken = TypeToken->getNextNonComment();
337 if (TypeToken && TypeToken->is(tok::kw_template))
338 TypeToken = TypeToken->getNextNonComment();
339 }
340
341 // Don't change declarations such as
342 // `foo(const struct Foo a);` -> `foo(const struct Foo a);`
343 // as they would currently change code such as
344 // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {}
345 // my_struct;`
346 if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class))
347 return Tok;
348
349 if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) {
350 // The case `const auto` -> `auto const`
351 // The case `const Foo` -> `Foo const`
352 // The case `const ::Foo` -> `::Foo const`
353 // The case `const Foo *` -> `Foo const *`
354 // The case `const Foo &` -> `Foo const &`
355 // The case `const Foo &&` -> `Foo const &&`
356 // The case `const std::Foo &&` -> `std::Foo const &&`
357 // The case `const std::Foo<T> &&` -> `std::Foo<T> const &&`
358 // The case `const ::template Foo` -> `::template Foo const`
359 // The case `const T::template Foo` -> `T::template Foo const`
360 const FormatToken *Next = nullptr;
361 while ((Next = TypeToken->getNextNonComment()) &&
362 (Next->is(TT_TemplateOpener) ||
363 Next->startsSequence(tok::coloncolon, tok::identifier) ||
364 Next->startsSequence(tok::coloncolon, tok::kw_template,
365 tok::identifier))) {
366 if (Next->is(TT_TemplateOpener)) {
367 assert(Next->MatchingParen && "Missing template closer");
368 TypeToken = Next->MatchingParen;
369 } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) {
370 TypeToken = Next->getNextNonComment();
371 } else {
372 TypeToken = Next->getNextNonComment()->getNextNonComment();
373 }
374 }
375
376 if (Next && Next->is(tok::kw_auto))
377 TypeToken = Next;
378
379 // Place the Qualifier at the end of the list of qualifiers.
380 while (isQualifier(TypeToken->getNextNonComment())) {
381 // The case `volatile Foo::iter const` -> `Foo::iter const volatile`
382 TypeToken = TypeToken->getNextNonComment();
383 }
384
385 insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier);
386 // Remove token and following whitespace.
388 Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace());
389 replaceToken(SourceMgr, Fixes, Range, "");
390 }
391
392 return Tok;
393}
394
396 const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
397 tooling::Replacements &Fixes, const FormatToken *const Tok,
398 const std::string &Qualifier, tok::TokenKind QualifierType) {
399 // We only need to think about streams that begin with a qualifier.
400 if (Tok->isNot(QualifierType))
401 return Tok;
402 // Don't concern yourself if nothing preceeds the qualifier.
403 if (!Tok->getPreviousNonComment())
404 return Tok;
405
406 // Skip qualifiers to the left to find what preceeds the qualifiers.
407 const FormatToken *TypeToken = Tok->getPreviousNonComment();
408 while (isQualifier(TypeToken))
409 TypeToken = TypeToken->getPreviousNonComment();
410
411 // For left qualifiers preceeded by nothing, a template declaration, or *,&,&&
412 // we only perform sorting.
413 if (!TypeToken || TypeToken->isPointerOrReference() ||
414 TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration ||
415 TypeToken->is(tok::r_square)) {
416
417 // Don't sort past a non-configured qualifier token.
418 const FormatToken *FirstQual = Tok;
419 while (isConfiguredQualifier(FirstQual->getPreviousNonComment(),
420 ConfiguredQualifierTokens)) {
421 FirstQual = FirstQual->getPreviousNonComment();
422 }
423
424 if (FirstQual != Tok)
425 rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true);
426 return Tok;
427 }
428
429 // Stay safe and don't move past macros, also don't bother with sorting.
430 if (TypeToken->isPossibleMacro())
431 return Tok;
432
433 // Examples given in order of ['const', 'volatile', 'type']
434
435 // The case `volatile long long int const` -> `const volatile long long int`
436 // The case `volatile long long const int` -> `const volatile long long int`
437 // The case `const long long volatile int` -> `const volatile long long int`
438 // The case `long volatile long int const` -> `const volatile long long int`
439 if (TypeToken->isTypeName(LangOpts)) {
440 for (const auto *Prev = TypeToken->Previous;
441 Prev && Prev->is(tok::coloncolon); Prev = Prev->Previous) {
442 TypeToken = Prev;
443 Prev = Prev->Previous;
444 if (!(Prev && Prev->is(tok::identifier)))
445 break;
446 TypeToken = Prev;
447 }
448 const FormatToken *LastSimpleTypeSpecifier = TypeToken;
450 LastSimpleTypeSpecifier->getPreviousNonComment(),
451 ConfiguredQualifierTokens, LangOpts)) {
452 LastSimpleTypeSpecifier =
453 LastSimpleTypeSpecifier->getPreviousNonComment();
454 }
455
456 rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok,
457 /*Left=*/true);
458 return Tok;
459 }
460
461 if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) {
462 const auto IsStartOfType = [](const FormatToken *const Tok) -> bool {
463 if (!Tok)
464 return true;
465
466 // A template closer is not the start of a type.
467 // The case `?<> const` -> `const ?<>`
468 if (Tok->is(TT_TemplateCloser))
469 return false;
470
471 const FormatToken *const Previous = Tok->getPreviousNonComment();
472 if (!Previous)
473 return true;
474
475 // An identifier preceeded by :: is not the start of a type.
476 // The case `?::Foo const` -> `const ?::Foo`
477 if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon))
478 return false;
479
480 const FormatToken *const PrePrevious = Previous->getPreviousNonComment();
481 // An identifier preceeded by ::template is not the start of a type.
482 // The case `?::template Foo const` -> `const ?::template Foo`
483 if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) &&
484 PrePrevious && PrePrevious->is(tok::coloncolon)) {
485 return false;
486 }
487
488 if (Tok->endsSequence(tok::kw_auto, tok::identifier))
489 return false;
490
491 return true;
492 };
493
494 while (!IsStartOfType(TypeToken)) {
495 // The case `?<>`
496 if (TypeToken->is(TT_TemplateCloser)) {
497 assert(TypeToken->MatchingParen && "Missing template opener");
498 TypeToken = TypeToken->MatchingParen->getPreviousNonComment();
499 } else {
500 // The cases
501 // `::Foo`
502 // `?>::Foo`
503 // `?Bar::Foo`
504 // `::template Foo`
505 // `?>::template Foo`
506 // `?Bar::template Foo`
507 if (TypeToken->getPreviousNonComment()->is(tok::kw_template))
508 TypeToken = TypeToken->getPreviousNonComment();
509
510 const FormatToken *const ColonColon =
511 TypeToken->getPreviousNonComment();
512 const FormatToken *const PreColonColon =
513 ColonColon->getPreviousNonComment();
514 if (PreColonColon &&
515 PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) {
516 TypeToken = PreColonColon;
517 } else {
518 TypeToken = ColonColon;
519 }
520 }
521 }
522
523 assert(TypeToken && "Should be auto or identifier");
524
525 // Place the Qualifier at the start of the list of qualifiers.
526 const FormatToken *Previous = nullptr;
527 while ((Previous = TypeToken->getPreviousNonComment()) &&
528 (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) ||
529 Previous->is(tok::kw_typename))) {
530 // The case `volatile Foo::iter const` -> `const volatile Foo::iter`
531 // The case `typename C::type const` -> `const typename C::type`
532 TypeToken = Previous;
533 }
534
535 // Don't change declarations such as
536 // `foo(struct Foo const a);` -> `foo(struct Foo const a);`
537 if (!Previous || Previous->isNoneOf(tok::kw_struct, tok::kw_class)) {
538 insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier);
539 removeToken(SourceMgr, Fixes, Tok);
540 }
541 }
542
543 return Tok;
544}
545
547 const std::string &Qualifier) {
548 // Don't let 'type' be an identifier, but steal typeof token.
549 return llvm::StringSwitch<tok::TokenKind>(Qualifier)
550 .Case("type", tok::kw_typeof)
551 .Case("const", tok::kw_const)
552 .Case("volatile", tok::kw_volatile)
553 .Case("static", tok::kw_static)
554 .Case("inline", tok::kw_inline)
555 .Case("constexpr", tok::kw_constexpr)
556 .Case("restrict", tok::kw_restrict)
557 .Case("friend", tok::kw_friend)
558 .Case("typedef", tok::kw_typedef)
559 .Case("consteval", tok::kw_consteval)
560 .Case("constinit", tok::kw_constinit)
561 .Case("thread_local", tok::kw_thread_local)
562 .Case("extern", tok::kw_extern)
563 .Case("mutable", tok::kw_mutable)
564 .Case("signed", tok::kw_signed)
565 .Case("unsigned", tok::kw_unsigned)
566 .Case("long", tok::kw_long)
567 .Case("short", tok::kw_short)
568 .Case("explicit", tok::kw_explicit)
569 .Default(tok::identifier);
570}
571
573 const Environment &Env, const FormatStyle &Style,
574 const std::string &Qualifier,
575 const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
576 : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
577 ConfiguredQualifierTokens(QualifierTokens) {}
578
579std::pair<tooling::Replacements, unsigned>
581 TokenAnnotator & /*Annotator*/,
582 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
583 FormatTokenLexer &Tokens) {
585 AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
586 fixQualifierAlignment(AnnotatedLines, Tokens, Fixes);
587 return {Fixes, 0};
588}
589
591 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens,
592 tooling::Replacements &Fixes) {
593 const AdditionalKeywords &Keywords = Tokens.getKeywords();
594 const SourceManager &SourceMgr = Env.getSourceManager();
595 tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier);
596 assert(QualifierToken != tok::identifier && "Unrecognised Qualifier");
597
598 for (AnnotatedLine *Line : AnnotatedLines) {
599 fixQualifierAlignment(Line->Children, Tokens, Fixes);
600 if (!Line->Affected || Line->InPPDirective)
601 continue;
602 FormatToken *First = Line->First;
603 assert(First);
604 if (First->Finalized)
605 continue;
606
607 const auto *Last = Line->Last;
608
609 for (const auto *Tok = First; Tok && Tok != Last && Tok->Next;
610 Tok = Tok->Next) {
611 if (Tok->MustBreakBefore && Tok != First)
612 break;
613 if (Tok->is(tok::comment))
614 continue;
615 if (RightAlign) {
616 Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier,
617 QualifierToken);
618 } else {
619 Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier,
620 QualifierToken);
621 }
622 }
623 }
624}
625
627 const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
628 std::vector<std::string> &RightOrder,
629 std::vector<tok::TokenKind> &Qualifiers) {
630
631 // Depending on the position of type in the order you need
632 // To iterate forward or backward through the order list as qualifier
633 // can push through each other.
634 // The Order list must define the position of "type" to signify
635 assert(llvm::is_contained(Order, "type") &&
636 "QualifierOrder must contain type");
637 // Split the Order list by type and reverse the left side.
638
639 bool left = true;
640 for (const auto &s : Order) {
641 if (s == "type") {
642 left = false;
643 continue;
644 }
645
646 tok::TokenKind QualifierToken =
648 if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) {
649 Qualifiers.push_back(QualifierToken);
650
651 // Ensure signed/unsigned and long/short qualifier pairs are positioned
652 // together by default unless the user has explicitly specified both in
653 // the QualifierOrder. This allows users to override the default pairing
654 // by listing both qualifiers in the order.
655 auto AddPairedQualifier = [&](tok::TokenKind PairedToken,
656 const std::string &PairedName) {
657 if (!llvm::is_contained(Order, PairedName)) {
658 Qualifiers.push_back(PairedToken);
659 if (left)
660 LeftOrder.insert(LeftOrder.begin(), PairedName);
661 else
662 RightOrder.push_back(PairedName);
663 }
664 };
665
666 if (QualifierToken == tok::kw_unsigned)
667 AddPairedQualifier(tok::kw_signed, "signed");
668 else if (QualifierToken == tok::kw_signed)
669 AddPairedQualifier(tok::kw_unsigned, "unsigned");
670 else if (QualifierToken == tok::kw_long)
671 AddPairedQualifier(tok::kw_short, "short");
672 else if (QualifierToken == tok::kw_short)
673 AddPairedQualifier(tok::kw_long, "long");
674 }
675
676 if (left) {
677 // Reverse the order for left aligned items.
678 LeftOrder.insert(LeftOrder.begin(), s);
679 } else {
680 RightOrder.push_back(s);
681 }
682 }
683}
684
685bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) {
686 return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
688}
689
691 const std::vector<tok::TokenKind> &Qualifiers,
692 const LangOptions &LangOpts) {
693 return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
695}
696
697} // namespace format
698} // namespace clang
This file contains the declaration of the FormatToken, a wrapper around Token with additional informa...
Token Tok
The Token.
FormatToken * Previous
The previous token in the unwrapped line.
FormatToken * Next
The next token in the unwrapped line.
This file declares QualifierAlignmentFixer, a TokenAnalyzer that enforces either east or west const d...
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
The collection of all-type qualifiers we support.
Definition TypeBase.h:332
This class handles loading and caching of source files into memory.
const AdditionalKeywords & getKeywords()
LeftRightQualifierAlignmentFixer(const Environment &Env, const FormatStyle &Style, const std::string &Qualifier, const std::vector< tok::TokenKind > &ConfiguredQualifierTokens, bool RightAlign)
const FormatToken * analyzeLeft(const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, tooling::Replacements &Fixes, const FormatToken *Tok, const std::string &Qualifier, tok::TokenKind QualifierType)
const FormatToken * analyzeRight(const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, tooling::Replacements &Fixes, const FormatToken *Tok, const std::string &Qualifier, tok::TokenKind QualifierType)
std::pair< tooling::Replacements, unsigned > analyze(TokenAnnotator &Annotator, SmallVectorImpl< AnnotatedLine * > &AnnotatedLines, FormatTokenLexer &Tokens) override
void fixQualifierAlignment(SmallVectorImpl< AnnotatedLine * > &AnnotatedLines, FormatTokenLexer &Tokens, tooling::Replacements &Fixes)
static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier)
AffectedRangeManager AffectedRangeMgr
const Environment & Env
TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
std::pair< tooling::Replacements, unsigned > process(bool SkipAnnotation=false)
Determines extra information about the tokens comprising an UnwrappedLine.
A text replacement.
Definition Replacement.h:83
Maintains a set of replacements that are conflict-free.
llvm::Error add(const Replacement &R)
Adds a new replacement R to the current set of replacements.
void addQualifierAlignmentFixerPasses(const FormatStyle &Style, SmallVectorImpl< AnalyzerPass > &Passes)
bool isConfiguredQualifierOrType(const FormatToken *Tok, const std::vector< tok::TokenKind > &Qualifiers, const LangOptions &LangOpts)
static void replaceToken(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const CharSourceRange &Range, std::string NewText)
static bool endsWithSpace(const std::string &s)
bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts)
static void insertQualifierAfter(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const FormatToken *First, const std::string &Qualifier)
static void insertQualifierBefore(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const FormatToken *First, const std::string &Qualifier)
static void rotateTokens(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const FormatToken *First, const FormatToken *Last, bool Left)
static void removeToken(const SourceManager &SourceMgr, tooling::Replacements &Fixes, const FormatToken *First)
static bool isConfiguredQualifier(const FormatToken *const Tok, const std::vector< tok::TokenKind > &Qualifiers)
void prepareLeftRightOrderingForQualifierAlignmentFixer(const std::vector< std::string > &Order, std::vector< std::string > &LeftOrder, std::vector< std::string > &RightOrder, std::vector< tok::TokenKind > &Qualifiers)
static bool startsWithSpace(const std::string &s)
static bool isQualifier(const FormatToken *const Tok)
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition TokenKinds.h:33
Top level wrappers for InstallAPI frontend operations.
Encapsulates keywords that are context sensitive or for languages not properly supported by Clang's l...
IdentifierInfo * kw_override
IdentifierInfo * kw_final
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition Format.h:56
A wrapper around a Token storing information about the whitespace characters preceding it.
unsigned ClosesTemplateDeclaration
true if this is the ">" of "template<..>".
bool is(tok::TokenKind Kind) const
bool isOneOf(A K1, B K2) const
unsigned ClosesRequiresClause
true if this is the last token within requires clause.
FormatToken * MatchingParen
If this is a bracket, this points to the matching one.
FormatToken * Previous
The previous token in the unwrapped line.