[SourceKit] Handle macro arguments in placeholder expansion

Allow macro argument placeholders to expand into trailing closures.

rdar://150550747
This commit is contained in:
Hamish Knight
2025-05-21 18:06:54 +01:00
parent ef74028c85
commit 60952784fc
2 changed files with 92 additions and 23 deletions

View File

@@ -1679,34 +1679,65 @@ private:
public:
const SourceManager &SM;
SourceLoc TargetLoc;
std::pair<Expr *, ArgumentList *> EnclosingCallAndArg;
std::pair<ASTNode, ArgumentList *> EnclosingCallAndArg;
Expr *OuterExpr;
Stmt *OuterStmt;
explicit CallExprFinder(const SourceManager &SM)
:SM(SM) { }
Decl *OuterDecl;
bool checkCallExpr(Expr *E) {
ArgumentList *Args = nullptr;
if (auto *CE = dyn_cast<CallExpr>(E)) {
// Call expression can have argument.
Args = CE->getArgs();
explicit CallExprFinder(const SourceManager &SM) : SM(SM) {}
void checkArgumentList(ArgumentList *Args) {
ASTNode Enclosing;
if (auto *E = Parent.getAsExpr()) {
// Must have a function call or macro parent.
if (!isa<CallExpr, MacroExpansionExpr>(E) ||
E->getArgs() != Args) {
return;
}
// If the outer expression is the call itself, disregard it.
if (OuterExpr == E)
OuterExpr = nullptr;
Enclosing = E;
}
if (!Args)
return false;
if (EnclosingCallAndArg.first)
OuterExpr = EnclosingCallAndArg.first;
EnclosingCallAndArg = {E, Args};
return true;
if (auto *D = Parent.getAsDecl()) {
// Must have a macro decl parent.
auto *MED = dyn_cast<MacroExpansionDecl>(D);
if (!MED || MED->getArgs() != Args)
return;
Enclosing = D;
}
if (!Enclosing)
return;
// If we have an outer enclosing call, update the outer nodes if needed.
if (auto EnclosingCall = EnclosingCallAndArg.first) {
if (!OuterExpr)
OuterExpr = EnclosingCall.dyn_cast<Expr *>();
if (!OuterDecl)
OuterDecl = EnclosingCall.dyn_cast<Decl *>();
}
EnclosingCallAndArg = {Enclosing, Args};
}
MacroWalking getMacroWalkingBehavior() const override {
return MacroWalking::Arguments;
}
PreWalkResult<ArgumentList *>
walkToArgumentListPre(ArgumentList *ArgList) override {
auto SR = ArgList->getSourceRange();
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc))
checkArgumentList(ArgList);
return Action::Continue(ArgList);
}
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
auto SR = E->getSourceRange();
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc) &&
!checkCallExpr(E) && !EnclosingCallAndArg.first) {
!OuterExpr && !EnclosingCallAndArg.first) {
if (!isa<TryExpr>(E) && !isa<AwaitExpr>(E) && !isa<UnsafeExpr>(E) &&
!isa<PrefixUnaryExpr>(E)) {
// We don't want to expand to trailing closures if the call is
@@ -1782,6 +1813,7 @@ private:
EnclosingCallAndArg = {nullptr, nullptr};
OuterExpr = nullptr;
OuterStmt = nullptr;
OuterDecl = nullptr;
TargetLoc = SL;
SF.walk(*this);
return EnclosingCallAndArg.second;
@@ -1791,14 +1823,9 @@ private:
CallExprFinder CEFinder(SM);
auto *Args = CEFinder.findEnclosingCallArg(SF, SL);
if (!Args)
return std::make_pair(Args, false);
if (CEFinder.OuterExpr)
return std::make_pair(Args, false);
if (CEFinder.OuterStmt)
return std::make_pair(Args, false);
return std::make_pair(Args, true);
auto HasOuterNode =
CEFinder.OuterExpr || CEFinder.OuterStmt || CEFinder.OuterDecl;
return std::make_pair(Args, /*useTrailingClosure*/ Args && !HasOuterNode);
}
struct ParamClosureInfo {