Skip to content

Commit 688bc95

Browse files
authored
[clang-format] Add TemplateNames option to help parse C++ angles (#109916)
Closes #109912.
1 parent 98281da commit 688bc95

File tree

9 files changed

+64
-17
lines changed

9 files changed

+64
-17
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6554,6 +6554,15 @@ the configuration (without a prefix: ``Auto``).
65546554
let DAGArgOtherID = (other i32:$other1, i32:$other2);
65556555
let DAGArgBang = (!cast<SomeType>("Some") i32:$src1, i32:$src2)
65566556

6557+
.. _TemplateNames:
6558+
6559+
**TemplateNames** (``List of Strings``) :versionbadge:`clang-format 20` :ref:`<TemplateNames>`
6560+
A vector of non-keyword identifiers that should be interpreted as
6561+
template names.
6562+
6563+
A ``<`` after a template name is annotated as a template opener instead of
6564+
a binary operator.
6565+
65576566
.. _TypeNames:
65586567

65596568
**TypeNames** (``List of Strings``) :versionbadge:`clang-format 17` :ref:`<TypeNames>`

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ clang-format
615615
------------
616616

617617
- Adds ``BreakBinaryOperations`` option.
618+
- Adds ``TemplateNames`` option.
618619

619620
libclang
620621
--------

clang/include/clang/Format/Format.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4974,6 +4974,15 @@ struct FormatStyle {
49744974
/// \version 3.7
49754975
unsigned TabWidth;
49764976

4977+
/// A vector of non-keyword identifiers that should be interpreted as
4978+
/// template names.
4979+
///
4980+
/// A ``<`` after a template name is annotated as a template opener instead of
4981+
/// a binary operator.
4982+
///
4983+
/// \version 20
4984+
std::vector<std::string> TemplateNames;
4985+
49774986
/// A vector of non-keyword identifiers that should be interpreted as type
49784987
/// names.
49794988
///
@@ -5230,6 +5239,7 @@ struct FormatStyle {
52305239
TableGenBreakingDAGArgOperators ==
52315240
R.TableGenBreakingDAGArgOperators &&
52325241
TableGenBreakInsideDAGArg == R.TableGenBreakInsideDAGArg &&
5242+
TabWidth == R.TabWidth && TemplateNames == R.TemplateNames &&
52335243
TabWidth == R.TabWidth && TypeNames == R.TypeNames &&
52345244
TypenameMacros == R.TypenameMacros && UseTab == R.UseTab &&
52355245
VerilogBreakBetweenInstancePorts ==

clang/lib/Format/Format.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ template <> struct MappingTraits<FormatStyle> {
11471147
IO.mapOptional("TableGenBreakInsideDAGArg",
11481148
Style.TableGenBreakInsideDAGArg);
11491149
IO.mapOptional("TabWidth", Style.TabWidth);
1150+
IO.mapOptional("TemplateNames", Style.TemplateNames);
11501151
IO.mapOptional("TypeNames", Style.TypeNames);
11511152
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
11521153
IO.mapOptional("UseTab", Style.UseTab);

clang/lib/Format/FormatToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ namespace format {
179179
TYPE(TrailingReturnArrow) \
180180
TYPE(TrailingUnaryOperator) \
181181
TYPE(TypeDeclarationParen) \
182+
TYPE(TemplateName) \
182183
TYPE(TypeName) \
183184
TYPE(TypenameMacro) \
184185
TYPE(UnaryOperator) \

clang/lib/Format/FormatTokenLexer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ FormatTokenLexer::FormatTokenLexer(
7272
Macros.insert({Identifier, TT_StatementAttributeLikeMacro});
7373
}
7474

75+
for (const auto &TemplateName : Style.TemplateNames)
76+
TemplateNames.insert(&IdentTable.get(TemplateName));
7577
for (const auto &TypeName : Style.TypeNames)
7678
TypeNames.insert(&IdentTable.get(TypeName));
7779
}
@@ -1368,6 +1370,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
13681370
FormatTok->setType(TT_MacroBlockBegin);
13691371
else if (MacroBlockEndRegex.match(Text))
13701372
FormatTok->setType(TT_MacroBlockEnd);
1373+
else if (TemplateNames.contains(Identifier))
1374+
FormatTok->setFinalizedType(TT_TemplateName);
13711375
else if (TypeNames.contains(Identifier))
13721376
FormatTok->setFinalizedType(TT_TypeName);
13731377
}

clang/lib/Format/FormatTokenLexer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class FormatTokenLexer {
129129

130130
llvm::SmallMapVector<IdentifierInfo *, TokenType, 8> Macros;
131131

132-
llvm::SmallPtrSet<IdentifierInfo *, 8> TypeNames;
132+
llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames;
133133

134134
bool FormattingDisabled;
135135

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,36 +149,36 @@ class AnnotatingParser {
149149
}
150150

151151
bool parseAngle() {
152-
if (!CurrentToken || !CurrentToken->Previous)
152+
if (!CurrentToken)
153+
return false;
154+
155+
auto *Left = CurrentToken->Previous; // The '<'.
156+
if (!Left)
153157
return false;
154-
if (NonTemplateLess.count(CurrentToken->Previous) > 0)
158+
159+
if (NonTemplateLess.count(Left) > 0)
155160
return false;
156161

157-
if (const auto &Previous = *CurrentToken->Previous; // The '<'.
158-
Previous.Previous) {
159-
if (Previous.Previous->Tok.isLiteral())
162+
const auto *BeforeLess = Left->Previous;
163+
164+
if (BeforeLess) {
165+
if (BeforeLess->Tok.isLiteral())
160166
return false;
161-
if (Previous.Previous->is(tok::r_brace))
167+
if (BeforeLess->is(tok::r_brace))
162168
return false;
163-
if (Previous.Previous->is(tok::r_paren) && Contexts.size() > 1 &&
164-
(!Previous.Previous->MatchingParen ||
165-
Previous.Previous->MatchingParen->isNot(
166-
TT_OverloadedOperatorLParen))) {
169+
if (BeforeLess->is(tok::r_paren) && Contexts.size() > 1 &&
170+
!(BeforeLess->MatchingParen &&
171+
BeforeLess->MatchingParen->is(TT_OverloadedOperatorLParen))) {
167172
return false;
168173
}
169-
if (Previous.Previous->is(tok::kw_operator) &&
170-
CurrentToken->is(tok::l_paren)) {
174+
if (BeforeLess->is(tok::kw_operator) && CurrentToken->is(tok::l_paren))
171175
return false;
172-
}
173176
}
174177

175-
FormatToken *Left = CurrentToken->Previous;
176178
Left->ParentBracket = Contexts.back().ContextKind;
177179
ScopedContextCreator ContextCreator(*this, tok::less, 12);
178180
Contexts.back().IsExpression = false;
179181

180-
const auto *BeforeLess = Left->Previous;
181-
182182
// If there's a template keyword before the opening angle bracket, this is a
183183
// template parameter, not an argument.
184184
if (BeforeLess && BeforeLess->isNot(tok::kw_template))
@@ -229,6 +229,10 @@ class AnnotatingParser {
229229
next();
230230
return true;
231231
}
232+
if (BeforeLess && BeforeLess->is(TT_TemplateName)) {
233+
next();
234+
continue;
235+
}
232236
if (CurrentToken->is(tok::question) &&
233237
Style.Language == FormatStyle::LK_Java) {
234238
next();

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,6 +3516,23 @@ TEST_F(TokenAnnotatorTest, SplitPenalty) {
35163516
EXPECT_SPLIT_PENALTY(Tokens[7], 23u);
35173517
}
35183518

3519+
TEST_F(TokenAnnotatorTest, TemplateName) {
3520+
constexpr StringRef Code{"return Foo < A || B > (C ^ D);"};
3521+
3522+
auto Tokens = annotate(Code);
3523+
ASSERT_EQ(Tokens.size(), 14u) << Tokens;
3524+
EXPECT_TOKEN(Tokens[2], tok::less, TT_BinaryOperator);
3525+
EXPECT_TOKEN(Tokens[6], tok::greater, TT_BinaryOperator);
3526+
3527+
auto Style = getLLVMStyle();
3528+
Style.TemplateNames.push_back("Foo");
3529+
3530+
Tokens = annotate(Code, Style);
3531+
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_TemplateName);
3532+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
3533+
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
3534+
}
3535+
35193536
} // namespace
35203537
} // namespace format
35213538
} // namespace clang

0 commit comments

Comments
 (0)