Skip to content

Commit 0baef3b

Browse files
authored
[clang-format] Handle common C++ non-keyword types as such (#83709)
Fixes #83400.
1 parent e1405e4 commit 0baef3b

7 files changed

+83
-41
lines changed

clang/lib/Format/FormatToken.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,22 @@ bool FormatToken::isSimpleTypeSpecifier() const {
7171
}
7272
}
7373

74-
bool FormatToken::isTypeOrIdentifier() const {
75-
return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier);
74+
// Sorted common C++ non-keyword types.
75+
static SmallVector<StringRef> CppNonKeywordTypes = {
76+
"clock_t", "int16_t", "int32_t", "int64_t", "int8_t",
77+
"intptr_t", "ptrdiff_t", "size_t", "time_t", "uint16_t",
78+
"uint32_t", "uint64_t", "uint8_t", "uintptr_t",
79+
};
80+
81+
bool FormatToken::isTypeName(bool IsCpp) const {
82+
return is(TT_TypeName) || isSimpleTypeSpecifier() ||
83+
(IsCpp && is(tok::identifier) &&
84+
std::binary_search(CppNonKeywordTypes.begin(),
85+
CppNonKeywordTypes.end(), TokenText));
86+
}
87+
88+
bool FormatToken::isTypeOrIdentifier(bool IsCpp) const {
89+
return isTypeName(IsCpp) || isOneOf(tok::kw_auto, tok::identifier);
7690
}
7791

7892
bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const {

clang/lib/Format/FormatToken.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,9 @@ struct FormatToken {
676676
/// Determine whether the token is a simple-type-specifier.
677677
[[nodiscard]] bool isSimpleTypeSpecifier() const;
678678

679-
[[nodiscard]] bool isTypeOrIdentifier() const;
679+
[[nodiscard]] bool isTypeName(bool IsCpp) const;
680+
681+
[[nodiscard]] bool isTypeOrIdentifier(bool IsCpp) const;
680682

681683
bool isObjCAccessSpecifier() const {
682684
return is(tok::at) && Next &&

clang/lib/Format/QualifierAlignmentFixer.cpp

+16-12
Original file line numberDiff line numberDiff line change
@@ -268,20 +268,24 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
268268
if (isPossibleMacro(TypeToken))
269269
return Tok;
270270

271+
const bool IsCpp = Style.isCpp();
272+
271273
// The case `const long long int volatile` -> `long long int const volatile`
272274
// The case `long const long int volatile` -> `long long int const volatile`
273275
// The case `long long volatile int const` -> `long long int const volatile`
274276
// The case `const long long volatile int` -> `long long int const volatile`
275-
if (TypeToken->isSimpleTypeSpecifier()) {
277+
if (TypeToken->isTypeName(IsCpp)) {
276278
// The case `const decltype(foo)` -> `const decltype(foo)`
277279
// The case `const typeof(foo)` -> `const typeof(foo)`
278280
// The case `const _Atomic(foo)` -> `const _Atomic(foo)`
279281
if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
280282
return Tok;
281283

282284
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
283-
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment()))
285+
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
286+
IsCpp)) {
284287
LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
288+
}
285289

286290
rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
287291
/*Left=*/false);
@@ -291,7 +295,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
291295
// The case `unsigned short const` -> `unsigned short const`
292296
// The case:
293297
// `unsigned short volatile const` -> `unsigned short const volatile`
294-
if (PreviousCheck && PreviousCheck->isSimpleTypeSpecifier()) {
298+
if (PreviousCheck && PreviousCheck->isTypeName(IsCpp)) {
295299
if (LastQual != Tok)
296300
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
297301
return Tok;
@@ -408,11 +412,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
408412
// The case `volatile long long const int` -> `const volatile long long int`
409413
// The case `const long long volatile int` -> `const volatile long long int`
410414
// The case `long volatile long int const` -> `const volatile long long int`
411-
if (TypeToken->isSimpleTypeSpecifier()) {
415+
if (const bool IsCpp = Style.isCpp(); TypeToken->isTypeName(IsCpp)) {
412416
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
413417
while (isConfiguredQualifierOrType(
414418
LastSimpleTypeSpecifier->getPreviousNonComment(),
415-
ConfiguredQualifierTokens)) {
419+
ConfiguredQualifierTokens, IsCpp)) {
416420
LastSimpleTypeSpecifier =
417421
LastSimpleTypeSpecifier->getPreviousNonComment();
418422
}
@@ -610,16 +614,16 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
610614
}
611615
}
612616

613-
bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
614-
const FormatToken *const Tok) {
615-
return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) ||
616-
isQualifier(Tok));
617+
bool LeftRightQualifierAlignmentFixer::isQualifierOrType(const FormatToken *Tok,
618+
bool IsCpp) {
619+
return Tok &&
620+
(Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) || isQualifier(Tok));
617621
}
618622

619623
bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType(
620-
const FormatToken *const Tok,
621-
const std::vector<tok::TokenKind> &Qualifiers) {
622-
return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) ||
624+
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers,
625+
bool IsCpp) {
626+
return Tok && (Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) ||
623627
isConfiguredQualifier(Tok, Qualifiers));
624628
}
625629

clang/lib/Format/QualifierAlignmentFixer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,11 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
7171
tok::TokenKind QualifierType);
7272

7373
// Is the Token a simple or qualifier type
74-
static bool isQualifierOrType(const FormatToken *Tok);
74+
static bool isQualifierOrType(const FormatToken *Tok, bool IsCpp = true);
7575
static bool
7676
isConfiguredQualifierOrType(const FormatToken *Tok,
77-
const std::vector<tok::TokenKind> &Qualifiers);
77+
const std::vector<tok::TokenKind> &Qualifiers,
78+
bool IsCpp = true);
7879

7980
// Is the Token likely a Macro
8081
static bool isPossibleMacro(const FormatToken *Tok);

clang/lib/Format/TokenAnnotator.cpp

+15-15
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ class AnnotatingParser {
562562
(CurrentToken->is(tok::l_paren) && CurrentToken->Next &&
563563
CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret));
564564
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
565-
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
565+
CurrentToken->Previous->isTypeName(IsCpp)) &&
566566
!(CurrentToken->is(tok::l_brace) ||
567567
(CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen))) {
568568
Contexts.back().IsExpression = false;
@@ -2573,7 +2573,7 @@ class AnnotatingParser {
25732573
return true;
25742574

25752575
// MyClass a;
2576-
if (PreviousNotConst->isSimpleTypeSpecifier())
2576+
if (PreviousNotConst->isTypeName(IsCpp))
25772577
return true;
25782578

25792579
// type[] a in Java
@@ -2704,9 +2704,9 @@ class AnnotatingParser {
27042704
}
27052705

27062706
// Heuristically try to determine whether the parentheses contain a type.
2707-
auto IsQualifiedPointerOrReference = [](FormatToken *T) {
2707+
auto IsQualifiedPointerOrReference = [this](FormatToken *T) {
27082708
// This is used to handle cases such as x = (foo *const)&y;
2709-
assert(!T->isSimpleTypeSpecifier() && "Should have already been checked");
2709+
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
27102710
// Strip trailing qualifiers such as const or volatile when checking
27112711
// whether the parens could be a cast to a pointer/reference type.
27122712
while (T) {
@@ -2738,7 +2738,7 @@ class AnnotatingParser {
27382738
bool ParensAreType =
27392739
!Tok.Previous ||
27402740
Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
2741-
Tok.Previous->isSimpleTypeSpecifier() ||
2741+
Tok.Previous->isTypeName(IsCpp) ||
27422742
IsQualifiedPointerOrReference(Tok.Previous);
27432743
bool ParensCouldEndDecl =
27442744
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
@@ -3595,7 +3595,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
35953595
if (!Current.Tok.getIdentifierInfo())
35963596
return false;
35973597

3598-
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
3598+
auto skipOperatorName =
3599+
[IsCpp](const FormatToken *Next) -> const FormatToken * {
35993600
for (; Next; Next = Next->Next) {
36003601
if (Next->is(TT_OverloadedOperatorLParen))
36013602
return Next;
@@ -3614,7 +3615,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
36143615
Next = Next->Next;
36153616
continue;
36163617
}
3617-
if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) &&
3618+
if ((Next->isTypeName(IsCpp) || Next->is(tok::identifier)) &&
36183619
Next->Next && Next->Next->isPointerOrReference()) {
36193620
// For operator void*(), operator char*(), operator Foo*().
36203621
Next = Next->Next;
@@ -3712,9 +3713,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
37123713
Tok = Tok->MatchingParen;
37133714
continue;
37143715
}
3715-
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
3716-
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis,
3717-
TT_TypeName)) {
3716+
if (Tok->is(tok::kw_const) || Tok->isTypeName(IsCpp) ||
3717+
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) {
37183718
return true;
37193719
}
37203720
if (Tok->isOneOf(tok::l_brace, TT_ObjCMethodExpr) || Tok->Tok.isLiteral())
@@ -4376,7 +4376,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
43764376
if (Left.Tok.isLiteral())
43774377
return true;
43784378
// for (auto a = 0, b = 0; const auto & c : {1, 2, 3})
4379-
if (Left.isTypeOrIdentifier() && Right.Next && Right.Next->Next &&
4379+
if (Left.isTypeOrIdentifier(IsCpp) && Right.Next && Right.Next->Next &&
43804380
Right.Next->Next->is(TT_RangeBasedForLoopColon)) {
43814381
return getTokenPointerOrReferenceAlignment(Right) !=
43824382
FormatStyle::PAS_Left;
@@ -4419,8 +4419,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
44194419
if (Right.is(tok::l_brace) && Right.is(BK_Block))
44204420
return true;
44214421
// for (auto a = 0, b = 0; const auto& c : {1, 2, 3})
4422-
if (Left.Previous && Left.Previous->isTypeOrIdentifier() && Right.Next &&
4423-
Right.Next->is(TT_RangeBasedForLoopColon)) {
4422+
if (Left.Previous && Left.Previous->isTypeOrIdentifier(IsCpp) &&
4423+
Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) {
44244424
return getTokenPointerOrReferenceAlignment(Left) !=
44254425
FormatStyle::PAS_Right;
44264426
}
@@ -4458,7 +4458,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
44584458
if (Right.isPointerOrReference()) {
44594459
const FormatToken *Previous = &Left;
44604460
while (Previous && Previous->isNot(tok::kw_operator)) {
4461-
if (Previous->is(tok::identifier) || Previous->isSimpleTypeSpecifier()) {
4461+
if (Previous->is(tok::identifier) || Previous->isTypeName(IsCpp)) {
44624462
Previous = Previous->getPreviousNonComment();
44634463
continue;
44644464
}
@@ -4647,7 +4647,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
46474647
if (!Style.isVerilog() &&
46484648
(Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
46494649
tok::r_paren) ||
4650-
Left.isSimpleTypeSpecifier()) &&
4650+
Left.isTypeName(IsCpp)) &&
46514651
Right.is(tok::l_brace) && Right.getNextNonComment() &&
46524652
Right.isNot(BK_Block)) {
46534653
return false;

clang/lib/Format/UnwrappedLineParser.cpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -1865,8 +1865,7 @@ void UnwrappedLineParser::parseStructuralElement(
18651865
case tok::caret:
18661866
nextToken();
18671867
// Block return type.
1868-
if (FormatTok->Tok.isAnyIdentifier() ||
1869-
FormatTok->isSimpleTypeSpecifier()) {
1868+
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(IsCpp)) {
18701869
nextToken();
18711870
// Return types: pointers are ok too.
18721871
while (FormatTok->is(tok::star))
@@ -2222,7 +2221,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
22222221
bool InTemplateParameterList = false;
22232222

22242223
while (FormatTok->isNot(tok::l_brace)) {
2225-
if (FormatTok->isSimpleTypeSpecifier()) {
2224+
if (FormatTok->isTypeName(IsCpp)) {
22262225
nextToken();
22272226
continue;
22282227
}
@@ -3415,7 +3414,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
34153414
break;
34163415
}
34173416
default:
3418-
if (PreviousNonComment->isTypeOrIdentifier()) {
3417+
if (PreviousNonComment->isTypeOrIdentifier(IsCpp)) {
34193418
// This is a requires clause.
34203419
parseRequiresClause(RequiresToken);
34213420
return true;
@@ -3478,7 +3477,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
34783477
--OpenAngles;
34793478
break;
34803479
default:
3481-
if (NextToken->isSimpleTypeSpecifier()) {
3480+
if (NextToken->isTypeName(IsCpp)) {
34823481
FormatTok = Tokens->setPosition(StoredPosition);
34833482
parseRequiresExpression(RequiresToken);
34843483
return false;
@@ -3962,8 +3961,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
39623961
}
39633962
if (FormatTok->is(tok::l_square)) {
39643963
FormatToken *Previous = FormatTok->Previous;
3965-
if (!Previous ||
3966-
!(Previous->is(tok::r_paren) || Previous->isTypeOrIdentifier())) {
3964+
if (!Previous || (Previous->isNot(tok::r_paren) &&
3965+
!Previous->isTypeOrIdentifier(IsCpp))) {
39673966
// Don't try parsing a lambda if we had a closing parenthesis before,
39683967
// it was probably a pointer to an array: int (*)[].
39693968
if (!tryToParseLambda())

clang/unittests/Format/TokenAnnotatorTest.cpp

+24-2
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,24 @@ TEST_F(TokenAnnotatorTest, UnderstandsCasts) {
620620
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
621621
EXPECT_TOKEN(Tokens[3], tok::r_paren, TT_Unknown);
622622
EXPECT_TOKEN(Tokens[4], tok::amp, TT_BinaryOperator);
623+
624+
Tokens = annotate("#define FOO(bar) foo((uint64_t)&bar)");
625+
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
626+
EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_CastRParen);
627+
EXPECT_TOKEN(Tokens[11], tok::amp, TT_UnaryOperator);
628+
629+
Tokens = annotate("#define FOO(bar) foo((Foo) & bar)");
630+
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
631+
EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_Unknown);
632+
EXPECT_TOKEN(Tokens[11], tok::amp, TT_BinaryOperator);
633+
634+
auto Style = getLLVMStyle();
635+
Style.TypeNames.push_back("Foo");
636+
Tokens = annotate("#define FOO(bar) foo((Foo)&bar)", Style);
637+
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
638+
EXPECT_TOKEN(Tokens[9], tok::identifier, TT_TypeName);
639+
EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_CastRParen);
640+
EXPECT_TOKEN(Tokens[11], tok::amp, TT_UnaryOperator);
623641
}
624642

625643
TEST_F(TokenAnnotatorTest, UnderstandsDynamicExceptionSpecifier) {
@@ -1751,9 +1769,13 @@ TEST_F(TokenAnnotatorTest, UnderstandsFunctionDeclarationNames) {
17511769
EXPECT_TOKEN(Tokens[3], tok::identifier, TT_Unknown);
17521770
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_FunctionTypeLParen);
17531771

1772+
Tokens = annotate("int iso_time(time_t);");
1773+
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
1774+
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
1775+
17541776
auto Style = getLLVMStyle();
1755-
Style.TypeNames.push_back("time_t");
1756-
Tokens = annotate("int iso_time(time_t);", Style);
1777+
Style.TypeNames.push_back("MyType");
1778+
Tokens = annotate("int iso_time(MyType);", Style);
17571779
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
17581780
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
17591781
EXPECT_TOKEN(Tokens[3], tok::identifier, TT_TypeName);

0 commit comments

Comments
 (0)