Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp
35233 views
1
//===--- QualifierAlignmentFixer.cpp ----------------------------*- C++--*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This file implements QualifierAlignmentFixer, a TokenAnalyzer that
11
/// enforces either left or right const depending on the style.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "QualifierAlignmentFixer.h"
16
#include "FormatToken.h"
17
#include "llvm/Support/Debug.h"
18
#include "llvm/Support/Regex.h"
19
20
#include <algorithm>
21
#include <optional>
22
23
#define DEBUG_TYPE "format-qualifier-alignment-fixer"
24
25
namespace clang {
26
namespace format {
27
28
void addQualifierAlignmentFixerPasses(const FormatStyle &Style,
29
SmallVectorImpl<AnalyzerPass> &Passes) {
30
std::vector<std::string> LeftOrder;
31
std::vector<std::string> RightOrder;
32
std::vector<tok::TokenKind> ConfiguredQualifierTokens;
33
prepareLeftRightOrderingForQualifierAlignmentFixer(
34
Style.QualifierOrder, LeftOrder, RightOrder, ConfiguredQualifierTokens);
35
36
// Handle the left and right alignment separately.
37
for (const auto &Qualifier : LeftOrder) {
38
Passes.emplace_back(
39
[&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
40
return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
41
ConfiguredQualifierTokens,
42
/*RightAlign=*/false)
43
.process();
44
});
45
}
46
for (const auto &Qualifier : RightOrder) {
47
Passes.emplace_back(
48
[&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
49
return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
50
ConfiguredQualifierTokens,
51
/*RightAlign=*/true)
52
.process();
53
});
54
}
55
}
56
57
static void replaceToken(const SourceManager &SourceMgr,
58
tooling::Replacements &Fixes,
59
const CharSourceRange &Range, std::string NewText) {
60
auto Replacement = tooling::Replacement(SourceMgr, Range, NewText);
61
auto Err = Fixes.add(Replacement);
62
63
if (Err) {
64
llvm::errs() << "Error while rearranging Qualifier : "
65
<< llvm::toString(std::move(Err)) << "\n";
66
}
67
}
68
69
static void removeToken(const SourceManager &SourceMgr,
70
tooling::Replacements &Fixes,
71
const FormatToken *First) {
72
auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
73
First->Tok.getEndLoc());
74
replaceToken(SourceMgr, Fixes, Range, "");
75
}
76
77
static void insertQualifierAfter(const SourceManager &SourceMgr,
78
tooling::Replacements &Fixes,
79
const FormatToken *First,
80
const std::string &Qualifier) {
81
auto Range = CharSourceRange::getCharRange(First->Tok.getLocation(),
82
First->Tok.getEndLoc());
83
84
std::string NewText{};
85
NewText += First->TokenText;
86
NewText += " " + Qualifier;
87
replaceToken(SourceMgr, Fixes, Range, NewText);
88
}
89
90
static void insertQualifierBefore(const SourceManager &SourceMgr,
91
tooling::Replacements &Fixes,
92
const FormatToken *First,
93
const std::string &Qualifier) {
94
auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
95
First->Tok.getEndLoc());
96
97
std::string NewText = " " + Qualifier + " ";
98
NewText += First->TokenText;
99
100
replaceToken(SourceMgr, Fixes, Range, NewText);
101
}
102
103
static bool endsWithSpace(const std::string &s) {
104
if (s.empty())
105
return false;
106
return isspace(s.back());
107
}
108
109
static bool startsWithSpace(const std::string &s) {
110
if (s.empty())
111
return false;
112
return isspace(s.front());
113
}
114
115
static void rotateTokens(const SourceManager &SourceMgr,
116
tooling::Replacements &Fixes, const FormatToken *First,
117
const FormatToken *Last, bool Left) {
118
auto *End = Last;
119
auto *Begin = First;
120
if (!Left) {
121
End = Last->Next;
122
Begin = First->Next;
123
}
124
125
std::string NewText;
126
// If we are rotating to the left we move the Last token to the front.
127
if (Left) {
128
NewText += Last->TokenText;
129
NewText += " ";
130
}
131
132
// Then move through the other tokens.
133
auto *Tok = Begin;
134
while (Tok != End) {
135
if (!NewText.empty() && !endsWithSpace(NewText))
136
NewText += " ";
137
138
NewText += Tok->TokenText;
139
Tok = Tok->Next;
140
}
141
142
// If we are rotating to the right we move the first token to the back.
143
if (!Left) {
144
if (!NewText.empty() && !startsWithSpace(NewText))
145
NewText += " ";
146
NewText += First->TokenText;
147
}
148
149
auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
150
Last->Tok.getEndLoc());
151
152
replaceToken(SourceMgr, Fixes, Range, NewText);
153
}
154
155
static bool
156
isConfiguredQualifier(const FormatToken *const Tok,
157
const std::vector<tok::TokenKind> &Qualifiers) {
158
return Tok && llvm::is_contained(Qualifiers, Tok->Tok.getKind());
159
}
160
161
static bool isQualifier(const FormatToken *const Tok) {
162
if (!Tok)
163
return false;
164
165
switch (Tok->Tok.getKind()) {
166
case tok::kw_const:
167
case tok::kw_volatile:
168
case tok::kw_static:
169
case tok::kw_inline:
170
case tok::kw_constexpr:
171
case tok::kw_restrict:
172
case tok::kw_friend:
173
return true;
174
default:
175
return false;
176
}
177
}
178
179
const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
180
const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
181
tooling::Replacements &Fixes, const FormatToken *const Tok,
182
const std::string &Qualifier, tok::TokenKind QualifierType) {
183
// We only need to think about streams that begin with a qualifier.
184
if (Tok->isNot(QualifierType))
185
return Tok;
186
// Don't concern yourself if nothing follows the qualifier.
187
if (!Tok->Next)
188
return Tok;
189
190
// Skip qualifiers to the left to find what preceeds the qualifiers.
191
// Use isQualifier rather than isConfiguredQualifier to cover all qualifiers.
192
const FormatToken *PreviousCheck = Tok->getPreviousNonComment();
193
while (isQualifier(PreviousCheck))
194
PreviousCheck = PreviousCheck->getPreviousNonComment();
195
196
// Examples given in order of ['type', 'const', 'volatile']
197
const bool IsRightQualifier = PreviousCheck && [PreviousCheck]() {
198
// The cases:
199
// `Foo() const` -> `Foo() const`
200
// `Foo() const final` -> `Foo() const final`
201
// `Foo() const override` -> `Foo() const final`
202
// `Foo() const volatile override` -> `Foo() const volatile override`
203
// `Foo() volatile const final` -> `Foo() const volatile final`
204
if (PreviousCheck->is(tok::r_paren))
205
return true;
206
207
// The cases:
208
// `struct {} volatile const a;` -> `struct {} const volatile a;`
209
// `class {} volatile const a;` -> `class {} const volatile a;`
210
if (PreviousCheck->is(tok::r_brace))
211
return true;
212
213
// The case:
214
// `template <class T> const Bar Foo()` ->
215
// `template <class T> Bar const Foo()`
216
// The cases:
217
// `Foo<int> const foo` -> `Foo<int> const foo`
218
// `Foo<int> volatile const` -> `Foo<int> const volatile`
219
// The case:
220
// ```
221
// template <class T>
222
// requires Concept1<T> && requires Concept2<T>
223
// const Foo f();
224
// ```
225
// ->
226
// ```
227
// template <class T>
228
// requires Concept1<T> && requires Concept2<T>
229
// Foo const f();
230
// ```
231
if (PreviousCheck->is(TT_TemplateCloser)) {
232
// If the token closes a template<> or requires clause, then it is a left
233
// qualifier and should be moved to the right.
234
return !(PreviousCheck->ClosesTemplateDeclaration ||
235
PreviousCheck->ClosesRequiresClause);
236
}
237
238
// The case `Foo* const` -> `Foo* const`
239
// The case `Foo* volatile const` -> `Foo* const volatile`
240
// The case `int32_t const` -> `int32_t const`
241
// The case `auto volatile const` -> `auto const volatile`
242
if (PreviousCheck->isOneOf(TT_PointerOrReference, tok::identifier,
243
tok::kw_auto)) {
244
return true;
245
}
246
247
return false;
248
}();
249
250
// Find the last qualifier to the right.
251
const FormatToken *LastQual = Tok;
252
while (isQualifier(LastQual->getNextNonComment()))
253
LastQual = LastQual->getNextNonComment();
254
255
// If this qualifier is to the right of a type or pointer do a partial sort
256
// and return.
257
if (IsRightQualifier) {
258
if (LastQual != Tok)
259
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
260
return Tok;
261
}
262
263
const FormatToken *TypeToken = LastQual->getNextNonComment();
264
if (!TypeToken)
265
return Tok;
266
267
// Stay safe and don't move past macros, also don't bother with sorting.
268
if (isPossibleMacro(TypeToken))
269
return Tok;
270
271
// The case `const long long int volatile` -> `long long int const volatile`
272
// The case `long const long int volatile` -> `long long int const volatile`
273
// The case `long long volatile int const` -> `long long int const volatile`
274
// The case `const long long volatile int` -> `long long int const volatile`
275
if (TypeToken->isTypeName(LangOpts)) {
276
// The case `const decltype(foo)` -> `const decltype(foo)`
277
// The case `const typeof(foo)` -> `const typeof(foo)`
278
// The case `const _Atomic(foo)` -> `const _Atomic(foo)`
279
if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
280
return Tok;
281
282
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
283
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
284
LangOpts)) {
285
LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
286
}
287
288
rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
289
/*Left=*/false);
290
return LastSimpleTypeSpecifier;
291
}
292
293
// The case `unsigned short const` -> `unsigned short const`
294
// The case:
295
// `unsigned short volatile const` -> `unsigned short const volatile`
296
if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) {
297
if (LastQual != Tok)
298
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
299
return Tok;
300
}
301
302
// Skip the typename keyword.
303
// The case `const typename C::type` -> `typename C::type const`
304
if (TypeToken->is(tok::kw_typename))
305
TypeToken = TypeToken->getNextNonComment();
306
307
// Skip the initial :: of a global-namespace type.
308
// The case `const ::...` -> `::... const`
309
if (TypeToken->is(tok::coloncolon)) {
310
// The case `const ::template Foo...` -> `::template Foo... const`
311
TypeToken = TypeToken->getNextNonComment();
312
if (TypeToken && TypeToken->is(tok::kw_template))
313
TypeToken = TypeToken->getNextNonComment();
314
}
315
316
// Don't change declarations such as
317
// `foo(const struct Foo a);` -> `foo(const struct Foo a);`
318
// as they would currently change code such as
319
// `const struct my_struct_t {} my_struct;` -> `struct my_struct_t const {}
320
// my_struct;`
321
if (TypeToken->isOneOf(tok::kw_struct, tok::kw_class))
322
return Tok;
323
324
if (TypeToken->isOneOf(tok::kw_auto, tok::identifier)) {
325
// The case `const auto` -> `auto const`
326
// The case `const Foo` -> `Foo const`
327
// The case `const ::Foo` -> `::Foo const`
328
// The case `const Foo *` -> `Foo const *`
329
// The case `const Foo &` -> `Foo const &`
330
// The case `const Foo &&` -> `Foo const &&`
331
// The case `const std::Foo &&` -> `std::Foo const &&`
332
// The case `const std::Foo<T> &&` -> `std::Foo<T> const &&`
333
// The case `const ::template Foo` -> `::template Foo const`
334
// The case `const T::template Foo` -> `T::template Foo const`
335
const FormatToken *Next = nullptr;
336
while ((Next = TypeToken->getNextNonComment()) &&
337
(Next->is(TT_TemplateOpener) ||
338
Next->startsSequence(tok::coloncolon, tok::identifier) ||
339
Next->startsSequence(tok::coloncolon, tok::kw_template,
340
tok::identifier))) {
341
if (Next->is(TT_TemplateOpener)) {
342
assert(Next->MatchingParen && "Missing template closer");
343
TypeToken = Next->MatchingParen;
344
} else if (Next->startsSequence(tok::coloncolon, tok::identifier)) {
345
TypeToken = Next->getNextNonComment();
346
} else {
347
TypeToken = Next->getNextNonComment()->getNextNonComment();
348
}
349
}
350
351
if (Next->is(tok::kw_auto))
352
TypeToken = Next;
353
354
// Place the Qualifier at the end of the list of qualifiers.
355
while (isQualifier(TypeToken->getNextNonComment())) {
356
// The case `volatile Foo::iter const` -> `Foo::iter const volatile`
357
TypeToken = TypeToken->getNextNonComment();
358
}
359
360
insertQualifierAfter(SourceMgr, Fixes, TypeToken, Qualifier);
361
// Remove token and following whitespace.
362
auto Range = CharSourceRange::getCharRange(
363
Tok->getStartOfNonWhitespace(), Tok->Next->getStartOfNonWhitespace());
364
replaceToken(SourceMgr, Fixes, Range, "");
365
}
366
367
return Tok;
368
}
369
370
const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
371
const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
372
tooling::Replacements &Fixes, const FormatToken *const Tok,
373
const std::string &Qualifier, tok::TokenKind QualifierType) {
374
// We only need to think about streams that begin with a qualifier.
375
if (Tok->isNot(QualifierType))
376
return Tok;
377
// Don't concern yourself if nothing preceeds the qualifier.
378
if (!Tok->getPreviousNonComment())
379
return Tok;
380
381
// Skip qualifiers to the left to find what preceeds the qualifiers.
382
const FormatToken *TypeToken = Tok->getPreviousNonComment();
383
while (isQualifier(TypeToken))
384
TypeToken = TypeToken->getPreviousNonComment();
385
386
// For left qualifiers preceeded by nothing, a template declaration, or *,&,&&
387
// we only perform sorting.
388
if (!TypeToken || TypeToken->isPointerOrReference() ||
389
TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) {
390
391
// Don't sort past a non-configured qualifier token.
392
const FormatToken *FirstQual = Tok;
393
while (isConfiguredQualifier(FirstQual->getPreviousNonComment(),
394
ConfiguredQualifierTokens)) {
395
FirstQual = FirstQual->getPreviousNonComment();
396
}
397
398
if (FirstQual != Tok)
399
rotateTokens(SourceMgr, Fixes, FirstQual, Tok, /*Left=*/true);
400
return Tok;
401
}
402
403
// Stay safe and don't move past macros, also don't bother with sorting.
404
if (isPossibleMacro(TypeToken))
405
return Tok;
406
407
// Examples given in order of ['const', 'volatile', 'type']
408
409
// The case `volatile long long int const` -> `const volatile long long int`
410
// The case `volatile long long const int` -> `const volatile long long int`
411
// The case `const long long volatile int` -> `const volatile long long int`
412
// The case `long volatile long int const` -> `const volatile long long int`
413
if (TypeToken->isTypeName(LangOpts)) {
414
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
415
while (isConfiguredQualifierOrType(
416
LastSimpleTypeSpecifier->getPreviousNonComment(),
417
ConfiguredQualifierTokens, LangOpts)) {
418
LastSimpleTypeSpecifier =
419
LastSimpleTypeSpecifier->getPreviousNonComment();
420
}
421
422
rotateTokens(SourceMgr, Fixes, LastSimpleTypeSpecifier, Tok,
423
/*Left=*/true);
424
return Tok;
425
}
426
427
if (TypeToken->isOneOf(tok::kw_auto, tok::identifier, TT_TemplateCloser)) {
428
const auto IsStartOfType = [](const FormatToken *const Tok) -> bool {
429
if (!Tok)
430
return true;
431
432
// A template closer is not the start of a type.
433
// The case `?<> const` -> `const ?<>`
434
if (Tok->is(TT_TemplateCloser))
435
return false;
436
437
const FormatToken *const Previous = Tok->getPreviousNonComment();
438
if (!Previous)
439
return true;
440
441
// An identifier preceeded by :: is not the start of a type.
442
// The case `?::Foo const` -> `const ?::Foo`
443
if (Tok->is(tok::identifier) && Previous->is(tok::coloncolon))
444
return false;
445
446
const FormatToken *const PrePrevious = Previous->getPreviousNonComment();
447
// An identifier preceeded by ::template is not the start of a type.
448
// The case `?::template Foo const` -> `const ?::template Foo`
449
if (Tok->is(tok::identifier) && Previous->is(tok::kw_template) &&
450
PrePrevious && PrePrevious->is(tok::coloncolon)) {
451
return false;
452
}
453
454
if (Tok->endsSequence(tok::kw_auto, tok::identifier))
455
return false;
456
457
return true;
458
};
459
460
while (!IsStartOfType(TypeToken)) {
461
// The case `?<>`
462
if (TypeToken->is(TT_TemplateCloser)) {
463
assert(TypeToken->MatchingParen && "Missing template opener");
464
TypeToken = TypeToken->MatchingParen->getPreviousNonComment();
465
} else {
466
// The cases
467
// `::Foo`
468
// `?>::Foo`
469
// `?Bar::Foo`
470
// `::template Foo`
471
// `?>::template Foo`
472
// `?Bar::template Foo`
473
if (TypeToken->getPreviousNonComment()->is(tok::kw_template))
474
TypeToken = TypeToken->getPreviousNonComment();
475
476
const FormatToken *const ColonColon =
477
TypeToken->getPreviousNonComment();
478
const FormatToken *const PreColonColon =
479
ColonColon->getPreviousNonComment();
480
if (PreColonColon &&
481
PreColonColon->isOneOf(TT_TemplateCloser, tok::identifier)) {
482
TypeToken = PreColonColon;
483
} else {
484
TypeToken = ColonColon;
485
}
486
}
487
}
488
489
assert(TypeToken && "Should be auto or identifier");
490
491
// Place the Qualifier at the start of the list of qualifiers.
492
const FormatToken *Previous = nullptr;
493
while ((Previous = TypeToken->getPreviousNonComment()) &&
494
(isConfiguredQualifier(Previous, ConfiguredQualifierTokens) ||
495
Previous->is(tok::kw_typename))) {
496
// The case `volatile Foo::iter const` -> `const volatile Foo::iter`
497
// The case `typename C::type const` -> `const typename C::type`
498
TypeToken = Previous;
499
}
500
501
// Don't change declarations such as
502
// `foo(struct Foo const a);` -> `foo(struct Foo const a);`
503
if (!Previous || !Previous->isOneOf(tok::kw_struct, tok::kw_class)) {
504
insertQualifierBefore(SourceMgr, Fixes, TypeToken, Qualifier);
505
removeToken(SourceMgr, Fixes, Tok);
506
}
507
}
508
509
return Tok;
510
}
511
512
tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
513
const std::string &Qualifier) {
514
// Don't let 'type' be an identifier, but steal typeof token.
515
return llvm::StringSwitch<tok::TokenKind>(Qualifier)
516
.Case("type", tok::kw_typeof)
517
.Case("const", tok::kw_const)
518
.Case("volatile", tok::kw_volatile)
519
.Case("static", tok::kw_static)
520
.Case("inline", tok::kw_inline)
521
.Case("constexpr", tok::kw_constexpr)
522
.Case("restrict", tok::kw_restrict)
523
.Case("friend", tok::kw_friend)
524
.Default(tok::identifier);
525
}
526
527
LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer(
528
const Environment &Env, const FormatStyle &Style,
529
const std::string &Qualifier,
530
const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
531
: TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
532
ConfiguredQualifierTokens(QualifierTokens) {}
533
534
std::pair<tooling::Replacements, unsigned>
535
LeftRightQualifierAlignmentFixer::analyze(
536
TokenAnnotator & /*Annotator*/,
537
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
538
FormatTokenLexer &Tokens) {
539
tooling::Replacements Fixes;
540
AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
541
fixQualifierAlignment(AnnotatedLines, Tokens, Fixes);
542
return {Fixes, 0};
543
}
544
545
void LeftRightQualifierAlignmentFixer::fixQualifierAlignment(
546
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens,
547
tooling::Replacements &Fixes) {
548
const AdditionalKeywords &Keywords = Tokens.getKeywords();
549
const SourceManager &SourceMgr = Env.getSourceManager();
550
tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier);
551
assert(QualifierToken != tok::identifier && "Unrecognised Qualifier");
552
553
for (AnnotatedLine *Line : AnnotatedLines) {
554
fixQualifierAlignment(Line->Children, Tokens, Fixes);
555
if (!Line->Affected || Line->InPPDirective)
556
continue;
557
FormatToken *First = Line->First;
558
assert(First);
559
if (First->Finalized)
560
continue;
561
562
const auto *Last = Line->Last;
563
564
for (const auto *Tok = First; Tok && Tok != Last && Tok->Next;
565
Tok = Tok->Next) {
566
if (Tok->MustBreakBefore)
567
break;
568
if (Tok->is(tok::comment))
569
continue;
570
if (RightAlign) {
571
Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier,
572
QualifierToken);
573
} else {
574
Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier,
575
QualifierToken);
576
}
577
}
578
}
579
}
580
581
void prepareLeftRightOrderingForQualifierAlignmentFixer(
582
const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
583
std::vector<std::string> &RightOrder,
584
std::vector<tok::TokenKind> &Qualifiers) {
585
586
// Depending on the position of type in the order you need
587
// To iterate forward or backward through the order list as qualifier
588
// can push through each other.
589
// The Order list must define the position of "type" to signify
590
assert(llvm::is_contained(Order, "type") &&
591
"QualifierOrder must contain type");
592
// Split the Order list by type and reverse the left side.
593
594
bool left = true;
595
for (const auto &s : Order) {
596
if (s == "type") {
597
left = false;
598
continue;
599
}
600
601
tok::TokenKind QualifierToken =
602
LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s);
603
if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier)
604
Qualifiers.push_back(QualifierToken);
605
606
if (left) {
607
// Reverse the order for left aligned items.
608
LeftOrder.insert(LeftOrder.begin(), s);
609
} else {
610
RightOrder.push_back(s);
611
}
612
}
613
}
614
615
bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) {
616
return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
617
isQualifier(Tok));
618
}
619
620
bool isConfiguredQualifierOrType(const FormatToken *Tok,
621
const std::vector<tok::TokenKind> &Qualifiers,
622
const LangOptions &LangOpts) {
623
return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) ||
624
isConfiguredQualifier(Tok, Qualifiers));
625
}
626
627
// If a token is an identifier and it's upper case, it could
628
// be a macro and hence we need to be able to ignore it.
629
bool isPossibleMacro(const FormatToken *Tok) {
630
if (!Tok)
631
return false;
632
if (Tok->isNot(tok::identifier))
633
return false;
634
if (Tok->TokenText.upper() == Tok->TokenText.str()) {
635
// T,K,U,V likely could be template arguments
636
return Tok->TokenText.size() != 1;
637
}
638
return false;
639
}
640
641
} // namespace format
642
} // namespace clang
643
644