Coverage Report

Created: 2020-02-25 14:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Transformer/Stencil.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Stencil.cpp - Stencil 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/Stencil.h"
10
#include "clang/AST/ASTContext.h"
11
#include "clang/AST/ASTTypeTraits.h"
12
#include "clang/AST/Expr.h"
13
#include "clang/ASTMatchers/ASTMatchFinder.h"
14
#include "clang/ASTMatchers/ASTMatchers.h"
15
#include "clang/Lex/Lexer.h"
16
#include "clang/Tooling/Transformer/SourceCode.h"
17
#include "clang/Tooling/Transformer/SourceCodeBuilders.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/ADT/Twine.h"
20
#include "llvm/Support/Errc.h"
21
#include <atomic>
22
#include <memory>
23
#include <string>
24
25
using namespace clang;
26
using namespace transformer;
27
28
using ast_matchers::MatchFinder;
29
using llvm::errc;
30
using llvm::Error;
31
using llvm::Expected;
32
using llvm::StringError;
33
34
static llvm::Expected<DynTypedNode>
35
0
getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) {
36
0
  auto &NodesMap = Nodes.getMap();
37
0
  auto It = NodesMap.find(Id);
38
0
  if (It == NodesMap.end())
39
0
    return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
40
0
                                               "Id not bound: " + Id);
41
0
  return It->second;
42
0
}
43
44
namespace {
45
// An arbitrary fragment of code within a stencil.
46
struct RawTextData {
47
84
  explicit RawTextData(std::string T) : Text(std::move(T)) {}
48
  std::string Text;
49
};
50
51
// A debugging operation to dump the AST for a particular (bound) AST node.
52
struct DebugPrintNodeData {
53
1
  explicit DebugPrintNodeData(std::string S) : Id(std::move(S)) {}
54
  std::string Id;
55
};
56
57
// Operators that take a single node Id as an argument.
58
enum class UnaryNodeOperator {
59
  Parens,
60
  Deref,
61
  MaybeDeref,
62
  AddressOf,
63
  MaybeAddressOf,
64
};
65
66
// Generic container for stencil operations with a (single) node-id argument.
67
struct UnaryOperationData {
68
  UnaryOperationData(UnaryNodeOperator Op, std::string Id)
69
20
      : Op(Op), Id(std::move(Id)) {}
70
  UnaryNodeOperator Op;
71
  std::string Id;
72
};
73
74
// The fragment of code corresponding to the selected range.
75
struct SelectorData {
76
9
  explicit SelectorData(RangeSelector S) : Selector(std::move(S)) {}
77
  RangeSelector Selector;
78
};
79
80
// A stencil operation to build a member access `e.m` or `e->m`, as appropriate.
81
struct AccessData {
82
  AccessData(StringRef BaseId, Stencil Member)
83
15
      : BaseId(std::string(BaseId)), Member(std::move(Member)) {}
84
  std::string BaseId;
85
  Stencil Member;
86
};
87
88
struct IfBoundData {
89
  IfBoundData(StringRef Id, Stencil TrueStencil, Stencil FalseStencil)
90
      : Id(std::string(Id)), TrueStencil(std::move(TrueStencil)),
91
5
        FalseStencil(std::move(FalseStencil)) {}
92
  std::string Id;
93
  Stencil TrueStencil;
94
  Stencil FalseStencil;
95
};
96
97
struct SequenceData {
98
6
  SequenceData(std::vector<Stencil> Stencils) : Stencils(std::move(Stencils)) {}
99
  std::vector<Stencil> Stencils;
100
};
101
102
18
std::string toStringData(const RawTextData &Data) {
103
18
  std::string Result;
104
18
  llvm::raw_string_ostream OS(Result);
105
18
  OS << "\"";
106
18
  OS.write_escaped(Data.Text);
107
18
  OS << "\"";
108
18
  OS.flush();
109
18
  return Result;
110
18
}
111
112
1
std::string toStringData(const DebugPrintNodeData &Data) {
113
1
  return (llvm::Twine("dPrint(\"") + Data.Id + "\")").str();
114
1
}
115
116
3
std::string toStringData(const UnaryOperationData &Data) {
117
3
  StringRef OpName;
118
3
  switch (Data.Op) {
119
1
  case UnaryNodeOperator::Parens:
120
1
    OpName = "expression";
121
1
    break;
122
1
  case UnaryNodeOperator::Deref:
123
1
    OpName = "deref";
124
1
    break;
125
0
  case UnaryNodeOperator::MaybeDeref:
126
0
    OpName = "maybeDeref";
127
0
    break;
128
1
  case UnaryNodeOperator::AddressOf:
129
1
    OpName = "addressOf";
130
1
    break;
131
0
  case UnaryNodeOperator::MaybeAddressOf:
132
0
    OpName = "maybeAddressOf";
133
0
    break;
134
3
  }
135
3
  return (OpName + "(\"" + Data.Id + "\")").str();
136
3
}
137
138
2
std::string toStringData(const SelectorData &) { return "selection(...)"; }
139
140
8
std::string toStringData(const AccessData &Data) {
141
8
  return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
142
8
          Data.Member->toString() + ")")
143
8
      .str();
144
8
}
145
146
3
std::string toStringData(const IfBoundData &Data) {
147
3
  return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
148
3
          Data.TrueStencil->toString() + ", " + Data.FalseStencil->toString() +
149
3
          ")")
150
3
      .str();
151
3
}
152
153
1
std::string toStringData(const MatchConsumer<std::string> &) {
154
1
  return "run(...)";
155
1
}
156
157
4
std::string toStringData(const SequenceData &Data) {
158
4
  llvm::SmallVector<std::string, 2> Parts;
159
4
  Parts.reserve(Data.Stencils.size());
160
4
  for (const auto &S : Data.Stencils)
161
10
    Parts.push_back(S->toString());
162
4
  return (llvm::Twine("seq(") + llvm::join(Parts, ", ") + ")").str();
163
4
}
164
165
// The `evalData()` overloads evaluate the given stencil data to a string, given
166
// the match result, and append it to `Result`. We define an overload for each
167
// type of stencil data.
168
169
Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
170
52
               std::string *Result) {
171
52
  Result->append(Data.Text);
172
52
  return Error::success();
173
52
}
174
175
Error evalData(const DebugPrintNodeData &Data,
176
0
               const MatchFinder::MatchResult &Match, std::string *Result) {
177
0
  std::string Output;
178
0
  llvm::raw_string_ostream Os(Output);
179
0
  auto NodeOrErr = getNode(Match.Nodes, Data.Id);
180
0
  if (auto Err = NodeOrErr.takeError())
181
0
    return Err;
182
0
  NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
183
0
  *Result += Os.str();
184
0
  return Error::success();
185
0
}
186
187
Error evalData(const UnaryOperationData &Data,
188
17
               const MatchFinder::MatchResult &Match, std::string *Result) {
189
17
  const auto *E = Match.Nodes.getNodeAs<Expr>(Data.Id);
190
17
  if (E == nullptr)
191
1
    return llvm::make_error<StringError>(
192
1
        errc::invalid_argument, "Id not bound or not Expr: " + Data.Id);
193
16
  llvm::Optional<std::string> Source;
194
16
  switch (Data.Op) {
195
3
  case UnaryNodeOperator::Parens:
196
3
    Source = tooling::buildParens(*E, *Match.Context);
197
3
    break;
198
3
  case UnaryNodeOperator::Deref:
199
3
    Source = tooling::buildDereference(*E, *Match.Context);
200
3
    break;
201
4
  case UnaryNodeOperator::MaybeDeref:
202
4
    if (!E->getType()->isAnyPointerType()) {
203
1
      *Result += tooling::getText(*E, *Match.Context);
204
1
      return Error::success();
205
1
    }
206
3
    Source = tooling::buildDereference(*E, *Match.Context);
207
3
    break;
208
4
  case UnaryNodeOperator::AddressOf:
209
4
    Source = tooling::buildAddressOf(*E, *Match.Context);
210
4
    break;
211
3
  case UnaryNodeOperator::MaybeAddressOf:
212
2
    if (E->getType()->isAnyPointerType()) {
213
1
      *Result += tooling::getText(*E, *Match.Context);
214
1
      return Error::success();
215
1
    }
216
1
    Source = tooling::buildAddressOf(*E, *Match.Context);
217
1
    break;
218
14
  }
219
14
  if (!Source)
220
0
    return llvm::make_error<StringError>(
221
0
        errc::invalid_argument,
222
0
        "Could not construct expression source from ID: " + Data.Id);
223
14
  *Result += *Source;
224
14
  return Error::success();
225
14
}
226
227
Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match,
228
7
               std::string *Result) {
229
7
  auto Range = Data.Selector(Match);
230
7
  if (!Range)
231
1
    return Range.takeError();
232
6
  if (auto Err = tooling::validateEditRange(*Range, *Match.SourceManager))
233
1
    return Err;
234
5
  *Result += tooling::getText(*Range, *Match.Context);
235
5
  return Error::success();
236
5
}
237
238
Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match,
239
7
               std::string *Result) {
240
7
  const auto *E = Match.Nodes.getNodeAs<Expr>(Data.BaseId);
241
7
  if (E == nullptr)
242
0
    return llvm::make_error<StringError>(errc::invalid_argument,
243
0
                                         "Id not bound: " + Data.BaseId);
244
7
  if (!E->isImplicitCXXThis()) {
245
6
    if (llvm::Optional<std::string> S =
246
6
            E->getType()->isAnyPointerType()
247
6
                ? tooling::buildArrow(*E, *Match.Context)
248
6
                : tooling::buildDot(*E, *Match.Context))
249
6
      *Result += *S;
250
0
    else
251
0
      return llvm::make_error<StringError>(
252
0
          errc::invalid_argument,
253
0
          "Could not construct object text from ID: " + Data.BaseId);
254
7
  }
255
7
  return Data.Member->eval(Match, Result);
256
7
}
257
258
Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match,
259
2
               std::string *Result) {
260
2
  auto &M = Match.Nodes.getMap();
261
2
  return (M.find(Data.Id) != M.end() ? 
Data.TrueStencil1
:
Data.FalseStencil1
)
262
2
      ->eval(Match, Result);
263
2
}
264
265
Error evalData(const MatchConsumer<std::string> &Fn,
266
1
               const MatchFinder::MatchResult &Match, std::string *Result) {
267
1
  Expected<std::string> Value = Fn(Match);
268
1
  if (!Value)
269
0
    return Value.takeError();
270
1
  *Result += *Value;
271
1
  return Error::success();
272
1
}
273
274
Error evalData(const SequenceData &Data, const MatchFinder::MatchResult &Match,
275
2
               std::string *Result) {
276
2
  for (const auto &S : Data.Stencils)
277
10
    if (auto Err = S->eval(Match, Result))
278
1
      return Err;
279
2
  
return Error::success()1
;
280
2
}
281
282
template <typename T> class StencilImpl : public StencilInterface {
283
  T Data;
284
285
public:
286
  template <typename... Ps>
287
142
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::RawTextData>::StencilImpl<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
287
84
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SelectorData>::StencilImpl<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> >(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>&&)
Line
Count
Source
287
9
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::DebugPrintNodeData>::StencilImpl<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
287
1
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::UnaryOperationData>::StencilImpl<(anonymous namespace)::UnaryNodeOperator, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >((anonymous namespace)::UnaryNodeOperator&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
287
20
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::AccessData>::StencilImpl<llvm::StringRef&, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(llvm::StringRef&&&, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&&)
Line
Count
Source
287
15
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::IfBoundData>::StencilImpl<llvm::StringRef&, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(llvm::StringRef&&&, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&&, std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&&)
Line
Count
Source
287
5
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<std::__1::function<llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (clang::ast_matchers::MatchFinder::MatchResult const&)> >::StencilImpl<std::__1::function<llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (clang::ast_matchers::MatchFinder::MatchResult const&)> >(std::__1::function<llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (clang::ast_matchers::MatchFinder::MatchResult const&)>&&)
Line
Count
Source
287
2
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SequenceData>::StencilImpl<std::__1::vector<std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > >(std::__1::vector<std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::shared_ptr<clang::transformer::MatchComputation<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > >&&)
Line
Count
Source
287
6
  explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
288
289
  Error eval(const MatchFinder::MatchResult &Match,
290
88
             std::string *Result) const override {
291
88
    return evalData(Data, Match, Result);
292
88
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::RawTextData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
52
             std::string *Result) const override {
291
52
    return evalData(Data, Match, Result);
292
52
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SelectorData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
7
             std::string *Result) const override {
291
7
    return evalData(Data, Match, Result);
292
7
  }
Unexecuted instantiation: Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::DebugPrintNodeData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::UnaryOperationData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
17
             std::string *Result) const override {
291
17
    return evalData(Data, Match, Result);
292
17
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::AccessData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
7
             std::string *Result) const override {
291
7
    return evalData(Data, Match, Result);
292
7
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::IfBoundData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
2
             std::string *Result) const override {
291
2
    return evalData(Data, Match, Result);
292
2
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<std::__1::function<llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (clang::ast_matchers::MatchFinder::MatchResult const&)> >::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
1
             std::string *Result) const override {
291
1
    return evalData(Data, Match, Result);
292
1
  }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SequenceData>::eval(clang::ast_matchers::MatchFinder::MatchResult const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
290
2
             std::string *Result) const override {
291
2
    return evalData(Data, Match, Result);
292
2
  }
293
294
40
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::RawTextData>::toString() const
Line
Count
Source
294
18
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SelectorData>::toString() const
Line
Count
Source
294
2
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::DebugPrintNodeData>::toString() const
Line
Count
Source
294
1
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::UnaryOperationData>::toString() const
Line
Count
Source
294
3
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::AccessData>::toString() const
Line
Count
Source
294
8
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::IfBoundData>::toString() const
Line
Count
Source
294
3
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<std::__1::function<llvm::Expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (clang::ast_matchers::MatchFinder::MatchResult const&)> >::toString() const
Line
Count
Source
294
1
  std::string toString() const override { return toStringData(Data); }
Stencil.cpp:(anonymous namespace)::StencilImpl<(anonymous namespace)::SequenceData>::toString() const
Line
Count
Source
294
4
  std::string toString() const override { return toStringData(Data); }
295
};
296
} // namespace
297
298
62
Stencil transformer::detail::makeStencil(StringRef Text) { return text(Text); }
299
300
8
Stencil transformer::detail::makeStencil(RangeSelector Selector) {
301
8
  return selection(std::move(Selector));
302
8
}
303
304
84
Stencil transformer::text(StringRef Text) {
305
84
  return std::make_shared<StencilImpl<RawTextData>>(std::string(Text));
306
84
}
307
308
9
Stencil transformer::selection(RangeSelector Selector) {
309
9
  return std::make_shared<StencilImpl<SelectorData>>(std::move(Selector));
310
9
}
311
312
1
Stencil transformer::dPrint(StringRef Id) {
313
1
  return std::make_shared<StencilImpl<DebugPrintNodeData>>(std::string(Id));
314
1
}
315
316
5
Stencil transformer::expression(llvm::StringRef Id) {
317
5
  return std::make_shared<StencilImpl<UnaryOperationData>>(
318
5
      UnaryNodeOperator::Parens, std::string(Id));
319
5
}
320
321
4
Stencil transformer::deref(llvm::StringRef ExprId) {
322
4
  return std::make_shared<StencilImpl<UnaryOperationData>>(
323
4
      UnaryNodeOperator::Deref, std::string(ExprId));
324
4
}
325
326
4
Stencil transformer::maybeDeref(llvm::StringRef ExprId) {
327
4
  return std::make_shared<StencilImpl<UnaryOperationData>>(
328
4
      UnaryNodeOperator::MaybeDeref, std::string(ExprId));
329
4
}
330
331
5
Stencil transformer::addressOf(llvm::StringRef ExprId) {
332
5
  return std::make_shared<StencilImpl<UnaryOperationData>>(
333
5
      UnaryNodeOperator::AddressOf, std::string(ExprId));
334
5
}
335
336
2
Stencil transformer::maybeAddressOf(llvm::StringRef ExprId) {
337
2
  return std::make_shared<StencilImpl<UnaryOperationData>>(
338
2
      UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
339
2
}
340
341
15
Stencil transformer::access(StringRef BaseId, Stencil Member) {
342
15
  return std::make_shared<StencilImpl<AccessData>>(BaseId, std::move(Member));
343
15
}
344
345
Stencil transformer::ifBound(StringRef Id, Stencil TrueStencil,
346
5
                             Stencil FalseStencil) {
347
5
  return std::make_shared<StencilImpl<IfBoundData>>(Id, std::move(TrueStencil),
348
5
                                                    std::move(FalseStencil));
349
5
}
350
351
2
Stencil transformer::run(MatchConsumer<std::string> Fn) {
352
2
  return std::make_shared<StencilImpl<MatchConsumer<std::string>>>(
353
2
      std::move(Fn));
354
2
}
355
356
61
Stencil transformer::catVector(std::vector<Stencil> Parts) {
357
61
  // Only one argument, so don't wrap in sequence.
358
61
  if (Parts.size() == 1)
359
55
    return std::move(Parts[0]);
360
6
  return std::make_shared<StencilImpl<SequenceData>>(std::move(Parts));
361
6
}