summaryrefslogtreecommitdiffstats
path: root/clang/lib/ASTMatchers/Dynamic/Marshallers.h
blob: c3a5260eb436f595ba57449bc3484440602ef2e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Functions templates and classes to wrap matcher construct functions.
///
/// A collection of template function and classes that provide a generic
/// marshalling layer on top of matcher construct functions.
/// These are used by the registry to export all marshaller constructors with
/// the same generic interface.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H

#include <string>

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
#include "llvm/Support/type_traits.h"

namespace clang {
namespace ast_matchers {
namespace dynamic {

namespace internal {

/// \brief Helper template class to just from argument type to the right is/get
///   functions in VariantValue.
/// Used to verify and extract the matcher arguments below.
template <class T> struct ArgTypeTraits;
template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {
};

template <> struct ArgTypeTraits<std::string> {
  static StringRef asString() { return "String"; }
  static bool is(const VariantValue &Value) { return Value.isString(); }
  static const std::string &get(const VariantValue &Value) {
    return Value.getString();
  }
};

template <>
struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> {
};

template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
  static std::string asString() {
    return (Twine("Matcher<") +
            ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() +
            ">").str();
  }
  static bool is(const VariantValue &Value) {
    return Value.hasTypedMatcher<T>();
  }
  static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
    return Value.getTypedMatcher<T>();
  }
};

template <> struct ArgTypeTraits<unsigned> {
  static std::string asString() { return "Unsigned"; }
  static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
  static unsigned get(const VariantValue &Value) {
    return Value.getUnsigned();
  }
};

/// \brief Generic MatcherCreate interface.
///
/// Provides a \c run() method that constructs the matcher from the provided
/// arguments.
class MatcherCreateCallback {
public:
  virtual ~MatcherCreateCallback() {}
  virtual MatcherList run(const SourceRange &NameRange,
                          ArrayRef<ParserValue> Args,
                          Diagnostics *Error) const = 0;
};

/// \brief Simple callback implementation. Marshaller and function are provided.
///
/// This class wraps a function of arbitrary signature and a marshaller
/// function into a MatcherCreateCallback.
/// The marshaller is in charge of taking the VariantValue arguments, checking
/// their types, unpacking them and calling the underlying function.
template <typename FuncType>
class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback {
public:
  /// FIXME: Use void(*)() as FuncType on this interface to remove the template
  /// argument of this class. The marshaller can cast the function pointer back
  /// to the original type.
  typedef MatcherList (*MarshallerType)(FuncType, StringRef,
                                        const SourceRange &,
                                        ArrayRef<ParserValue>,
                                        Diagnostics *);

  /// \param Marshaller Function to unpack the arguments and call \c Func
  /// \param Func Matcher construct function. This is the function that
  ///   compile-time matcher expressions would use to create the matcher.
  FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, FuncType Func,
                                     StringRef MatcherName)
      : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {}

  MatcherList run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
                  Diagnostics *Error) const {
    return Marshaller(Func, MatcherName, NameRange, Args, Error);
  }

private:
  const MarshallerType Marshaller;
  const FuncType Func;
  const std::string MatcherName;
};

/// \brief Simple callback implementation. Free function is wrapped.
///
/// This class simply wraps a free function with the right signature to export
/// it as a MatcherCreateCallback.
/// This allows us to have one implementation of the interface for as many free
/// functions as we want, reducing the number of symbols and size of the
/// object file.
class FreeFuncMatcherCreateCallback : public MatcherCreateCallback {
public:
  typedef MatcherList (*RunFunc)(StringRef MatcherName,
                                 const SourceRange &NameRange,
                                 ArrayRef<ParserValue> Args,
                                 Diagnostics *Error);

  FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName)
      : Func(Func), MatcherName(MatcherName.str()) {}

  MatcherList run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
                  Diagnostics *Error) const {
    return Func(MatcherName, NameRange, Args, Error);
  }

private:
  const RunFunc Func;
  const std::string MatcherName;
};

/// \brief Helper macros to check the arguments on all marshaller functions.
#define CHECK_ARG_COUNT(count)                                                 \
  if (Args.size() != count) {                                                  \
    Error->pushErrorFrame(NameRange, Error->ET_RegistryWrongArgCount)          \
        << count << Args.size();                                               \
    return MatcherList();                                                      \
  }

#define CHECK_ARG_TYPE(index, type)                                            \
  if (!ArgTypeTraits<type>::is(Args[index].Value)) {                           \
    Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType)   \
        << (index + 1) << ArgTypeTraits<type>::asString()                      \
        << Args[index].Value.getTypeAsString();                                \
    return MatcherList();                                                      \
  }

/// \brief Helper methods to extract and merge all possible typed matchers
/// out of the polymorphic object.
template <class PolyMatcher>
static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out,
                              ast_matchers::internal::EmptyTypeList) {}

template <class PolyMatcher, class TypeList>
static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out,
                              TypeList) {
  Out->add(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
  mergePolyMatchers(Poly, Out, typename TypeList::tail());
}

/// \brief Convert the return values of the functions into a MatcherList.
///
/// There are 2 cases right now: The return value is a Matcher<T> or is a
/// polymorphic matcher. For the former, we just construct the MatcherList. For
/// the latter, we instantiate all the possible Matcher<T> of the poly matcher.
template <typename T>
static MatcherList
outvalueToMatcherList(const ast_matchers::internal::Matcher<T> &Matcher) {
  return MatcherList(Matcher);
}

template <typename T>
static MatcherList
outvalueToMatcherList(const T& PolyMatcher, typename T::ReturnTypes* = NULL) {
  MatcherList Matchers;
  mergePolyMatchers(PolyMatcher, &Matchers, typename T::ReturnTypes());
  return Matchers;
}

/// \brief 0-arg marshaller function.
template <typename ReturnType>
static MatcherList matcherMarshall0(ReturnType (*Func)(),
                                    StringRef MatcherName,
                                    const SourceRange &NameRange,
                                    ArrayRef<ParserValue> Args,
                                    Diagnostics *Error) {
  CHECK_ARG_COUNT(0);
  return outvalueToMatcherList(Func());
}

/// \brief 1-arg marshaller function.
template <typename ReturnType, typename ArgType1>
static MatcherList matcherMarshall1(ReturnType (*Func)(ArgType1),
                                    StringRef MatcherName,
                                    const SourceRange &NameRange,
                                    ArrayRef<ParserValue> Args,
                                    Diagnostics *Error) {
  CHECK_ARG_COUNT(1);
  CHECK_ARG_TYPE(0, ArgType1);
  return outvalueToMatcherList(
      Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)));
}

/// \brief 2-arg marshaller function.
template <typename ReturnType, typename ArgType1, typename ArgType2>
static MatcherList matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2),
                                    StringRef MatcherName,
                                    const SourceRange &NameRange,
                                    ArrayRef<ParserValue> Args,
                                    Diagnostics *Error) {
  CHECK_ARG_COUNT(2);
  CHECK_ARG_TYPE(0, ArgType1);
  CHECK_ARG_TYPE(1, ArgType2);
  return outvalueToMatcherList(
      Func(ArgTypeTraits<ArgType1>::get(Args[0].Value),
           ArgTypeTraits<ArgType2>::get(Args[1].Value)));
}

#undef CHECK_ARG_COUNT
#undef CHECK_ARG_TYPE

/// \brief Variadic marshaller function.
template <typename BaseType, typename DerivedType>
MatcherList VariadicMatcherCreateCallback(StringRef MatcherName,
                                          const SourceRange &NameRange,
                                          ArrayRef<ParserValue> Args,
                                          Diagnostics *Error) {
  typedef ast_matchers::internal::Matcher<DerivedType> DerivedMatcherType;
  DerivedMatcherType **InnerArgs = new DerivedMatcherType *[Args.size()]();

  bool HasError = false;
  for (size_t i = 0, e = Args.size(); i != e; ++i) {
    typedef ArgTypeTraits<DerivedMatcherType> DerivedTraits;
    const ParserValue &Arg = Args[i];
    const VariantValue &Value = Arg.Value;
    if (!DerivedTraits::is(Value)) {
      Error->pushErrorFrame(Arg.Range, Error->ET_RegistryWrongArgType)
          << (i + 1) << DerivedTraits::asString() << Value.getTypeAsString();
      HasError = true;
      break;
    }
    InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value));
  }

  MatcherList Out;
  if (!HasError) {
    Out = ast_matchers::internal::makeDynCastAllOfComposite<BaseType>(
        ArrayRef<const DerivedMatcherType *>(InnerArgs, Args.size()));
  }

  for (size_t i = 0, e = Args.size(); i != e; ++i) {
    delete InnerArgs[i];
  }
  delete[] InnerArgs;
  return Out;
}

/// Helper functions to select the appropriate marshaller functions.
/// They detect the number of arguments, arguments types and return type.

/// \brief 0-arg overload
template <typename ReturnType>
MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(),
                                               StringRef MatcherName) {
  return new FixedArgCountMatcherCreateCallback<ReturnType (*)()>(
      matcherMarshall0, Func, MatcherName);
}

/// \brief 1-arg overload
template <typename ReturnType, typename ArgType1>
MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1),
                                               StringRef MatcherName) {
  return new FixedArgCountMatcherCreateCallback<ReturnType (*)(ArgType1)>(
      matcherMarshall1, Func, MatcherName);
}

/// \brief 2-arg overload
template <typename ReturnType, typename ArgType1, typename ArgType2>
MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1,
                                                                  ArgType2),
                                               StringRef MatcherName) {
  return new FixedArgCountMatcherCreateCallback<
      ReturnType (*)(ArgType1, ArgType2)>(matcherMarshall2, Func, MatcherName);
}

/// \brief Variadic overloads.
template <typename MatcherType>
MatcherCreateCallback *makeMatcherAutoMarshall(
    ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func,
    StringRef MatcherName) {
  return new FreeFuncMatcherCreateCallback(
      &VariadicMatcherCreateCallback<MatcherType, MatcherType>, MatcherName);
}

template <typename BaseType, typename MatcherType>
MatcherCreateCallback *
makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher<
                            BaseType, MatcherType> Func,
                        StringRef MatcherName) {
  return new FreeFuncMatcherCreateCallback(
      &VariadicMatcherCreateCallback<BaseType, MatcherType>, MatcherName);
}

}  // namespace internal
}  // namespace dynamic
}  // namespace ast_matchers
}  // namespace clang

#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
OpenPOWER on IntegriCloud