Skip to content

Commit 4a7bf42

Browse files
authored
[clang-format] Don't count template template parameter as declaration (#95025)
In ContinuationIndenter::mustBreak, a break is required between a template declaration and the function/class declaration it applies to, if the template declaration spans multiple lines. However, this also includes template template parameters, which can cause extra erroneous line breaks in some declarations. This patch makes template template parameters not be counted as template declarations. Fixes #93793 Fixes #48746
1 parent 8e9c6bf commit 4a7bf42

File tree

2 files changed

+36
-11
lines changed

2 files changed

+36
-11
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class AnnotatingParser {
127127
SmallVector<ScopeType> &Scopes)
128128
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
129129
IsCpp(Style.isCpp()), LangOpts(getFormattingLangOpts(Style)),
130-
Keywords(Keywords), Scopes(Scopes) {
130+
Keywords(Keywords), Scopes(Scopes), TemplateDeclarationDepth(0) {
131131
assert(IsCpp == LangOpts.CXXOperatorNames);
132132
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
133133
resetTokenMetadata();
@@ -1266,16 +1266,22 @@ class AnnotatingParser {
12661266
}
12671267

12681268
bool parseTemplateDeclaration() {
1269-
if (CurrentToken && CurrentToken->is(tok::less)) {
1270-
CurrentToken->setType(TT_TemplateOpener);
1271-
next();
1272-
if (!parseAngle())
1273-
return false;
1274-
if (CurrentToken)
1275-
CurrentToken->Previous->ClosesTemplateDeclaration = true;
1276-
return true;
1277-
}
1278-
return false;
1269+
if (!CurrentToken || CurrentToken->isNot(tok::less))
1270+
return false;
1271+
1272+
CurrentToken->setType(TT_TemplateOpener);
1273+
next();
1274+
1275+
TemplateDeclarationDepth++;
1276+
const bool WellFormed = parseAngle();
1277+
TemplateDeclarationDepth--;
1278+
if (!WellFormed)
1279+
return false;
1280+
1281+
if (CurrentToken && TemplateDeclarationDepth == 0)
1282+
CurrentToken->Previous->ClosesTemplateDeclaration = true;
1283+
1284+
return true;
12791285
}
12801286

12811287
bool consumeToken() {
@@ -3091,6 +3097,8 @@ class AnnotatingParser {
30913097
// same decision irrespective of the decisions for tokens leading up to it.
30923098
// Store this information to prevent this from causing exponential runtime.
30933099
llvm::SmallPtrSet<FormatToken *, 16> NonTemplateLess;
3100+
3101+
int TemplateDeclarationDepth;
30943102
};
30953103

30963104
static const int PrecedenceUnaryOperator = prec::PointerToMember + 1;

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,23 @@ TEST_F(TokenAnnotatorTest, UnderstandsNonTemplateAngleBrackets) {
584584
EXPECT_TOKEN(Tokens[20], tok::greater, TT_BinaryOperator);
585585
}
586586

587+
TEST_F(TokenAnnotatorTest, UnderstandsTemplateTemplateParameters) {
588+
auto Tokens = annotate("template <template <typename...> typename X,\n"
589+
" template <typename...> class Y,\n"
590+
" typename... T>\n"
591+
"class A {};");
592+
ASSERT_EQ(Tokens.size(), 28u) << Tokens;
593+
EXPECT_TOKEN(Tokens[1], tok::less, TT_TemplateOpener);
594+
EXPECT_TOKEN(Tokens[3], tok::less, TT_TemplateOpener);
595+
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
596+
EXPECT_FALSE(Tokens[6]->ClosesTemplateDeclaration);
597+
EXPECT_TOKEN(Tokens[11], tok::less, TT_TemplateOpener);
598+
EXPECT_TOKEN(Tokens[14], tok::greater, TT_TemplateCloser);
599+
EXPECT_FALSE(Tokens[14]->ClosesTemplateDeclaration);
600+
EXPECT_TOKEN(Tokens[21], tok::greater, TT_TemplateCloser);
601+
EXPECT_TRUE(Tokens[21]->ClosesTemplateDeclaration);
602+
}
603+
587604
TEST_F(TokenAnnotatorTest, UnderstandsWhitespaceSensitiveMacros) {
588605
FormatStyle Style = getLLVMStyle();
589606
Style.WhitespaceSensitiveMacros.push_back("FOO");

0 commit comments

Comments
 (0)