summaryrefslogtreecommitdiffstats
path: root/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
blob: 4cff381f3f4abb3c7e56a40f83002c303a58411a (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
//===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  Implements the base layer of the matcher framework.
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"

namespace clang {
namespace ast_matchers {
namespace internal {

void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
  if (Bindings.empty())
    Bindings.push_back(BoundNodesMap());
  for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
    ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
  }
}

namespace {

class VariadicMatcher : public DynMatcherInterface {
 public:
  VariadicMatcher(VariadicOperatorFunction Func,
                  std::vector<DynTypedMatcher> InnerMatchers)
      : Func(Func), InnerMatchers(std::move(InnerMatchers)) {}

  bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
                  ASTMatchFinder *Finder,
                  BoundNodesTreeBuilder *Builder) const override {
    return Func(DynNode, Finder, Builder, InnerMatchers);
  }

 private:
  VariadicOperatorFunction Func;
  std::vector<DynTypedMatcher> InnerMatchers;
};

class IdDynMatcher : public DynMatcherInterface {
 public:
  IdDynMatcher(StringRef ID,
               const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher)
      : ID(ID), InnerMatcher(InnerMatcher) {}

  bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
                  ASTMatchFinder *Finder,
                  BoundNodesTreeBuilder *Builder) const override {
    bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder);
    if (Result) Builder->setBinding(ID, DynNode);
    return Result;
  }

 private:
  const std::string ID;
  const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
};

/// \brief Return the most derived type between \p Kind1 and \p Kind2.
///
/// Return the null type if they are not related.
ast_type_traits::ASTNodeKind getMostDerivedType(
    const ast_type_traits::ASTNodeKind Kind1,
    const ast_type_traits::ASTNodeKind Kind2) {
  if (Kind1.isBaseOf(Kind2)) return Kind2;
  if (Kind2.isBaseOf(Kind1)) return Kind1;
  return ast_type_traits::ASTNodeKind();
}

/// \brief Return the least derived type between \p Kind1 and \p Kind2.
///
/// Return the null type if they are not related.
static ast_type_traits::ASTNodeKind getLeastDerivedType(
    const ast_type_traits::ASTNodeKind Kind1,
    const ast_type_traits::ASTNodeKind Kind2) {
  if (Kind1.isBaseOf(Kind2)) return Kind1;
  if (Kind2.isBaseOf(Kind1)) return Kind2;
  return ast_type_traits::ASTNodeKind();
}

}  // namespace

DynTypedMatcher DynTypedMatcher::constructVariadic(
    VariadicOperatorFunction Func, std::vector<DynTypedMatcher> InnerMatchers) {
  assert(InnerMatchers.size() > 0 && "Array must not be empty.");
  DynTypedMatcher Result = InnerMatchers[0];
  // Use the least derived type as the restriction for the wrapper.
  // This allows mismatches to be resolved on the inner matchers.
  for (const DynTypedMatcher &M : InnerMatchers) {
    assert(Result.SupportedKind.isSame(M.SupportedKind) &&
           "SupportedKind must match!");
    Result.RestrictKind =
        getLeastDerivedType(Result.RestrictKind, M.RestrictKind);
  }
  Result.Implementation = new VariadicMatcher(Func, std::move(InnerMatchers));
  return Result;
}

DynTypedMatcher DynTypedMatcher::dynCastTo(
    const ast_type_traits::ASTNodeKind Kind) const {
  auto Copy = *this;
  Copy.SupportedKind = Kind;
  Copy.RestrictKind = getMostDerivedType(Kind, RestrictKind);
  return Copy;
}

bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
                              ASTMatchFinder *Finder,
                              BoundNodesTreeBuilder *Builder) const {
  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
      Implementation->dynMatches(DynNode, Finder, Builder)) {
    return true;
  }
  // Delete all bindings when a matcher does not match.
  // This prevents unexpected exposure of bound nodes in unmatches
  // branches of the match tree.
  Builder->removeBindings([](const BoundNodesMap &) { return true; });
  return false;
}

llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
  if (!AllowBind) return llvm::None;
  auto Result = *this;
  Result.Implementation = new IdDynMatcher(ID, Result.Implementation);
  return Result;
}

bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
  const auto From = getSupportedKind();
  auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
  auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
  /// Mimic the implicit conversions of Matcher<>.
  /// - From Matcher<Type> to Matcher<QualType>
  if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
  /// - From Matcher<Base> to Matcher<Derived>
  return From.isBaseOf(To);
}

void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
  for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
    Bindings.push_back(Other.Bindings[i]);
  }
}

bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
                      ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
                      ArrayRef<DynTypedMatcher> InnerMatchers) {
  if (InnerMatchers.size() != 1)
    return false;

  // The 'unless' matcher will always discard the result:
  // If the inner matcher doesn't match, unless returns true,
  // but the inner matcher cannot have bound anything.
  // If the inner matcher matches, the result is false, and
  // any possible binding will be discarded.
  // We still need to hand in all the bound nodes up to this
  // point so the inner matcher can depend on bound nodes,
  // and we need to actively discard the bound nodes, otherwise
  // the inner matcher will reset the bound nodes if it doesn't
  // match, but this would be inversed by 'unless'.
  BoundNodesTreeBuilder Discard(*Builder);
  return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
}

bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
                           ASTMatchFinder *Finder,
                           BoundNodesTreeBuilder *Builder,
                           ArrayRef<DynTypedMatcher> InnerMatchers) {
  // allOf leads to one matcher for each alternative in the first
  // matcher combined with each alternative in the second matcher.
  // Thus, we can reuse the same Builder.
  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
    if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
      return false;
  }
  return true;
}

bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
                            ASTMatchFinder *Finder,
                            BoundNodesTreeBuilder *Builder,
                            ArrayRef<DynTypedMatcher> InnerMatchers) {
  BoundNodesTreeBuilder Result;
  bool Matched = false;
  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
    BoundNodesTreeBuilder BuilderInner(*Builder);
    if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
      Matched = true;
      Result.addMatch(BuilderInner);
    }
  }
  *Builder = std::move(Result);
  return Matched;
}

bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
                           ASTMatchFinder *Finder,
                           BoundNodesTreeBuilder *Builder,
                           ArrayRef<DynTypedMatcher> InnerMatchers) {
  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
    BoundNodesTreeBuilder Result = *Builder;
    if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
      *Builder = std::move(Result);
      return true;
    }
  }
  return false;
}

} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
OpenPOWER on IntegriCloud