#include "Macros.h"
#include "UnwrappedLineParser.h"
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Debug.h"
#include <cassert>
#define DEBUG_TYPE "format-reconstruct"
namespace clang {
namespace format {
template <typename T>
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);
First = false;
for (const auto &Child : N.Children) {
forEachToken(Child, Call, N.Tok);
}
}
}
MacroCallReconstructor::MacroCallReconstructor(
unsigned Level,
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
&ActiveExpansions)
: Level(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);
});
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);
assert(!Final.Tokens.empty());
return Final;
}
void MacroCallReconstructor::add(FormatToken *Token,
FormatToken *ExpandedParent, bool First) {
LLVM_DEBUG(
llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: "
<< (ExpandedParent ? ExpandedParent->TokenText : "<null>")
<< ", First: " << First << "\n");
if (!ActiveExpansions.empty() && Token->MacroCtx &&
(Token->MacroCtx->Role != MR_Hidden ||
ActiveExpansions.size() != Token->MacroCtx->ExpandedFrom.size())) {
if ( reconstructActiveCallUntil(Token))
First = true;
}
prepareParent(ExpandedParent, First);
if (Token->MacroCtx) {
reconstruct(Token);
} else {
appendToken(Token);
}
}
void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
bool NewLine) {
LLVM_DEBUG({
llvm::dbgs() << "ParentMap:\n";
debugParentMap();
});
FormatToken *Parent = getParentInResult(ExpandedParent);
LLVM_DEBUG(llvm::dbgs() << "MCR: New parent: "
<< (Parent ? Parent->TokenText : "<null>") << "\n");
FormatToken *OpenMacroParent = nullptr;
if (!MacroCallStructure.empty()) {
OpenMacroParent =
getParentInResult(MacroCallStructure.back().MacroCallLParen);
LLVM_DEBUG(llvm::dbgs()
<< "MacroCallLParen: "
<< MacroCallStructure.back().MacroCallLParen->TokenText
<< ", OpenMacroParent: "
<< (OpenMacroParent ? OpenMacroParent->TokenText : "<null>")
<< "\n");
}
if (NewLine ||
(!ActiveReconstructedLines.back()->Tokens.empty() &&
Parent == ActiveReconstructedLines.back()->Tokens.back()->Tok)) {
while (ActiveReconstructedLines.back()->Tokens.empty() ||
(Parent != ActiveReconstructedLines.back()->Tokens.back()->Tok &&
ActiveReconstructedLines.back()->Tokens.back()->Tok !=
OpenMacroParent)) {
ActiveReconstructedLines.pop_back();
assert(!ActiveReconstructedLines.empty());
}
assert(!ActiveReconstructedLines.empty());
ActiveReconstructedLines.back()->Tokens.back()->Children.push_back(
std::make_unique<ReconstructedLine>());
ActiveReconstructedLines.push_back(
&*ActiveReconstructedLines.back()->Tokens.back()->Children.back());
} else if (parentLine().Tokens.back()->Tok != Parent) {
while (Parent != parentLine().Tokens.back()->Tok &&
parentLine().Tokens.back()->Tok &&
parentLine().Tokens.back()->Tok != OpenMacroParent) {
ActiveReconstructedLines.pop_back();
assert(!ActiveReconstructedLines.empty());
}
}
assert(!ActiveReconstructedLines.empty());
}
FormatToken *MacroCallReconstructor::getParentInResult(FormatToken *Parent) {
FormatToken *Mapped = SpelledParentToReconstructedParent.lookup(Parent);
if (!Mapped)
return Parent;
for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) {
Parent = Mapped;
}
Parent->MacroParent = true;
return Parent;
}
void MacroCallReconstructor::reconstruct(FormatToken *Token) {
assert(Token->MacroCtx);
if (Token->MacroCtx->StartOfExpansion) {
startReconstruction(Token);
if (Token->MacroCtx->Role != MR_Hidden) {
reconstructActiveCallUntil(Token);
}
}
assert(!ActiveExpansions.empty());
if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) {
assert(ActiveExpansions.size() == Token->MacroCtx->ExpandedFrom.size());
if (Token->MacroCtx->Role != MR_Hidden) {
assert(ActiveExpansions.back().SpelledI->Tok == Token);
processNextReconstructed();
} else if (!currentLine()->Tokens.empty()) {
SpelledParentToReconstructedParent[Token] =
currentLine()->Tokens.back()->Tok;
} else {
for (auto I = ActiveReconstructedLines.rbegin(),
E = ActiveReconstructedLines.rend();
I != E; ++I) {
if (!(*I)->Tokens.empty()) {
SpelledParentToReconstructedParent[Token] = (*I)->Tokens.back()->Tok;
break;
}
}
}
}
if (Token->MacroCtx->EndOfExpansion)
endReconstruction(Token);
}
void MacroCallReconstructor::startReconstruction(FormatToken *Token) {
assert(Token->MacroCtx);
assert(!Token->MacroCtx->ExpandedFrom.empty());
assert(ActiveExpansions.size() <= Token->MacroCtx->ExpandedFrom.size());
#ifndef NDEBUG
for (size_t I = 0; I < ActiveExpansions.size(); ++I) {
assert(ActiveExpansions[I].ID ==
Token->MacroCtx
->ExpandedFrom[Token->MacroCtx->ExpandedFrom.size() - 1 - I]);
}
#endif
ArrayRef<FormatToken *> StartedMacros =
makeArrayRef(Token->MacroCtx->ExpandedFrom)
.drop_back(ActiveExpansions.size());
assert(StartedMacros.size() == Token->MacroCtx->StartOfExpansion);
for (FormatToken *ID : llvm::reverse(StartedMacros)) {
#ifndef NDEBUG
State = InProgress;
#endif
auto IU = IdToReconstructed.find(ID);
assert(IU != IdToReconstructed.end());
ActiveExpansions.push_back(
{ID, IU->second->Tokens.begin(), IU->second->Tokens.end()});
processNextReconstructed();
if (ActiveExpansions.back().SpelledI == ActiveExpansions.back().SpelledE)
continue;
if (ActiveExpansions.back().SpelledI->Tok->is(tok::l_paren)) {
processNextReconstructed();
}
}
}
bool MacroCallReconstructor::reconstructActiveCallUntil(FormatToken *Token) {
assert(!ActiveExpansions.empty());
bool PassedMacroComma = false;
while (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE &&
ActiveExpansions.back().SpelledI->Tok != Token) {
PassedMacroComma = processNextReconstructed() || PassedMacroComma;
}
return PassedMacroComma;
}
void MacroCallReconstructor::endReconstruction(FormatToken *Token) {
assert(Token->MacroCtx &&
(ActiveExpansions.size() >= Token->MacroCtx->EndOfExpansion));
for (size_t I = 0; I < Token->MacroCtx->EndOfExpansion; ++I) {
#ifndef NDEBUG
for (auto T = ActiveExpansions.back().SpelledI;
T != ActiveExpansions.back().SpelledE; ++T) {
FormatToken *Token = T->Tok;
bool ClosingParen = (std::next(T) == ActiveExpansions.back().SpelledE ||
std::next(T)->Tok->isTrailingComment()) &&
!Token->MacroCtx && Token->is(tok::r_paren);
bool TrailingComment = Token->isTrailingComment();
bool PreviousLevel =
Token->MacroCtx &&
(ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size());
if (!ClosingParen && !TrailingComment && !PreviousLevel) {
llvm::dbgs() << "At token: " << Token->TokenText << "\n";
}
}
#endif
for (auto T = ActiveExpansions.back().SpelledI;
T != ActiveExpansions.back().SpelledE; ++T) {
processNextReconstructed();
}
ActiveExpansions.pop_back();
}
}
void MacroCallReconstructor::debugParentMap() const {
llvm::DenseSet<FormatToken *> Values;
for (const auto &P : SpelledParentToReconstructedParent)
Values.insert(P.second);
for (const auto &P : SpelledParentToReconstructedParent) {
if (Values.contains(P.first))
continue;
llvm::dbgs() << (P.first ? P.first->TokenText : "<null>");
for (auto I = SpelledParentToReconstructedParent.find(P.first),
E = SpelledParentToReconstructedParent.end();
I != E; I = SpelledParentToReconstructedParent.find(I->second)) {
llvm::dbgs() << " -> " << (I->second ? I->second->TokenText : "<null>");
}
llvm::dbgs() << "\n";
}
}
bool MacroCallReconstructor::processNextReconstructed() {
FormatToken *Token = ActiveExpansions.back().SpelledI->Tok;
++ActiveExpansions.back().SpelledI;
if (Token->MacroCtx) {
if (Token->MacroCtx->Role == MR_Hidden) {
return false;
}
if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) {
return false;
}
}
if (!Token->MacroCtx) {
if (Token->is(tok::l_paren)) {
MacroCallStructure.push_back(MacroCallState(
currentLine(), parentLine().Tokens.back()->Tok, Token));
SpelledParentToReconstructedParent[MacroCallStructure.back()
.ParentLastToken] = Token;
appendToken(Token);
prepareParent(Token, true);
Token->MacroParent = true;
return false;
}
if (!MacroCallStructure.empty()) {
if (Token->is(tok::comma)) {
SpelledParentToReconstructedParent
[MacroCallStructure.back().Line->Tokens.back()->Tok] = Token;
Token->MacroParent = true;
appendToken(Token, MacroCallStructure.back().Line);
prepareParent(Token, true);
return true;
}
if (Token->is(tok::r_paren)) {
appendToken(Token, MacroCallStructure.back().Line);
SpelledParentToReconstructedParent.erase(
MacroCallStructure.back().ParentLastToken);
MacroCallStructure.pop_back();
return false;
}
}
}
appendToken(Token);
return false;
}
void MacroCallReconstructor::finalize() {
#ifndef NDEBUG
assert(State != Finalized && finished());
State = Finalized;
#endif
assert(Result.Tokens.size() == 1 && !Result.Tokens.front()->Children.empty());
LLVM_DEBUG({
llvm::dbgs() << "Finalizing reconstructed lines:\n";
debug(Result, 0);
});
LineNode &Top = *Result.Tokens.front();
auto *I = Top.Children.begin();
LineNode *Last = (*I)->Tokens.back().get();
++I;
for (auto *E = Top.Children.end(); I != E; ++I) {
assert(Last->Children.empty());
Last->Children.push_back(std::move(*I));
Last->Tok->MacroParent = true;
Last = Last->Children.back()->Tokens.back().get();
}
Top.Children.resize(1);
}
void MacroCallReconstructor::appendToken(FormatToken *Token,
ReconstructedLine *L) {
L = L ? L : currentLine();
LLVM_DEBUG(llvm::dbgs() << "-> " << Token->TokenText << "\n");
L->Tokens.push_back(std::make_unique<LineNode>(Token));
}
UnwrappedLine
MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line,
int Level) {
UnwrappedLine Result;
Result.Level = Level;
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();
}
}
return Result;
}
void MacroCallReconstructor::debug(const ReconstructedLine &Line, int Level) {
for (int i = 0; i < Level; ++i)
llvm::dbgs() << " ";
for (const auto &N : Line.Tokens) {
if (!N)
continue;
if (N->Tok)
llvm::dbgs() << N->Tok->TokenText << " ";
for (const auto &Child : N->Children) {
llvm::dbgs() << "\n";
debug(*Child, Level + 1);
for (int i = 0; i < Level; ++i)
llvm::dbgs() << " ";
}
}
llvm::dbgs() << "\n";
}
MacroCallReconstructor::ReconstructedLine &
MacroCallReconstructor::parentLine() {
return **std::prev(std::prev(ActiveReconstructedLines.end()));
}
MacroCallReconstructor::ReconstructedLine *
MacroCallReconstructor::currentLine() {
return ActiveReconstructedLines.back();
}
MacroCallReconstructor::MacroCallState::MacroCallState(
MacroCallReconstructor::ReconstructedLine *Line,
FormatToken *ParentLastToken, FormatToken *MacroCallLParen)
: Line(Line), ParentLastToken(ParentLastToken),
MacroCallLParen(MacroCallLParen) {
LLVM_DEBUG(
llvm::dbgs() << "ParentLastToken: "
<< (ParentLastToken ? ParentLastToken->TokenText : "<null>")
<< "\n");
assert(MacroCallLParen->is(tok::l_paren));
}
} }