Skip to content

Commit d1b412a

Browse files
author
Jonathan Coe
committed
[clang-format] Correct line breaks in C# generic type constraints
Reviewers: krasimir Reviewed By: krasimir Subscribers: cfe-commits Tags: #clang-format, #clang Differential Revision: https://reviews.llvm.org/D77064
1 parent 38aebe5 commit d1b412a

File tree

4 files changed

+27
-2
lines changed

4 files changed

+27
-2
lines changed

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,11 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
346346
Current.startsSequence(TT_SelectorName, tok::colon, tok::caret)) {
347347
return true;
348348
}
349+
// Avoid producing inconsistent states by requiring breaks where they are not
350+
// permitted for C# generic type constraints.
351+
if (State.Stack.back().IsCSharpGenericTypeConstraint &&
352+
Previous.isNot(TT_CSharpGenericTypeConstraintComma))
353+
return false;
349354
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
350355
(Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
351356
Style.isCpp() &&

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,15 +1060,20 @@ class AnnotatingParser {
10601060
}
10611061

10621062
void parseCSharpGenericTypeConstraint() {
1063+
int OpenAngleBracketsCount = 0;
10631064
while (CurrentToken) {
10641065
if (CurrentToken->is(tok::less)) {
10651066
// parseAngle is too greedy and will consume the whole line.
10661067
CurrentToken->Type = TT_TemplateOpener;
1068+
++OpenAngleBracketsCount;
10671069
next();
10681070
} else if (CurrentToken->is(tok::greater)) {
10691071
CurrentToken->Type = TT_TemplateCloser;
1072+
--OpenAngleBracketsCount;
10701073
next();
1071-
} else if (CurrentToken->is(tok::comma)) {
1074+
} else if (CurrentToken->is(tok::comma) && OpenAngleBracketsCount == 0) {
1075+
// We allow line breaks after GenericTypeConstraintComma's
1076+
// so do not flag commas in Generics as GenericTypeConstraintComma's.
10721077
CurrentToken->Type = TT_CSharpGenericTypeConstraintComma;
10731078
next();
10741079
} else if (CurrentToken->is(Keywords.kw_where)) {

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,6 +2340,12 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
23402340
}
23412341
if (FormatTok->Tok.is(tok::semi))
23422342
return;
2343+
if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
2344+
addUnwrappedLine();
2345+
nextToken();
2346+
parseCSharpGenericTypeConstraint();
2347+
break;
2348+
}
23432349
nextToken();
23442350
}
23452351
}

clang/unittests/Format/FormatTestCSharp.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ var myDict = new Dictionary<string, string> {
564564

565565
TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
566566
FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
567-
567+
568568
verifyFormat(R"(//
569569
private MySet<Node>[] setPoints = {
570570
new Point<Node>(),
@@ -710,6 +710,15 @@ class ItemFactory<T>
710710
IAnotherInterfaceStill<T> {})",
711711
Style);
712712

713+
Style.ColumnLimit = 50; // Force lines to be wrapped.
714+
verifyFormat(R"(//
715+
class ItemFactory<T, U>
716+
where T : new(),
717+
IAnInterface<T>,
718+
IAnotherInterface<T, U>,
719+
IAnotherInterfaceStill<T, U> {})",
720+
Style);
721+
713722
// In other languages `where` can be used as a normal identifier.
714723
// This example is in C++!
715724
verifyFormat(R"(//

0 commit comments

Comments
 (0)