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