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> 21349cc55cSDimitry Andric 22349cc55cSDimitry Andric #define DEBUG_TYPE "format-qualifier-alignment-fixer" 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric namespace clang { 25349cc55cSDimitry Andric namespace format { 26349cc55cSDimitry Andric 27349cc55cSDimitry Andric QualifierAlignmentFixer::QualifierAlignmentFixer( 28349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, StringRef &Code, 29349cc55cSDimitry Andric ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn, 30349cc55cSDimitry Andric unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName) 31349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Code(Code), Ranges(Ranges), 32349cc55cSDimitry Andric FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn), 33349cc55cSDimitry Andric LastStartColumn(LastStartColumn), FileName(FileName) { 34349cc55cSDimitry Andric std::vector<std::string> LeftOrder; 35349cc55cSDimitry Andric std::vector<std::string> RightOrder; 36349cc55cSDimitry Andric std::vector<tok::TokenKind> ConfiguredQualifierTokens; 37349cc55cSDimitry Andric PrepareLeftRightOrdering(Style.QualifierOrder, LeftOrder, RightOrder, 38349cc55cSDimitry Andric ConfiguredQualifierTokens); 39349cc55cSDimitry Andric 40349cc55cSDimitry Andric // Handle the left and right Alignment Seperately 41349cc55cSDimitry Andric for (const auto &Qualifier : LeftOrder) { 42349cc55cSDimitry Andric Passes.emplace_back( 43349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 44349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 45349cc55cSDimitry Andric ConfiguredQualifierTokens, 46349cc55cSDimitry Andric /*RightAlign=*/false) 47349cc55cSDimitry Andric .process(); 48349cc55cSDimitry Andric }); 49349cc55cSDimitry Andric } 50349cc55cSDimitry Andric for (const auto &Qualifier : RightOrder) { 51349cc55cSDimitry Andric Passes.emplace_back( 52349cc55cSDimitry Andric [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { 53349cc55cSDimitry Andric return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, 54349cc55cSDimitry Andric ConfiguredQualifierTokens, 55349cc55cSDimitry Andric /*RightAlign=*/true) 56349cc55cSDimitry Andric .process(); 57349cc55cSDimitry Andric }); 58349cc55cSDimitry Andric } 59349cc55cSDimitry Andric } 60349cc55cSDimitry Andric 61349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze( 62349cc55cSDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 63349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 64349cc55cSDimitry Andric auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, 65349cc55cSDimitry Andric NextStartColumn, LastStartColumn); 66349cc55cSDimitry Andric if (!Env) 67349cc55cSDimitry Andric return {}; 68349cc55cSDimitry Andric llvm::Optional<std::string> CurrentCode = None; 69349cc55cSDimitry Andric tooling::Replacements Fixes; 70349cc55cSDimitry Andric for (size_t I = 0, E = Passes.size(); I < E; ++I) { 71349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env); 72349cc55cSDimitry Andric auto NewCode = applyAllReplacements( 73349cc55cSDimitry Andric CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first); 74349cc55cSDimitry Andric if (NewCode) { 75349cc55cSDimitry Andric Fixes = Fixes.merge(PassFixes.first); 76349cc55cSDimitry Andric if (I + 1 < E) { 77349cc55cSDimitry Andric CurrentCode = std::move(*NewCode); 78349cc55cSDimitry Andric Env = Environment::make( 79349cc55cSDimitry Andric *CurrentCode, FileName, 80349cc55cSDimitry Andric tooling::calculateRangesAfterReplacements(Fixes, Ranges), 81349cc55cSDimitry Andric FirstStartColumn, NextStartColumn, LastStartColumn); 82349cc55cSDimitry Andric if (!Env) 83349cc55cSDimitry Andric return {}; 84349cc55cSDimitry Andric } 85349cc55cSDimitry Andric } 86349cc55cSDimitry Andric } 87349cc55cSDimitry Andric 88349cc55cSDimitry Andric // Don't make replacements that replace nothing. 89349cc55cSDimitry Andric tooling::Replacements NonNoOpFixes; 90349cc55cSDimitry Andric 9104eeddc0SDimitry Andric for (const tooling::Replacement &Fix : Fixes) { 9204eeddc0SDimitry Andric StringRef OriginalCode = Code.substr(Fix.getOffset(), Fix.getLength()); 93349cc55cSDimitry Andric 9404eeddc0SDimitry Andric if (!OriginalCode.equals(Fix.getReplacementText())) { 9504eeddc0SDimitry Andric auto Err = NonNoOpFixes.add(Fix); 96349cc55cSDimitry Andric if (Err) 97349cc55cSDimitry Andric llvm::errs() << "Error adding replacements : " 98349cc55cSDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 99349cc55cSDimitry Andric } 100349cc55cSDimitry Andric } 101349cc55cSDimitry Andric return {NonNoOpFixes, 0}; 102349cc55cSDimitry Andric } 103349cc55cSDimitry Andric 104349cc55cSDimitry Andric static void replaceToken(const SourceManager &SourceMgr, 105349cc55cSDimitry Andric tooling::Replacements &Fixes, 106349cc55cSDimitry Andric const CharSourceRange &Range, std::string NewText) { 107349cc55cSDimitry Andric auto Replacement = tooling::Replacement(SourceMgr, Range, NewText); 108349cc55cSDimitry Andric auto Err = Fixes.add(Replacement); 109349cc55cSDimitry Andric 110349cc55cSDimitry Andric if (Err) 111349cc55cSDimitry Andric llvm::errs() << "Error while rearranging Qualifier : " 112349cc55cSDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 113349cc55cSDimitry Andric } 114349cc55cSDimitry Andric 115349cc55cSDimitry Andric static void removeToken(const SourceManager &SourceMgr, 116349cc55cSDimitry Andric tooling::Replacements &Fixes, 117349cc55cSDimitry Andric const FormatToken *First) { 118349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 119349cc55cSDimitry Andric First->Tok.getEndLoc()); 120349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, ""); 121349cc55cSDimitry Andric } 122349cc55cSDimitry Andric 123349cc55cSDimitry Andric static void insertQualifierAfter(const SourceManager &SourceMgr, 124349cc55cSDimitry Andric tooling::Replacements &Fixes, 125349cc55cSDimitry Andric const FormatToken *First, 126349cc55cSDimitry Andric const std::string &Qualifier) { 127349cc55cSDimitry Andric FormatToken *Next = First->Next; 128349cc55cSDimitry Andric if (!Next) 129349cc55cSDimitry Andric return; 130349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(Next->getStartOfNonWhitespace(), 131349cc55cSDimitry Andric Next->Tok.getEndLoc()); 132349cc55cSDimitry Andric 133349cc55cSDimitry Andric std::string NewText = " " + Qualifier + " "; 134349cc55cSDimitry Andric NewText += Next->TokenText; 135349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 136349cc55cSDimitry Andric } 137349cc55cSDimitry Andric 138349cc55cSDimitry Andric static void insertQualifierBefore(const SourceManager &SourceMgr, 139349cc55cSDimitry Andric tooling::Replacements &Fixes, 140349cc55cSDimitry Andric const FormatToken *First, 141349cc55cSDimitry Andric const std::string &Qualifier) { 142349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 143349cc55cSDimitry Andric First->Tok.getEndLoc()); 144349cc55cSDimitry Andric 145349cc55cSDimitry Andric std::string NewText = " " + Qualifier + " "; 146349cc55cSDimitry Andric NewText += First->TokenText; 147349cc55cSDimitry Andric 148349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 149349cc55cSDimitry Andric } 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric static bool endsWithSpace(const std::string &s) { 152349cc55cSDimitry Andric if (s.empty()) { 153349cc55cSDimitry Andric return false; 154349cc55cSDimitry Andric } 155349cc55cSDimitry Andric return isspace(s.back()); 156349cc55cSDimitry Andric } 157349cc55cSDimitry Andric 158349cc55cSDimitry Andric static bool startsWithSpace(const std::string &s) { 159349cc55cSDimitry Andric if (s.empty()) { 160349cc55cSDimitry Andric return false; 161349cc55cSDimitry Andric } 162349cc55cSDimitry Andric return isspace(s.front()); 163349cc55cSDimitry Andric } 164349cc55cSDimitry Andric 165349cc55cSDimitry Andric static void rotateTokens(const SourceManager &SourceMgr, 166349cc55cSDimitry Andric tooling::Replacements &Fixes, const FormatToken *First, 167349cc55cSDimitry Andric const FormatToken *Last, bool Left) { 168349cc55cSDimitry Andric auto *End = Last; 169349cc55cSDimitry Andric auto *Begin = First; 170349cc55cSDimitry Andric if (!Left) { 171349cc55cSDimitry Andric End = Last->Next; 172349cc55cSDimitry Andric Begin = First->Next; 173349cc55cSDimitry Andric } 174349cc55cSDimitry Andric 175349cc55cSDimitry Andric std::string NewText; 176349cc55cSDimitry Andric // If we are rotating to the left we move the Last token to the front. 177349cc55cSDimitry Andric if (Left) { 178349cc55cSDimitry Andric NewText += Last->TokenText; 179349cc55cSDimitry Andric NewText += " "; 180349cc55cSDimitry Andric } 181349cc55cSDimitry Andric 182349cc55cSDimitry Andric // Then move through the other tokens. 183349cc55cSDimitry Andric auto *Tok = Begin; 184349cc55cSDimitry Andric while (Tok != End) { 185349cc55cSDimitry Andric if (!NewText.empty() && !endsWithSpace(NewText)) { 186349cc55cSDimitry Andric NewText += " "; 187349cc55cSDimitry Andric } 188349cc55cSDimitry Andric 189349cc55cSDimitry Andric NewText += Tok->TokenText; 190349cc55cSDimitry Andric Tok = Tok->Next; 191349cc55cSDimitry Andric } 192349cc55cSDimitry Andric 193349cc55cSDimitry Andric // If we are rotating to the right we move the first token to the back. 194349cc55cSDimitry Andric if (!Left) { 195349cc55cSDimitry Andric if (!NewText.empty() && !startsWithSpace(NewText)) { 196349cc55cSDimitry Andric NewText += " "; 197349cc55cSDimitry Andric } 198349cc55cSDimitry Andric NewText += First->TokenText; 199349cc55cSDimitry Andric } 200349cc55cSDimitry Andric 201349cc55cSDimitry Andric auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), 202349cc55cSDimitry Andric Last->Tok.getEndLoc()); 203349cc55cSDimitry Andric 204349cc55cSDimitry Andric replaceToken(SourceMgr, Fixes, Range, NewText); 205349cc55cSDimitry Andric } 206349cc55cSDimitry Andric 20704eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( 208349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 20904eeddc0SDimitry Andric tooling::Replacements &Fixes, const FormatToken *Tok, 210349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 211349cc55cSDimitry Andric // We only need to think about streams that begin with a qualifier. 212349cc55cSDimitry Andric if (!Tok->is(QualifierType)) 213349cc55cSDimitry Andric return Tok; 214349cc55cSDimitry Andric // Don't concern yourself if nothing follows the qualifier. 215349cc55cSDimitry Andric if (!Tok->Next) 216349cc55cSDimitry Andric return Tok; 217349cc55cSDimitry Andric if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next)) 218349cc55cSDimitry Andric return Tok; 219349cc55cSDimitry Andric 220349cc55cSDimitry Andric FormatToken *Qual = Tok->Next; 221349cc55cSDimitry Andric FormatToken *LastQual = Qual; 222349cc55cSDimitry Andric while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { 223349cc55cSDimitry Andric LastQual = Qual; 224349cc55cSDimitry Andric Qual = Qual->Next; 225349cc55cSDimitry Andric } 226349cc55cSDimitry Andric if (LastQual && Qual != LastQual) { 227349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); 228349cc55cSDimitry Andric Tok = LastQual; 229349cc55cSDimitry Andric } else if (Tok->startsSequence(QualifierType, tok::identifier, 230349cc55cSDimitry Andric TT_TemplateOpener)) { 231349cc55cSDimitry Andric // Read from the TemplateOpener to 232349cc55cSDimitry Andric // TemplateCloser as in const ArrayRef<int> a; const ArrayRef<int> &a; 233349cc55cSDimitry Andric FormatToken *EndTemplate = Tok->Next->Next->MatchingParen; 234349cc55cSDimitry Andric if (EndTemplate) { 235349cc55cSDimitry Andric // Move to the end of any template class members e.g. 236349cc55cSDimitry Andric // `Foo<int>::iterator`. 237349cc55cSDimitry Andric if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon, 238349cc55cSDimitry Andric tok::identifier)) 239349cc55cSDimitry Andric EndTemplate = EndTemplate->Next->Next; 240349cc55cSDimitry Andric } 241349cc55cSDimitry Andric if (EndTemplate && EndTemplate->Next && 242349cc55cSDimitry Andric !EndTemplate->Next->isOneOf(tok::equal, tok::l_paren)) { 243349cc55cSDimitry Andric insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier); 244349cc55cSDimitry Andric // Remove the qualifier. 245349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Tok); 246349cc55cSDimitry Andric return Tok; 247349cc55cSDimitry Andric } 248349cc55cSDimitry Andric } else if (Tok->startsSequence(QualifierType, tok::identifier)) { 249349cc55cSDimitry Andric FormatToken *Next = Tok->Next; 250349cc55cSDimitry Andric // The case `const Foo` -> `Foo const` 251349cc55cSDimitry Andric // The case `const Foo *` -> `Foo const *` 252349cc55cSDimitry Andric // The case `const Foo &` -> `Foo const &` 253349cc55cSDimitry Andric // The case `const Foo &&` -> `Foo const &&` 254349cc55cSDimitry Andric // The case `const std::Foo &&` -> `std::Foo const &&` 255349cc55cSDimitry Andric // The case `const std::Foo<T> &&` -> `std::Foo<T> const &&` 256349cc55cSDimitry Andric while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) { 257349cc55cSDimitry Andric Next = Next->Next; 258349cc55cSDimitry Andric } 259349cc55cSDimitry Andric if (Next && Next->is(TT_TemplateOpener)) { 260349cc55cSDimitry Andric Next = Next->MatchingParen; 261349cc55cSDimitry Andric // Move to the end of any template class members e.g. 262349cc55cSDimitry Andric // `Foo<int>::iterator`. 263349cc55cSDimitry Andric if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon, 26404eeddc0SDimitry Andric tok::identifier)) 265349cc55cSDimitry Andric return Tok; 266349cc55cSDimitry Andric assert(Next && "Missing template opener"); 267349cc55cSDimitry Andric Next = Next->Next; 268349cc55cSDimitry Andric } 269349cc55cSDimitry Andric if (Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) && 270349cc55cSDimitry Andric !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) { 271349cc55cSDimitry Andric if (Next->Previous && !Next->Previous->is(QualifierType)) { 272349cc55cSDimitry Andric insertQualifierAfter(SourceMgr, Fixes, Next->Previous, Qualifier); 273349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Tok); 274349cc55cSDimitry Andric } 275349cc55cSDimitry Andric return Next; 276349cc55cSDimitry Andric } 277349cc55cSDimitry Andric } 278349cc55cSDimitry Andric 279349cc55cSDimitry Andric return Tok; 280349cc55cSDimitry Andric } 281349cc55cSDimitry Andric 28204eeddc0SDimitry Andric const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 283349cc55cSDimitry Andric const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, 28404eeddc0SDimitry Andric tooling::Replacements &Fixes, const FormatToken *Tok, 285349cc55cSDimitry Andric const std::string &Qualifier, tok::TokenKind QualifierType) { 286349cc55cSDimitry Andric // if Tok is an identifier and possibly a macro then don't convert. 287349cc55cSDimitry Andric if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok)) 288349cc55cSDimitry Andric return Tok; 289349cc55cSDimitry Andric 29004eeddc0SDimitry Andric const FormatToken *Qual = Tok; 29104eeddc0SDimitry Andric const FormatToken *LastQual = Qual; 292349cc55cSDimitry Andric while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { 293349cc55cSDimitry Andric LastQual = Qual; 294349cc55cSDimitry Andric Qual = Qual->Next; 295349cc55cSDimitry Andric if (Qual && Qual->is(QualifierType)) 296349cc55cSDimitry Andric break; 297349cc55cSDimitry Andric } 298349cc55cSDimitry Andric 299349cc55cSDimitry Andric if (!Qual) { 300349cc55cSDimitry Andric return Tok; 301349cc55cSDimitry Andric } 302349cc55cSDimitry Andric 303349cc55cSDimitry Andric if (LastQual && Qual != LastQual && Qual->is(QualifierType)) { 304349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, Qual, /*Left=*/true); 305349cc55cSDimitry Andric Tok = Qual->Next; 306349cc55cSDimitry Andric } else if (Tok->startsSequence(tok::identifier, QualifierType)) { 307349cc55cSDimitry Andric if (Tok->Next->Next && Tok->Next->Next->isOneOf(tok::identifier, tok::star, 308349cc55cSDimitry Andric tok::amp, tok::ampamp)) { 309349cc55cSDimitry Andric // Don't swap `::iterator const` to `::const iterator`. 310349cc55cSDimitry Andric if (!Tok->Previous || 311349cc55cSDimitry Andric (Tok->Previous && !Tok->Previous->is(tok::coloncolon))) { 312349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true); 313349cc55cSDimitry Andric Tok = Tok->Next; 314349cc55cSDimitry Andric } 315349cc55cSDimitry Andric } 316349cc55cSDimitry Andric } 317349cc55cSDimitry Andric if (Tok->is(TT_TemplateOpener) && Tok->Next && 318349cc55cSDimitry Andric (Tok->Next->is(tok::identifier) || Tok->Next->isSimpleTypeSpecifier()) && 319349cc55cSDimitry Andric Tok->Next->Next && Tok->Next->Next->is(QualifierType)) { 320349cc55cSDimitry Andric rotateTokens(SourceMgr, Fixes, Tok->Next, Tok->Next->Next, /*Left=*/true); 321349cc55cSDimitry Andric } 322349cc55cSDimitry Andric if (Tok->startsSequence(tok::identifier) && Tok->Next) { 323349cc55cSDimitry Andric if (Tok->Previous && 324349cc55cSDimitry Andric Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { 325349cc55cSDimitry Andric return Tok; 326349cc55cSDimitry Andric } 32704eeddc0SDimitry Andric const FormatToken *Next = Tok->Next; 328349cc55cSDimitry Andric // The case `std::Foo<T> const` -> `const std::Foo<T> &&` 329349cc55cSDimitry Andric while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) 330349cc55cSDimitry Andric Next = Next->Next; 331349cc55cSDimitry Andric if (Next && Next->Previous && 332349cc55cSDimitry Andric Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) { 333349cc55cSDimitry Andric // Read from to the end of the TemplateOpener to 334349cc55cSDimitry Andric // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a; 33504eeddc0SDimitry Andric if (Next->is(tok::comment) && Next->getNextNonComment()) 33604eeddc0SDimitry Andric Next = Next->getNextNonComment(); 337349cc55cSDimitry Andric assert(Next->MatchingParen && "Missing template closer"); 338349cc55cSDimitry Andric Next = Next->MatchingParen->Next; 339349cc55cSDimitry Andric 340349cc55cSDimitry Andric // Move to the end of any template class members e.g. 341349cc55cSDimitry Andric // `Foo<int>::iterator`. 342349cc55cSDimitry Andric if (Next && Next->startsSequence(tok::coloncolon, tok::identifier)) 343349cc55cSDimitry Andric Next = Next->Next->Next; 344349cc55cSDimitry Andric if (Next && Next->is(QualifierType)) { 345349cc55cSDimitry Andric // Remove the const. 346349cc55cSDimitry Andric insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); 347349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Next); 348349cc55cSDimitry Andric return Next; 349349cc55cSDimitry Andric } 350349cc55cSDimitry Andric } 351349cc55cSDimitry Andric if (Next && Next->Next && 352349cc55cSDimitry Andric Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) { 353349cc55cSDimitry Andric if (Next->is(QualifierType)) { 354349cc55cSDimitry Andric // Remove the qualifier. 355349cc55cSDimitry Andric insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); 356349cc55cSDimitry Andric removeToken(SourceMgr, Fixes, Next); 357349cc55cSDimitry Andric return Next; 358349cc55cSDimitry Andric } 359349cc55cSDimitry Andric } 360349cc55cSDimitry Andric } 361349cc55cSDimitry Andric return Tok; 362349cc55cSDimitry Andric } 363349cc55cSDimitry Andric 364349cc55cSDimitry Andric tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( 365349cc55cSDimitry Andric const std::string &Qualifier) { 366349cc55cSDimitry Andric // Don't let 'type' be an identifier, but steal typeof token. 367349cc55cSDimitry Andric return llvm::StringSwitch<tok::TokenKind>(Qualifier) 368349cc55cSDimitry Andric .Case("type", tok::kw_typeof) 369349cc55cSDimitry Andric .Case("const", tok::kw_const) 370349cc55cSDimitry Andric .Case("volatile", tok::kw_volatile) 371349cc55cSDimitry Andric .Case("static", tok::kw_static) 372349cc55cSDimitry Andric .Case("inline", tok::kw_inline) 373349cc55cSDimitry Andric .Case("constexpr", tok::kw_constexpr) 374349cc55cSDimitry Andric .Case("restrict", tok::kw_restrict) 375349cc55cSDimitry Andric .Default(tok::identifier); 376349cc55cSDimitry Andric } 377349cc55cSDimitry Andric 378349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( 379349cc55cSDimitry Andric const Environment &Env, const FormatStyle &Style, 380349cc55cSDimitry Andric const std::string &Qualifier, 381349cc55cSDimitry Andric const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign) 382349cc55cSDimitry Andric : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), 383349cc55cSDimitry Andric ConfiguredQualifierTokens(QualifierTokens) {} 384349cc55cSDimitry Andric 385349cc55cSDimitry Andric std::pair<tooling::Replacements, unsigned> 386349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::analyze( 387349cc55cSDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 388349cc55cSDimitry Andric FormatTokenLexer &Tokens) { 389349cc55cSDimitry Andric tooling::Replacements Fixes; 390349cc55cSDimitry Andric const AdditionalKeywords &Keywords = Tokens.getKeywords(); 391349cc55cSDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager(); 392349cc55cSDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 393349cc55cSDimitry Andric 394349cc55cSDimitry Andric tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); 395349cc55cSDimitry Andric assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); 396349cc55cSDimitry Andric 39704eeddc0SDimitry Andric for (AnnotatedLine *Line : AnnotatedLines) { 39804eeddc0SDimitry Andric FormatToken *First = Line->First; 399*d56accc7SDimitry Andric assert(First); 400*d56accc7SDimitry Andric if (First->Finalized) 401*d56accc7SDimitry Andric continue; 402*d56accc7SDimitry Andric 40304eeddc0SDimitry Andric const auto *Last = Line->Last; 404349cc55cSDimitry Andric 40504eeddc0SDimitry Andric for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; 40604eeddc0SDimitry Andric Tok = Tok->Next) { 407349cc55cSDimitry Andric if (Tok->is(tok::comment)) 408349cc55cSDimitry Andric continue; 409349cc55cSDimitry Andric if (RightAlign) 410349cc55cSDimitry Andric Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, 411349cc55cSDimitry Andric QualifierToken); 412349cc55cSDimitry Andric else 413349cc55cSDimitry Andric Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, 414349cc55cSDimitry Andric QualifierToken); 415349cc55cSDimitry Andric } 416349cc55cSDimitry Andric } 417349cc55cSDimitry Andric return {Fixes, 0}; 418349cc55cSDimitry Andric } 419349cc55cSDimitry Andric 420349cc55cSDimitry Andric void QualifierAlignmentFixer::PrepareLeftRightOrdering( 421349cc55cSDimitry Andric const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder, 422349cc55cSDimitry Andric std::vector<std::string> &RightOrder, 423349cc55cSDimitry Andric std::vector<tok::TokenKind> &Qualifiers) { 424349cc55cSDimitry Andric 425349cc55cSDimitry Andric // Depending on the position of type in the order you need 426349cc55cSDimitry Andric // To iterate forward or backward through the order list as qualifier 427349cc55cSDimitry Andric // can push through each other. 428349cc55cSDimitry Andric // The Order list must define the position of "type" to signify 429349cc55cSDimitry Andric assert(llvm::is_contained(Order, "type") && 430349cc55cSDimitry Andric "QualifierOrder must contain type"); 431349cc55cSDimitry Andric // Split the Order list by type and reverse the left side. 432349cc55cSDimitry Andric 433349cc55cSDimitry Andric bool left = true; 434349cc55cSDimitry Andric for (const auto &s : Order) { 435349cc55cSDimitry Andric if (s == "type") { 436349cc55cSDimitry Andric left = false; 437349cc55cSDimitry Andric continue; 438349cc55cSDimitry Andric } 439349cc55cSDimitry Andric 440349cc55cSDimitry Andric tok::TokenKind QualifierToken = 441349cc55cSDimitry Andric LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); 442349cc55cSDimitry Andric if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) { 443349cc55cSDimitry Andric Qualifiers.push_back(QualifierToken); 444349cc55cSDimitry Andric } 445349cc55cSDimitry Andric 446349cc55cSDimitry Andric if (left) 447349cc55cSDimitry Andric // Reverse the order for left aligned items. 448349cc55cSDimitry Andric LeftOrder.insert(LeftOrder.begin(), s); 449349cc55cSDimitry Andric else 450349cc55cSDimitry Andric RightOrder.push_back(s); 451349cc55cSDimitry Andric } 452349cc55cSDimitry Andric } 453349cc55cSDimitry Andric 454349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isQualifierOrType( 455349cc55cSDimitry Andric const FormatToken *Tok, const std::vector<tok::TokenKind> &specifiedTypes) { 456349cc55cSDimitry Andric return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || 457349cc55cSDimitry Andric llvm::is_contained(specifiedTypes, Tok->Tok.getKind())); 458349cc55cSDimitry Andric } 459349cc55cSDimitry Andric 460349cc55cSDimitry Andric // If a token is an identifier and it's upper case, it could 461349cc55cSDimitry Andric // be a macro and hence we need to be able to ignore it. 462349cc55cSDimitry Andric bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { 463349cc55cSDimitry Andric if (!Tok) 464349cc55cSDimitry Andric return false; 465349cc55cSDimitry Andric if (!Tok->is(tok::identifier)) 466349cc55cSDimitry Andric return false; 467349cc55cSDimitry Andric if (Tok->TokenText.upper() == Tok->TokenText.str()) 468349cc55cSDimitry Andric return true; 469349cc55cSDimitry Andric return false; 470349cc55cSDimitry Andric } 471349cc55cSDimitry Andric 472349cc55cSDimitry Andric } // namespace format 473349cc55cSDimitry Andric } // namespace clang 474