Skip to content

[clang][Sema] Unify getPrototypeLoc helpers in SemaCodeComplete and clangd #143345

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
51 changes: 2 additions & 49 deletions clang-tools-extra/clangd/InlayHints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/identity.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
Expand Down Expand Up @@ -339,53 +338,6 @@ QualType maybeDesugar(ASTContext &AST, QualType QT) {
return QT;
}

// Given a callee expression `Fn`, if the call is through a function pointer,
// try to find the declaration of the corresponding function pointer type,
// so that we can recover argument names from it.
// FIXME: This function is mostly duplicated in SemaCodeComplete.cpp; unify.
static FunctionProtoTypeLoc getPrototypeLoc(Expr *Fn) {
TypeLoc Target;
Expr *NakedFn = Fn->IgnoreParenCasts();
if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
} else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
const auto *D = DR->getDecl();
if (const auto *const VD = dyn_cast<VarDecl>(D)) {
Target = VD->getTypeSourceInfo()->getTypeLoc();
}
}

if (!Target)
return {};

// Unwrap types that may be wrapping the function type
while (true) {
if (auto P = Target.getAs<PointerTypeLoc>()) {
Target = P.getPointeeLoc();
continue;
}
if (auto A = Target.getAs<AttributedTypeLoc>()) {
Target = A.getModifiedLoc();
continue;
}
if (auto P = Target.getAs<ParenTypeLoc>()) {
Target = P.getInnerLoc();
continue;
}
break;
}

if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
// In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc
// which has null parameters. Avoid these as they don't contain useful
// information.
if (llvm::all_of(F.getParams(), llvm::identity<ParmVarDecl *>()))
return F;
}

return {};
}

ArrayRef<const ParmVarDecl *>
maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
if (!Params.empty() && Params.front()->isExplicitObjectParameter())
Expand Down Expand Up @@ -514,7 +466,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
Callee.Decl = FD;
else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
Callee.Decl = FTD->getTemplatedDecl();
else if (FunctionProtoTypeLoc Loc = getPrototypeLoc(E->getCallee()))
else if (FunctionProtoTypeLoc Loc =
Resolver->getProtoTypeLoc(E->getCallee()))
Callee.Loc = Loc;
else
return true;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/HeuristicResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CXXBasePath;
class CXXDependentScopeMemberExpr;
class DeclarationName;
class DependentScopeDeclRefExpr;
class FunctionProtoTypeLoc;
class NamedDecl;
class Type;
class UnresolvedUsingValueDecl;
Expand Down Expand Up @@ -93,6 +94,12 @@ class HeuristicResolver {
// during simplification, and the operation fails if no pointer type is found.
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);

// Given an expression `Fn` representing the callee in a function call,
// if the call is through a function pointer, try to find the declaration of
// the corresponding function pointer type, so that we can recover argument
// names from it.
FunctionProtoTypeLoc getProtoTypeLoc(Expr *Fn) const;

private:
ASTContext &Ctx;
};
Expand Down
55 changes: 55 additions & 0 deletions clang/lib/Sema/HeuristicResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/identity.h"

namespace clang {

Expand Down Expand Up @@ -50,6 +51,7 @@ class HeuristicResolverImpl {
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
TagDecl *resolveTypeToTagDecl(QualType T);
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
FunctionProtoTypeLoc getProtoTypeLoc(Expr *Fn);

private:
ASTContext &Ctx;
Expand Down Expand Up @@ -506,6 +508,55 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
}
return {};
}

FunctionProtoTypeLoc HeuristicResolverImpl::getProtoTypeLoc(Expr *Fn) {
TypeLoc Target;
Expr *NakedFn = Fn->IgnoreParenCasts();
if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
} else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
const auto *D = DR->getDecl();
if (const auto *const VD = dyn_cast<VarDecl>(D)) {
Target = VD->getTypeSourceInfo()->getTypeLoc();
}
} else if (const auto *ME = dyn_cast<MemberExpr>(Fn)) {
const auto *MD = ME->getMemberDecl();
if (const auto *FD = dyn_cast<FieldDecl>(MD)) {
Target = FD->getTypeSourceInfo()->getTypeLoc();
}
}

if (!Target)
return {};

// Unwrap types that may be wrapping the function type
while (true) {
if (auto P = Target.getAs<PointerTypeLoc>()) {
Target = P.getPointeeLoc();
continue;
}
if (auto A = Target.getAs<AttributedTypeLoc>()) {
Target = A.getModifiedLoc();
continue;
}
if (auto P = Target.getAs<ParenTypeLoc>()) {
Target = P.getInnerLoc();
continue;
}
break;
}

if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
// In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc
// which has null parameters. Avoid these as they don't contain useful
// information.
if (llvm::all_of(F.getParams(), llvm::identity<ParmVarDecl *>()))
return F;
}

return {};
}

} // namespace

std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
Expand Down Expand Up @@ -557,4 +608,8 @@ QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,
return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);
}

FunctionProtoTypeLoc HeuristicResolver::getProtoTypeLoc(Expr *Fn) const {
return HeuristicResolverImpl(Ctx).getProtoTypeLoc(Fn);
}

} // namespace clang
50 changes: 1 addition & 49 deletions clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6283,54 +6283,6 @@ ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates,
return getParamType(SemaRef, Candidates, CurrentArg);
}

// Given a callee expression `Fn`, if the call is through a function pointer,
// try to find the declaration of the corresponding function pointer type,
// so that we can recover argument names from it.
static FunctionProtoTypeLoc GetPrototypeLoc(Expr *Fn) {
TypeLoc Target;

if (const auto *T = Fn->getType().getTypePtr()->getAs<TypedefType>()) {
Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();

} else if (const auto *DR = dyn_cast<DeclRefExpr>(Fn)) {
const auto *D = DR->getDecl();
if (const auto *const VD = dyn_cast<VarDecl>(D)) {
Target = VD->getTypeSourceInfo()->getTypeLoc();
}
} else if (const auto *ME = dyn_cast<MemberExpr>(Fn)) {
const auto *MD = ME->getMemberDecl();
if (const auto *FD = dyn_cast<FieldDecl>(MD)) {
Target = FD->getTypeSourceInfo()->getTypeLoc();
}
}

if (!Target)
return {};

// Unwrap types that may be wrapping the function type
while (true) {
if (auto P = Target.getAs<PointerTypeLoc>()) {
Target = P.getPointeeLoc();
continue;
}
if (auto A = Target.getAs<AttributedTypeLoc>()) {
Target = A.getModifiedLoc();
continue;
}
if (auto P = Target.getAs<ParenTypeLoc>()) {
Target = P.getInnerLoc();
continue;
}
break;
}

if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
return F;
}

return {};
}

QualType
SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) {
Expand Down Expand Up @@ -6419,7 +6371,7 @@ SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
// Lastly we check whether expression's type is function pointer or
// function.

FunctionProtoTypeLoc P = GetPrototypeLoc(NakedFn);
FunctionProtoTypeLoc P = Resolver.getProtoTypeLoc(NakedFn);
QualType T = NakedFn->getType();
if (!T->getPointeeType().isNull())
T = T->getPointeeType();
Expand Down
Loading