1//=== AnyCall.h - Abstraction over different callables --------*- 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// A utility class for performing generic operations over different callables.
10//
11//===----------------------------------------------------------------------===//
12//
13#ifndef LLVM_CLANG_ANALYSIS_ANY_CALL_H
14#define LLVM_CLANG_ANALYSIS_ANY_CALL_H
15
16#include "clang/AST/Decl.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/AST/ExprObjC.h"
19
20namespace clang {
21
22/// An instance of this class corresponds to a call.
23/// It might be a syntactically-concrete call, done as a part of evaluating an
24/// expression, or it may be an abstract callee with no associated expression.
25class AnyCall {
26public:
27  enum Kind {
28    /// A function, function pointer, or a C++ method call
29    Function,
30
31    /// A call to an Objective-C method
32    ObjCMethod,
33
34    /// A call to an Objective-C block
35    Block,
36
37    /// An implicit C++ destructor call (called implicitly
38    /// or by operator 'delete')
39    Destructor,
40
41    /// An implicit or explicit C++ constructor call
42    Constructor,
43
44    /// A C++ allocation function call (operator `new`), via C++ new-expression
45    Allocator,
46
47    /// A C++ deallocation function call (operator `delete`), via C++
48    /// delete-expression
49    Deallocator
50  };
51
52private:
53  /// Either expression or declaration (but not both at the same time)
54  /// can be null.
55
56  /// Call expression, is null when is not known (then declaration is non-null),
57  /// or for implicit destructor calls (when no expression exists.)
58  const Expr *E = nullptr;
59
60  /// Corresponds to a statically known declaration of the called function,
61  /// or null if it is not known (e.g. for a function pointer).
62  const Decl *D = nullptr;
63  Kind K;
64
65public:
66  AnyCall(const CallExpr *CE) : E(CE) {
67    D = CE->getCalleeDecl();
68    K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
69                                                                : Function;
70    if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
71              (K == Block && !isa<BlockDecl>(D))))
72      D = nullptr;
73  }
74
75  AnyCall(const ObjCMessageExpr *ME)
76      : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
77
78  AnyCall(const CXXNewExpr *NE)
79      : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
80
81  AnyCall(const CXXDeleteExpr *NE)
82      : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
83
84  AnyCall(const CXXConstructExpr *NE)
85      : E(NE), D(NE->getConstructor()), K(Constructor) {}
86
87  AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
88
89  AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
90
91  AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
92
93  AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
94    if (isa<CXXConstructorDecl>(D)) {
95      K = Constructor;
96    } else if (isa <CXXDestructorDecl>(D)) {
97      K = Destructor;
98    } else {
99      K = Function;
100    }
101
102  }
103
104  /// If {@code E} is a generic call (to ObjC method /function/block/etc),
105  /// return a constructed {@code AnyCall} object. Return None otherwise.
106  static Optional<AnyCall> forExpr(const Expr *E) {
107    if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
108      return AnyCall(ME);
109    } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
110      return AnyCall(CE);
111    } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
112      return AnyCall(CXNE);
113    } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
114      return AnyCall(CXDE);
115    } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
116      return AnyCall(CXCE);
117    } else {
118      return None;
119    }
120  }
121
122  /// If {@code D} is a callable (Objective-C method or a function), return
123  /// a constructed {@code AnyCall} object. Return None otherwise.
124  // FIXME: block support.
125  static Optional<AnyCall> forDecl(const Decl *D) {
126    if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
127      return AnyCall(FD);
128    } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
129      return AnyCall(MD);
130    }
131    return None;
132  }
133
134  /// \returns formal parameters for direct calls (including virtual calls)
135  ArrayRef<ParmVarDecl *> parameters() const {
136    if (!D)
137      return None;
138
139    if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
140      return FD->parameters();
141    } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
142      return MD->parameters();
143    } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
144      return BD->parameters();
145    } else {
146      return None;
147    }
148  }
149
150  using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
151  param_const_iterator param_begin() const { return parameters().begin(); }
152  param_const_iterator param_end() const { return parameters().end(); }
153  size_t param_size() const { return parameters().size(); }
154  bool param_empty() const { return parameters().empty(); }
155
156  QualType getReturnType(ASTContext &Ctx) const {
157    switch (K) {
158    case Function:
159      if (E)
160        return cast<CallExpr>(E)->getCallReturnType(Ctx);
161      return cast<FunctionDecl>(D)->getReturnType();
162    case ObjCMethod:
163      if (E)
164        return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
165      return cast<ObjCMethodDecl>(D)->getReturnType();
166    case Block:
167      // FIXME: BlockDecl does not know its return type,
168      // hence the asymmetry with the function and method cases above.
169      return cast<CallExpr>(E)->getCallReturnType(Ctx);
170    case Destructor:
171    case Constructor:
172    case Allocator:
173    case Deallocator:
174      return cast<FunctionDecl>(D)->getReturnType();
175    }
176    llvm_unreachable("Unknown AnyCall::Kind");
177  }
178
179  /// \returns Function identifier if it is a named declaration,
180  /// {@code nullptr} otherwise.
181  const IdentifierInfo *getIdentifier() const {
182    if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
183      return ND->getIdentifier();
184    return nullptr;
185  }
186
187  const Decl *getDecl() const {
188    return D;
189  }
190
191  const Expr *getExpr() const {
192    return E;
193  }
194
195  Kind getKind() const {
196    return K;
197  }
198
199  void dump() const {
200    if (E)
201      E->dump();
202    if (D)
203      D->dump();
204  }
205};
206
207}
208
209#endif // LLVM_CLANG_ANALYSIS_ANY_CALL_H
210