1*5f757f3fSDimitry Andric //===--- QualifierAlignmentFixer.cpp ----------------------------*- C++--*-===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric /// 9349cc55cSDimitry Andric /// \file 10*5f757f3fSDimitry Andric /// This file implements QualifierAlignmentFixer, a TokenAnalyzer that 11349cc55cSDimitry Andric /// enforces either left or right const depending on the style. 12349cc55cSDimitry Andric /// 13349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 14349cc55cSDimitry Andric 15349cc55cSDimitry Andric #include "QualifierAlignmentFixer.h" 16349cc55cSDimitry Andric #include "FormatToken.h" 17349cc55cSDimitry Andric #include "llvm/Support/Debug.h" 18349cc55cSDimitry Andric #include "llvm/Support/Regex.h" 19349cc55cSDimitry Andric 20349cc55cSDimitry Andric #include <algorithm> 21bdd1243dSDimitry Andric #include <optional> 22349cc55cSDimitry Andric 23349cc55cSDimitry Andric #define DEBUG_TYPE "format-qualifier-alignment-fixer" 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric namespace clang { 26349cc55cSDimitry Andric namespace format { 27349cc55cSDimitry Andric 2806c3fb27SDimitry Andric void addQualifierAlignmentFixerPasses(const FormatStyle &Style, 2906c3fb27SDimitry Andric SmallVectorImpl<AnalyzerPass> &Passes) { 30349cc55cSDimitry Andric std::vector<std::string> LeftOrder; 31349cc55cSDimitry Andric std::vector<std::string> RightOrder; 32349cc55cSDimitry Andric std::vector<tok::TokenKind> ConfiguredQualifierTokens; 3306c3fb27SDimitry Andric prepareLeftRightOrderingForQualifierAlignmentFixer( 3406c3fb27SDimitry Andric Style.QualifierOrder, LeftOrder, RightOrder, ConfiguredQualifierTokens); 35349cc55cSDimitry Andric 3681ad6265SDimitry Andric // Handle the left and right alignment separately. 37349cc55cSDimitry Andric for (const auto &Qualifier : LeftOrder) { 38349cc55cSDimitry Andric Passes.emplace_back( 39349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 40349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 41349cc55cSDimitry Andric ConfiguredQualifierTokens, 42349cc55cSDimitry Andric /*RightAlign=*/false) 43349cc55cSDimitry Andric .process(); 44349cc55cSDimitry Andric }); 45349cc55cSDimitry Andric } 46349cc55cSDimitry Andric for (const auto &Qualifier : RightOrder) { 47349cc55cSDimitry Andric Passes.emplace_back( 48349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 49349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 50349cc55cSDimitry Andric ConfiguredQualifierTokens, 51349cc55cSDimitry Andric /*RightAlign=*/true) 52349cc55cSDimitry Andric .process(); 53349cc55cSDimitry Andric }); 54349cc55cSDimitry Andric } 55349cc55cSDimitry Andric } 56349cc55cSDimitry Andric 57349cc55cSDimitry Andric static void replaceToken(const SourceManager &SourceMgr, 58349cc55cSDimitry Andric tooling::Replacements &Fixes, 59349cc55cSDimitry Andric const CharSourceRange &Range, std::string NewText) { 60349cc55cSDimitry Andric auto Replacement = tooling::Replacement(SourceMgr, Range, NewText); 61349cc55cSDimitry Andric auto Err = Fixes.add(Replacement); 62349cc55cSDimitry Andric 6381ad6265SDimitry Andric if (Err) { 64349cc55cSDimitry Andric llvm::errs() << "Error while rearranging Qualifier : " 65349cc55cSDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 66349cc55cSDimitry Andric } 6781ad6265SDimitry Andric } 68349cc55cSDimitry Andric 69349cc55cSDimitry Andric static void removeToken(const SourceManager &SourceMgr, 70349cc55cSDimitry Andric tooling::Replacements &Fixes, 71349cc55cSDimitry Andric const FormatToken *First) { 72349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 73349cc55cSDimitry Andric First->Tok.getEndLoc()); 74349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, ""); 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77349cc55cSDimitry Andric static void insertQualifierAfter(const SourceManager &SourceMgr, 78349cc55cSDimitry Andric tooling::Replacements &Fixes, 79349cc55cSDimitry Andric const FormatToken *First, 80349cc55cSDimitry Andric const std::string &Qualifier) { 8106c3fb27SDimitry Andric auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(), 8206c3fb27SDimitry Andric First->Tok.getEndLoc()); 83349cc55cSDimitry Andric 8406c3fb27SDimitry Andric std::string NewText{}; 8506c3fb27SDimitry Andric NewText += First->TokenText; 8606c3fb27SDimitry Andric NewText += " " + Qualifier; 87349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 88349cc55cSDimitry Andric } 89349cc55cSDimitry Andric 90349cc55cSDimitry Andric static void insertQualifierBefore(const SourceManager &SourceMgr, 91349cc55cSDimitry Andric tooling::Replacements &Fixes, 92349cc55cSDimitry Andric const FormatToken *First, 93349cc55cSDimitry Andric const std::string &Qualifier) { 94349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 95349cc55cSDimitry Andric First->Tok.getEndLoc()); 96349cc55cSDimitry Andric 97349cc55cSDimitry Andric std::string NewText = " " + Qualifier + " "; 98349cc55cSDimitry Andric NewText += First->TokenText; 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 101349cc55cSDimitry Andric } 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric static bool endsWithSpace(const std::string &s) { 10481ad6265SDimitry Andric if (s.empty()) 105349cc55cSDimitry Andric return false; 106349cc55cSDimitry Andric return isspace(s.back()); 107349cc55cSDimitry Andric } 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric static bool startsWithSpace(const std::string &s) { 11081ad6265SDimitry Andric if (s.empty()) 111349cc55cSDimitry Andric return false; 112349cc55cSDimitry Andric return isspace(s.front()); 113349cc55cSDimitry Andric } 114349cc55cSDimitry Andric 115349cc55cSDimitry Andric static void rotateTokens(const SourceManager &SourceMgr, 116349cc55cSDimitry Andric tooling::Replacements &Fixes, const FormatToken *First, 117349cc55cSDimitry Andric const FormatToken *Last, bool Left) { 118349cc55cSDimitry Andric auto *End = Last; 119349cc55cSDimitry Andric auto *Begin = First; 120349cc55cSDimitry Andric if (!Left) { 121349cc55cSDimitry Andric End = Last->Next; 122349cc55cSDimitry Andric Begin = First->Next; 123349cc55cSDimitry Andric } 124349cc55cSDimitry Andric 125349cc55cSDimitry Andric std::string NewText; 126349cc55cSDimitry Andric // If we are rotating to the left we move the Last token to the front. 127349cc55cSDimitry Andric if (Left) { 128349cc55cSDimitry Andric NewText += Last->TokenText; 129349cc55cSDimitry Andric NewText += " "; 130349cc55cSDimitry Andric } 131349cc55cSDimitry Andric 132349cc55cSDimitry Andric // Then move through the other tokens. 133349cc55cSDimitry Andric auto *Tok = Begin; 134349cc55cSDimitry Andric while (Tok != End) { 13581ad6265SDimitry Andric if (!NewText.empty() && !endsWithSpace(NewText)) 136349cc55cSDimitry Andric NewText += " "; 137349cc55cSDimitry Andric 138349cc55cSDimitry Andric NewText += Tok->TokenText; 139349cc55cSDimitry Andric Tok = Tok->Next; 140349cc55cSDimitry Andric } 141349cc55cSDimitry Andric 142349cc55cSDimitry Andric // If we are rotating to the right we move the first token to the back. 143349cc55cSDimitry Andric if (!Left) { 14481ad6265SDimitry Andric if (!NewText.empty() && !startsWithSpace(NewText)) 145349cc55cSDimitry Andric NewText += " "; 146349cc55cSDimitry Andric NewText += First->TokenText; 147349cc55cSDimitry Andric } 148349cc55cSDimitry Andric 149349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 150349cc55cSDimitry Andric Last->Tok.getEndLoc()); 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 153349cc55cSDimitry Andric } 154349cc55cSDimitry Andric 15506c3fb27SDimitry Andric static bool 15606c3fb27SDimitry Andric isConfiguredQualifier(const FormatToken *const Tok, 15706c3fb27SDimitry Andric const std::vector<tok::TokenKind> &Qualifiers) { 15806c3fb27SDimitry Andric return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind()); 15906c3fb27SDimitry Andric } 16006c3fb27SDimitry Andric 16106c3fb27SDimitry Andric static bool isQualifier(const FormatToken *const Tok) { 16206c3fb27SDimitry Andric if (!Tok) 16306c3fb27SDimitry Andric return false; 16406c3fb27SDimitry Andric 16506c3fb27SDimitry Andric switch (Tok->Tok.getKind()) { 16606c3fb27SDimitry Andric case tok::kw_const: 16706c3fb27SDimitry Andric case tok::kw_volatile: 16806c3fb27SDimitry Andric case tok::kw_static: 16906c3fb27SDimitry Andric case tok::kw_inline: 17006c3fb27SDimitry Andric case tok::kw_constexpr: 17106c3fb27SDimitry Andric case tok::kw_restrict: 17206c3fb27SDimitry Andric case tok::kw_friend: 17306c3fb27SDimitry Andric return true; 17406c3fb27SDimitry Andric default: 17506c3fb27SDimitry Andric return false; 17606c3fb27SDimitry Andric } 17706c3fb27SDimitry Andric } 17806c3fb27SDimitry Andric 17904eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( 180349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 18106c3fb27SDimitry Andric tooling::Replacements &Fixes, const FormatToken *const Tok, 182349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 183349cc55cSDimitry Andric // We only need to think about streams that begin with a qualifier. 184*5f757f3fSDimitry Andric if (Tok->isNot(QualifierType)) 185349cc55cSDimitry Andric return Tok; 186349cc55cSDimitry Andric // Don't concern yourself if nothing follows the qualifier. 187349cc55cSDimitry Andric if (!Tok->Next) 188349cc55cSDimitry Andric return Tok; 189349cc55cSDimitry Andric 19006c3fb27SDimitry Andric // Skip qualifiers to the left to find what preceeds the qualifiers. 19106c3fb27SDimitry Andric // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers. 19206c3fb27SDimitry Andric const FormatToken *PreviousCheck = Tok->getPreviousNonComment(); 19306c3fb27SDimitry Andric while (isQualifier(PreviousCheck)) 19406c3fb27SDimitry Andric PreviousCheck = PreviousCheck->getPreviousNonComment(); 19581ad6265SDimitry Andric 19606c3fb27SDimitry Andric // Examples given in order of ['type', 'const', 'volatile'] 19706c3fb27SDimitry Andric const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() { 19806c3fb27SDimitry Andric // The cases: 19906c3fb27SDimitry Andric // `Foo() const` -> `Foo() const` 20006c3fb27SDimitry Andric // `Foo() const final` -> `Foo() const final` 20106c3fb27SDimitry Andric // `Foo() const override` -> `Foo() const final` 20206c3fb27SDimitry Andric // `Foo() const volatile override` -> `Foo() const volatile override` 20306c3fb27SDimitry Andric // `Foo() volatile const final` -> `Foo() const volatile final` 20406c3fb27SDimitry Andric if (PreviousCheck->is(tok::r_paren)) 20506c3fb27SDimitry Andric return true; 20606c3fb27SDimitry Andric 20706c3fb27SDimitry Andric // The cases: 20806c3fb27SDimitry Andric // `struct {} volatile const a;` -> `struct {} const volatile a;` 20906c3fb27SDimitry Andric // `class {} volatile const a;` -> `class {} const volatile a;` 21006c3fb27SDimitry Andric if (PreviousCheck->is(tok::r_brace)) 21106c3fb27SDimitry Andric return true; 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric // The case: 21406c3fb27SDimitry Andric // `template <class T> const Bar Foo()` -> 21506c3fb27SDimitry Andric // `template <class T> Bar const Foo()` 21606c3fb27SDimitry Andric // The cases: 21706c3fb27SDimitry Andric // `Foo<int> const foo` -> `Foo<int> const foo` 21806c3fb27SDimitry Andric // `Foo<int> volatile const` -> `Foo<int> const volatile` 21906c3fb27SDimitry Andric // The case: 22006c3fb27SDimitry Andric // ``` 22106c3fb27SDimitry Andric // template <class T> 22206c3fb27SDimitry Andric // requires Concept1<T> && requires Concept2<T> 22306c3fb27SDimitry Andric // const Foo f(); 22406c3fb27SDimitry Andric // ``` 22506c3fb27SDimitry Andric // -> 22606c3fb27SDimitry Andric // ``` 22706c3fb27SDimitry Andric // template <class T> 22806c3fb27SDimitry Andric // requires Concept1<T> && requires Concept2<T> 22906c3fb27SDimitry Andric // Foo const f(); 23006c3fb27SDimitry Andric // ``` 23106c3fb27SDimitry Andric if (PreviousCheck->is(TT_TemplateCloser)) { 23206c3fb27SDimitry Andric // If the token closes a template<> or requires clause, then it is a left 23306c3fb27SDimitry Andric // qualifier and should be moved to the right. 23406c3fb27SDimitry Andric return !(PreviousCheck->ClosesTemplateDeclaration || 23506c3fb27SDimitry Andric PreviousCheck->ClosesRequiresClause); 236349cc55cSDimitry Andric } 23706c3fb27SDimitry Andric 23806c3fb27SDimitry Andric // The case `Foo* const` -> `Foo* const` 23906c3fb27SDimitry Andric // The case `Foo* volatile const` -> `Foo* const volatile` 24006c3fb27SDimitry Andric // The case `int32_t const` -> `int32_t const` 24106c3fb27SDimitry Andric // The case `auto volatile const` -> `auto const volatile` 24206c3fb27SDimitry Andric if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier, 24306c3fb27SDimitry Andric tok::kw_auto)) { 24406c3fb27SDimitry Andric return true; 24506c3fb27SDimitry Andric } 24606c3fb27SDimitry Andric 24706c3fb27SDimitry Andric return false; 24806c3fb27SDimitry Andric }(); 24906c3fb27SDimitry Andric 25006c3fb27SDimitry Andric // Find the last qualifier to the right. 25106c3fb27SDimitry Andric const FormatToken *LastQual = Tok; 25206c3fb27SDimitry Andric while (isQualifier(LastQual->getNextNonComment())) 25306c3fb27SDimitry Andric LastQual = LastQual->getNextNonComment(); 25406c3fb27SDimitry Andric 25506c3fb27SDimitry Andric // If this qualifier is to the right of a type or pointer do a partial sort 25606c3fb27SDimitry Andric // and return. 25706c3fb27SDimitry Andric if (IsRightQualifier) { 25806c3fb27SDimitry Andric if (LastQual != Tok) 259349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 260349cc55cSDimitry Andric return Tok; 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric 26306c3fb27SDimitry Andric const FormatToken *TypeToken = LastQual->getNextNonComment(); 26406c3fb27SDimitry Andric if (!TypeToken) 26506c3fb27SDimitry Andric return Tok; 26606c3fb27SDimitry Andric 26706c3fb27SDimitry Andric // Stay safe and don't move past macros, also don't bother with sorting. 26806c3fb27SDimitry Andric if (isPossibleMacro(TypeToken)) 26906c3fb27SDimitry Andric return Tok; 27006c3fb27SDimitry Andric 27106c3fb27SDimitry Andric // The case `const long long int volatile` -> `long long int const volatile` 27206c3fb27SDimitry Andric // The case `long const long int volatile` -> `long long int const volatile` 27306c3fb27SDimitry Andric // The case `long long volatile int const` -> `long long int const volatile` 27406c3fb27SDimitry Andric // The case `const long long volatile int` -> `long long int const volatile` 27506c3fb27SDimitry Andric if (TypeToken->isSimpleTypeSpecifier()) { 27606c3fb27SDimitry Andric // The case `const decltype(foo)` -> `const decltype(foo)` 27706c3fb27SDimitry Andric // The case `const typeof(foo)` -> `const typeof(foo)` 27806c3fb27SDimitry Andric // The case `const _Atomic(foo)` -> `const _Atomic(foo)` 27906c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic)) 28006c3fb27SDimitry Andric return Tok; 28106c3fb27SDimitry Andric 28206c3fb27SDimitry Andric const FormatToken *LastSimpleTypeSpecifier = TypeToken; 28306c3fb27SDimitry Andric while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment())) 28406c3fb27SDimitry Andric LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment(); 28506c3fb27SDimitry Andric 28606c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier, 28706c3fb27SDimitry Andric /*Left=*/false); 28806c3fb27SDimitry Andric return LastSimpleTypeSpecifier; 28906c3fb27SDimitry Andric } 29006c3fb27SDimitry Andric 29106c3fb27SDimitry Andric // The case `unsigned short const` -> `unsigned short const` 29206c3fb27SDimitry Andric // The case: 29306c3fb27SDimitry Andric // `unsigned short volatile const` -> `unsigned short const volatile` 29406c3fb27SDimitry Andric if (PreviousCheck && PreviousCheck->isSimpleTypeSpecifier()) { 29506c3fb27SDimitry Andric if (LastQual != Tok) 29606c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 29706c3fb27SDimitry Andric return Tok; 29806c3fb27SDimitry Andric } 29906c3fb27SDimitry Andric 30006c3fb27SDimitry Andric // Skip the typename keyword. 30106c3fb27SDimitry Andric // The case `const typename C::type` -> `typename C::type const` 30206c3fb27SDimitry Andric if (TypeToken->is(tok::kw_typename)) 30306c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 30406c3fb27SDimitry Andric 30506c3fb27SDimitry Andric // Skip the initial :: of a global-namespace type. 30606c3fb27SDimitry Andric // The case `const ::...` -> `::... const` 30706c3fb27SDimitry Andric if (TypeToken->is(tok::coloncolon)) { 30806c3fb27SDimitry Andric // The case `const ::template Foo...` -> `::template Foo... const` 30906c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 31006c3fb27SDimitry Andric if (TypeToken && TypeToken->is(tok::kw_template)) 31106c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 31206c3fb27SDimitry Andric } 31306c3fb27SDimitry Andric 31406c3fb27SDimitry Andric // Don't change declarations such as 31506c3fb27SDimitry Andric // `foo(const struct Foo a);` -> `foo(const struct Foo a);` 31606c3fb27SDimitry Andric // as they would currently change code such as 31706c3fb27SDimitry Andric // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {} 31806c3fb27SDimitry Andric // my_struct;` 31906c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class)) 32006c3fb27SDimitry Andric return Tok; 32106c3fb27SDimitry Andric 32206c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) { 32306c3fb27SDimitry Andric // The case `const auto` -> `auto const` 324349cc55cSDimitry Andric // The case `const Foo` -> `Foo const` 32581ad6265SDimitry Andric // The case `const ::Foo` -> `::Foo const` 326349cc55cSDimitry Andric // The case `const Foo *` -> `Foo const *` 327349cc55cSDimitry Andric // The case `const Foo &` -> `Foo const &` 328349cc55cSDimitry Andric // The case `const Foo &&` -> `Foo const &&` 329349cc55cSDimitry Andric // The case `const std::Foo &&` -> `std::Foo const &&` 330349cc55cSDimitry Andric // The case `const std::Foo<T> &&` -> `std::Foo<T> const &&` 33106c3fb27SDimitry Andric // The case `const ::template Foo` -> `::template Foo const` 33206c3fb27SDimitry Andric // The case `const T::template Foo` -> `T::template Foo const` 33306c3fb27SDimitry Andric const FormatToken *Next = nullptr; 33406c3fb27SDimitry Andric while ((Next = TypeToken->getNextNonComment()) && 33506c3fb27SDimitry Andric (Next->is(TT_TemplateOpener) || 33606c3fb27SDimitry Andric Next->startsSequence(tok::coloncolon, tok::identifier) || 33706c3fb27SDimitry Andric Next->startsSequence(tok::coloncolon, tok::kw_template, 33806c3fb27SDimitry Andric tok::identifier))) { 33906c3fb27SDimitry Andric if (Next->is(TT_TemplateOpener)) { 34006c3fb27SDimitry Andric assert(Next->MatchingParen && "Missing template closer"); 34106c3fb27SDimitry Andric TypeToken = Next->MatchingParen; 34206c3fb27SDimitry Andric } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) { 34306c3fb27SDimitry Andric TypeToken = Next->getNextNonComment(); 34406c3fb27SDimitry Andric } else { 34506c3fb27SDimitry Andric TypeToken = Next->getNextNonComment()->getNextNonComment(); 3461ac55f4cSDimitry Andric } 34781ad6265SDimitry Andric } 34806c3fb27SDimitry Andric 349*5f757f3fSDimitry Andric if (Next->is(tok::kw_auto)) 350*5f757f3fSDimitry Andric TypeToken = Next; 351*5f757f3fSDimitry Andric 35206c3fb27SDimitry Andric // Place the Qualifier at the end of the list of qualifiers. 35306c3fb27SDimitry Andric while (isQualifier(TypeToken->getNextNonComment())) { 35406c3fb27SDimitry Andric // The case `volatile Foo::iter const` -> `Foo::iter const volatile` 35506c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 356349cc55cSDimitry Andric } 35706c3fb27SDimitry Andric 35806c3fb27SDimitry Andric insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier); 35906c3fb27SDimitry Andric // Remove token and following whitespace. 36006c3fb27SDimitry Andric auto Range = CharSourceRange::getCharRange( 36106c3fb27SDimitry Andric Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace()); 36206c3fb27SDimitry Andric replaceToken(SourceMgr, Fixes, Range, ""); 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric 365349cc55cSDimitry Andric return Tok; 366349cc55cSDimitry Andric } 367349cc55cSDimitry Andric 36804eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 369349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 37006c3fb27SDimitry Andric tooling::Replacements &Fixes, const FormatToken *const Tok, 371349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 37206c3fb27SDimitry Andric // We only need to think about streams that begin with a qualifier. 373*5f757f3fSDimitry Andric if (Tok->isNot(QualifierType)) 37406c3fb27SDimitry Andric return Tok; 37506c3fb27SDimitry Andric // Don't concern yourself if nothing preceeds the qualifier. 37606c3fb27SDimitry Andric if (!Tok->getPreviousNonComment()) 377349cc55cSDimitry Andric return Tok; 378349cc55cSDimitry Andric 37906c3fb27SDimitry Andric // Skip qualifiers to the left to find what preceeds the qualifiers. 38006c3fb27SDimitry Andric const FormatToken *TypeToken = Tok->getPreviousNonComment(); 38106c3fb27SDimitry Andric while (isQualifier(TypeToken)) 38206c3fb27SDimitry Andric TypeToken = TypeToken->getPreviousNonComment(); 38306c3fb27SDimitry Andric 38406c3fb27SDimitry Andric // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& 38506c3fb27SDimitry Andric // we only perform sorting. 386*5f757f3fSDimitry Andric if (!TypeToken || TypeToken->isPointerOrReference() || 38706c3fb27SDimitry Andric TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) { 38806c3fb27SDimitry Andric 38906c3fb27SDimitry Andric // Don't sort past a non-configured qualifier token. 39006c3fb27SDimitry Andric const FormatToken *FirstQual = Tok; 39106c3fb27SDimitry Andric while (isConfiguredQualifier(FirstQual->getPreviousNonComment(), 39206c3fb27SDimitry Andric ConfiguredQualifierTokens)) { 39306c3fb27SDimitry Andric FirstQual = FirstQual->getPreviousNonComment(); 394349cc55cSDimitry Andric } 395349cc55cSDimitry Andric 39606c3fb27SDimitry Andric if (FirstQual != Tok) 39706c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true); 398349cc55cSDimitry Andric return Tok; 399349cc55cSDimitry Andric } 40081ad6265SDimitry Andric 40106c3fb27SDimitry Andric // Stay safe and don't move past macros, also don't bother with sorting. 40206c3fb27SDimitry Andric if (isPossibleMacro(TypeToken)) 40306c3fb27SDimitry Andric return Tok; 404349cc55cSDimitry Andric 40506c3fb27SDimitry Andric // Examples given in order of ['const', 'volatile', 'type'] 40606c3fb27SDimitry Andric 40706c3fb27SDimitry Andric // The case `volatile long long int const` -> `const volatile long long int` 40806c3fb27SDimitry Andric // The case `volatile long long const int` -> `const volatile long long int` 40906c3fb27SDimitry Andric // The case `const long long volatile int` -> `const volatile long long int` 41006c3fb27SDimitry Andric // The case `long volatile long int const` -> `const volatile long long int` 41106c3fb27SDimitry Andric if (TypeToken->isSimpleTypeSpecifier()) { 41206c3fb27SDimitry Andric const FormatToken *LastSimpleTypeSpecifier = TypeToken; 41306c3fb27SDimitry Andric while (isConfiguredQualifierOrType( 41406c3fb27SDimitry Andric LastSimpleTypeSpecifier->getPreviousNonComment(), 41506c3fb27SDimitry Andric ConfiguredQualifierTokens)) { 41606c3fb27SDimitry Andric LastSimpleTypeSpecifier = 41706c3fb27SDimitry Andric LastSimpleTypeSpecifier->getPreviousNonComment(); 418349cc55cSDimitry Andric } 41906c3fb27SDimitry Andric 42006c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok, 42106c3fb27SDimitry Andric /*Left=*/true); 42206c3fb27SDimitry Andric return Tok; 423349cc55cSDimitry Andric } 42406c3fb27SDimitry Andric 42506c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) { 42606c3fb27SDimitry Andric const auto IsStartOfType = [](const FormatToken *const Tok) -> bool { 42706c3fb27SDimitry Andric if (!Tok) 42806c3fb27SDimitry Andric return true; 42906c3fb27SDimitry Andric 43006c3fb27SDimitry Andric // A template closer is not the start of a type. 43106c3fb27SDimitry Andric // The case `?<> const` -> `const ?<>` 43206c3fb27SDimitry Andric if (Tok->is(TT_TemplateCloser)) 43306c3fb27SDimitry Andric return false; 43406c3fb27SDimitry Andric 43506c3fb27SDimitry Andric const FormatToken *const Previous = Tok->getPreviousNonComment(); 43606c3fb27SDimitry Andric if (!Previous) 43706c3fb27SDimitry Andric return true; 43806c3fb27SDimitry Andric 43906c3fb27SDimitry Andric // An identifier preceeded by :: is not the start of a type. 44006c3fb27SDimitry Andric // The case `?::Foo const` -> `const ?::Foo` 44106c3fb27SDimitry Andric if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon)) 44206c3fb27SDimitry Andric return false; 44306c3fb27SDimitry Andric 44406c3fb27SDimitry Andric const FormatToken *const PrePrevious = Previous->getPreviousNonComment(); 44506c3fb27SDimitry Andric // An identifier preceeded by ::template is not the start of a type. 44606c3fb27SDimitry Andric // The case `?::template Foo const` -> `const ?::template Foo` 44706c3fb27SDimitry Andric if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) && 44806c3fb27SDimitry Andric PrePrevious && PrePrevious->is(tok::coloncolon)) { 44906c3fb27SDimitry Andric return false; 45006c3fb27SDimitry Andric } 45106c3fb27SDimitry Andric 452*5f757f3fSDimitry Andric if (Tok->endsSequence(tok::kw_auto, tok::identifier)) 453*5f757f3fSDimitry Andric return false; 454*5f757f3fSDimitry Andric 45506c3fb27SDimitry Andric return true; 45606c3fb27SDimitry Andric }; 45706c3fb27SDimitry Andric 45806c3fb27SDimitry Andric while (!IsStartOfType(TypeToken)) { 45906c3fb27SDimitry Andric // The case `?<>` 46006c3fb27SDimitry Andric if (TypeToken->is(TT_TemplateCloser)) { 46106c3fb27SDimitry Andric assert(TypeToken->MatchingParen && "Missing template opener"); 46206c3fb27SDimitry Andric TypeToken = TypeToken->MatchingParen->getPreviousNonComment(); 46306c3fb27SDimitry Andric } else { 46406c3fb27SDimitry Andric // The cases 46506c3fb27SDimitry Andric // `::Foo` 46606c3fb27SDimitry Andric // `?>::Foo` 46706c3fb27SDimitry Andric // `?Bar::Foo` 46806c3fb27SDimitry Andric // `::template Foo` 46906c3fb27SDimitry Andric // `?>::template Foo` 47006c3fb27SDimitry Andric // `?Bar::template Foo` 47106c3fb27SDimitry Andric if (TypeToken->getPreviousNonComment()->is(tok::kw_template)) 47206c3fb27SDimitry Andric TypeToken = TypeToken->getPreviousNonComment(); 47306c3fb27SDimitry Andric 47406c3fb27SDimitry Andric const FormatToken *const ColonColon = 47506c3fb27SDimitry Andric TypeToken->getPreviousNonComment(); 47606c3fb27SDimitry Andric const FormatToken *const PreColonColon = 47706c3fb27SDimitry Andric ColonColon->getPreviousNonComment(); 47806c3fb27SDimitry Andric if (PreColonColon && 47906c3fb27SDimitry Andric PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) { 48006c3fb27SDimitry Andric TypeToken = PreColonColon; 48106c3fb27SDimitry Andric } else { 48206c3fb27SDimitry Andric TypeToken = ColonColon; 483349cc55cSDimitry Andric } 484349cc55cSDimitry Andric } 485349cc55cSDimitry Andric } 48606c3fb27SDimitry Andric 48706c3fb27SDimitry Andric assert(TypeToken && "Should be auto or identifier"); 48806c3fb27SDimitry Andric 48906c3fb27SDimitry Andric // Place the Qualifier at the start of the list of qualifiers. 49006c3fb27SDimitry Andric const FormatToken *Previous = nullptr; 49106c3fb27SDimitry Andric while ((Previous = TypeToken->getPreviousNonComment()) && 49206c3fb27SDimitry Andric (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) || 49306c3fb27SDimitry Andric Previous->is(tok::kw_typename))) { 49406c3fb27SDimitry Andric // The case `volatile Foo::iter const` -> `const volatile Foo::iter` 49506c3fb27SDimitry Andric // The case `typename C::type const` -> `const typename C::type` 49606c3fb27SDimitry Andric TypeToken = Previous; 49706c3fb27SDimitry Andric } 49806c3fb27SDimitry Andric 49906c3fb27SDimitry Andric // Don't change declarations such as 50006c3fb27SDimitry Andric // `foo(struct Foo const a);` -> `foo(struct Foo const a);` 50106c3fb27SDimitry Andric if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) { 50206c3fb27SDimitry Andric insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier); 50306c3fb27SDimitry Andric removeToken(SourceMgr, Fixes, Tok); 50406c3fb27SDimitry Andric } 50506c3fb27SDimitry Andric } 50606c3fb27SDimitry Andric 507349cc55cSDimitry Andric return Tok; 508349cc55cSDimitry Andric } 509349cc55cSDimitry Andric 510349cc55cSDimitry Andric tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( 511349cc55cSDimitry Andric const std::string &Qualifier) { 512349cc55cSDimitry Andric // Don't let 'type' be an identifier, but steal typeof token. 513349cc55cSDimitry Andric return llvm::StringSwitch<tok::TokenKind>(Qualifier) 514349cc55cSDimitry Andric .Case("type", tok::kw_typeof) 515349cc55cSDimitry Andric .Case("const", tok::kw_const) 516349cc55cSDimitry Andric .Case("volatile", tok::kw_volatile) 517349cc55cSDimitry Andric .Case("static", tok::kw_static) 518349cc55cSDimitry Andric .Case("inline", tok::kw_inline) 519349cc55cSDimitry Andric .Case("constexpr", tok::kw_constexpr) 520349cc55cSDimitry Andric .Case("restrict", tok::kw_restrict) 521bdd1243dSDimitry Andric .Case("friend", tok::kw_friend) 522349cc55cSDimitry Andric .Default(tok::identifier); 523349cc55cSDimitry Andric } 524349cc55cSDimitry Andric 525349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( 526349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, 527349cc55cSDimitry Andric const std::string &Qualifier, 528349cc55cSDimitry Andric const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign) 529349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), 530349cc55cSDimitry Andric ConfiguredQualifierTokens(QualifierTokens) {} 531349cc55cSDimitry Andric 532349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> 533349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::analyze( 53481ad6265SDimitry Andric TokenAnnotator & /*Annotator*/, 53581ad6265SDimitry Andric SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 536349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 537349cc55cSDimitry Andric tooling::Replacements Fixes; 538*5f757f3fSDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 539*5f757f3fSDimitry Andric fixQualifierAlignment(AnnotatedLines, Tokens, Fixes); 540*5f757f3fSDimitry Andric return {Fixes, 0}; 541*5f757f3fSDimitry Andric } 542*5f757f3fSDimitry Andric 543*5f757f3fSDimitry Andric void LeftRightQualifierAlignmentFixer::fixQualifierAlignment( 544*5f757f3fSDimitry Andric SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens, 545*5f757f3fSDimitry Andric tooling::Replacements &Fixes) { 546349cc55cSDimitry Andric const AdditionalKeywords &Keywords = Tokens.getKeywords(); 547349cc55cSDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager(); 548349cc55cSDimitry Andric tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); 549349cc55cSDimitry Andric assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); 550349cc55cSDimitry Andric 55104eeddc0SDimitry Andric for (AnnotatedLine *Line : AnnotatedLines) { 552*5f757f3fSDimitry Andric fixQualifierAlignment(Line->Children, Tokens, Fixes); 55306c3fb27SDimitry Andric if (!Line->Affected || Line->InPPDirective) 55481ad6265SDimitry Andric continue; 55504eeddc0SDimitry Andric FormatToken *First = Line->First; 556d56accc7SDimitry Andric assert(First); 557d56accc7SDimitry Andric if (First->Finalized) 558d56accc7SDimitry Andric continue; 559d56accc7SDimitry Andric 56004eeddc0SDimitry Andric const auto *Last = Line->Last; 561349cc55cSDimitry Andric 56204eeddc0SDimitry Andric for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; 56304eeddc0SDimitry Andric Tok = Tok->Next) { 564349cc55cSDimitry Andric if (Tok->is(tok::comment)) 565349cc55cSDimitry Andric continue; 56681ad6265SDimitry Andric if (RightAlign) { 567349cc55cSDimitry Andric Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, 568349cc55cSDimitry Andric QualifierToken); 56981ad6265SDimitry Andric } else { 570349cc55cSDimitry Andric Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, 571349cc55cSDimitry Andric QualifierToken); 572349cc55cSDimitry Andric } 573349cc55cSDimitry Andric } 57481ad6265SDimitry Andric } 575349cc55cSDimitry Andric } 576349cc55cSDimitry Andric 57706c3fb27SDimitry Andric void prepareLeftRightOrderingForQualifierAlignmentFixer( 578349cc55cSDimitry Andric const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder, 579349cc55cSDimitry Andric std::vector<std::string> &RightOrder, 580349cc55cSDimitry Andric std::vector<tok::TokenKind> &Qualifiers) { 581349cc55cSDimitry Andric 582349cc55cSDimitry Andric // Depending on the position of type in the order you need 583349cc55cSDimitry Andric // To iterate forward or backward through the order list as qualifier 584349cc55cSDimitry Andric // can push through each other. 585349cc55cSDimitry Andric // The Order list must define the position of "type" to signify 586349cc55cSDimitry Andric assert(llvm::is_contained(Order, "type") && 587349cc55cSDimitry Andric "QualifierOrder must contain type"); 588349cc55cSDimitry Andric // Split the Order list by type and reverse the left side. 589349cc55cSDimitry Andric 590349cc55cSDimitry Andric bool left = true; 591349cc55cSDimitry Andric for (const auto &s : Order) { 592349cc55cSDimitry Andric if (s == "type") { 593349cc55cSDimitry Andric left = false; 594349cc55cSDimitry Andric continue; 595349cc55cSDimitry Andric } 596349cc55cSDimitry Andric 597349cc55cSDimitry Andric tok::TokenKind QualifierToken = 598349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); 59981ad6265SDimitry Andric if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) 600349cc55cSDimitry Andric Qualifiers.push_back(QualifierToken); 601349cc55cSDimitry Andric 60281ad6265SDimitry Andric if (left) { 603349cc55cSDimitry Andric // Reverse the order for left aligned items. 604349cc55cSDimitry Andric LeftOrder.insert(LeftOrder.begin(), s); 60581ad6265SDimitry Andric } else { 606349cc55cSDimitry Andric RightOrder.push_back(s); 607349cc55cSDimitry Andric } 608349cc55cSDimitry Andric } 60981ad6265SDimitry Andric } 610349cc55cSDimitry Andric 611349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isQualifierOrType( 61206c3fb27SDimitry Andric const FormatToken *const Tok) { 613349cc55cSDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 61406c3fb27SDimitry Andric isQualifier(Tok)); 61506c3fb27SDimitry Andric } 61606c3fb27SDimitry Andric 61706c3fb27SDimitry Andric bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( 61806c3fb27SDimitry Andric const FormatToken *const Tok, 61906c3fb27SDimitry Andric const std::vector<tok::TokenKind> &Qualifiers) { 62006c3fb27SDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 62106c3fb27SDimitry Andric isConfiguredQualifier(Tok, Qualifiers)); 622349cc55cSDimitry Andric } 623349cc55cSDimitry Andric 624349cc55cSDimitry Andric // If a token is an identifier and it's upper case, it could 625349cc55cSDimitry Andric // be a macro and hence we need to be able to ignore it. 626349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { 627349cc55cSDimitry Andric if (!Tok) 628349cc55cSDimitry Andric return false; 629*5f757f3fSDimitry Andric if (Tok->isNot(tok::identifier)) 630349cc55cSDimitry Andric return false; 63181ad6265SDimitry Andric if (Tok->TokenText.upper() == Tok->TokenText.str()) { 63281ad6265SDimitry Andric // T,K,U,V likely could be template arguments 63306c3fb27SDimitry Andric return Tok->TokenText.size() != 1; 63481ad6265SDimitry Andric } 635349cc55cSDimitry Andric return false; 636349cc55cSDimitry Andric } 637349cc55cSDimitry Andric 638349cc55cSDimitry Andric } // namespace format 639349cc55cSDimitry Andric } // namespace clang 640