[clangd] Refactor forwarding call detection logic

Differential Revision: https://reviews.llvm.org/D130261
This commit is contained in:
Kadir Cetinkaya 2022-07-21 12:41:00 +02:00
parent 1515490c80
commit b5871dfaf3
No known key found for this signature in database
GPG Key ID: E39E36B8D2057ED6

View File

@ -791,51 +791,46 @@ private:
})) {
return;
}
auto OptPackLocation = findPack(Args);
if (OptPackLocation) {
size_t PackLocation = OptPackLocation.value();
ArrayRef<ParmVarDecl *> MatchingParams =
Callee->parameters().slice(PackLocation, Parameters.size());
// Check whether the function has a parameter pack as the last template
// parameter
if (const auto *TTPT = getFunctionPackType(Callee)) {
// In this case: Separate the parameters into head, pack and tail
auto IsExpandedPack = [&](const ParmVarDecl *P) {
return getUnderylingPackType(P) == TTPT;
};
ForwardingInfo FI;
FI.Head = MatchingParams.take_until(IsExpandedPack);
FI.Pack = MatchingParams.drop_front(FI.Head.size())
.take_while(IsExpandedPack);
FI.Tail = MatchingParams.drop_front(FI.Head.size() + FI.Pack.size());
FI.PackTarget = Callee;
Info = FI;
return;
}
// Default case: assume all parameters were fully resolved
auto PackLocation = findPack(Args);
if (!PackLocation)
return;
ArrayRef<ParmVarDecl *> MatchingParams =
Callee->parameters().slice(*PackLocation, Parameters.size());
// Check whether the function has a parameter pack as the last template
// parameter
if (const auto *TTPT = getFunctionPackType(Callee)) {
// In this case: Separate the parameters into head, pack and tail
auto IsExpandedPack = [&](const ParmVarDecl *P) {
return getUnderylingPackType(P) == TTPT;
};
ForwardingInfo FI;
FI.Head = MatchingParams;
FI.Head = MatchingParams.take_until(IsExpandedPack);
FI.Pack =
MatchingParams.drop_front(FI.Head.size()).take_while(IsExpandedPack);
FI.Tail = MatchingParams.drop_front(FI.Head.size() + FI.Pack.size());
FI.PackTarget = Callee;
Info = FI;
return;
}
// Default case: assume all parameters were fully resolved
ForwardingInfo FI;
FI.Head = MatchingParams;
Info = FI;
}
// Returns the beginning of the expanded pack represented by Parameters
// in the given arguments, if it is there.
llvm::Optional<size_t> findPack(typename CallExpr::arg_range Args) {
// find the argument directly referring to the first parameter
auto FirstMatch = std::find_if(Args.begin(), Args.end(), [&](Expr *Arg) {
const auto *RefArg = unwrapArgument(Arg);
if (RefArg) {
if (Parameters.front() == dyn_cast<ParmVarDecl>(RefArg->getDecl())) {
return true;
}
for (auto It = Args.begin(); It != Args.end(); ++It) {
const Expr *Arg = *It;
if (const auto *RefArg = unwrapForward(Arg)) {
if (Parameters.front() != RefArg->getDecl())
continue;
return std::distance(Args.begin(), It);
}
return false;
});
if (FirstMatch == Args.end()) {
return llvm::None;
}
return std::distance(Args.begin(), FirstMatch);
return llvm::None;
}
static FunctionDecl *getCalleeDeclOrUniqueOverload(CallExpr *E) {
@ -847,7 +842,7 @@ private:
}
}
// Ignore the callee if the number of arguments is wrong (deal with va_args)
if (Callee->getNumParams() == E->getNumArgs())
if (Callee && Callee->getNumParams() == E->getNumArgs())
return Callee;
return nullptr;
}
@ -873,31 +868,17 @@ private:
return MatchingDecl;
}
// Removes any implicit cast expressions around the given expression.
static const Expr *unwrapImplicitCast(const Expr *E) {
while (const auto *Cast = dyn_cast<ImplicitCastExpr>(E)) {
E = Cast->getSubExpr();
}
return E;
}
// Maps std::forward(E) to E, nullptr otherwise
static const Expr *unwrapForward(const Expr *E) {
// Tries to get to the underlying argument by unwrapping implicit nodes and
// std::forward.
static const DeclRefExpr *unwrapForward(const Expr *E) {
E = E->IgnoreImplicitAsWritten();
if (const auto *Call = dyn_cast<CallExpr>(E)) {
const auto Callee = Call->getBuiltinCallee();
if (Callee == Builtin::BIforward) {
return Call->getArg(0);
return dyn_cast<DeclRefExpr>(
Call->getArg(0)->IgnoreImplicitAsWritten());
}
}
return E;
}
// Maps std::forward(DeclRefExpr) to DeclRefExpr, removing any intermediate
// implicit casts, nullptr otherwise
static const DeclRefExpr *unwrapArgument(const Expr *E) {
E = unwrapImplicitCast(E);
E = unwrapForward(E);
E = unwrapImplicitCast(E);
return dyn_cast<DeclRefExpr>(E);
}
};