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 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 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 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 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> 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 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 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 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 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. 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