Skip to content

[ClangFormat] Fix indent in child lines within a macro argument. #82523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 45 additions & 23 deletions clang/lib/Format/MacroCallReconstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void forEachToken(const UnwrappedLine &Line, const T &Call,
FormatToken *Parent = nullptr) {
bool First = true;
for (const auto &N : Line.Tokens) {
Call(N.Tok, Parent, First);
Call(N.Tok, Parent, First, Line.Level);
First = false;
for (const auto &Child : N.Children)
forEachToken(Child, Call, N.Tok);
Expand All @@ -44,26 +44,25 @@ MacroCallReconstructor::MacroCallReconstructor(
unsigned Level,
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
&ActiveExpansions)
: Level(Level), IdToReconstructed(ActiveExpansions) {
: Result(Level), IdToReconstructed(ActiveExpansions) {
Result.Tokens.push_back(std::make_unique<LineNode>());
ActiveReconstructedLines.push_back(&Result);
}

void MacroCallReconstructor::addLine(const UnwrappedLine &Line) {
assert(State != Finalized);
LLVM_DEBUG(llvm::dbgs() << "MCR: new line...\n");
forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First) {
add(Token, Parent, First);
});
forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First,
unsigned Level) { add(Token, Parent, First, Level); });
assert(InProgress || finished());
}

UnwrappedLine MacroCallReconstructor::takeResult() && {
finalize();
assert(Result.Tokens.size() == 1 &&
Result.Tokens.front()->Children.size() == 1);
UnwrappedLine Final =
createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level);
UnwrappedLine Final = createUnwrappedLine(
*Result.Tokens.front()->Children.front(), Result.Level);
assert(!Final.Tokens.empty());
return Final;
}
Expand All @@ -72,7 +71,8 @@ UnwrappedLine MacroCallReconstructor::takeResult() && {
// ExpandedParent in the incoming unwrapped line. \p First specifies whether it
// is the first token in a given unwrapped line.
void MacroCallReconstructor::add(FormatToken *Token,
FormatToken *ExpandedParent, bool First) {
FormatToken *ExpandedParent, bool First,
unsigned Level) {
LLVM_DEBUG(
llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: "
<< (ExpandedParent ? ExpandedParent->TokenText : "<null>")
Expand Down Expand Up @@ -102,7 +102,7 @@ void MacroCallReconstructor::add(FormatToken *Token,
First = true;
}

prepareParent(ExpandedParent, First);
prepareParent(ExpandedParent, First, Level);

if (Token->MacroCtx) {
// If this token was generated by a macro call, add the reconstructed
Expand All @@ -129,7 +129,7 @@ void MacroCallReconstructor::add(FormatToken *Token,
// is the parent of ActiveReconstructedLines.back() in the reconstructed
// unwrapped line.
void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
bool NewLine) {
bool NewLine, unsigned Level) {
LLVM_DEBUG({
llvm::dbgs() << "ParentMap:\n";
debugParentMap();
Expand Down Expand Up @@ -172,7 +172,7 @@ void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
}
assert(!ActiveReconstructedLines.empty());
ActiveReconstructedLines.back()->Tokens.back()->Children.push_back(
std::make_unique<ReconstructedLine>());
std::make_unique<ReconstructedLine>(Level));
ActiveReconstructedLines.push_back(
&*ActiveReconstructedLines.back()->Tokens.back()->Children.back());
} else if (parentLine().Tokens.back()->Tok != Parent) {
Expand Down Expand Up @@ -424,7 +424,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
SpelledParentToReconstructedParent[MacroCallStructure.back()
.ParentLastToken] = Token;
appendToken(Token);
prepareParent(Token, /*NewLine=*/true);
prepareParent(Token, /*NewLine=*/true,
MacroCallStructure.back().Line->Level);
Token->MacroParent = true;
return false;
}
Expand All @@ -435,7 +436,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
[MacroCallStructure.back().Line->Tokens.back()->Tok] = Token;
Token->MacroParent = true;
appendToken(Token, MacroCallStructure.back().Line);
prepareParent(Token, /*NewLine=*/true);
prepareParent(Token, /*NewLine=*/true,
MacroCallStructure.back().Line->Level);
return true;
}
if (Token->is(tok::r_paren)) {
Expand Down Expand Up @@ -509,16 +511,36 @@ MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line,
for (const auto &N : Line.Tokens) {
Result.Tokens.push_back(N->Tok);
UnwrappedLineNode &Current = Result.Tokens.back();
for (const auto &Child : N->Children) {
if (Child->Tokens.empty())
continue;
Current.Children.push_back(createUnwrappedLine(*Child, Level + 1));
}
if (Current.Children.size() == 1 &&
Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
Result.Tokens.splice(Result.Tokens.end(),
Current.Children.front().Tokens);
Current.Children.clear();
auto NumChildren =
std::count_if(N->Children.begin(), N->Children.end(),
[](const auto &Child) { return !Child->Tokens.empty(); });
if (NumChildren == 1 && Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
// If we only have one child, and the child is due to a macro expansion
// (either attached to a left parenthesis or comma), merge the child into
// the current line to prevent forced breaks for macro arguments.
auto *Child = std::find_if(
N->Children.begin(), N->Children.end(),
[](const auto &Child) { return !Child->Tokens.empty(); });
auto Line = createUnwrappedLine(**Child, Level);
Result.Tokens.splice(Result.Tokens.end(), Line.Tokens);
} else if (NumChildren > 0) {
// When there are multiple children with different indent, make sure that
// we indent them:
// 1. One level below the current line's level.
// 2. At the correct level relative to each other.
unsigned MinChildLevel =
std::min_element(N->Children.begin(), N->Children.end(),
[](const auto &E1, const auto &E2) {
return E1->Level < E2->Level;
})
->get()
->Level;
for (const auto &Child : N->Children) {
if (Child->Tokens.empty())
continue;
Current.Children.push_back(createUnwrappedLine(
*Child, Level + 1 + (Child->Level - MinChildLevel)));
}
}
}
return Result;
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Format/Macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,9 @@ class MacroCallReconstructor {
UnwrappedLine takeResult() &&;

private:
void add(FormatToken *Token, FormatToken *ExpandedParent, bool First);
void prepareParent(FormatToken *ExpandedParent, bool First);
void add(FormatToken *Token, FormatToken *ExpandedParent, bool First,
unsigned Level);
void prepareParent(FormatToken *ExpandedParent, bool First, unsigned Level);
FormatToken *getParentInResult(FormatToken *Parent);
void reconstruct(FormatToken *Token);
void startReconstruction(FormatToken *Token);
Expand Down Expand Up @@ -272,6 +273,8 @@ class MacroCallReconstructor {
// FIXME: Investigate changing UnwrappedLine to a pointer type and using it
// instead of rolling our own type.
struct ReconstructedLine {
explicit ReconstructedLine(unsigned Level) : Level(Level) {}
unsigned Level;
llvm::SmallVector<std::unique_ptr<LineNode>> Tokens;
};

Expand Down Expand Up @@ -373,9 +376,6 @@ class MacroCallReconstructor {
// \- )
llvm::SmallVector<MacroCallState> MacroCallStructure;

// Level the generated UnwrappedLine will be at.
const unsigned Level;

// Maps from identifier of the macro call to an unwrapped line containing
// all tokens of the macro call.
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ class ScopedDeclarationState {

} // end anonymous namespace

std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line) {
llvm::raw_os_ostream OS(Stream);
printLine(OS, Line);
return Stream;
}

class ScopedLineState {
public:
ScopedLineState(UnwrappedLineParser &Parser,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ struct UnwrappedLineNode {
SmallVector<UnwrappedLine, 0> Children;
};

std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line);

} // end namespace format
} // end namespace clang

Expand Down
21 changes: 17 additions & 4 deletions clang/unittests/Format/FormatTestMacroExpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ TEST_F(FormatTestMacroExpansion, UnexpandConfiguredMacros) {
)",
Style);
verifyIncompleteFormat("ID3({, ID(a *b),\n"
" ;\n"
" ;\n"
" });",
Style);

Expand Down Expand Up @@ -131,9 +131,9 @@ ID(CALL(CALL(a * b)));
EXPECT_EQ(R"(
ID3(
{
CLASS
a *b;
};
CLASS
a *b;
};
},
ID(x *y);
,
Expand Down Expand Up @@ -287,6 +287,19 @@ TEST_F(FormatTestMacroExpansion,
Style);
}

TEST_F(FormatTestMacroExpansion, IndentChildrenWithinMacroCall) {
FormatStyle Style = getGoogleStyleWithColumns(22);
Style.Macros.push_back("MACRO(a, b)=a=(b)");
verifyFormat("void f() {\n"
" MACRO(a b, call([] {\n"
" if (expr) {\n"
" indent();\n"
" }\n"
" }));\n"
"}",
Style);
}

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