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 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 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 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 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 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 100 static bool endsWithSpace(const std::string &s) { 101 if (s.empty()) 102 return false; 103 return isspace(s.back()); 104 } 105 106 static bool startsWithSpace(const std::string &s) { 107 if (s.empty()) 108 return false; 109 return isspace(s.front()); 110 } 111 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 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 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 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 // Don't concern yourself if nothing follows the qualifier. 186 if (!Tok->Next) 187 return Tok; 188 189 // Skip qualifiers to the left to find what preceeds the qualifiers. 190 // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers. 191 const FormatToken *PreviousCheck = Tok->getPreviousNonComment(); 192 while (isQualifier(PreviousCheck)) 193 PreviousCheck = PreviousCheck->getPreviousNonComment(); 194 195 // Examples given in order of ['type', 'const', 'volatile'] 196 const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() { 197 // The cases: 198 // `Foo() const` -> `Foo() const` 199 // `Foo() const final` -> `Foo() const final` 200 // `Foo() const override` -> `Foo() const final` 201 // `Foo() const volatile override` -> `Foo() const volatile override` 202 // `Foo() volatile const final` -> `Foo() const volatile final` 203 if (PreviousCheck->is(tok::r_paren)) 204 return true; 205 206 // The cases: 207 // `struct {} volatile const a;` -> `struct {} const volatile a;` 208 // `class {} volatile const a;` -> `class {} const volatile a;` 209 if (PreviousCheck->is(tok::r_brace)) 210 return true; 211 212 // The case: 213 // `template <class T> const Bar Foo()` -> 214 // `template <class T> Bar const Foo()` 215 // The cases: 216 // `Foo<int> const foo` -> `Foo<int> const foo` 217 // `Foo<int> volatile const` -> `Foo<int> const volatile` 218 // The case: 219 // ``` 220 // template <class T> 221 // requires Concept1<T> && requires Concept2<T> 222 // const Foo f(); 223 // ``` 224 // -> 225 // ``` 226 // template <class T> 227 // requires Concept1<T> && requires Concept2<T> 228 // Foo const f(); 229 // ``` 230 if (PreviousCheck->is(TT_TemplateCloser)) { 231 // If the token closes a template<> or requires clause, then it is a left 232 // qualifier and should be moved to the right. 233 return !(PreviousCheck->ClosesTemplateDeclaration || 234 PreviousCheck->ClosesRequiresClause); 235 } 236 237 // The case `Foo* const` -> `Foo* const` 238 // The case `Foo* volatile const` -> `Foo* const volatile` 239 // The case `int32_t const` -> `int32_t const` 240 // The case `auto volatile const` -> `auto const volatile` 241 if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier, 242 tok::kw_auto)) { 243 return true; 244 } 245 246 return false; 247 }(); 248 249 // Find the last qualifier to the right. 250 const FormatToken *LastQual = Tok; 251 while (isQualifier(LastQual->getNextNonComment())) 252 LastQual = LastQual->getNextNonComment(); 253 254 // If this qualifier is to the right of a type or pointer do a partial sort 255 // and return. 256 if (IsRightQualifier) { 257 if (LastQual != Tok) 258 rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 259 return Tok; 260 } 261 262 const FormatToken *TypeToken = LastQual->getNextNonComment(); 263 if (!TypeToken) 264 return Tok; 265 266 // Stay safe and don't move past macros, also don't bother with sorting. 267 if (isPossibleMacro(TypeToken)) 268 return Tok; 269 270 // The case `const long long int volatile` -> `long long int const volatile` 271 // The case `long const long int volatile` -> `long long int const volatile` 272 // The case `long long volatile int const` -> `long long int const volatile` 273 // The case `const long long volatile int` -> `long long int const volatile` 274 if (TypeToken->isTypeName(LangOpts)) { 275 // The case `const decltype(foo)` -> `const decltype(foo)` 276 // The case `const typeof(foo)` -> `const typeof(foo)` 277 // The case `const _Atomic(foo)` -> `const _Atomic(foo)` 278 if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic)) 279 return Tok; 280 281 const FormatToken *LastSimpleTypeSpecifier = TypeToken; 282 while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(), 283 LangOpts)) { 284 LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment(); 285 } 286 287 rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier, 288 /*Left=*/false); 289 return LastSimpleTypeSpecifier; 290 } 291 292 // The case `unsigned short const` -> `unsigned short const` 293 // The case: 294 // `unsigned short volatile const` -> `unsigned short const volatile` 295 if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) { 296 if (LastQual != Tok) 297 rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 298 return Tok; 299 } 300 301 // Skip the typename keyword. 302 // The case `const typename C::type` -> `typename C::type const` 303 if (TypeToken->is(tok::kw_typename)) 304 TypeToken = TypeToken->getNextNonComment(); 305 306 // Skip the initial :: of a global-namespace type. 307 // The case `const ::...` -> `::... const` 308 if (TypeToken->is(tok::coloncolon)) { 309 // The case `const ::template Foo...` -> `::template Foo... const` 310 TypeToken = TypeToken->getNextNonComment(); 311 if (TypeToken && TypeToken->is(tok::kw_template)) 312 TypeToken = TypeToken->getNextNonComment(); 313 } 314 315 // Don't change declarations such as 316 // `foo(const struct Foo a);` -> `foo(const struct Foo a);` 317 // as they would currently change code such as 318 // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {} 319 // my_struct;` 320 if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class)) 321 return Tok; 322 323 if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) { 324 // The case `const auto` -> `auto const` 325 // The case `const Foo` -> `Foo const` 326 // The case `const ::Foo` -> `::Foo const` 327 // The case `const Foo *` -> `Foo const *` 328 // The case `const Foo &` -> `Foo const &` 329 // The case `const Foo &&` -> `Foo const &&` 330 // The case `const std::Foo &&` -> `std::Foo const &&` 331 // The case `const std::Foo<T> &&` -> `std::Foo<T> const &&` 332 // The case `const ::template Foo` -> `::template Foo const` 333 // The case `const T::template Foo` -> `T::template Foo const` 334 const FormatToken *Next = nullptr; 335 while ((Next = TypeToken->getNextNonComment()) && 336 (Next->is(TT_TemplateOpener) || 337 Next->startsSequence(tok::coloncolon, tok::identifier) || 338 Next->startsSequence(tok::coloncolon, tok::kw_template, 339 tok::identifier))) { 340 if (Next->is(TT_TemplateOpener)) { 341 assert(Next->MatchingParen && "Missing template closer"); 342 TypeToken = Next->MatchingParen; 343 } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) { 344 TypeToken = Next->getNextNonComment(); 345 } else { 346 TypeToken = Next->getNextNonComment()->getNextNonComment(); 347 } 348 } 349 350 if (Next && Next->is(tok::kw_auto)) 351 TypeToken = Next; 352 353 // Place the Qualifier at the end of the list of qualifiers. 354 while (isQualifier(TypeToken->getNextNonComment())) { 355 // The case `volatile Foo::iter const` -> `Foo::iter const volatile` 356 TypeToken = TypeToken->getNextNonComment(); 357 } 358 359 insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier); 360 // Remove token and following whitespace. 361 auto Range = CharSourceRange::getCharRange( 362 Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace()); 363 replaceToken(SourceMgr, Fixes, Range, ""); 364 } 365 366 return Tok; 367 } 368 369 const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 370 const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 371 tooling::Replacements &Fixes, const FormatToken *const Tok, 372 const std::string &Qualifier, tok::TokenKind QualifierType) { 373 // We only need to think about streams that begin with a qualifier. 374 if (Tok->isNot(QualifierType)) 375 return Tok; 376 // Don't concern yourself if nothing preceeds the qualifier. 377 if (!Tok->getPreviousNonComment()) 378 return Tok; 379 380 // Skip qualifiers to the left to find what preceeds the qualifiers. 381 const FormatToken *TypeToken = Tok->getPreviousNonComment(); 382 while (isQualifier(TypeToken)) 383 TypeToken = TypeToken->getPreviousNonComment(); 384 385 // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& 386 // we only perform sorting. 387 if (!TypeToken || TypeToken->isPointerOrReference() || 388 TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration || 389 TypeToken->is(tok::r_square)) { 390 391 // Don't sort past a non-configured qualifier token. 392 const FormatToken *FirstQual = Tok; 393 while (isConfiguredQualifier(FirstQual->getPreviousNonComment(), 394 ConfiguredQualifierTokens)) { 395 FirstQual = FirstQual->getPreviousNonComment(); 396 } 397 398 if (FirstQual != Tok) 399 rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true); 400 return Tok; 401 } 402 403 // Stay safe and don't move past macros, also don't bother with sorting. 404 if (isPossibleMacro(TypeToken)) 405 return Tok; 406 407 // Examples given in order of ['const', 'volatile', 'type'] 408 409 // The case `volatile long long int const` -> `const volatile long long int` 410 // The case `volatile long long const int` -> `const volatile long long int` 411 // The case `const long long volatile int` -> `const volatile long long int` 412 // The case `long volatile long int const` -> `const volatile long long int` 413 if (TypeToken->isTypeName(LangOpts)) { 414 for (const auto *Prev = TypeToken->Previous; 415 Prev && Prev->is(tok::coloncolon); Prev = Prev->Previous) { 416 TypeToken = Prev; 417 Prev = Prev->Previous; 418 if (!(Prev && Prev->is(tok::identifier))) 419 break; 420 TypeToken = Prev; 421 } 422 const FormatToken *LastSimpleTypeSpecifier = TypeToken; 423 while (isConfiguredQualifierOrType( 424 LastSimpleTypeSpecifier->getPreviousNonComment(), 425 ConfiguredQualifierTokens, LangOpts)) { 426 LastSimpleTypeSpecifier = 427 LastSimpleTypeSpecifier->getPreviousNonComment(); 428 } 429 430 rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok, 431 /*Left=*/true); 432 return Tok; 433 } 434 435 if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) { 436 const auto IsStartOfType = [](const FormatToken *const Tok) -> bool { 437 if (!Tok) 438 return true; 439 440 // A template closer is not the start of a type. 441 // The case `?<> const` -> `const ?<>` 442 if (Tok->is(TT_TemplateCloser)) 443 return false; 444 445 const FormatToken *const Previous = Tok->getPreviousNonComment(); 446 if (!Previous) 447 return true; 448 449 // An identifier preceeded by :: is not the start of a type. 450 // The case `?::Foo const` -> `const ?::Foo` 451 if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon)) 452 return false; 453 454 const FormatToken *const PrePrevious = Previous->getPreviousNonComment(); 455 // An identifier preceeded by ::template is not the start of a type. 456 // The case `?::template Foo const` -> `const ?::template Foo` 457 if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) && 458 PrePrevious && PrePrevious->is(tok::coloncolon)) { 459 return false; 460 } 461 462 if (Tok->endsSequence(tok::kw_auto, tok::identifier)) 463 return false; 464 465 return true; 466 }; 467 468 while (!IsStartOfType(TypeToken)) { 469 // The case `?<>` 470 if (TypeToken->is(TT_TemplateCloser)) { 471 assert(TypeToken->MatchingParen && "Missing template opener"); 472 TypeToken = TypeToken->MatchingParen->getPreviousNonComment(); 473 } else { 474 // The cases 475 // `::Foo` 476 // `?>::Foo` 477 // `?Bar::Foo` 478 // `::template Foo` 479 // `?>::template Foo` 480 // `?Bar::template Foo` 481 if (TypeToken->getPreviousNonComment()->is(tok::kw_template)) 482 TypeToken = TypeToken->getPreviousNonComment(); 483 484 const FormatToken *const ColonColon = 485 TypeToken->getPreviousNonComment(); 486 const FormatToken *const PreColonColon = 487 ColonColon->getPreviousNonComment(); 488 if (PreColonColon && 489 PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) { 490 TypeToken = PreColonColon; 491 } else { 492 TypeToken = ColonColon; 493 } 494 } 495 } 496 497 assert(TypeToken && "Should be auto or identifier"); 498 499 // Place the Qualifier at the start of the list of qualifiers. 500 const FormatToken *Previous = nullptr; 501 while ((Previous = TypeToken->getPreviousNonComment()) && 502 (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) || 503 Previous->is(tok::kw_typename))) { 504 // The case `volatile Foo::iter const` -> `const volatile Foo::iter` 505 // The case `typename C::type const` -> `const typename C::type` 506 TypeToken = Previous; 507 } 508 509 // Don't change declarations such as 510 // `foo(struct Foo const a);` -> `foo(struct Foo const a);` 511 if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) { 512 insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier); 513 removeToken(SourceMgr, Fixes, Tok); 514 } 515 } 516 517 return Tok; 518 } 519 520 tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( 521 const std::string &Qualifier) { 522 // Don't let 'type' be an identifier, but steal typeof token. 523 return llvm::StringSwitch<tok::TokenKind>(Qualifier) 524 .Case("type", tok::kw_typeof) 525 .Case("const", tok::kw_const) 526 .Case("volatile", tok::kw_volatile) 527 .Case("static", tok::kw_static) 528 .Case("inline", tok::kw_inline) 529 .Case("constexpr", tok::kw_constexpr) 530 .Case("restrict", tok::kw_restrict) 531 .Case("friend", tok::kw_friend) 532 .Default(tok::identifier); 533 } 534 535 LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( 536 const Environment &Env, const FormatStyle &Style, 537 const std::string &Qualifier, 538 const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign) 539 : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), 540 ConfiguredQualifierTokens(QualifierTokens) {} 541 542 std::pair<tooling::Replacements, unsigned> 543 LeftRightQualifierAlignmentFixer::analyze( 544 TokenAnnotator & /*Annotator*/, 545 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 546 FormatTokenLexer &Tokens) { 547 tooling::Replacements Fixes; 548 AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 549 fixQualifierAlignment(AnnotatedLines, Tokens, Fixes); 550 return {Fixes, 0}; 551 } 552 553 void LeftRightQualifierAlignmentFixer::fixQualifierAlignment( 554 SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens, 555 tooling::Replacements &Fixes) { 556 const AdditionalKeywords &Keywords = Tokens.getKeywords(); 557 const SourceManager &SourceMgr = Env.getSourceManager(); 558 tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); 559 assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); 560 561 for (AnnotatedLine *Line : AnnotatedLines) { 562 fixQualifierAlignment(Line->Children, Tokens, Fixes); 563 if (!Line->Affected || Line->InPPDirective) 564 continue; 565 FormatToken *First = Line->First; 566 assert(First); 567 if (First->Finalized) 568 continue; 569 570 const auto *Last = Line->Last; 571 572 for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; 573 Tok = Tok->Next) { 574 if (Tok->MustBreakBefore) 575 break; 576 if (Tok->is(tok::comment)) 577 continue; 578 if (RightAlign) { 579 Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, 580 QualifierToken); 581 } else { 582 Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, 583 QualifierToken); 584 } 585 } 586 } 587 } 588 589 void prepareLeftRightOrderingForQualifierAlignmentFixer( 590 const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder, 591 std::vector<std::string> &RightOrder, 592 std::vector<tok::TokenKind> &Qualifiers) { 593 594 // Depending on the position of type in the order you need 595 // To iterate forward or backward through the order list as qualifier 596 // can push through each other. 597 // The Order list must define the position of "type" to signify 598 assert(llvm::is_contained(Order, "type") && 599 "QualifierOrder must contain type"); 600 // Split the Order list by type and reverse the left side. 601 602 bool left = true; 603 for (const auto &s : Order) { 604 if (s == "type") { 605 left = false; 606 continue; 607 } 608 609 tok::TokenKind QualifierToken = 610 LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); 611 if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) 612 Qualifiers.push_back(QualifierToken); 613 614 if (left) { 615 // Reverse the order for left aligned items. 616 LeftOrder.insert(LeftOrder.begin(), s); 617 } else { 618 RightOrder.push_back(s); 619 } 620 } 621 } 622 623 bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) { 624 return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) || 625 isQualifier(Tok)); 626 } 627 628 bool isConfiguredQualifierOrType(const FormatToken *Tok, 629 const std::vector<tok::TokenKind> &Qualifiers, 630 const LangOptions &LangOpts) { 631 return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) || 632 isConfiguredQualifier(Tok, Qualifiers)); 633 } 634 635 // If a token is an identifier and it's upper case, it could 636 // be a macro and hence we need to be able to ignore it. 637 bool isPossibleMacro(const FormatToken *Tok) { 638 assert(Tok); 639 if (Tok->isNot(tok::identifier)) 640 return false; 641 642 const auto Text = Tok->TokenText; 643 assert(!Text.empty()); 644 645 // T,K,U,V likely could be template arguments 646 if (Text.size() == 1) 647 return false; 648 649 // It's unlikely that qualified names are object-like macros. 650 const auto *Prev = Tok->getPreviousNonComment(); 651 if (Prev && Prev->is(tok::coloncolon)) 652 return false; 653 const auto *Next = Tok->getNextNonComment(); 654 if (Next && Next->is(tok::coloncolon)) 655 return false; 656 657 return Text == Text.upper(); 658 } 659 660 } // namespace format 661 } // namespace clang 662