brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.7 KiB · eb0f886 Raw
671 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements QualifierAlignmentFixer, a TokenAnalyzer that11/// 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 22namespace clang {23namespace format {24 25void 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 54static 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 66static 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 74static 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 87static 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 100static bool endsWithSpace(const std::string &s) {101  if (s.empty())102    return false;103  return isspace(s.back());104}105 106static bool startsWithSpace(const std::string &s) {107  if (s.empty())108    return false;109  return isspace(s.front());110}111 112static 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 154static bool155isConfiguredQualifier(const FormatToken *const Tok,156                      const std::vector<tok::TokenKind> &Qualifiers) {157  return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind());158}159 160static 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 178const 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 left235      // 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 sort264  // 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 as325  // `foo(const struct Foo a);` -> `foo(const struct Foo a);`326  // as they would currently change code such as327  // `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 378const 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 cases484        // `::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 as519    // `foo(struct Foo const a);` -> `foo(struct Foo const a);`520    if (!Previous || Previous->isNoneOf(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 529tok::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 544LeftRightQualifierAlignmentFixer::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 551std::pair<tooling::Replacements, unsigned>552LeftRightQualifierAlignmentFixer::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 562void 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 && Tok != First)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 598void 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 need604  // To iterate forward or backward through the order list as qualifier605  // can push through each other.606  // The Order list must define the position of "type" to signify607  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 632bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) {633  return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||634                 isQualifier(Tok));635}636 637bool 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 could645// be a macro and hence we need to be able to ignore it.646bool 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 arguments655  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 format670} // namespace clang671