17#include "llvm/Support/Debug.h"
18#include "llvm/Support/Regex.h"
20#define DEBUG_TYPE "format-qualifier-alignment-fixer"
27 std::vector<std::string> LeftOrder;
28 std::vector<std::string> RightOrder;
29 std::vector<tok::TokenKind> ConfiguredQualifierTokens;
31 Style.QualifierOrder, LeftOrder, RightOrder, ConfiguredQualifierTokens);
33 const auto AddPass = [&](
const std::string &Qualifier,
bool RightAlign) {
34 Passes.emplace_back([&, Qualifier, ConfiguredQualifierTokens,
37 Env, Style, Qualifier, ConfiguredQualifierTokens, RightAlign)
43 for (
const auto &Qualifier : LeftOrder) {
44 AddPass(Qualifier,
false);
48 if (Qualifier ==
"long")
49 AddPass(Qualifier,
false);
51 for (
const auto &Qualifier : RightOrder) {
52 AddPass(Qualifier,
true);
53 if (Qualifier ==
"long")
54 AddPass(Qualifier,
true);
62 auto Err = Fixes.
add(Replacement);
65 llvm::errs() <<
"Error while rearranging Qualifier : "
66 << llvm::toString(std::move(Err)) <<
"\n";
74 First->Tok.getEndLoc());
81 const std::string &Qualifier) {
83 First->Tok.getEndLoc());
85 std::string NewText{};
86 NewText +=
First->TokenText;
87 NewText +=
" " + Qualifier;
94 const std::string &Qualifier) {
96 First->Tok.getEndLoc());
98 std::string NewText =
" " + Qualifier +
" ";
99 NewText +=
First->TokenText;
107 return isspace(s.back());
113 return isspace(s.front());
129 NewText +=
Last->TokenText;
137 Tok->isNot(tok::coloncolon)) {
141 NewText +=
Tok->TokenText;
149 NewText +=
First->TokenText;
153 Last->Tok.getEndLoc());
160 const std::vector<tok::TokenKind> &
Qualifiers) {
168 switch (
Tok->Tok.getKind()) {
170 case tok::kw_volatile:
173 case tok::kw_constexpr:
174 case tok::kw_restrict:
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:
187 case tok::kw_mutable:
188 case tok::kw_explicit:
200 if (
Tok->isNot(QualifierType))
203 const auto *
Next =
Tok->getNextNonComment();
213 PreviousCheck = PreviousCheck->getPreviousNonComment();
216 const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() {
223 if (PreviousCheck->
is(tok::r_paren))
229 if (PreviousCheck->
is(tok::r_brace))
250 if (PreviousCheck->
is(TT_TemplateCloser)) {
261 if (PreviousCheck->
isOneOf(TT_PointerOrReference, tok::identifier,
270 const auto *LastQual =
Tok;
274 if (!LastQual || !
Next ||
275 (LastQual->isOneOf(tok::kw_const, tok::kw_volatile) &&
282 if (IsRightQualifier) {
288 const FormatToken *TypeToken = LastQual->getNextNonComment();
293 if (TypeToken->isPossibleMacro())
300 if (TypeToken->isTypeName(
LangOpts)) {
304 if (TypeToken->
isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
307 const FormatToken *LastSimpleTypeSpecifier = TypeToken;
310 LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
315 return LastSimpleTypeSpecifier;
321 if (PreviousCheck && PreviousCheck->isTypeName(
LangOpts)) {
329 if (TypeToken->
is(tok::kw_typename))
330 TypeToken = TypeToken->getNextNonComment();
334 if (TypeToken->
is(tok::coloncolon)) {
336 TypeToken = TypeToken->getNextNonComment();
337 if (TypeToken && TypeToken->
is(tok::kw_template))
338 TypeToken = TypeToken->getNextNonComment();
346 if (TypeToken->
isOneOf(tok::kw_struct, tok::kw_class))
349 if (TypeToken->
isOneOf(tok::kw_auto, tok::identifier)) {
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,
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();
372 TypeToken =
Next->getNextNonComment()->getNextNonComment();
380 while (
isQualifier(TypeToken->getNextNonComment())) {
382 TypeToken = TypeToken->getNextNonComment();
388 Tok->getStartOfNonWhitespace(),
Tok->Next->getStartOfNonWhitespace());
400 if (
Tok->isNot(QualifierType))
403 if (!
Tok->getPreviousNonComment())
409 TypeToken = TypeToken->getPreviousNonComment();
413 if (!TypeToken || TypeToken->isPointerOrReference() ||
415 TypeToken->
is(tok::r_square)) {
420 ConfiguredQualifierTokens)) {
421 FirstQual = FirstQual->getPreviousNonComment();
424 if (FirstQual !=
Tok)
430 if (TypeToken->isPossibleMacro())
439 if (TypeToken->isTypeName(
LangOpts)) {
440 for (
const auto *Prev = TypeToken->
Previous;
441 Prev && Prev->
is(tok::coloncolon); Prev = Prev->Previous) {
444 if (!(Prev && Prev->is(tok::identifier)))
448 const FormatToken *LastSimpleTypeSpecifier = TypeToken;
450 LastSimpleTypeSpecifier->getPreviousNonComment(),
451 ConfiguredQualifierTokens,
LangOpts)) {
452 LastSimpleTypeSpecifier =
453 LastSimpleTypeSpecifier->getPreviousNonComment();
461 if (TypeToken->
isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) {
462 const auto IsStartOfType = [](
const FormatToken *
const Tok) ->
bool {
468 if (
Tok->is(TT_TemplateCloser))
477 if (
Tok->is(tok::identifier) &&
Previous->is(tok::coloncolon))
483 if (
Tok->is(tok::identifier) &&
Previous->is(tok::kw_template) &&
484 PrePrevious && PrePrevious->
is(tok::coloncolon)) {
488 if (
Tok->endsSequence(tok::kw_auto, tok::identifier))
494 while (!IsStartOfType(TypeToken)) {
496 if (TypeToken->
is(TT_TemplateCloser)) {
497 assert(TypeToken->
MatchingParen &&
"Missing template opener");
498 TypeToken = TypeToken->
MatchingParen->getPreviousNonComment();
507 if (TypeToken->getPreviousNonComment()->
is(tok::kw_template))
508 TypeToken = TypeToken->getPreviousNonComment();
511 TypeToken->getPreviousNonComment();
513 ColonColon->getPreviousNonComment();
515 PreColonColon->
isOneOf(TT_TemplateCloser, tok::identifier)) {
516 TypeToken = PreColonColon;
518 TypeToken = ColonColon;
523 assert(TypeToken &&
"Should be auto or identifier");
527 while ((
Previous = TypeToken->getPreviousNonComment()) &&
547 const std::string &Qualifier) {
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);
574 const std::string &Qualifier,
575 const std::vector<tok::TokenKind> &QualifierTokens,
bool RightAlign)
577 ConfiguredQualifierTokens(QualifierTokens) {}
579std::pair<tooling::Replacements, unsigned>
596 assert(QualifierToken != tok::identifier &&
"Unrecognised Qualifier");
600 if (!
Line->Affected ||
Line->InPPDirective)
604 if (
First->Finalized)
613 if (
Tok->is(tok::comment))
627 const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
628 std::vector<std::string> &RightOrder,
635 assert(llvm::is_contained(Order,
"type") &&
636 "QualifierOrder must contain type");
640 for (
const auto &s : Order) {
648 if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) {
656 const std::string &PairedName) {
657 if (!llvm::is_contained(Order, PairedName)) {
660 LeftOrder.insert(LeftOrder.begin(), PairedName);
662 RightOrder.push_back(PairedName);
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");
678 LeftOrder.insert(LeftOrder.begin(), s);
680 RightOrder.push_back(s);
686 return Tok && (
Tok->isTypeName(LangOpts) ||
Tok->is(tok::kw_auto) ||
691 const std::vector<tok::TokenKind> &
Qualifiers,
693 return Tok && (
Tok->isTypeName(LangOpts) ||
Tok->is(tok::kw_auto) ||
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.
This class handles loading and caching of source files into memory.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
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