xref: /freebsd/contrib/llvm-project/clang/lib/ASTMatchers/LowLevelHelpers.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- LowLevelHelpers.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/ASTMatchers/LowLevelHelpers.h"
10 #include "clang/AST/Decl.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/AST/Expr.h"
13 #include "clang/AST/ExprCXX.h"
14 #include <type_traits>
15 
16 namespace clang {
17 namespace ast_matchers {
18 
getCallee(const CXXConstructExpr & D)19 static const FunctionDecl *getCallee(const CXXConstructExpr &D) {
20   return D.getConstructor();
21 }
getCallee(const CallExpr & D)22 static const FunctionDecl *getCallee(const CallExpr &D) {
23   return D.getDirectCallee();
24 }
25 
26 template <class ExprNode>
matchEachArgumentWithParamTypeImpl(const ExprNode & Node,llvm::function_ref<void (QualType,const Expr *)> OnParamAndArg)27 static void matchEachArgumentWithParamTypeImpl(
28     const ExprNode &Node,
29     llvm::function_ref<void(QualType /*Param*/, const Expr * /*Arg*/)>
30         OnParamAndArg) {
31   static_assert(std::is_same_v<CallExpr, ExprNode> ||
32                 std::is_same_v<CXXConstructExpr, ExprNode>);
33   // The first argument of an overloaded member operator is the implicit object
34   // argument of the method which should not be matched against a parameter, so
35   // we skip over it here.
36   unsigned ArgIndex = 0;
37   if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(&Node)) {
38     const auto *MD = dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
39     if (MD && !MD->isExplicitObjectMemberFunction()) {
40       // This is an overloaded operator call.
41       // We need to skip the first argument, which is the implicit object
42       // argument of the method which should not be matched against a
43       // parameter.
44       ++ArgIndex;
45     }
46   }
47 
48   const FunctionProtoType *FProto = nullptr;
49 
50   if (const auto *Call = dyn_cast<CallExpr>(&Node)) {
51     if (const auto *Value =
52             dyn_cast_or_null<ValueDecl>(Call->getCalleeDecl())) {
53       QualType QT = Value->getType().getCanonicalType();
54 
55       // This does not necessarily lead to a `FunctionProtoType`,
56       // e.g. K&R functions do not have a function prototype.
57       if (QT->isFunctionPointerType())
58         FProto = QT->getPointeeType()->getAs<FunctionProtoType>();
59 
60       if (QT->isMemberFunctionPointerType()) {
61         const auto *MP = QT->getAs<MemberPointerType>();
62         assert(MP && "Must be member-pointer if its a memberfunctionpointer");
63         FProto = MP->getPointeeType()->getAs<FunctionProtoType>();
64         assert(FProto &&
65                "The call must have happened through a member function "
66                "pointer");
67       }
68     }
69   }
70 
71   unsigned ParamIndex = 0;
72   unsigned NumArgs = Node.getNumArgs();
73   if (FProto && FProto->isVariadic())
74     NumArgs = std::min(NumArgs, FProto->getNumParams());
75 
76   for (; ArgIndex < NumArgs; ++ArgIndex, ++ParamIndex) {
77     QualType ParamType;
78     if (FProto && FProto->getNumParams() > ParamIndex)
79       ParamType = FProto->getParamType(ParamIndex);
80     else if (const FunctionDecl *FD = getCallee(Node);
81              FD && FD->getNumParams() > ParamIndex)
82       ParamType = FD->getParamDecl(ParamIndex)->getType();
83     else
84       continue;
85 
86     OnParamAndArg(ParamType, Node.getArg(ArgIndex)->IgnoreParenCasts());
87   }
88 }
89 
matchEachArgumentWithParamType(const CallExpr & Node,llvm::function_ref<void (QualType,const Expr *)> OnParamAndArg)90 void matchEachArgumentWithParamType(
91     const CallExpr &Node,
92     llvm::function_ref<void(QualType /*Param*/, const Expr * /*Arg*/)>
93         OnParamAndArg) {
94   matchEachArgumentWithParamTypeImpl(Node, OnParamAndArg);
95 }
96 
matchEachArgumentWithParamType(const CXXConstructExpr & Node,llvm::function_ref<void (QualType,const Expr *)> OnParamAndArg)97 void matchEachArgumentWithParamType(
98     const CXXConstructExpr &Node,
99     llvm::function_ref<void(QualType /*Param*/, const Expr * /*Arg*/)>
100         OnParamAndArg) {
101   matchEachArgumentWithParamTypeImpl(Node, OnParamAndArg);
102 }
103 
104 } // namespace ast_matchers
105 
106 } // namespace clang
107