Skip to content

Commit

Permalink
[ClangFormat] Fix formatting bugs. (llvm#76245)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
r4nt authored and justinfargnoli committed Jan 28, 2024
1 parent 9c7e770 commit 7b2d95c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 19 deletions.
25 changes: 17 additions & 8 deletions clang/lib/Format/FormatToken.h
Expand Up @@ -275,14 +275,15 @@ class AnnotatedLine;
struct FormatToken {
FormatToken()
: HasUnescapedNewline(false), IsMultiline(false), IsFirst(false),
MustBreakBefore(false), IsUnterminatedLiteral(false),
CanBreakBefore(false), ClosesTemplateDeclaration(false),
StartsBinaryExpression(false), EndsBinaryExpression(false),
PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false),
Finalized(false), ClosesRequiresClause(false),
EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
TypeIsFinalized(false), Type(TT_Unknown) {}
MustBreakBefore(false), MustBreakBeforeFinalized(false),
IsUnterminatedLiteral(false), CanBreakBefore(false),
ClosesTemplateDeclaration(false), StartsBinaryExpression(false),
EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false),
ContinuesLineCommentSection(false), Finalized(false),
ClosesRequiresClause(false), EndsCppAttributeGroup(false),
BlockKind(BK_Unknown), Decision(FD_Unformatted),
PackingKind(PPK_Inconclusive), TypeIsFinalized(false),
Type(TT_Unknown) {}

/// The \c Token.
Token Tok;
Expand Down Expand Up @@ -318,6 +319,10 @@ struct FormatToken {
/// before the token.
unsigned MustBreakBefore : 1;

/// Whether MustBreakBefore is finalized during parsing and must not
/// be reset between runs.
unsigned MustBreakBeforeFinalized : 1;

/// Set to \c true if this token is an unterminated literal.
unsigned IsUnterminatedLiteral : 1;

Expand Down Expand Up @@ -416,10 +421,14 @@ struct FormatToken {
/// to another one please use overwriteFixedType, or even better remove the
/// need to reassign the type.
void setFinalizedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
Type = T;
TypeIsFinalized = true;
}
void overwriteFixedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
TypeIsFinalized = false;
setType(T);
}
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/Format/TokenAnnotator.cpp
Expand Up @@ -2769,13 +2769,6 @@ class ExpressionParser {
// Consume operators with higher precedence.
parse(Precedence + 1);

// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Current && Current->MacroParent)
break;

int CurrentPrecedence = getCurrentPrecedence();

if (Precedence == CurrentPrecedence && Current &&
Expand Down Expand Up @@ -2919,6 +2912,13 @@ class ExpressionParser {

void addFakeParenthesis(FormatToken *Start, prec::Level Precedence,
FormatToken *End = nullptr) {
// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Start->MacroParent)
return;

Start->FakeLParens.push_back(Precedence);
if (Precedence > prec::Unknown)
Start->StartsBinaryExpression = true;
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Format/UnwrappedLineFormatter.cpp
Expand Up @@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) {
// will be modified as unexpanded arguments (as part of the macro call
// formatting) in the next pass.
Tok->MacroCtx->Role = MR_UnexpandedArg;
// Reset whether spaces are required before this token, as that is context
// dependent, and that context may change when formatting the macro call.
// For example, given M(x) -> 2 * x, and the macro call M(var),
// the token 'var' will have SpacesRequiredBefore = 1 after being
// Reset whether spaces or a line break are required before this token, as
// that is context dependent, and that context may change when formatting
// the macro call. For example, given M(x) -> 2 * x, and the macro call
// M(var), the token 'var' will have SpacesRequiredBefore = 1 after being
// formatted as part of the expanded macro, but SpacesRequiredBefore = 0
// for its position within the macro call.
Tok->SpacesRequiredBefore = 0;
if (!Tok->MustBreakBeforeFinalized)
Tok->MustBreakBefore = 0;
} else {
Tok->Finalized = true;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.cpp
Expand Up @@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
conditionalCompilationEnd();
FormatTok = Tokens->getNextToken();
FormatTok->MustBreakBefore = true;
FormatTok->MustBreakBeforeFinalized = true;
}

auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine,
Expand Down Expand Up @@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) {
Line->Tokens.push_back(UnwrappedLineNode(Tok));
if (MustBreakBeforeNextToken) {
Line->Tokens.back().Tok->MustBreakBefore = true;
Line->Tokens.back().Tok->MustBreakBeforeFinalized = true;
MustBreakBeforeNextToken = false;
}
}
Expand Down
32 changes: 32 additions & 0 deletions clang/unittests/Format/FormatTestMacroExpansion.cpp
Expand Up @@ -255,6 +255,38 @@ TEST_F(FormatTestMacroExpansion,
Style);
}

TEST_F(FormatTestMacroExpansion, CommaAsOperator) {
FormatStyle Style = getGoogleStyleWithColumns(42);
Style.Macros.push_back("MACRO(a, b, c)=a=(b); if(x) c");
verifyFormat("MACRO(auto a,\n"
" looooongfunction(first, second,\n"
" third),\n"
" fourth);",
Style);
}

TEST_F(FormatTestMacroExpansion, ForcedBreakDiffers) {
FormatStyle Style = getGoogleStyleWithColumns(40);
Style.Macros.push_back("MACRO(a, b)=a=(b)");
verifyFormat("//\n"
"MACRO(const type variable,\n"
" functtioncall(\n"
" first, longsecondarg, third));",
Style);
}

TEST_F(FormatTestMacroExpansion,
PreferNotBreakingBetweenReturnTypeAndFunction) {
FormatStyle Style = getGoogleStyleWithColumns(22);
Style.Macros.push_back("MOCK_METHOD(r, n, a)=r n a");
// In the expanded code, we parse a full function signature, and afterwards
// know that we prefer not to break before the function name.
verifyFormat("MOCK_METHOD(\n"
" type, variable,\n"
" (type));",
Style);
}

} // namespace
} // namespace test
} // namespace format
Expand Down

0 comments on commit 7b2d95c

Please sign in to comment.