1349cc55cSDimitry Andric //===--- LeftRightQualifierAlignmentFixer.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 10349cc55cSDimitry Andric /// This file implements LeftRightQualifierAlignmentFixer, 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 28*06c3fb27SDimitry Andric void addQualifierAlignmentFixerPasses(const FormatStyle &Style, 29*06c3fb27SDimitry 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; 33*06c3fb27SDimitry Andric prepareLeftRightOrderingForQualifierAlignmentFixer( 34*06c3fb27SDimitry 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) { 81*06c3fb27SDimitry Andric auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(), 82*06c3fb27SDimitry Andric First->Tok.getEndLoc()); 83349cc55cSDimitry Andric 84*06c3fb27SDimitry Andric std::string NewText{}; 85*06c3fb27SDimitry Andric NewText += First->TokenText; 86*06c3fb27SDimitry 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 155*06c3fb27SDimitry Andric static bool 156*06c3fb27SDimitry Andric isConfiguredQualifier(const FormatToken *const Tok, 157*06c3fb27SDimitry Andric const std::vector<tok::TokenKind> &Qualifiers) { 158*06c3fb27SDimitry Andric return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind()); 159*06c3fb27SDimitry Andric } 160*06c3fb27SDimitry Andric 161*06c3fb27SDimitry Andric static bool isQualifier(const FormatToken *const Tok) { 162*06c3fb27SDimitry Andric if (!Tok) 163*06c3fb27SDimitry Andric return false; 164*06c3fb27SDimitry Andric 165*06c3fb27SDimitry Andric switch (Tok->Tok.getKind()) { 166*06c3fb27SDimitry Andric case tok::kw_const: 167*06c3fb27SDimitry Andric case tok::kw_volatile: 168*06c3fb27SDimitry Andric case tok::kw_static: 169*06c3fb27SDimitry Andric case tok::kw_inline: 170*06c3fb27SDimitry Andric case tok::kw_constexpr: 171*06c3fb27SDimitry Andric case tok::kw_restrict: 172*06c3fb27SDimitry Andric case tok::kw_friend: 173*06c3fb27SDimitry Andric return true; 174*06c3fb27SDimitry Andric default: 175*06c3fb27SDimitry Andric return false; 176*06c3fb27SDimitry Andric } 177*06c3fb27SDimitry Andric } 178*06c3fb27SDimitry Andric 17904eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( 180349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 181*06c3fb27SDimitry 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. 184349cc55cSDimitry Andric if (!Tok->is(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 190*06c3fb27SDimitry Andric // Skip qualifiers to the left to find what preceeds the qualifiers. 191*06c3fb27SDimitry Andric // Use isQualifier rather than isConfiguredQualifier to cover all qualifiers. 192*06c3fb27SDimitry Andric const FormatToken *PreviousCheck = Tok->getPreviousNonComment(); 193*06c3fb27SDimitry Andric while (isQualifier(PreviousCheck)) 194*06c3fb27SDimitry Andric PreviousCheck = PreviousCheck->getPreviousNonComment(); 19581ad6265SDimitry Andric 196*06c3fb27SDimitry Andric // Examples given in order of ['type', 'const', 'volatile'] 197*06c3fb27SDimitry Andric const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() { 198*06c3fb27SDimitry Andric // The cases: 199*06c3fb27SDimitry Andric // `Foo() const` -> `Foo() const` 200*06c3fb27SDimitry Andric // `Foo() const final` -> `Foo() const final` 201*06c3fb27SDimitry Andric // `Foo() const override` -> `Foo() const final` 202*06c3fb27SDimitry Andric // `Foo() const volatile override` -> `Foo() const volatile override` 203*06c3fb27SDimitry Andric // `Foo() volatile const final` -> `Foo() const volatile final` 204*06c3fb27SDimitry Andric if (PreviousCheck->is(tok::r_paren)) 205*06c3fb27SDimitry Andric return true; 206*06c3fb27SDimitry Andric 207*06c3fb27SDimitry Andric // The cases: 208*06c3fb27SDimitry Andric // `struct {} volatile const a;` -> `struct {} const volatile a;` 209*06c3fb27SDimitry Andric // `class {} volatile const a;` -> `class {} const volatile a;` 210*06c3fb27SDimitry Andric if (PreviousCheck->is(tok::r_brace)) 211*06c3fb27SDimitry Andric return true; 212*06c3fb27SDimitry Andric 213*06c3fb27SDimitry Andric // The case: 214*06c3fb27SDimitry Andric // `template <class T> const Bar Foo()` -> 215*06c3fb27SDimitry Andric // `template <class T> Bar const Foo()` 216*06c3fb27SDimitry Andric // The cases: 217*06c3fb27SDimitry Andric // `Foo<int> const foo` -> `Foo<int> const foo` 218*06c3fb27SDimitry Andric // `Foo<int> volatile const` -> `Foo<int> const volatile` 219*06c3fb27SDimitry Andric // The case: 220*06c3fb27SDimitry Andric // ``` 221*06c3fb27SDimitry Andric // template <class T> 222*06c3fb27SDimitry Andric // requires Concept1<T> && requires Concept2<T> 223*06c3fb27SDimitry Andric // const Foo f(); 224*06c3fb27SDimitry Andric // ``` 225*06c3fb27SDimitry Andric // -> 226*06c3fb27SDimitry Andric // ``` 227*06c3fb27SDimitry Andric // template <class T> 228*06c3fb27SDimitry Andric // requires Concept1<T> && requires Concept2<T> 229*06c3fb27SDimitry Andric // Foo const f(); 230*06c3fb27SDimitry Andric // ``` 231*06c3fb27SDimitry Andric if (PreviousCheck->is(TT_TemplateCloser)) { 232*06c3fb27SDimitry Andric // If the token closes a template<> or requires clause, then it is a left 233*06c3fb27SDimitry Andric // qualifier and should be moved to the right. 234*06c3fb27SDimitry Andric return !(PreviousCheck->ClosesTemplateDeclaration || 235*06c3fb27SDimitry Andric PreviousCheck->ClosesRequiresClause); 236349cc55cSDimitry Andric } 237*06c3fb27SDimitry Andric 238*06c3fb27SDimitry Andric // The case `Foo* const` -> `Foo* const` 239*06c3fb27SDimitry Andric // The case `Foo* volatile const` -> `Foo* const volatile` 240*06c3fb27SDimitry Andric // The case `int32_t const` -> `int32_t const` 241*06c3fb27SDimitry Andric // The case `auto volatile const` -> `auto const volatile` 242*06c3fb27SDimitry Andric if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier, 243*06c3fb27SDimitry Andric tok::kw_auto)) { 244*06c3fb27SDimitry Andric return true; 245*06c3fb27SDimitry Andric } 246*06c3fb27SDimitry Andric 247*06c3fb27SDimitry Andric return false; 248*06c3fb27SDimitry Andric }(); 249*06c3fb27SDimitry Andric 250*06c3fb27SDimitry Andric // Find the last qualifier to the right. 251*06c3fb27SDimitry Andric const FormatToken *LastQual = Tok; 252*06c3fb27SDimitry Andric while (isQualifier(LastQual->getNextNonComment())) 253*06c3fb27SDimitry Andric LastQual = LastQual->getNextNonComment(); 254*06c3fb27SDimitry Andric 255*06c3fb27SDimitry Andric // If this qualifier is to the right of a type or pointer do a partial sort 256*06c3fb27SDimitry Andric // and return. 257*06c3fb27SDimitry Andric if (IsRightQualifier) { 258*06c3fb27SDimitry Andric if (LastQual != Tok) 259349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 260349cc55cSDimitry Andric return Tok; 261*06c3fb27SDimitry Andric } 262*06c3fb27SDimitry Andric 263*06c3fb27SDimitry Andric const FormatToken *TypeToken = LastQual->getNextNonComment(); 264*06c3fb27SDimitry Andric if (!TypeToken) 265*06c3fb27SDimitry Andric return Tok; 266*06c3fb27SDimitry Andric 267*06c3fb27SDimitry Andric // Stay safe and don't move past macros, also don't bother with sorting. 268*06c3fb27SDimitry Andric if (isPossibleMacro(TypeToken)) 269*06c3fb27SDimitry Andric return Tok; 270*06c3fb27SDimitry Andric 271*06c3fb27SDimitry Andric // The case `const long long int volatile` -> `long long int const volatile` 272*06c3fb27SDimitry Andric // The case `long const long int volatile` -> `long long int const volatile` 273*06c3fb27SDimitry Andric // The case `long long volatile int const` -> `long long int const volatile` 274*06c3fb27SDimitry Andric // The case `const long long volatile int` -> `long long int const volatile` 275*06c3fb27SDimitry Andric if (TypeToken->isSimpleTypeSpecifier()) { 276*06c3fb27SDimitry Andric // The case `const decltype(foo)` -> `const decltype(foo)` 277*06c3fb27SDimitry Andric // The case `const typeof(foo)` -> `const typeof(foo)` 278*06c3fb27SDimitry Andric // The case `const _Atomic(foo)` -> `const _Atomic(foo)` 279*06c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic)) 280*06c3fb27SDimitry Andric return Tok; 281*06c3fb27SDimitry Andric 282*06c3fb27SDimitry Andric const FormatToken *LastSimpleTypeSpecifier = TypeToken; 283*06c3fb27SDimitry Andric while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment())) 284*06c3fb27SDimitry Andric LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment(); 285*06c3fb27SDimitry Andric 286*06c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier, 287*06c3fb27SDimitry Andric /*Left=*/false); 288*06c3fb27SDimitry Andric return LastSimpleTypeSpecifier; 289*06c3fb27SDimitry Andric } 290*06c3fb27SDimitry Andric 291*06c3fb27SDimitry Andric // The case `unsigned short const` -> `unsigned short const` 292*06c3fb27SDimitry Andric // The case: 293*06c3fb27SDimitry Andric // `unsigned short volatile const` -> `unsigned short const volatile` 294*06c3fb27SDimitry Andric if (PreviousCheck && PreviousCheck->isSimpleTypeSpecifier()) { 295*06c3fb27SDimitry Andric if (LastQual != Tok) 296*06c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 297*06c3fb27SDimitry Andric return Tok; 298*06c3fb27SDimitry Andric } 299*06c3fb27SDimitry Andric 300*06c3fb27SDimitry Andric // Skip the typename keyword. 301*06c3fb27SDimitry Andric // The case `const typename C::type` -> `typename C::type const` 302*06c3fb27SDimitry Andric if (TypeToken->is(tok::kw_typename)) 303*06c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 304*06c3fb27SDimitry Andric 305*06c3fb27SDimitry Andric // Skip the initial :: of a global-namespace type. 306*06c3fb27SDimitry Andric // The case `const ::...` -> `::... const` 307*06c3fb27SDimitry Andric if (TypeToken->is(tok::coloncolon)) { 308*06c3fb27SDimitry Andric // The case `const ::template Foo...` -> `::template Foo... const` 309*06c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 310*06c3fb27SDimitry Andric if (TypeToken && TypeToken->is(tok::kw_template)) 311*06c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 312*06c3fb27SDimitry Andric } 313*06c3fb27SDimitry Andric 314*06c3fb27SDimitry Andric // Don't change declarations such as 315*06c3fb27SDimitry Andric // `foo(const struct Foo a);` -> `foo(const struct Foo a);` 316*06c3fb27SDimitry Andric // as they would currently change code such as 317*06c3fb27SDimitry Andric // `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {} 318*06c3fb27SDimitry Andric // my_struct;` 319*06c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class)) 320*06c3fb27SDimitry Andric return Tok; 321*06c3fb27SDimitry Andric 322*06c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) { 323*06c3fb27SDimitry 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 &&` 331*06c3fb27SDimitry Andric // The case `const ::template Foo` -> `::template Foo const` 332*06c3fb27SDimitry Andric // The case `const T::template Foo` -> `T::template Foo const` 333*06c3fb27SDimitry Andric const FormatToken *Next = nullptr; 334*06c3fb27SDimitry Andric while ((Next = TypeToken->getNextNonComment()) && 335*06c3fb27SDimitry Andric (Next->is(TT_TemplateOpener) || 336*06c3fb27SDimitry Andric Next->startsSequence(tok::coloncolon, tok::identifier) || 337*06c3fb27SDimitry Andric Next->startsSequence(tok::coloncolon, tok::kw_template, 338*06c3fb27SDimitry Andric tok::identifier))) { 339*06c3fb27SDimitry Andric if (Next->is(TT_TemplateOpener)) { 340*06c3fb27SDimitry Andric assert(Next->MatchingParen && "Missing template closer"); 341*06c3fb27SDimitry Andric TypeToken = Next->MatchingParen; 342*06c3fb27SDimitry Andric } else if (Next->startsSequence(tok::coloncolon, tok::identifier)) { 343*06c3fb27SDimitry Andric TypeToken = Next->getNextNonComment(); 344*06c3fb27SDimitry Andric } else { 345*06c3fb27SDimitry Andric TypeToken = Next->getNextNonComment()->getNextNonComment(); 3461ac55f4cSDimitry Andric } 34781ad6265SDimitry Andric } 348*06c3fb27SDimitry Andric 349*06c3fb27SDimitry Andric // Place the Qualifier at the end of the list of qualifiers. 350*06c3fb27SDimitry Andric while (isQualifier(TypeToken->getNextNonComment())) { 351*06c3fb27SDimitry Andric // The case `volatile Foo::iter const` -> `Foo::iter const volatile` 352*06c3fb27SDimitry Andric TypeToken = TypeToken->getNextNonComment(); 353349cc55cSDimitry Andric } 354*06c3fb27SDimitry Andric 355*06c3fb27SDimitry Andric insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier); 356*06c3fb27SDimitry Andric // Remove token and following whitespace. 357*06c3fb27SDimitry Andric auto Range = CharSourceRange::getCharRange( 358*06c3fb27SDimitry Andric Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace()); 359*06c3fb27SDimitry Andric replaceToken(SourceMgr, Fixes, Range, ""); 360349cc55cSDimitry Andric } 361349cc55cSDimitry Andric 362349cc55cSDimitry Andric return Tok; 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric 36504eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 366349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 367*06c3fb27SDimitry Andric tooling::Replacements &Fixes, const FormatToken *const Tok, 368349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 369*06c3fb27SDimitry Andric // We only need to think about streams that begin with a qualifier. 370*06c3fb27SDimitry Andric if (!Tok->is(QualifierType)) 371*06c3fb27SDimitry Andric return Tok; 372*06c3fb27SDimitry Andric // Don't concern yourself if nothing preceeds the qualifier. 373*06c3fb27SDimitry Andric if (!Tok->getPreviousNonComment()) 374349cc55cSDimitry Andric return Tok; 375349cc55cSDimitry Andric 376*06c3fb27SDimitry Andric // Skip qualifiers to the left to find what preceeds the qualifiers. 377*06c3fb27SDimitry Andric const FormatToken *TypeToken = Tok->getPreviousNonComment(); 378*06c3fb27SDimitry Andric while (isQualifier(TypeToken)) 379*06c3fb27SDimitry Andric TypeToken = TypeToken->getPreviousNonComment(); 380*06c3fb27SDimitry Andric 381*06c3fb27SDimitry Andric // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& 382*06c3fb27SDimitry Andric // we only perform sorting. 383*06c3fb27SDimitry Andric if (!TypeToken || TypeToken->isOneOf(tok::star, tok::amp, tok::ampamp) || 384*06c3fb27SDimitry Andric TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) { 385*06c3fb27SDimitry Andric 386*06c3fb27SDimitry Andric // Don't sort past a non-configured qualifier token. 387*06c3fb27SDimitry Andric const FormatToken *FirstQual = Tok; 388*06c3fb27SDimitry Andric while (isConfiguredQualifier(FirstQual->getPreviousNonComment(), 389*06c3fb27SDimitry Andric ConfiguredQualifierTokens)) { 390*06c3fb27SDimitry Andric FirstQual = FirstQual->getPreviousNonComment(); 391349cc55cSDimitry Andric } 392349cc55cSDimitry Andric 393*06c3fb27SDimitry Andric if (FirstQual != Tok) 394*06c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true); 395349cc55cSDimitry Andric return Tok; 396349cc55cSDimitry Andric } 39781ad6265SDimitry Andric 398*06c3fb27SDimitry Andric // Stay safe and don't move past macros, also don't bother with sorting. 399*06c3fb27SDimitry Andric if (isPossibleMacro(TypeToken)) 400*06c3fb27SDimitry Andric return Tok; 401349cc55cSDimitry Andric 402*06c3fb27SDimitry Andric // Examples given in order of ['const', 'volatile', 'type'] 403*06c3fb27SDimitry Andric 404*06c3fb27SDimitry Andric // The case `volatile long long int const` -> `const volatile long long int` 405*06c3fb27SDimitry Andric // The case `volatile long long const int` -> `const volatile long long int` 406*06c3fb27SDimitry Andric // The case `const long long volatile int` -> `const volatile long long int` 407*06c3fb27SDimitry Andric // The case `long volatile long int const` -> `const volatile long long int` 408*06c3fb27SDimitry Andric if (TypeToken->isSimpleTypeSpecifier()) { 409*06c3fb27SDimitry Andric const FormatToken *LastSimpleTypeSpecifier = TypeToken; 410*06c3fb27SDimitry Andric while (isConfiguredQualifierOrType( 411*06c3fb27SDimitry Andric LastSimpleTypeSpecifier->getPreviousNonComment(), 412*06c3fb27SDimitry Andric ConfiguredQualifierTokens)) { 413*06c3fb27SDimitry Andric LastSimpleTypeSpecifier = 414*06c3fb27SDimitry Andric LastSimpleTypeSpecifier->getPreviousNonComment(); 415349cc55cSDimitry Andric } 416*06c3fb27SDimitry Andric 417*06c3fb27SDimitry Andric rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok, 418*06c3fb27SDimitry Andric /*Left=*/true); 419*06c3fb27SDimitry Andric return Tok; 420349cc55cSDimitry Andric } 421*06c3fb27SDimitry Andric 422*06c3fb27SDimitry Andric if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) { 423*06c3fb27SDimitry Andric const auto IsStartOfType = [](const FormatToken *const Tok) -> bool { 424*06c3fb27SDimitry Andric if (!Tok) 425*06c3fb27SDimitry Andric return true; 426*06c3fb27SDimitry Andric 427*06c3fb27SDimitry Andric // A template closer is not the start of a type. 428*06c3fb27SDimitry Andric // The case `?<> const` -> `const ?<>` 429*06c3fb27SDimitry Andric if (Tok->is(TT_TemplateCloser)) 430*06c3fb27SDimitry Andric return false; 431*06c3fb27SDimitry Andric 432*06c3fb27SDimitry Andric const FormatToken *const Previous = Tok->getPreviousNonComment(); 433*06c3fb27SDimitry Andric if (!Previous) 434*06c3fb27SDimitry Andric return true; 435*06c3fb27SDimitry Andric 436*06c3fb27SDimitry Andric // An identifier preceeded by :: is not the start of a type. 437*06c3fb27SDimitry Andric // The case `?::Foo const` -> `const ?::Foo` 438*06c3fb27SDimitry Andric if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon)) 439*06c3fb27SDimitry Andric return false; 440*06c3fb27SDimitry Andric 441*06c3fb27SDimitry Andric const FormatToken *const PrePrevious = Previous->getPreviousNonComment(); 442*06c3fb27SDimitry Andric // An identifier preceeded by ::template is not the start of a type. 443*06c3fb27SDimitry Andric // The case `?::template Foo const` -> `const ?::template Foo` 444*06c3fb27SDimitry Andric if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) && 445*06c3fb27SDimitry Andric PrePrevious && PrePrevious->is(tok::coloncolon)) { 446*06c3fb27SDimitry Andric return false; 447*06c3fb27SDimitry Andric } 448*06c3fb27SDimitry Andric 449*06c3fb27SDimitry Andric return true; 450*06c3fb27SDimitry Andric }; 451*06c3fb27SDimitry Andric 452*06c3fb27SDimitry Andric while (!IsStartOfType(TypeToken)) { 453*06c3fb27SDimitry Andric // The case `?<>` 454*06c3fb27SDimitry Andric if (TypeToken->is(TT_TemplateCloser)) { 455*06c3fb27SDimitry Andric assert(TypeToken->MatchingParen && "Missing template opener"); 456*06c3fb27SDimitry Andric TypeToken = TypeToken->MatchingParen->getPreviousNonComment(); 457*06c3fb27SDimitry Andric } else { 458*06c3fb27SDimitry Andric // The cases 459*06c3fb27SDimitry Andric // `::Foo` 460*06c3fb27SDimitry Andric // `?>::Foo` 461*06c3fb27SDimitry Andric // `?Bar::Foo` 462*06c3fb27SDimitry Andric // `::template Foo` 463*06c3fb27SDimitry Andric // `?>::template Foo` 464*06c3fb27SDimitry Andric // `?Bar::template Foo` 465*06c3fb27SDimitry Andric if (TypeToken->getPreviousNonComment()->is(tok::kw_template)) 466*06c3fb27SDimitry Andric TypeToken = TypeToken->getPreviousNonComment(); 467*06c3fb27SDimitry Andric 468*06c3fb27SDimitry Andric const FormatToken *const ColonColon = 469*06c3fb27SDimitry Andric TypeToken->getPreviousNonComment(); 470*06c3fb27SDimitry Andric const FormatToken *const PreColonColon = 471*06c3fb27SDimitry Andric ColonColon->getPreviousNonComment(); 472*06c3fb27SDimitry Andric if (PreColonColon && 473*06c3fb27SDimitry Andric PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) { 474*06c3fb27SDimitry Andric TypeToken = PreColonColon; 475*06c3fb27SDimitry Andric } else { 476*06c3fb27SDimitry Andric TypeToken = ColonColon; 477349cc55cSDimitry Andric } 478349cc55cSDimitry Andric } 479349cc55cSDimitry Andric } 480*06c3fb27SDimitry Andric 481*06c3fb27SDimitry Andric assert(TypeToken && "Should be auto or identifier"); 482*06c3fb27SDimitry Andric 483*06c3fb27SDimitry Andric // Place the Qualifier at the start of the list of qualifiers. 484*06c3fb27SDimitry Andric const FormatToken *Previous = nullptr; 485*06c3fb27SDimitry Andric while ((Previous = TypeToken->getPreviousNonComment()) && 486*06c3fb27SDimitry Andric (isConfiguredQualifier(Previous, ConfiguredQualifierTokens) || 487*06c3fb27SDimitry Andric Previous->is(tok::kw_typename))) { 488*06c3fb27SDimitry Andric // The case `volatile Foo::iter const` -> `const volatile Foo::iter` 489*06c3fb27SDimitry Andric // The case `typename C::type const` -> `const typename C::type` 490*06c3fb27SDimitry Andric TypeToken = Previous; 491*06c3fb27SDimitry Andric } 492*06c3fb27SDimitry Andric 493*06c3fb27SDimitry Andric // Don't change declarations such as 494*06c3fb27SDimitry Andric // `foo(struct Foo const a);` -> `foo(struct Foo const a);` 495*06c3fb27SDimitry Andric if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) { 496*06c3fb27SDimitry Andric insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier); 497*06c3fb27SDimitry Andric removeToken(SourceMgr, Fixes, Tok); 498*06c3fb27SDimitry Andric } 499*06c3fb27SDimitry Andric } 500*06c3fb27SDimitry Andric 501349cc55cSDimitry Andric return Tok; 502349cc55cSDimitry Andric } 503349cc55cSDimitry Andric 504349cc55cSDimitry Andric tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( 505349cc55cSDimitry Andric const std::string &Qualifier) { 506349cc55cSDimitry Andric // Don't let 'type' be an identifier, but steal typeof token. 507349cc55cSDimitry Andric return llvm::StringSwitch<tok::TokenKind>(Qualifier) 508349cc55cSDimitry Andric .Case("type", tok::kw_typeof) 509349cc55cSDimitry Andric .Case("const", tok::kw_const) 510349cc55cSDimitry Andric .Case("volatile", tok::kw_volatile) 511349cc55cSDimitry Andric .Case("static", tok::kw_static) 512349cc55cSDimitry Andric .Case("inline", tok::kw_inline) 513349cc55cSDimitry Andric .Case("constexpr", tok::kw_constexpr) 514349cc55cSDimitry Andric .Case("restrict", tok::kw_restrict) 515bdd1243dSDimitry Andric .Case("friend", tok::kw_friend) 516349cc55cSDimitry Andric .Default(tok::identifier); 517349cc55cSDimitry Andric } 518349cc55cSDimitry Andric 519349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( 520349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, 521349cc55cSDimitry Andric const std::string &Qualifier, 522349cc55cSDimitry Andric const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign) 523349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), 524349cc55cSDimitry Andric ConfiguredQualifierTokens(QualifierTokens) {} 525349cc55cSDimitry Andric 526349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> 527349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::analyze( 52881ad6265SDimitry Andric TokenAnnotator & /*Annotator*/, 52981ad6265SDimitry Andric SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 530349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 531349cc55cSDimitry Andric tooling::Replacements Fixes; 532349cc55cSDimitry Andric const AdditionalKeywords &Keywords = Tokens.getKeywords(); 533349cc55cSDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager(); 534349cc55cSDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 535349cc55cSDimitry Andric 536349cc55cSDimitry Andric tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); 537349cc55cSDimitry Andric assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); 538349cc55cSDimitry Andric 53904eeddc0SDimitry Andric for (AnnotatedLine *Line : AnnotatedLines) { 540*06c3fb27SDimitry Andric if (!Line->Affected || Line->InPPDirective) 54181ad6265SDimitry Andric continue; 54204eeddc0SDimitry Andric FormatToken *First = Line->First; 543d56accc7SDimitry Andric assert(First); 544d56accc7SDimitry Andric if (First->Finalized) 545d56accc7SDimitry Andric continue; 546d56accc7SDimitry Andric 54704eeddc0SDimitry Andric const auto *Last = Line->Last; 548349cc55cSDimitry Andric 54904eeddc0SDimitry Andric for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; 55004eeddc0SDimitry Andric Tok = Tok->Next) { 551349cc55cSDimitry Andric if (Tok->is(tok::comment)) 552349cc55cSDimitry Andric continue; 55381ad6265SDimitry Andric if (RightAlign) { 554349cc55cSDimitry Andric Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, 555349cc55cSDimitry Andric QualifierToken); 55681ad6265SDimitry Andric } else { 557349cc55cSDimitry Andric Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, 558349cc55cSDimitry Andric QualifierToken); 559349cc55cSDimitry Andric } 560349cc55cSDimitry Andric } 56181ad6265SDimitry Andric } 562349cc55cSDimitry Andric return {Fixes, 0}; 563349cc55cSDimitry Andric } 564349cc55cSDimitry Andric 565*06c3fb27SDimitry Andric void prepareLeftRightOrderingForQualifierAlignmentFixer( 566349cc55cSDimitry Andric const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder, 567349cc55cSDimitry Andric std::vector<std::string> &RightOrder, 568349cc55cSDimitry Andric std::vector<tok::TokenKind> &Qualifiers) { 569349cc55cSDimitry Andric 570349cc55cSDimitry Andric // Depending on the position of type in the order you need 571349cc55cSDimitry Andric // To iterate forward or backward through the order list as qualifier 572349cc55cSDimitry Andric // can push through each other. 573349cc55cSDimitry Andric // The Order list must define the position of "type" to signify 574349cc55cSDimitry Andric assert(llvm::is_contained(Order, "type") && 575349cc55cSDimitry Andric "QualifierOrder must contain type"); 576349cc55cSDimitry Andric // Split the Order list by type and reverse the left side. 577349cc55cSDimitry Andric 578349cc55cSDimitry Andric bool left = true; 579349cc55cSDimitry Andric for (const auto &s : Order) { 580349cc55cSDimitry Andric if (s == "type") { 581349cc55cSDimitry Andric left = false; 582349cc55cSDimitry Andric continue; 583349cc55cSDimitry Andric } 584349cc55cSDimitry Andric 585349cc55cSDimitry Andric tok::TokenKind QualifierToken = 586349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); 58781ad6265SDimitry Andric if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) 588349cc55cSDimitry Andric Qualifiers.push_back(QualifierToken); 589349cc55cSDimitry Andric 59081ad6265SDimitry Andric if (left) { 591349cc55cSDimitry Andric // Reverse the order for left aligned items. 592349cc55cSDimitry Andric LeftOrder.insert(LeftOrder.begin(), s); 59381ad6265SDimitry Andric } else { 594349cc55cSDimitry Andric RightOrder.push_back(s); 595349cc55cSDimitry Andric } 596349cc55cSDimitry Andric } 59781ad6265SDimitry Andric } 598349cc55cSDimitry Andric 599349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isQualifierOrType( 600*06c3fb27SDimitry Andric const FormatToken *const Tok) { 601349cc55cSDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 602*06c3fb27SDimitry Andric isQualifier(Tok)); 603*06c3fb27SDimitry Andric } 604*06c3fb27SDimitry Andric 605*06c3fb27SDimitry Andric bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( 606*06c3fb27SDimitry Andric const FormatToken *const Tok, 607*06c3fb27SDimitry Andric const std::vector<tok::TokenKind> &Qualifiers) { 608*06c3fb27SDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 609*06c3fb27SDimitry Andric isConfiguredQualifier(Tok, Qualifiers)); 610349cc55cSDimitry Andric } 611349cc55cSDimitry Andric 612349cc55cSDimitry Andric // If a token is an identifier and it's upper case, it could 613349cc55cSDimitry Andric // be a macro and hence we need to be able to ignore it. 614349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { 615349cc55cSDimitry Andric if (!Tok) 616349cc55cSDimitry Andric return false; 617349cc55cSDimitry Andric if (!Tok->is(tok::identifier)) 618349cc55cSDimitry Andric return false; 61981ad6265SDimitry Andric if (Tok->TokenText.upper() == Tok->TokenText.str()) { 62081ad6265SDimitry Andric // T,K,U,V likely could be template arguments 621*06c3fb27SDimitry Andric return Tok->TokenText.size() != 1; 62281ad6265SDimitry Andric } 623349cc55cSDimitry Andric return false; 624349cc55cSDimitry Andric } 625349cc55cSDimitry Andric 626349cc55cSDimitry Andric } // namespace format 627349cc55cSDimitry Andric } // namespace clang 628