Skip to content

Commit b7770be

Browse files
authored
[ClangFormat] Fix formatting bugs. (#76245)
1. There are multiple calls to addFakeParenthesis; move the guard to not assign fake parenthesis into the function to make sure we cover all calls. 2. MustBreakBefore can be set on a token in two cases: either during unwrapped line parsing, or later, during token annotation. We must keep the latter, but reset the former. 3. Added a test to document that the intended behavior of preferring not to break between a return type and a function identifier. For example, with MOCK_METHOD(r, n, a)=r n a, the code MOCK_METHOD(void, f, (int a, int b)) should prefer the same breaks as the expanded void f(int a, int b).
1 parent 5e40661 commit b7770be

File tree

5 files changed

+64
-19
lines changed

5 files changed

+64
-19
lines changed

clang/lib/Format/FormatToken.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,15 @@ class AnnotatedLine;
275275
struct FormatToken {
276276
FormatToken()
277277
: HasUnescapedNewline(false), IsMultiline(false), IsFirst(false),
278-
MustBreakBefore(false), IsUnterminatedLiteral(false),
279-
CanBreakBefore(false), ClosesTemplateDeclaration(false),
280-
StartsBinaryExpression(false), EndsBinaryExpression(false),
281-
PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false),
282-
Finalized(false), ClosesRequiresClause(false),
283-
EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
284-
Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
285-
TypeIsFinalized(false), Type(TT_Unknown) {}
278+
MustBreakBefore(false), MustBreakBeforeFinalized(false),
279+
IsUnterminatedLiteral(false), CanBreakBefore(false),
280+
ClosesTemplateDeclaration(false), StartsBinaryExpression(false),
281+
EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false),
282+
ContinuesLineCommentSection(false), Finalized(false),
283+
ClosesRequiresClause(false), EndsCppAttributeGroup(false),
284+
BlockKind(BK_Unknown), Decision(FD_Unformatted),
285+
PackingKind(PPK_Inconclusive), TypeIsFinalized(false),
286+
Type(TT_Unknown) {}
286287

287288
/// The \c Token.
288289
Token Tok;
@@ -318,6 +319,10 @@ struct FormatToken {
318319
/// before the token.
319320
unsigned MustBreakBefore : 1;
320321

322+
/// Whether MustBreakBefore is finalized during parsing and must not
323+
/// be reset between runs.
324+
unsigned MustBreakBeforeFinalized : 1;
325+
321326
/// Set to \c true if this token is an unterminated literal.
322327
unsigned IsUnterminatedLiteral : 1;
323328

@@ -416,10 +421,14 @@ struct FormatToken {
416421
/// to another one please use overwriteFixedType, or even better remove the
417422
/// need to reassign the type.
418423
void setFinalizedType(TokenType T) {
424+
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
425+
return;
419426
Type = T;
420427
TypeIsFinalized = true;
421428
}
422429
void overwriteFixedType(TokenType T) {
430+
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
431+
return;
423432
TypeIsFinalized = false;
424433
setType(T);
425434
}

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,13 +2769,6 @@ class ExpressionParser {
27692769
// Consume operators with higher precedence.
27702770
parse(Precedence + 1);
27712771

2772-
// Do not assign fake parenthesis to tokens that are part of an
2773-
// unexpanded macro call. The line within the macro call contains
2774-
// the parenthesis and commas, and we will not find operators within
2775-
// that structure.
2776-
if (Current && Current->MacroParent)
2777-
break;
2778-
27792772
int CurrentPrecedence = getCurrentPrecedence();
27802773

27812774
if (Precedence == CurrentPrecedence && Current &&
@@ -2919,6 +2912,13 @@ class ExpressionParser {
29192912

29202913
void addFakeParenthesis(FormatToken *Start, prec::Level Precedence,
29212914
FormatToken *End = nullptr) {
2915+
// Do not assign fake parenthesis to tokens that are part of an
2916+
// unexpanded macro call. The line within the macro call contains
2917+
// the parenthesis and commas, and we will not find operators within
2918+
// that structure.
2919+
if (Start->MacroParent)
2920+
return;
2921+
29222922
Start->FakeLParens.push_back(Precedence);
29232923
if (Precedence > prec::Unknown)
29242924
Start->StartsBinaryExpression = true;

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) {
954954
// will be modified as unexpanded arguments (as part of the macro call
955955
// formatting) in the next pass.
956956
Tok->MacroCtx->Role = MR_UnexpandedArg;
957-
// Reset whether spaces are required before this token, as that is context
958-
// dependent, and that context may change when formatting the macro call.
959-
// For example, given M(x) -> 2 * x, and the macro call M(var),
960-
// the token 'var' will have SpacesRequiredBefore = 1 after being
957+
// Reset whether spaces or a line break are required before this token, as
958+
// that is context dependent, and that context may change when formatting
959+
// the macro call. For example, given M(x) -> 2 * x, and the macro call
960+
// M(var), the token 'var' will have SpacesRequiredBefore = 1 after being
961961
// formatted as part of the expanded macro, but SpacesRequiredBefore = 0
962962
// for its position within the macro call.
963963
Tok->SpacesRequiredBefore = 0;
964+
if (!Tok->MustBreakBeforeFinalized)
965+
Tok->MustBreakBefore = 0;
964966
} else {
965967
Tok->Finalized = true;
966968
}

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
46754675
conditionalCompilationEnd();
46764676
FormatTok = Tokens->getNextToken();
46774677
FormatTok->MustBreakBefore = true;
4678+
FormatTok->MustBreakBeforeFinalized = true;
46784679
}
46794680

46804681
auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine,
@@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) {
48914892
Line->Tokens.push_back(UnwrappedLineNode(Tok));
48924893
if (MustBreakBeforeNextToken) {
48934894
Line->Tokens.back().Tok->MustBreakBefore = true;
4895+
Line->Tokens.back().Tok->MustBreakBeforeFinalized = true;
48944896
MustBreakBeforeNextToken = false;
48954897
}
48964898
}

clang/unittests/Format/FormatTestMacroExpansion.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,38 @@ TEST_F(FormatTestMacroExpansion,
255255
Style);
256256
}
257257

258+
TEST_F(FormatTestMacroExpansion, CommaAsOperator) {
259+
FormatStyle Style = getGoogleStyleWithColumns(42);
260+
Style.Macros.push_back("MACRO(a, b, c)=a=(b); if(x) c");
261+
verifyFormat("MACRO(auto a,\n"
262+
" looooongfunction(first, second,\n"
263+
" third),\n"
264+
" fourth);",
265+
Style);
266+
}
267+
268+
TEST_F(FormatTestMacroExpansion, ForcedBreakDiffers) {
269+
FormatStyle Style = getGoogleStyleWithColumns(40);
270+
Style.Macros.push_back("MACRO(a, b)=a=(b)");
271+
verifyFormat("//\n"
272+
"MACRO(const type variable,\n"
273+
" functtioncall(\n"
274+
" first, longsecondarg, third));",
275+
Style);
276+
}
277+
278+
TEST_F(FormatTestMacroExpansion,
279+
PreferNotBreakingBetweenReturnTypeAndFunction) {
280+
FormatStyle Style = getGoogleStyleWithColumns(22);
281+
Style.Macros.push_back("MOCK_METHOD(r, n, a)=r n a");
282+
// In the expanded code, we parse a full function signature, and afterwards
283+
// know that we prefer not to break before the function name.
284+
verifyFormat("MOCK_METHOD(\n"
285+
" type, variable,\n"
286+
" (type));",
287+
Style);
288+
}
289+
258290
} // namespace
259291
} // namespace test
260292
} // namespace format

0 commit comments

Comments
 (0)