Coverage Report

Created: 2021-06-15 06:44

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Transformer/RewriteRule.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Transformer.cpp - Transformer library implementation ---*- 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/Tooling/Transformer/RewriteRule.h"
10
#include "clang/AST/ASTTypeTraits.h"
11
#include "clang/AST/Stmt.h"
12
#include "clang/ASTMatchers/ASTMatchFinder.h"
13
#include "clang/ASTMatchers/ASTMatchers.h"
14
#include "clang/Basic/SourceLocation.h"
15
#include "clang/Tooling/Transformer/SourceCode.h"
16
#include "llvm/ADT/Optional.h"
17
#include "llvm/ADT/StringRef.h"
18
#include "llvm/Support/Errc.h"
19
#include "llvm/Support/Error.h"
20
#include <map>
21
#include <string>
22
#include <utility>
23
#include <vector>
24
25
using namespace clang;
26
using namespace transformer;
27
28
using ast_matchers::MatchFinder;
29
using ast_matchers::internal::DynTypedMatcher;
30
31
using MatchResult = MatchFinder::MatchResult;
32
33
const char transformer::RootID[] = "___root___";
34
35
static Expected<SmallVector<transformer::Edit, 1>>
36
121
translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
37
121
  SmallVector<transformer::Edit, 1> Edits;
38
128
  for (const auto &E : ASTEdits) {
39
128
    Expected<CharSourceRange> Range = E.TargetRange(Result);
40
128
    if (!Range)
41
2
      return Range.takeError();
42
126
    llvm::Optional<CharSourceRange> EditRange =
43
126
        tooling::getRangeForEdit(*Range, *Result.Context);
44
    // FIXME: let user specify whether to treat this case as an error or ignore
45
    // it as is currently done. This behavior is problematic in that it hides
46
    // failures from bad ranges. Also, the behavior here differs from
47
    // `flatten`. Here, we abort (without error), whereas flatten, if it hits an
48
    // empty list, does not abort. As a result, `editList({A,B})` is not
49
    // equivalent to `flatten(edit(A), edit(B))`. The former will abort if `A`
50
    // produces a bad range, whereas the latter will simply ignore A.
51
126
    if (!EditRange)
52
2
      return SmallVector<Edit, 0>();
53
124
    auto Replacement = E.Replacement->eval(Result);
54
124
    if (!Replacement)
55
3
      return Replacement.takeError();
56
121
    auto Metadata = E.Metadata(Result);
57
121
    if (!Metadata)
58
0
      return Metadata.takeError();
59
121
    transformer::Edit T;
60
121
    T.Kind = E.Kind;
61
121
    T.Range = *EditRange;
62
121
    T.Replacement = std::move(*Replacement);
63
121
    T.Metadata = std::move(*Metadata);
64
121
    Edits.push_back(std::move(T));
65
121
  }
66
114
  return Edits;
67
121
}
68
69
9
EditGenerator transformer::editList(SmallVector<ASTEdit, 1> Edits) {
70
9
  return [Edits = std::move(Edits)](const MatchResult &Result) {
71
8
    return translateEdits(Result, Edits);
72
8
  };
73
9
}
74
75
76
EditGenerator transformer::edit(ASTEdit Edit) {
76
113
  return [Edit = std::move(Edit)](const MatchResult &Result) {
77
113
    return translateEdits(Result, {Edit});
78
113
  };
79
76
}
80
81
1
EditGenerator transformer::noopEdit(RangeSelector Anchor) {
82
1
  return [Anchor = std::move(Anchor)](const MatchResult &Result)
83
1
             -> Expected<SmallVector<transformer::Edit, 1>> {
84
1
    Expected<CharSourceRange> Range = Anchor(Result);
85
1
    if (!Range)
86
0
      return Range.takeError();
87
    // In case the range is inside a macro expansion, map the location back to a
88
    // "real" source location.
89
1
    SourceLocation Begin =
90
1
        Result.SourceManager->getSpellingLoc(Range->getBegin());
91
1
    Edit E;
92
    // Implicitly, leave `E.Replacement` as the empty string.
93
1
    E.Kind = EditKind::Range;
94
1
    E.Range = CharSourceRange::getCharRange(Begin, Begin);
95
1
    return SmallVector<Edit, 1>{E};
96
1
  };
97
1
}
98
99
EditGenerator
100
5
transformer::flattenVector(SmallVector<EditGenerator, 2> Generators) {
101
5
  if (Generators.size() == 1)
102
0
    return std::move(Generators[0]);
103
5
  return
104
5
      [Gs = std::move(Generators)](
105
5
          const MatchResult &Result) -> llvm::Expected<SmallVector<Edit, 1>> {
106
5
        SmallVector<Edit, 1> AllEdits;
107
12
        for (const auto &G : Gs) {
108
12
          llvm::Expected<SmallVector<Edit, 1>> Edits = G(Result);
109
12
          if (!Edits)
110
0
            return Edits.takeError();
111
12
          AllEdits.append(Edits->begin(), Edits->end());
112
12
        }
113
5
        return AllEdits;
114
5
      };
115
5
}
116
117
82
ASTEdit transformer::changeTo(RangeSelector Target, TextGenerator Replacement) {
118
82
  ASTEdit E;
119
82
  E.TargetRange = std::move(Target);
120
82
  E.Replacement = std::move(Replacement);
121
82
  return E;
122
82
}
123
124
namespace {
125
/// A \c TextGenerator that always returns a fixed string.
126
class SimpleTextGenerator : public MatchComputation<std::string> {
127
  std::string S;
128
129
public:
130
9
  SimpleTextGenerator(std::string S) : S(std::move(S)) {}
131
  llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
132
9
                   std::string *Result) const override {
133
9
    Result->append(S);
134
9
    return llvm::Error::success();
135
9
  }
136
0
  std::string toString() const override {
137
0
    return (llvm::Twine("text(\"") + S + "\")").str();
138
0
  }
139
};
140
} // namespace
141
142
9
static TextGenerator makeText(std::string S) {
143
9
  return std::make_shared<SimpleTextGenerator>(std::move(S));
144
9
}
145
146
4
ASTEdit transformer::remove(RangeSelector S) {
147
4
  return change(std::move(S), makeText(""));
148
4
}
149
150
5
static std::string formatHeaderPath(StringRef Header, IncludeFormat Format) {
151
5
  switch (Format) {
152
3
  case transformer::IncludeFormat::Quoted:
153
3
    return Header.str();
154
2
  case transformer::IncludeFormat::Angled:
155
2
    return ("<" + Header + ">").str();
156
5
  }
157
5
  
llvm_unreachable0
("Unknown transformer::IncludeFormat enum");
158
5
}
159
160
ASTEdit transformer::addInclude(RangeSelector Target, StringRef Header,
161
5
                                IncludeFormat Format) {
162
5
  ASTEdit E;
163
5
  E.Kind = EditKind::AddInclude;
164
5
  E.TargetRange = Target;
165
5
  E.Replacement = makeText(formatHeaderPath(Header, Format));
166
5
  return E;
167
5
}
168
169
RewriteRule transformer::makeRule(DynTypedMatcher M, EditGenerator Edits,
170
89
                                  TextGenerator Explanation) {
171
89
  return RewriteRule{{RewriteRule::Case{std::move(M), std::move(Edits),
172
89
                                        std::move(Explanation)}}};
173
89
}
174
175
namespace {
176
177
/// Unconditionally binds the given node set before trying `InnerMatcher` and
178
/// keeps the bound nodes on a successful match.
179
template <typename T>
180
class BindingsMatcher : public ast_matchers::internal::MatcherInterface<T> {
181
  ast_matchers::BoundNodes Nodes;
182
  const ast_matchers::internal::Matcher<T> InnerMatcher;
183
184
public:
185
  explicit BindingsMatcher(ast_matchers::BoundNodes Nodes,
186
                           ast_matchers::internal::Matcher<T> InnerMatcher)
187
10
      : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::Decl>::BindingsMatcher(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::Matcher<clang::Decl>)
Line
Count
Source
187
4
      : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::Stmt>::BindingsMatcher(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::Matcher<clang::Stmt>)
Line
Count
Source
187
4
      : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::TypeLoc>::BindingsMatcher(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::Matcher<clang::TypeLoc>)
Line
Count
Source
187
2
      : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}
188
189
  bool matches(
190
      const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,
191
10
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
192
10
    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
193
10
    for (const auto &N : Nodes.getMap())
194
32
      Result.setBinding(N.first, N.second);
195
10
    if (InnerMatcher.matches(Node, Finder, &Result)) {
196
10
      *Builder = std::move(Result);
197
10
      return true;
198
10
    }
199
0
    return false;
200
10
  }
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::Decl>::matches(clang::Decl const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
191
4
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
192
4
    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
193
4
    for (const auto &N : Nodes.getMap())
194
13
      Result.setBinding(N.first, N.second);
195
4
    if (InnerMatcher.matches(Node, Finder, &Result)) {
196
4
      *Builder = std::move(Result);
197
4
      return true;
198
4
    }
199
0
    return false;
200
4
  }
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::Stmt>::matches(clang::Stmt const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
191
4
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
192
4
    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
193
4
    for (const auto &N : Nodes.getMap())
194
13
      Result.setBinding(N.first, N.second);
195
4
    if (InnerMatcher.matches(Node, Finder, &Result)) {
196
4
      *Builder = std::move(Result);
197
4
      return true;
198
4
    }
199
0
    return false;
200
4
  }
RewriteRule.cpp:(anonymous namespace)::BindingsMatcher<clang::TypeLoc>::matches(clang::TypeLoc const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
191
2
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
192
2
    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
193
2
    for (const auto &N : Nodes.getMap())
194
6
      Result.setBinding(N.first, N.second);
195
2
    if (InnerMatcher.matches(Node, Finder, &Result)) {
196
2
      *Builder = std::move(Result);
197
2
      return true;
198
2
    }
199
0
    return false;
200
2
  }
201
};
202
203
/// Matches nodes of type T that have at least one descendant node for which the
204
/// given inner matcher matches.  Will match for each descendant node that
205
/// matches.  Based on ForEachDescendantMatcher, but takes a dynamic matcher,
206
/// instead of a static one, because it is used by RewriteRule, which carries
207
/// (only top-level) dynamic matchers.
208
template <typename T>
209
class DynamicForEachDescendantMatcher
210
    : public ast_matchers::internal::MatcherInterface<T> {
211
  const DynTypedMatcher DescendantMatcher;
212
213
public:
214
  explicit DynamicForEachDescendantMatcher(DynTypedMatcher DescendantMatcher)
215
10
      : DescendantMatcher(std::move(DescendantMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::Decl>::DynamicForEachDescendantMatcher(clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
215
4
      : DescendantMatcher(std::move(DescendantMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::Stmt>::DynamicForEachDescendantMatcher(clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
215
4
      : DescendantMatcher(std::move(DescendantMatcher)) {}
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::TypeLoc>::DynamicForEachDescendantMatcher(clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
215
2
      : DescendantMatcher(std::move(DescendantMatcher)) {}
216
217
  bool matches(
218
      const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,
219
10
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
220
10
    return Finder->matchesDescendantOf(
221
10
        Node, this->DescendantMatcher, Builder,
222
10
        ast_matchers::internal::ASTMatchFinder::BK_All);
223
10
  }
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::Decl>::matches(clang::Decl const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
219
4
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
220
4
    return Finder->matchesDescendantOf(
221
4
        Node, this->DescendantMatcher, Builder,
222
4
        ast_matchers::internal::ASTMatchFinder::BK_All);
223
4
  }
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::Stmt>::matches(clang::Stmt const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
219
4
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
220
4
    return Finder->matchesDescendantOf(
221
4
        Node, this->DescendantMatcher, Builder,
222
4
        ast_matchers::internal::ASTMatchFinder::BK_All);
223
4
  }
RewriteRule.cpp:(anonymous namespace)::DynamicForEachDescendantMatcher<clang::TypeLoc>::matches(clang::TypeLoc const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const
Line
Count
Source
219
2
      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
220
2
    return Finder->matchesDescendantOf(
221
2
        Node, this->DescendantMatcher, Builder,
222
2
        ast_matchers::internal::ASTMatchFinder::BK_All);
223
2
  }
224
};
225
226
template <typename T>
227
ast_matchers::internal::Matcher<T>
228
forEachDescendantDynamically(ast_matchers::BoundNodes Nodes,
229
10
                             DynTypedMatcher M) {
230
10
  return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>(
231
10
      std::move(Nodes),
232
10
      ast_matchers::internal::makeMatcher(
233
10
          new DynamicForEachDescendantMatcher<T>(std::move(M)))));
234
10
}
RewriteRule.cpp:clang::ast_matchers::internal::Matcher<clang::Decl> (anonymous namespace)::forEachDescendantDynamically<clang::Decl>(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
229
4
                             DynTypedMatcher M) {
230
4
  return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>(
231
4
      std::move(Nodes),
232
4
      ast_matchers::internal::makeMatcher(
233
4
          new DynamicForEachDescendantMatcher<T>(std::move(M)))));
234
4
}
RewriteRule.cpp:clang::ast_matchers::internal::Matcher<clang::Stmt> (anonymous namespace)::forEachDescendantDynamically<clang::Stmt>(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
229
4
                             DynTypedMatcher M) {
230
4
  return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>(
231
4
      std::move(Nodes),
232
4
      ast_matchers::internal::makeMatcher(
233
4
          new DynamicForEachDescendantMatcher<T>(std::move(M)))));
234
4
}
RewriteRule.cpp:clang::ast_matchers::internal::Matcher<clang::TypeLoc> (anonymous namespace)::forEachDescendantDynamically<clang::TypeLoc>(clang::ast_matchers::BoundNodes, clang::ast_matchers::internal::DynTypedMatcher)
Line
Count
Source
229
2
                             DynTypedMatcher M) {
230
2
  return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>(
231
2
      std::move(Nodes),
232
2
      ast_matchers::internal::makeMatcher(
233
2
          new DynamicForEachDescendantMatcher<T>(std::move(M)))));
234
2
}
235
236
class ApplyRuleCallback : public MatchFinder::MatchCallback {
237
public:
238
10
  ApplyRuleCallback(RewriteRule Rule) : Rule(std::move(Rule)) {}
239
240
  template <typename T>
241
  void registerMatchers(const ast_matchers::BoundNodes &Nodes,
242
10
                        MatchFinder *MF) {
243
10
    for (auto &Matcher : transformer::detail::buildMatchers(Rule))
244
10
      MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this);
245
10
  }
RewriteRule.cpp:void (anonymous namespace)::ApplyRuleCallback::registerMatchers<clang::Decl>(clang::ast_matchers::BoundNodes const&, clang::ast_matchers::MatchFinder*)
Line
Count
Source
242
4
                        MatchFinder *MF) {
243
4
    for (auto &Matcher : transformer::detail::buildMatchers(Rule))
244
4
      MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this);
245
4
  }
RewriteRule.cpp:void (anonymous namespace)::ApplyRuleCallback::registerMatchers<clang::Stmt>(clang::ast_matchers::BoundNodes const&, clang::ast_matchers::MatchFinder*)
Line
Count
Source
242
4
                        MatchFinder *MF) {
243
4
    for (auto &Matcher : transformer::detail::buildMatchers(Rule))
244
4
      MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this);
245
4
  }
RewriteRule.cpp:void (anonymous namespace)::ApplyRuleCallback::registerMatchers<clang::TypeLoc>(clang::ast_matchers::BoundNodes const&, clang::ast_matchers::MatchFinder*)
Line
Count
Source
242
2
                        MatchFinder *MF) {
243
2
    for (auto &Matcher : transformer::detail::buildMatchers(Rule))
244
2
      MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this);
245
2
  }
246
247
32
  void run(const MatchFinder::MatchResult &Result) override {
248
32
    if (!Edits)
249
0
      return;
250
32
    transformer::RewriteRule::Case Case =
251
32
        transformer::detail::findSelectedCase(Result, Rule);
252
32
    auto Transformations = Case.Edits(Result);
253
32
    if (!Transformations) {
254
0
      Edits = Transformations.takeError();
255
0
      return;
256
0
    }
257
32
    Edits->append(Transformations->begin(), Transformations->end());
258
32
  }
259
260
  RewriteRule Rule;
261
262
  // Initialize to a non-error state.
263
  Expected<SmallVector<Edit, 1>> Edits = SmallVector<Edit, 1>();
264
};
265
} // namespace
266
267
template <typename T>
268
llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
269
rewriteDescendantsImpl(const T &Node, RewriteRule Rule,
270
10
                       const MatchResult &Result) {
271
10
  ApplyRuleCallback Callback(std::move(Rule));
272
10
  MatchFinder Finder;
273
10
  Callback.registerMatchers<T>(Result.Nodes, &Finder);
274
10
  Finder.match(Node, *Result.Context);
275
10
  return std::move(Callback.Edits);
276
10
}
llvm::Expected<llvm::SmallVector<clang::transformer::Edit, 1u> > rewriteDescendantsImpl<clang::Decl>(clang::Decl const&, clang::transformer::RewriteRule, clang::ast_matchers::MatchFinder::MatchResult const&)
Line
Count
Source
270
4
                       const MatchResult &Result) {
271
4
  ApplyRuleCallback Callback(std::move(Rule));
272
4
  MatchFinder Finder;
273
4
  Callback.registerMatchers<T>(Result.Nodes, &Finder);
274
4
  Finder.match(Node, *Result.Context);
275
4
  return std::move(Callback.Edits);
276
4
}
llvm::Expected<llvm::SmallVector<clang::transformer::Edit, 1u> > rewriteDescendantsImpl<clang::Stmt>(clang::Stmt const&, clang::transformer::RewriteRule, clang::ast_matchers::MatchFinder::MatchResult const&)
Line
Count
Source
270
4
                       const MatchResult &Result) {
271
4
  ApplyRuleCallback Callback(std::move(Rule));
272
4
  MatchFinder Finder;
273
4
  Callback.registerMatchers<T>(Result.Nodes, &Finder);
274
4
  Finder.match(Node, *Result.Context);
275
4
  return std::move(Callback.Edits);
276
4
}
llvm::Expected<llvm::SmallVector<clang::transformer::Edit, 1u> > rewriteDescendantsImpl<clang::TypeLoc>(clang::TypeLoc const&, clang::transformer::RewriteRule, clang::ast_matchers::MatchFinder::MatchResult const&)
Line
Count
Source
270
2
                       const MatchResult &Result) {
271
2
  ApplyRuleCallback Callback(std::move(Rule));
272
2
  MatchFinder Finder;
273
2
  Callback.registerMatchers<T>(Result.Nodes, &Finder);
274
2
  Finder.match(Node, *Result.Context);
275
2
  return std::move(Callback.Edits);
276
2
}
277
278
llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
279
transformer::detail::rewriteDescendants(const Decl &Node, RewriteRule Rule,
280
1
                                        const MatchResult &Result) {
281
1
  return rewriteDescendantsImpl(Node, std::move(Rule), Result);
282
1
}
283
284
llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
285
transformer::detail::rewriteDescendants(const Stmt &Node, RewriteRule Rule,
286
1
                                        const MatchResult &Result) {
287
1
  return rewriteDescendantsImpl(Node, std::move(Rule), Result);
288
1
}
289
290
llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
291
transformer::detail::rewriteDescendants(const TypeLoc &Node, RewriteRule Rule,
292
1
                                        const MatchResult &Result) {
293
1
  return rewriteDescendantsImpl(Node, std::move(Rule), Result);
294
1
}
295
296
llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
297
transformer::detail::rewriteDescendants(const DynTypedNode &DNode,
298
                                        RewriteRule Rule,
299
8
                                        const MatchResult &Result) {
300
8
  if (const auto *Node = DNode.get<Decl>())
301
3
    return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
302
5
  if (const auto *Node = DNode.get<Stmt>())
303
3
    return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
304
2
  if (const auto *Node = DNode.get<TypeLoc>())
305
1
    return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
306
307
1
  return llvm::make_error<llvm::StringError>(
308
1
      llvm::errc::invalid_argument,
309
1
      "type unsupported for recursive rewriting, Kind=" +
310
1
          DNode.getNodeKind().asStringRef());
311
2
}
312
313
EditGenerator transformer::rewriteDescendants(std::string NodeId,
314
8
                                              RewriteRule Rule) {
315
8
  return [NodeId = std::move(NodeId),
316
8
          Rule = std::move(Rule)](const MatchResult &Result)
317
8
             -> llvm::Expected<SmallVector<clang::transformer::Edit, 1>> {
318
8
    const ast_matchers::BoundNodes::IDToNodeMap &NodesMap =
319
8
        Result.Nodes.getMap();
320
8
    auto It = NodesMap.find(NodeId);
321
8
    if (It == NodesMap.end())
322
1
      return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
323
1
                                                 "ID not bound: " + NodeId);
324
7
    return detail::rewriteDescendants(It->second, std::move(Rule), Result);
325
8
  };
326
8
}
327
328
void transformer::addInclude(RewriteRule &Rule, StringRef Header,
329
2
                             IncludeFormat Format) {
330
2
  for (auto &Case : Rule.Cases)
331
2
    Case.Edits = flatten(std::move(Case.Edits), addInclude(Header, Format));
332
2
}
333
334
#ifndef NDEBUG
335
// Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
336
// (all node matcher types except for `QualType` and `Type`), rather than just
337
// banning `QualType` and `Type`.
338
88
static bool hasValidKind(const DynTypedMatcher &M) {
339
88
  return !M.canConvertTo<QualType>();
340
88
}
341
#endif
342
343
// Binds each rule's matcher to a unique (and deterministic) tag based on
344
// `TagBase` and the id paired with the case. All of the returned matchers have
345
// their traversal kind explicitly set, either based on a pre-set kind or to the
346
// provided `DefaultTraversalKind`.
347
static std::vector<DynTypedMatcher> taggedMatchers(
348
    StringRef TagBase,
349
    const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases,
350
82
    TraversalKind DefaultTraversalKind) {
351
82
  std::vector<DynTypedMatcher> Matchers;
352
82
  Matchers.reserve(Cases.size());
353
88
  for (const auto &Case : Cases) {
354
88
    std::string Tag = (TagBase + Twine(Case.first)).str();
355
    // HACK: Many matchers are not bindable, so ensure that tryBind will work.
356
88
    DynTypedMatcher BoundMatcher(Case.second.Matcher);
357
88
    BoundMatcher.setAllowBind(true);
358
88
    auto M = *BoundMatcher.tryBind(Tag);
359
88
    Matchers.push_back(!M.getTraversalKind()
360
88
                           ? 
M.withTraversalKind(DefaultTraversalKind)78
361
88
                           : 
std::move(M)10
);
362
88
  }
363
82
  return Matchers;
364
82
}
365
366
// Simply gathers the contents of the various rules into a single rule. The
367
// actual work to combine these into an ordered choice is deferred to matcher
368
// registration.
369
5
RewriteRule transformer::applyFirst(ArrayRef<RewriteRule> Rules) {
370
5
  RewriteRule R;
371
5
  for (auto &Rule : Rules)
372
11
    R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
373
5
  return R;
374
5
}
375
376
std::vector<DynTypedMatcher>
377
80
transformer::detail::buildMatchers(const RewriteRule &Rule) {
378
  // Map the cases into buckets of matchers -- one for each "root" AST kind,
379
  // which guarantees that they can be combined in a single anyOf matcher. Each
380
  // case is paired with an identifying number that is converted to a string id
381
  // in `taggedMatchers`.
382
80
  std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
383
80
      Buckets;
384
80
  const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
385
168
  for (int I = 0, N = Cases.size(); I < N; 
++I88
) {
386
88
    assert(hasValidKind(Cases[I].Matcher) &&
387
88
           "Matcher must be non-(Qual)Type node matcher");
388
0
    Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
389
88
  }
390
391
  // Each anyOf explicitly controls the traversal kind. The anyOf itself is set
392
  // to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to the kind
393
  // of the branches. Then, each branch is either left as is, if the kind is
394
  // already set, or explicitly set to `TK_AsIs`. We choose this setting because
395
  // it is the default interpretation of matchers.
396
80
  std::vector<DynTypedMatcher> Matchers;
397
82
  for (const auto &Bucket : Buckets) {
398
82
    DynTypedMatcher M = DynTypedMatcher::constructVariadic(
399
82
        DynTypedMatcher::VO_AnyOf, Bucket.first,
400
82
        taggedMatchers("Tag", Bucket.second, TK_AsIs));
401
82
    M.setAllowBind(true);
402
    // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
403
82
    Matchers.push_back(M.tryBind(RootID)->withTraversalKind(TK_AsIs));
404
82
  }
405
80
  return Matchers;
406
80
}
407
408
0
DynTypedMatcher transformer::detail::buildMatcher(const RewriteRule &Rule) {
409
0
  std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
410
0
  assert(Ms.size() == 1 && "Cases must have compatible matchers.");
411
0
  return Ms[0];
412
0
}
413
414
0
SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
415
0
  auto &NodesMap = Result.Nodes.getMap();
416
0
  auto Root = NodesMap.find(RootID);
417
0
  assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
418
0
  llvm::Optional<CharSourceRange> RootRange = tooling::getRangeForEdit(
419
0
      CharSourceRange::getTokenRange(Root->second.getSourceRange()),
420
0
      *Result.Context);
421
0
  if (RootRange)
422
0
    return RootRange->getBegin();
423
  // The match doesn't have a coherent range, so fall back to the expansion
424
  // location as the "beginning" of the match.
425
0
  return Result.SourceManager->getExpansionLoc(
426
0
      Root->second.getSourceRange().getBegin());
427
0
}
428
429
// Finds the case that was "selected" -- that is, whose matcher triggered the
430
// `MatchResult`.
431
const RewriteRule::Case &
432
transformer::detail::findSelectedCase(const MatchResult &Result,
433
127
                                  const RewriteRule &Rule) {
434
127
  if (Rule.Cases.size() == 1)
435
116
    return Rule.Cases[0];
436
437
11
  auto &NodesMap = Result.Nodes.getMap();
438
17
  for (size_t i = 0, N = Rule.Cases.size(); i < N; 
++i6
) {
439
17
    std::string Tag = ("Tag" + Twine(i)).str();
440
17
    if (NodesMap.find(Tag) != NodesMap.end())
441
11
      return Rule.Cases[i];
442
17
  }
443
0
  llvm_unreachable("No tag found for this rule.");
444
11
}
445
446
const llvm::StringRef RewriteRule::RootID = ::clang::transformer::RootID;