Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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