Skip to content

Commit 37c7cde

Browse files
committed
Fix identifiers not being marked as constructor/destructor names if they are qualified by a template type, or have template typename declarations in front of them.
1 parent d1ca8d8 commit 37c7cde

File tree

2 files changed

+114
-6
lines changed

2 files changed

+114
-6
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,36 @@ static unsigned maxNestingDepth(const AnnotatedLine &Line) {
36303630
return Result;
36313631
}
36323632

3633+
// Returns the token after the first qualifier of the name, or nullptr if there
3634+
// is no qualifier.
3635+
static FormatToken* skipNameQualifier(const FormatToken *Tok) {
3636+
// Qualified names must start with an identifier.
3637+
if (!Tok->is(tok::identifier))
3638+
return nullptr;
3639+
3640+
Tok = Tok->getNextNonComment();
3641+
if (Tok == nullptr)
3642+
return nullptr;
3643+
3644+
// Consider: A::B::B()
3645+
// Tok --^
3646+
if (Tok->is(tok::coloncolon))
3647+
return Tok->getNextNonComment();
3648+
3649+
// Consider: A<float>::B<int>::B()
3650+
// Tok --^
3651+
if (Tok->is(TT_TemplateOpener)) {
3652+
if (!Tok->MatchingParen)
3653+
return nullptr;
3654+
3655+
Tok = Tok->MatchingParen;
3656+
if (Tok->startsSequence(TT_TemplateCloser, tok::coloncolon))
3657+
return Tok->getNextNonComment()->getNextNonComment();
3658+
}
3659+
3660+
return nullptr;
3661+
}
3662+
36333663
// Returns the name of a function with no return type, e.g. a constructor or
36343664
// destructor.
36353665
static FormatToken *getFunctionName(const AnnotatedLine &Line,
@@ -3659,6 +3689,21 @@ static FormatToken *getFunctionName(const AnnotatedLine &Line,
36593689
continue;
36603690
}
36613691

3692+
// Skip past template typename declarations that may precede the
3693+
// constructor/destructor name
3694+
if (Tok->is(tok::kw_template)) {
3695+
Tok = Tok->getNextNonComment();
3696+
if (!Tok)
3697+
return nullptr;
3698+
3699+
assert(Tok->is(TT_TemplateOpener));
3700+
Tok = Tok->MatchingParen;
3701+
if (!Tok)
3702+
return nullptr;
3703+
3704+
continue;
3705+
}
3706+
36623707
// A qualified name may start from the global namespace.
36633708
if (Tok->is(tok::coloncolon)) {
36643709
Tok = Tok->Next;
@@ -3667,13 +3712,13 @@ static FormatToken *getFunctionName(const AnnotatedLine &Line,
36673712
}
36683713

36693714
// Skip to the unqualified part of the name.
3670-
while (Tok->startsSequence(tok::identifier, tok::coloncolon)) {
3671-
assert(Tok->Next);
3672-
Tok = Tok->Next->Next;
3673-
if (!Tok)
3674-
return nullptr;
3715+
while (FormatToken* Next = skipNameQualifier(Tok)) {
3716+
Tok = Next;
36753717
}
36763718

3719+
if (!Tok)
3720+
return nullptr;
3721+
36773722
// Skip the `~` if a destructor name.
36783723
if (Tok->is(tok::tilde)) {
36793724
Tok = Tok->Next;
@@ -3699,10 +3744,18 @@ static bool isCtorOrDtorName(const FormatToken *Tok) {
36993744
if (Prev && Prev->is(tok::tilde))
37003745
Prev = Prev->Previous;
37013746

3702-
if (!Prev || !Prev->endsSequence(tok::coloncolon, tok::identifier))
3747+
// Consider: A::A() and A<int>::A()
3748+
if (!Prev || (!Prev->endsSequence(tok::coloncolon, tok::identifier) &&
3749+
!Prev->endsSequence(tok::coloncolon, TT_TemplateCloser))) {
37033750
return false;
3751+
}
37043752

37053753
assert(Prev->Previous);
3754+
if (Prev->Previous->is(TT_TemplateCloser) && Prev->Previous->MatchingParen) {
3755+
Prev = Prev->Previous->MatchingParen;
3756+
assert(Prev->Previous);
3757+
}
3758+
37063759
return Prev->Previous->TokenText == Tok->TokenText;
37073760
}
37083761

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,6 +2351,61 @@ TEST_F(TokenAnnotatorTest, UnderstandsCtorAndDtorDeclNames) {
23512351
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_FunctionDeclarationLParen);
23522352
EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_FunctionLBrace);
23532353

2354+
Tokens = annotate("Foo<int>::Foo() {}");
2355+
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
2356+
EXPECT_TOKEN(Tokens[5], tok::identifier, TT_CtorDtorDeclName);
2357+
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_FunctionDeclarationLParen);
2358+
EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_FunctionLBrace);
2359+
2360+
Tokens = annotate("Foo<int>::~Foo() {}");
2361+
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
2362+
EXPECT_TOKEN(Tokens[6], tok::identifier, TT_CtorDtorDeclName);
2363+
EXPECT_TOKEN(Tokens[7], tok::l_paren, TT_FunctionDeclarationLParen);
2364+
EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_FunctionLBrace);
2365+
2366+
Tokens = annotate("template <typename V> Foo<V>::Foo() {}");
2367+
ASSERT_EQ(Tokens.size(), 16u) << Tokens;
2368+
EXPECT_TOKEN(Tokens[10], tok::identifier, TT_CtorDtorDeclName);
2369+
EXPECT_TOKEN(Tokens[11], tok::l_paren, TT_FunctionDeclarationLParen);
2370+
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_FunctionLBrace);
2371+
2372+
Tokens = annotate("template <typename V> Foo<V>::~Foo() {}");
2373+
ASSERT_EQ(Tokens.size(), 17u) << Tokens;
2374+
EXPECT_TOKEN(Tokens[11], tok::identifier, TT_CtorDtorDeclName);
2375+
EXPECT_TOKEN(Tokens[12], tok::l_paren, TT_FunctionDeclarationLParen);
2376+
EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_FunctionLBrace);
2377+
2378+
Tokens = annotate("template <typename V> [[nodiscard]] Foo<V>::Foo() {}");
2379+
ASSERT_EQ(Tokens.size(), 21u) << Tokens;
2380+
EXPECT_TOKEN(Tokens[15], tok::identifier, TT_CtorDtorDeclName);
2381+
EXPECT_TOKEN(Tokens[16], tok::l_paren, TT_FunctionDeclarationLParen);
2382+
EXPECT_TOKEN(Tokens[18], tok::l_brace, TT_FunctionLBrace);
2383+
2384+
Tokens = annotate("template <typename V> Foo<V>::Foo() [[nodiscard]] {}");
2385+
ASSERT_EQ(Tokens.size(), 21u) << Tokens;
2386+
EXPECT_TOKEN(Tokens[10], tok::identifier, TT_CtorDtorDeclName);
2387+
EXPECT_TOKEN(Tokens[11], tok::l_paren, TT_FunctionDeclarationLParen);
2388+
EXPECT_TOKEN(Tokens[18], tok::l_brace, TT_FunctionLBrace);
2389+
2390+
Tokens = annotate("template <typename V, typename U> Foo<V, U>::Foo() {}");
2391+
ASSERT_EQ(Tokens.size(), 21u) << Tokens;
2392+
EXPECT_TOKEN(Tokens[15], tok::identifier, TT_CtorDtorDeclName);
2393+
EXPECT_TOKEN(Tokens[16], tok::l_paren, TT_FunctionDeclarationLParen);
2394+
EXPECT_TOKEN(Tokens[18], tok::l_brace, TT_FunctionLBrace);
2395+
2396+
Tokens = annotate("template <typename V, typename U> Foo<V, U>::~Foo() {}");
2397+
ASSERT_EQ(Tokens.size(), 22u) << Tokens;
2398+
EXPECT_TOKEN(Tokens[16], tok::identifier, TT_CtorDtorDeclName);
2399+
EXPECT_TOKEN(Tokens[17], tok::l_paren, TT_FunctionDeclarationLParen);
2400+
EXPECT_TOKEN(Tokens[19], tok::l_brace, TT_FunctionLBrace);
2401+
2402+
Tokens = annotate(
2403+
"template <typename V> template<typename W> Foo<V>::Foo(W x) {}");
2404+
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
2405+
EXPECT_TOKEN(Tokens[15], tok::identifier, TT_CtorDtorDeclName);
2406+
EXPECT_TOKEN(Tokens[16], tok::l_paren, TT_FunctionDeclarationLParen);
2407+
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_FunctionLBrace);
2408+
23542409
Tokens = annotate("struct Test {\n"
23552410
" Test()\n"
23562411
" : l([] {\n"

0 commit comments

Comments
 (0)