1*349cc55cSDimitry Andric //===--- LeftRightQualifierAlignmentFixer.cpp -------------------*- C++--*-===// 2*349cc55cSDimitry Andric // 3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*349cc55cSDimitry Andric // 7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8*349cc55cSDimitry Andric /// 9*349cc55cSDimitry Andric /// \file 10*349cc55cSDimitry Andric /// This file implements LeftRightQualifierAlignmentFixer, a TokenAnalyzer that 11*349cc55cSDimitry Andric /// enforces either left or right const depending on the style. 12*349cc55cSDimitry Andric /// 13*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 14*349cc55cSDimitry Andric 15*349cc55cSDimitry Andric #include "QualifierAlignmentFixer.h" 16*349cc55cSDimitry Andric #include "FormatToken.h" 17*349cc55cSDimitry Andric #include "llvm/Support/Debug.h" 18*349cc55cSDimitry Andric #include "llvm/Support/Regex.h" 19*349cc55cSDimitry Andric 20*349cc55cSDimitry Andric #include <algorithm> 21*349cc55cSDimitry Andric 22*349cc55cSDimitry Andric #define DEBUG_TYPE "format-qualifier-alignment-fixer" 23*349cc55cSDimitry Andric 24*349cc55cSDimitry Andric namespace clang { 25*349cc55cSDimitry Andric namespace format { 26*349cc55cSDimitry Andric 27*349cc55cSDimitry Andric QualifierAlignmentFixer::QualifierAlignmentFixer( 28*349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, StringRef &Code, 29*349cc55cSDimitry Andric ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn, 30*349cc55cSDimitry Andric unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName) 31*349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Code(Code), Ranges(Ranges), 32*349cc55cSDimitry Andric FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn), 33*349cc55cSDimitry Andric LastStartColumn(LastStartColumn), FileName(FileName) { 34*349cc55cSDimitry Andric std::vector<std::string> LeftOrder; 35*349cc55cSDimitry Andric std::vector<std::string> RightOrder; 36*349cc55cSDimitry Andric std::vector<tok::TokenKind> ConfiguredQualifierTokens; 37*349cc55cSDimitry Andric PrepareLeftRightOrdering(Style.QualifierOrder, LeftOrder, RightOrder, 38*349cc55cSDimitry Andric ConfiguredQualifierTokens); 39*349cc55cSDimitry Andric 40*349cc55cSDimitry Andric // Handle the left and right Alignment Seperately 41*349cc55cSDimitry Andric for (const auto &Qualifier : LeftOrder) { 42*349cc55cSDimitry Andric Passes.emplace_back( 43*349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 44*349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 45*349cc55cSDimitry Andric ConfiguredQualifierTokens, 46*349cc55cSDimitry Andric /*RightAlign=*/false) 47*349cc55cSDimitry Andric .process(); 48*349cc55cSDimitry Andric }); 49*349cc55cSDimitry Andric } 50*349cc55cSDimitry Andric for (const auto &Qualifier : RightOrder) { 51*349cc55cSDimitry Andric Passes.emplace_back( 52*349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 53*349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 54*349cc55cSDimitry Andric ConfiguredQualifierTokens, 55*349cc55cSDimitry Andric /*RightAlign=*/true) 56*349cc55cSDimitry Andric .process(); 57*349cc55cSDimitry Andric }); 58*349cc55cSDimitry Andric } 59*349cc55cSDimitry Andric } 60*349cc55cSDimitry Andric 61*349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze( 62*349cc55cSDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 63*349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 64*349cc55cSDimitry Andric auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, 65*349cc55cSDimitry Andric NextStartColumn, LastStartColumn); 66*349cc55cSDimitry Andric if (!Env) 67*349cc55cSDimitry Andric return {}; 68*349cc55cSDimitry Andric llvm::Optional<std::string> CurrentCode = None; 69*349cc55cSDimitry Andric tooling::Replacements Fixes; 70*349cc55cSDimitry Andric for (size_t I = 0, E = Passes.size(); I < E; ++I) { 71*349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env); 72*349cc55cSDimitry Andric auto NewCode = applyAllReplacements( 73*349cc55cSDimitry Andric CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first); 74*349cc55cSDimitry Andric if (NewCode) { 75*349cc55cSDimitry Andric Fixes = Fixes.merge(PassFixes.first); 76*349cc55cSDimitry Andric if (I + 1 < E) { 77*349cc55cSDimitry Andric CurrentCode = std::move(*NewCode); 78*349cc55cSDimitry Andric Env = Environment::make( 79*349cc55cSDimitry Andric *CurrentCode, FileName, 80*349cc55cSDimitry Andric tooling::calculateRangesAfterReplacements(Fixes, Ranges), 81*349cc55cSDimitry Andric FirstStartColumn, NextStartColumn, LastStartColumn); 82*349cc55cSDimitry Andric if (!Env) 83*349cc55cSDimitry Andric return {}; 84*349cc55cSDimitry Andric } 85*349cc55cSDimitry Andric } 86*349cc55cSDimitry Andric } 87*349cc55cSDimitry Andric 88*349cc55cSDimitry Andric // Don't make replacements that replace nothing. 89*349cc55cSDimitry Andric tooling::Replacements NonNoOpFixes; 90*349cc55cSDimitry Andric 91*349cc55cSDimitry Andric for (auto I = Fixes.begin(), E = Fixes.end(); I != E; ++I) { 92*349cc55cSDimitry Andric StringRef OriginalCode = Code.substr(I->getOffset(), I->getLength()); 93*349cc55cSDimitry Andric 94*349cc55cSDimitry Andric if (!OriginalCode.equals(I->getReplacementText())) { 95*349cc55cSDimitry Andric auto Err = NonNoOpFixes.add(*I); 96*349cc55cSDimitry Andric if (Err) 97*349cc55cSDimitry Andric llvm::errs() << "Error adding replacements : " 98*349cc55cSDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 99*349cc55cSDimitry Andric } 100*349cc55cSDimitry Andric } 101*349cc55cSDimitry Andric return {NonNoOpFixes, 0}; 102*349cc55cSDimitry Andric } 103*349cc55cSDimitry Andric 104*349cc55cSDimitry Andric static void replaceToken(const SourceManager &SourceMgr, 105*349cc55cSDimitry Andric tooling::Replacements &Fixes, 106*349cc55cSDimitry Andric const CharSourceRange &Range, std::string NewText) { 107*349cc55cSDimitry Andric auto Replacement = tooling::Replacement(SourceMgr, Range, NewText); 108*349cc55cSDimitry Andric auto Err = Fixes.add(Replacement); 109*349cc55cSDimitry Andric 110*349cc55cSDimitry Andric if (Err) 111*349cc55cSDimitry Andric llvm::errs() << "Error while rearranging Qualifier : " 112*349cc55cSDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 113*349cc55cSDimitry Andric } 114*349cc55cSDimitry Andric 115*349cc55cSDimitry Andric static void removeToken(const SourceManager &SourceMgr, 116*349cc55cSDimitry Andric tooling::Replacements &Fixes, 117*349cc55cSDimitry Andric const FormatToken *First) { 118*349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 119*349cc55cSDimitry Andric First->Tok.getEndLoc()); 120*349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, ""); 121*349cc55cSDimitry Andric } 122*349cc55cSDimitry Andric 123*349cc55cSDimitry Andric static void insertQualifierAfter(const SourceManager &SourceMgr, 124*349cc55cSDimitry Andric tooling::Replacements &Fixes, 125*349cc55cSDimitry Andric const FormatToken *First, 126*349cc55cSDimitry Andric const std::string &Qualifier) { 127*349cc55cSDimitry Andric FormatToken *Next = First->Next; 128*349cc55cSDimitry Andric if (!Next) 129*349cc55cSDimitry Andric return; 130*349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(Next->getStartOfNonWhitespace(), 131*349cc55cSDimitry Andric Next->Tok.getEndLoc()); 132*349cc55cSDimitry Andric 133*349cc55cSDimitry Andric std::string NewText = " " + Qualifier + " "; 134*349cc55cSDimitry Andric NewText += Next->TokenText; 135*349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 136*349cc55cSDimitry Andric } 137*349cc55cSDimitry Andric 138*349cc55cSDimitry Andric static void insertQualifierBefore(const SourceManager &SourceMgr, 139*349cc55cSDimitry Andric tooling::Replacements &Fixes, 140*349cc55cSDimitry Andric const FormatToken *First, 141*349cc55cSDimitry Andric const std::string &Qualifier) { 142*349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 143*349cc55cSDimitry Andric First->Tok.getEndLoc()); 144*349cc55cSDimitry Andric 145*349cc55cSDimitry Andric std::string NewText = " " + Qualifier + " "; 146*349cc55cSDimitry Andric NewText += First->TokenText; 147*349cc55cSDimitry Andric 148*349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 149*349cc55cSDimitry Andric } 150*349cc55cSDimitry Andric 151*349cc55cSDimitry Andric static bool endsWithSpace(const std::string &s) { 152*349cc55cSDimitry Andric if (s.empty()) { 153*349cc55cSDimitry Andric return false; 154*349cc55cSDimitry Andric } 155*349cc55cSDimitry Andric return isspace(s.back()); 156*349cc55cSDimitry Andric } 157*349cc55cSDimitry Andric 158*349cc55cSDimitry Andric static bool startsWithSpace(const std::string &s) { 159*349cc55cSDimitry Andric if (s.empty()) { 160*349cc55cSDimitry Andric return false; 161*349cc55cSDimitry Andric } 162*349cc55cSDimitry Andric return isspace(s.front()); 163*349cc55cSDimitry Andric } 164*349cc55cSDimitry Andric 165*349cc55cSDimitry Andric static void rotateTokens(const SourceManager &SourceMgr, 166*349cc55cSDimitry Andric tooling::Replacements &Fixes, const FormatToken *First, 167*349cc55cSDimitry Andric const FormatToken *Last, bool Left) { 168*349cc55cSDimitry Andric auto *End = Last; 169*349cc55cSDimitry Andric auto *Begin = First; 170*349cc55cSDimitry Andric if (!Left) { 171*349cc55cSDimitry Andric End = Last->Next; 172*349cc55cSDimitry Andric Begin = First->Next; 173*349cc55cSDimitry Andric } 174*349cc55cSDimitry Andric 175*349cc55cSDimitry Andric std::string NewText; 176*349cc55cSDimitry Andric // If we are rotating to the left we move the Last token to the front. 177*349cc55cSDimitry Andric if (Left) { 178*349cc55cSDimitry Andric NewText += Last->TokenText; 179*349cc55cSDimitry Andric NewText += " "; 180*349cc55cSDimitry Andric } 181*349cc55cSDimitry Andric 182*349cc55cSDimitry Andric // Then move through the other tokens. 183*349cc55cSDimitry Andric auto *Tok = Begin; 184*349cc55cSDimitry Andric while (Tok != End) { 185*349cc55cSDimitry Andric if (!NewText.empty() && !endsWithSpace(NewText)) { 186*349cc55cSDimitry Andric NewText += " "; 187*349cc55cSDimitry Andric } 188*349cc55cSDimitry Andric 189*349cc55cSDimitry Andric NewText += Tok->TokenText; 190*349cc55cSDimitry Andric Tok = Tok->Next; 191*349cc55cSDimitry Andric } 192*349cc55cSDimitry Andric 193*349cc55cSDimitry Andric // If we are rotating to the right we move the first token to the back. 194*349cc55cSDimitry Andric if (!Left) { 195*349cc55cSDimitry Andric if (!NewText.empty() && !startsWithSpace(NewText)) { 196*349cc55cSDimitry Andric NewText += " "; 197*349cc55cSDimitry Andric } 198*349cc55cSDimitry Andric NewText += First->TokenText; 199*349cc55cSDimitry Andric } 200*349cc55cSDimitry Andric 201*349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 202*349cc55cSDimitry Andric Last->Tok.getEndLoc()); 203*349cc55cSDimitry Andric 204*349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 205*349cc55cSDimitry Andric } 206*349cc55cSDimitry Andric 207*349cc55cSDimitry Andric FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( 208*349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 209*349cc55cSDimitry Andric tooling::Replacements &Fixes, FormatToken *Tok, 210*349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 211*349cc55cSDimitry Andric // We only need to think about streams that begin with a qualifier. 212*349cc55cSDimitry Andric if (!Tok->is(QualifierType)) 213*349cc55cSDimitry Andric return Tok; 214*349cc55cSDimitry Andric // Don't concern yourself if nothing follows the qualifier. 215*349cc55cSDimitry Andric if (!Tok->Next) 216*349cc55cSDimitry Andric return Tok; 217*349cc55cSDimitry Andric if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next)) 218*349cc55cSDimitry Andric return Tok; 219*349cc55cSDimitry Andric 220*349cc55cSDimitry Andric FormatToken *Qual = Tok->Next; 221*349cc55cSDimitry Andric FormatToken *LastQual = Qual; 222*349cc55cSDimitry Andric while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { 223*349cc55cSDimitry Andric LastQual = Qual; 224*349cc55cSDimitry Andric Qual = Qual->Next; 225*349cc55cSDimitry Andric } 226*349cc55cSDimitry Andric if (LastQual && Qual != LastQual) { 227*349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 228*349cc55cSDimitry Andric Tok = LastQual; 229*349cc55cSDimitry Andric } else if (Tok->startsSequence(QualifierType, tok::identifier, 230*349cc55cSDimitry Andric TT_TemplateOpener)) { 231*349cc55cSDimitry Andric // Read from the TemplateOpener to 232*349cc55cSDimitry Andric // TemplateCloser as in const ArrayRef<int> a; const ArrayRef<int> &a; 233*349cc55cSDimitry Andric FormatToken *EndTemplate = Tok->Next->Next->MatchingParen; 234*349cc55cSDimitry Andric if (EndTemplate) { 235*349cc55cSDimitry Andric // Move to the end of any template class members e.g. 236*349cc55cSDimitry Andric // `Foo<int>::iterator`. 237*349cc55cSDimitry Andric if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon, 238*349cc55cSDimitry Andric tok::identifier)) 239*349cc55cSDimitry Andric EndTemplate = EndTemplate->Next->Next; 240*349cc55cSDimitry Andric } 241*349cc55cSDimitry Andric if (EndTemplate && EndTemplate->Next && 242*349cc55cSDimitry Andric !EndTemplate->Next->isOneOf(tok::equal, tok::l_paren)) { 243*349cc55cSDimitry Andric insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier); 244*349cc55cSDimitry Andric // Remove the qualifier. 245*349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Tok); 246*349cc55cSDimitry Andric return Tok; 247*349cc55cSDimitry Andric } 248*349cc55cSDimitry Andric } else if (Tok->startsSequence(QualifierType, tok::identifier)) { 249*349cc55cSDimitry Andric FormatToken *Next = Tok->Next; 250*349cc55cSDimitry Andric // The case `const Foo` -> `Foo const` 251*349cc55cSDimitry Andric // The case `const Foo *` -> `Foo const *` 252*349cc55cSDimitry Andric // The case `const Foo &` -> `Foo const &` 253*349cc55cSDimitry Andric // The case `const Foo &&` -> `Foo const &&` 254*349cc55cSDimitry Andric // The case `const std::Foo &&` -> `std::Foo const &&` 255*349cc55cSDimitry Andric // The case `const std::Foo<T> &&` -> `std::Foo<T> const &&` 256*349cc55cSDimitry Andric while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) { 257*349cc55cSDimitry Andric Next = Next->Next; 258*349cc55cSDimitry Andric } 259*349cc55cSDimitry Andric if (Next && Next->is(TT_TemplateOpener)) { 260*349cc55cSDimitry Andric Next = Next->MatchingParen; 261*349cc55cSDimitry Andric // Move to the end of any template class members e.g. 262*349cc55cSDimitry Andric // `Foo<int>::iterator`. 263*349cc55cSDimitry Andric if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon, 264*349cc55cSDimitry Andric tok::identifier)) { 265*349cc55cSDimitry Andric Next = Next->Next->Next; 266*349cc55cSDimitry Andric return Tok; 267*349cc55cSDimitry Andric } 268*349cc55cSDimitry Andric assert(Next && "Missing template opener"); 269*349cc55cSDimitry Andric Next = Next->Next; 270*349cc55cSDimitry Andric } 271*349cc55cSDimitry Andric if (Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) && 272*349cc55cSDimitry Andric !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) { 273*349cc55cSDimitry Andric if (Next->Previous && !Next->Previous->is(QualifierType)) { 274*349cc55cSDimitry Andric insertQualifierAfter(SourceMgr, Fixes, Next->Previous, Qualifier); 275*349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Tok); 276*349cc55cSDimitry Andric } 277*349cc55cSDimitry Andric return Next; 278*349cc55cSDimitry Andric } 279*349cc55cSDimitry Andric } 280*349cc55cSDimitry Andric 281*349cc55cSDimitry Andric return Tok; 282*349cc55cSDimitry Andric } 283*349cc55cSDimitry Andric 284*349cc55cSDimitry Andric FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 285*349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 286*349cc55cSDimitry Andric tooling::Replacements &Fixes, FormatToken *Tok, 287*349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 288*349cc55cSDimitry Andric // if Tok is an identifier and possibly a macro then don't convert. 289*349cc55cSDimitry Andric if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok)) 290*349cc55cSDimitry Andric return Tok; 291*349cc55cSDimitry Andric 292*349cc55cSDimitry Andric FormatToken *Qual = Tok; 293*349cc55cSDimitry Andric FormatToken *LastQual = Qual; 294*349cc55cSDimitry Andric while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { 295*349cc55cSDimitry Andric LastQual = Qual; 296*349cc55cSDimitry Andric Qual = Qual->Next; 297*349cc55cSDimitry Andric if (Qual && Qual->is(QualifierType)) 298*349cc55cSDimitry Andric break; 299*349cc55cSDimitry Andric } 300*349cc55cSDimitry Andric 301*349cc55cSDimitry Andric if (!Qual) { 302*349cc55cSDimitry Andric return Tok; 303*349cc55cSDimitry Andric } 304*349cc55cSDimitry Andric 305*349cc55cSDimitry Andric if (LastQual && Qual != LastQual && Qual->is(QualifierType)) { 306*349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, Qual, /*Left=*/true); 307*349cc55cSDimitry Andric Tok = Qual->Next; 308*349cc55cSDimitry Andric } else if (Tok->startsSequence(tok::identifier, QualifierType)) { 309*349cc55cSDimitry Andric if (Tok->Next->Next && Tok->Next->Next->isOneOf(tok::identifier, tok::star, 310*349cc55cSDimitry Andric tok::amp, tok::ampamp)) { 311*349cc55cSDimitry Andric // Don't swap `::iterator const` to `::const iterator`. 312*349cc55cSDimitry Andric if (!Tok->Previous || 313*349cc55cSDimitry Andric (Tok->Previous && !Tok->Previous->is(tok::coloncolon))) { 314*349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true); 315*349cc55cSDimitry Andric Tok = Tok->Next; 316*349cc55cSDimitry Andric } 317*349cc55cSDimitry Andric } 318*349cc55cSDimitry Andric } 319*349cc55cSDimitry Andric if (Tok->is(TT_TemplateOpener) && Tok->Next && 320*349cc55cSDimitry Andric (Tok->Next->is(tok::identifier) || Tok->Next->isSimpleTypeSpecifier()) && 321*349cc55cSDimitry Andric Tok->Next->Next && Tok->Next->Next->is(QualifierType)) { 322*349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok->Next, Tok->Next->Next, /*Left=*/true); 323*349cc55cSDimitry Andric } 324*349cc55cSDimitry Andric if (Tok->startsSequence(tok::identifier) && Tok->Next) { 325*349cc55cSDimitry Andric if (Tok->Previous && 326*349cc55cSDimitry Andric Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { 327*349cc55cSDimitry Andric return Tok; 328*349cc55cSDimitry Andric } 329*349cc55cSDimitry Andric FormatToken *Next = Tok->Next; 330*349cc55cSDimitry Andric // The case `std::Foo<T> const` -> `const std::Foo<T> &&` 331*349cc55cSDimitry Andric while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) 332*349cc55cSDimitry Andric Next = Next->Next; 333*349cc55cSDimitry Andric if (Next && Next->Previous && 334*349cc55cSDimitry Andric Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) { 335*349cc55cSDimitry Andric // Read from to the end of the TemplateOpener to 336*349cc55cSDimitry Andric // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a; 337*349cc55cSDimitry Andric assert(Next->MatchingParen && "Missing template closer"); 338*349cc55cSDimitry Andric Next = Next->MatchingParen->Next; 339*349cc55cSDimitry Andric 340*349cc55cSDimitry Andric // Move to the end of any template class members e.g. 341*349cc55cSDimitry Andric // `Foo<int>::iterator`. 342*349cc55cSDimitry Andric if (Next && Next->startsSequence(tok::coloncolon, tok::identifier)) 343*349cc55cSDimitry Andric Next = Next->Next->Next; 344*349cc55cSDimitry Andric if (Next && Next->is(QualifierType)) { 345*349cc55cSDimitry Andric // Remove the const. 346*349cc55cSDimitry Andric insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); 347*349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Next); 348*349cc55cSDimitry Andric return Next; 349*349cc55cSDimitry Andric } 350*349cc55cSDimitry Andric } 351*349cc55cSDimitry Andric if (Next && Next->Next && 352*349cc55cSDimitry Andric Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) { 353*349cc55cSDimitry Andric if (Next->is(QualifierType)) { 354*349cc55cSDimitry Andric // Remove the qualifier. 355*349cc55cSDimitry Andric insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); 356*349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Next); 357*349cc55cSDimitry Andric return Next; 358*349cc55cSDimitry Andric } 359*349cc55cSDimitry Andric } 360*349cc55cSDimitry Andric } 361*349cc55cSDimitry Andric return Tok; 362*349cc55cSDimitry Andric } 363*349cc55cSDimitry Andric 364*349cc55cSDimitry Andric tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( 365*349cc55cSDimitry Andric const std::string &Qualifier) { 366*349cc55cSDimitry Andric // Don't let 'type' be an identifier, but steal typeof token. 367*349cc55cSDimitry Andric return llvm::StringSwitch<tok::TokenKind>(Qualifier) 368*349cc55cSDimitry Andric .Case("type", tok::kw_typeof) 369*349cc55cSDimitry Andric .Case("const", tok::kw_const) 370*349cc55cSDimitry Andric .Case("volatile", tok::kw_volatile) 371*349cc55cSDimitry Andric .Case("static", tok::kw_static) 372*349cc55cSDimitry Andric .Case("inline", tok::kw_inline) 373*349cc55cSDimitry Andric .Case("constexpr", tok::kw_constexpr) 374*349cc55cSDimitry Andric .Case("restrict", tok::kw_restrict) 375*349cc55cSDimitry Andric .Default(tok::identifier); 376*349cc55cSDimitry Andric } 377*349cc55cSDimitry Andric 378*349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( 379*349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, 380*349cc55cSDimitry Andric const std::string &Qualifier, 381*349cc55cSDimitry Andric const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign) 382*349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), 383*349cc55cSDimitry Andric ConfiguredQualifierTokens(QualifierTokens) {} 384*349cc55cSDimitry Andric 385*349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> 386*349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::analyze( 387*349cc55cSDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 388*349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 389*349cc55cSDimitry Andric tooling::Replacements Fixes; 390*349cc55cSDimitry Andric const AdditionalKeywords &Keywords = Tokens.getKeywords(); 391*349cc55cSDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager(); 392*349cc55cSDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 393*349cc55cSDimitry Andric 394*349cc55cSDimitry Andric tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); 395*349cc55cSDimitry Andric assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); 396*349cc55cSDimitry Andric 397*349cc55cSDimitry Andric for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { 398*349cc55cSDimitry Andric FormatToken *First = AnnotatedLines[I]->First; 399*349cc55cSDimitry Andric const auto *Last = AnnotatedLines[I]->Last; 400*349cc55cSDimitry Andric 401*349cc55cSDimitry Andric for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) { 402*349cc55cSDimitry Andric if (Tok->is(tok::comment)) 403*349cc55cSDimitry Andric continue; 404*349cc55cSDimitry Andric if (RightAlign) 405*349cc55cSDimitry Andric Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, 406*349cc55cSDimitry Andric QualifierToken); 407*349cc55cSDimitry Andric else 408*349cc55cSDimitry Andric Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, 409*349cc55cSDimitry Andric QualifierToken); 410*349cc55cSDimitry Andric } 411*349cc55cSDimitry Andric } 412*349cc55cSDimitry Andric return {Fixes, 0}; 413*349cc55cSDimitry Andric } 414*349cc55cSDimitry Andric 415*349cc55cSDimitry Andric void QualifierAlignmentFixer::PrepareLeftRightOrdering( 416*349cc55cSDimitry Andric const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder, 417*349cc55cSDimitry Andric std::vector<std::string> &RightOrder, 418*349cc55cSDimitry Andric std::vector<tok::TokenKind> &Qualifiers) { 419*349cc55cSDimitry Andric 420*349cc55cSDimitry Andric // Depending on the position of type in the order you need 421*349cc55cSDimitry Andric // To iterate forward or backward through the order list as qualifier 422*349cc55cSDimitry Andric // can push through each other. 423*349cc55cSDimitry Andric // The Order list must define the position of "type" to signify 424*349cc55cSDimitry Andric assert(llvm::is_contained(Order, "type") && 425*349cc55cSDimitry Andric "QualifierOrder must contain type"); 426*349cc55cSDimitry Andric // Split the Order list by type and reverse the left side. 427*349cc55cSDimitry Andric 428*349cc55cSDimitry Andric bool left = true; 429*349cc55cSDimitry Andric for (const auto &s : Order) { 430*349cc55cSDimitry Andric if (s == "type") { 431*349cc55cSDimitry Andric left = false; 432*349cc55cSDimitry Andric continue; 433*349cc55cSDimitry Andric } 434*349cc55cSDimitry Andric 435*349cc55cSDimitry Andric tok::TokenKind QualifierToken = 436*349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); 437*349cc55cSDimitry Andric if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) { 438*349cc55cSDimitry Andric Qualifiers.push_back(QualifierToken); 439*349cc55cSDimitry Andric } 440*349cc55cSDimitry Andric 441*349cc55cSDimitry Andric if (left) 442*349cc55cSDimitry Andric // Reverse the order for left aligned items. 443*349cc55cSDimitry Andric LeftOrder.insert(LeftOrder.begin(), s); 444*349cc55cSDimitry Andric else 445*349cc55cSDimitry Andric RightOrder.push_back(s); 446*349cc55cSDimitry Andric } 447*349cc55cSDimitry Andric } 448*349cc55cSDimitry Andric 449*349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isQualifierOrType( 450*349cc55cSDimitry Andric const FormatToken *Tok, const std::vector<tok::TokenKind> &specifiedTypes) { 451*349cc55cSDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 452*349cc55cSDimitry Andric llvm::is_contained(specifiedTypes, Tok->Tok.getKind())); 453*349cc55cSDimitry Andric } 454*349cc55cSDimitry Andric 455*349cc55cSDimitry Andric // If a token is an identifier and it's upper case, it could 456*349cc55cSDimitry Andric // be a macro and hence we need to be able to ignore it. 457*349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { 458*349cc55cSDimitry Andric if (!Tok) 459*349cc55cSDimitry Andric return false; 460*349cc55cSDimitry Andric if (!Tok->is(tok::identifier)) 461*349cc55cSDimitry Andric return false; 462*349cc55cSDimitry Andric if (Tok->TokenText.upper() == Tok->TokenText.str()) 463*349cc55cSDimitry Andric return true; 464*349cc55cSDimitry Andric return false; 465*349cc55cSDimitry Andric } 466*349cc55cSDimitry Andric 467*349cc55cSDimitry Andric } // namespace format 468*349cc55cSDimitry Andric } // namespace clang 469