106f32e7eSjoerg //===--- Stencil.cpp - Stencil implementation -------------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "clang/Tooling/Transformer/Stencil.h"
1006f32e7eSjoerg #include "clang/AST/ASTContext.h"
1106f32e7eSjoerg #include "clang/AST/ASTTypeTraits.h"
1206f32e7eSjoerg #include "clang/AST/Expr.h"
1306f32e7eSjoerg #include "clang/ASTMatchers/ASTMatchFinder.h"
1406f32e7eSjoerg #include "clang/ASTMatchers/ASTMatchers.h"
15*13fbcb42Sjoerg #include "clang/Basic/SourceLocation.h"
1606f32e7eSjoerg #include "clang/Lex/Lexer.h"
1706f32e7eSjoerg #include "clang/Tooling/Transformer/SourceCode.h"
1806f32e7eSjoerg #include "clang/Tooling/Transformer/SourceCodeBuilders.h"
19*13fbcb42Sjoerg #include "llvm/ADT/SmallVector.h"
2006f32e7eSjoerg #include "llvm/ADT/Twine.h"
2106f32e7eSjoerg #include "llvm/Support/Errc.h"
22*13fbcb42Sjoerg #include "llvm/Support/Error.h"
2306f32e7eSjoerg #include <atomic>
2406f32e7eSjoerg #include <memory>
2506f32e7eSjoerg #include <string>
2606f32e7eSjoerg 
2706f32e7eSjoerg using namespace clang;
2806f32e7eSjoerg using namespace transformer;
2906f32e7eSjoerg 
3006f32e7eSjoerg using ast_matchers::MatchFinder;
3106f32e7eSjoerg using llvm::errc;
3206f32e7eSjoerg using llvm::Error;
3306f32e7eSjoerg using llvm::Expected;
3406f32e7eSjoerg using llvm::StringError;
3506f32e7eSjoerg 
3606f32e7eSjoerg static llvm::Expected<DynTypedNode>
getNode(const ast_matchers::BoundNodes & Nodes,StringRef Id)3706f32e7eSjoerg getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) {
3806f32e7eSjoerg   auto &NodesMap = Nodes.getMap();
3906f32e7eSjoerg   auto It = NodesMap.find(Id);
4006f32e7eSjoerg   if (It == NodesMap.end())
4106f32e7eSjoerg     return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
4206f32e7eSjoerg                                                "Id not bound: " + Id);
4306f32e7eSjoerg   return It->second;
4406f32e7eSjoerg }
4506f32e7eSjoerg 
4606f32e7eSjoerg namespace {
4706f32e7eSjoerg // An arbitrary fragment of code within a stencil.
4806f32e7eSjoerg struct RawTextData {
RawTextData__anon373aca1a0111::RawTextData4906f32e7eSjoerg   explicit RawTextData(std::string T) : Text(std::move(T)) {}
5006f32e7eSjoerg   std::string Text;
5106f32e7eSjoerg };
5206f32e7eSjoerg 
5306f32e7eSjoerg // A debugging operation to dump the AST for a particular (bound) AST node.
5406f32e7eSjoerg struct DebugPrintNodeData {
DebugPrintNodeData__anon373aca1a0111::DebugPrintNodeData5506f32e7eSjoerg   explicit DebugPrintNodeData(std::string S) : Id(std::move(S)) {}
5606f32e7eSjoerg   std::string Id;
5706f32e7eSjoerg };
5806f32e7eSjoerg 
5906f32e7eSjoerg // Operators that take a single node Id as an argument.
6006f32e7eSjoerg enum class UnaryNodeOperator {
6106f32e7eSjoerg   Parens,
6206f32e7eSjoerg   Deref,
63*13fbcb42Sjoerg   MaybeDeref,
64*13fbcb42Sjoerg   AddressOf,
65*13fbcb42Sjoerg   MaybeAddressOf,
66*13fbcb42Sjoerg   Describe,
6706f32e7eSjoerg };
6806f32e7eSjoerg 
6906f32e7eSjoerg // Generic container for stencil operations with a (single) node-id argument.
7006f32e7eSjoerg struct UnaryOperationData {
UnaryOperationData__anon373aca1a0111::UnaryOperationData7106f32e7eSjoerg   UnaryOperationData(UnaryNodeOperator Op, std::string Id)
7206f32e7eSjoerg       : Op(Op), Id(std::move(Id)) {}
7306f32e7eSjoerg   UnaryNodeOperator Op;
7406f32e7eSjoerg   std::string Id;
7506f32e7eSjoerg };
7606f32e7eSjoerg 
7706f32e7eSjoerg // The fragment of code corresponding to the selected range.
7806f32e7eSjoerg struct SelectorData {
SelectorData__anon373aca1a0111::SelectorData7906f32e7eSjoerg   explicit SelectorData(RangeSelector S) : Selector(std::move(S)) {}
8006f32e7eSjoerg   RangeSelector Selector;
8106f32e7eSjoerg };
8206f32e7eSjoerg 
8306f32e7eSjoerg // A stencil operation to build a member access `e.m` or `e->m`, as appropriate.
8406f32e7eSjoerg struct AccessData {
AccessData__anon373aca1a0111::AccessData85*13fbcb42Sjoerg   AccessData(StringRef BaseId, Stencil Member)
86*13fbcb42Sjoerg       : BaseId(std::string(BaseId)), Member(std::move(Member)) {}
8706f32e7eSjoerg   std::string BaseId;
88*13fbcb42Sjoerg   Stencil Member;
8906f32e7eSjoerg };
9006f32e7eSjoerg 
9106f32e7eSjoerg struct IfBoundData {
IfBoundData__anon373aca1a0111::IfBoundData92*13fbcb42Sjoerg   IfBoundData(StringRef Id, Stencil TrueStencil, Stencil FalseStencil)
93*13fbcb42Sjoerg       : Id(std::string(Id)), TrueStencil(std::move(TrueStencil)),
94*13fbcb42Sjoerg         FalseStencil(std::move(FalseStencil)) {}
9506f32e7eSjoerg   std::string Id;
96*13fbcb42Sjoerg   Stencil TrueStencil;
97*13fbcb42Sjoerg   Stencil FalseStencil;
98*13fbcb42Sjoerg };
99*13fbcb42Sjoerg 
100*13fbcb42Sjoerg struct SequenceData {
SequenceData__anon373aca1a0111::SequenceData101*13fbcb42Sjoerg   SequenceData(std::vector<Stencil> Stencils) : Stencils(std::move(Stencils)) {}
102*13fbcb42Sjoerg   std::vector<Stencil> Stencils;
10306f32e7eSjoerg };
10406f32e7eSjoerg 
toStringData(const RawTextData & Data)10506f32e7eSjoerg std::string toStringData(const RawTextData &Data) {
10606f32e7eSjoerg   std::string Result;
10706f32e7eSjoerg   llvm::raw_string_ostream OS(Result);
10806f32e7eSjoerg   OS << "\"";
10906f32e7eSjoerg   OS.write_escaped(Data.Text);
11006f32e7eSjoerg   OS << "\"";
11106f32e7eSjoerg   OS.flush();
11206f32e7eSjoerg   return Result;
11306f32e7eSjoerg }
11406f32e7eSjoerg 
toStringData(const DebugPrintNodeData & Data)11506f32e7eSjoerg std::string toStringData(const DebugPrintNodeData &Data) {
11606f32e7eSjoerg   return (llvm::Twine("dPrint(\"") + Data.Id + "\")").str();
11706f32e7eSjoerg }
11806f32e7eSjoerg 
toStringData(const UnaryOperationData & Data)11906f32e7eSjoerg std::string toStringData(const UnaryOperationData &Data) {
12006f32e7eSjoerg   StringRef OpName;
12106f32e7eSjoerg   switch (Data.Op) {
12206f32e7eSjoerg   case UnaryNodeOperator::Parens:
12306f32e7eSjoerg     OpName = "expression";
12406f32e7eSjoerg     break;
12506f32e7eSjoerg   case UnaryNodeOperator::Deref:
12606f32e7eSjoerg     OpName = "deref";
12706f32e7eSjoerg     break;
128*13fbcb42Sjoerg   case UnaryNodeOperator::MaybeDeref:
129*13fbcb42Sjoerg     OpName = "maybeDeref";
130*13fbcb42Sjoerg     break;
131*13fbcb42Sjoerg   case UnaryNodeOperator::AddressOf:
13206f32e7eSjoerg     OpName = "addressOf";
13306f32e7eSjoerg     break;
134*13fbcb42Sjoerg   case UnaryNodeOperator::MaybeAddressOf:
135*13fbcb42Sjoerg     OpName = "maybeAddressOf";
136*13fbcb42Sjoerg     break;
137*13fbcb42Sjoerg   case UnaryNodeOperator::Describe:
138*13fbcb42Sjoerg     OpName = "describe";
139*13fbcb42Sjoerg     break;
14006f32e7eSjoerg   }
14106f32e7eSjoerg   return (OpName + "(\"" + Data.Id + "\")").str();
14206f32e7eSjoerg }
14306f32e7eSjoerg 
toStringData(const SelectorData &)14406f32e7eSjoerg std::string toStringData(const SelectorData &) { return "selection(...)"; }
14506f32e7eSjoerg 
toStringData(const AccessData & Data)14606f32e7eSjoerg std::string toStringData(const AccessData &Data) {
14706f32e7eSjoerg   return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
148*13fbcb42Sjoerg           Data.Member->toString() + ")")
14906f32e7eSjoerg       .str();
15006f32e7eSjoerg }
15106f32e7eSjoerg 
toStringData(const IfBoundData & Data)15206f32e7eSjoerg std::string toStringData(const IfBoundData &Data) {
15306f32e7eSjoerg   return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
154*13fbcb42Sjoerg           Data.TrueStencil->toString() + ", " + Data.FalseStencil->toString() +
155*13fbcb42Sjoerg           ")")
15606f32e7eSjoerg       .str();
15706f32e7eSjoerg }
15806f32e7eSjoerg 
toStringData(const MatchConsumer<std::string> &)15906f32e7eSjoerg std::string toStringData(const MatchConsumer<std::string> &) {
16006f32e7eSjoerg   return "run(...)";
16106f32e7eSjoerg }
16206f32e7eSjoerg 
toStringData(const SequenceData & Data)163*13fbcb42Sjoerg std::string toStringData(const SequenceData &Data) {
164*13fbcb42Sjoerg   llvm::SmallVector<std::string, 2> Parts;
165*13fbcb42Sjoerg   Parts.reserve(Data.Stencils.size());
166*13fbcb42Sjoerg   for (const auto &S : Data.Stencils)
167*13fbcb42Sjoerg     Parts.push_back(S->toString());
168*13fbcb42Sjoerg   return (llvm::Twine("seq(") + llvm::join(Parts, ", ") + ")").str();
169*13fbcb42Sjoerg }
170*13fbcb42Sjoerg 
17106f32e7eSjoerg // The `evalData()` overloads evaluate the given stencil data to a string, given
17206f32e7eSjoerg // the match result, and append it to `Result`. We define an overload for each
17306f32e7eSjoerg // type of stencil data.
17406f32e7eSjoerg 
evalData(const RawTextData & Data,const MatchFinder::MatchResult &,std::string * Result)17506f32e7eSjoerg Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
17606f32e7eSjoerg                std::string *Result) {
17706f32e7eSjoerg   Result->append(Data.Text);
17806f32e7eSjoerg   return Error::success();
17906f32e7eSjoerg }
18006f32e7eSjoerg 
printNode(StringRef Id,const MatchFinder::MatchResult & Match,std::string * Result)181*13fbcb42Sjoerg static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match,
182*13fbcb42Sjoerg                        std::string *Result) {
18306f32e7eSjoerg   std::string Output;
18406f32e7eSjoerg   llvm::raw_string_ostream Os(Output);
185*13fbcb42Sjoerg   auto NodeOrErr = getNode(Match.Nodes, Id);
18606f32e7eSjoerg   if (auto Err = NodeOrErr.takeError())
18706f32e7eSjoerg     return Err;
18806f32e7eSjoerg   NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
18906f32e7eSjoerg   *Result += Os.str();
19006f32e7eSjoerg   return Error::success();
19106f32e7eSjoerg }
19206f32e7eSjoerg 
evalData(const DebugPrintNodeData & Data,const MatchFinder::MatchResult & Match,std::string * Result)193*13fbcb42Sjoerg Error evalData(const DebugPrintNodeData &Data,
194*13fbcb42Sjoerg                const MatchFinder::MatchResult &Match, std::string *Result) {
195*13fbcb42Sjoerg   return printNode(Data.Id, Match, Result);
196*13fbcb42Sjoerg }
197*13fbcb42Sjoerg 
198*13fbcb42Sjoerg // FIXME: Consider memoizing this function using the `ASTContext`.
isSmartPointerType(QualType Ty,ASTContext & Context)199*13fbcb42Sjoerg static bool isSmartPointerType(QualType Ty, ASTContext &Context) {
200*13fbcb42Sjoerg   using namespace ::clang::ast_matchers;
201*13fbcb42Sjoerg 
202*13fbcb42Sjoerg   // Optimization: hard-code common smart-pointer types. This can/should be
203*13fbcb42Sjoerg   // removed if we start caching the results of this function.
204*13fbcb42Sjoerg   auto KnownSmartPointer =
205*13fbcb42Sjoerg       cxxRecordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr"));
206*13fbcb42Sjoerg   const auto QuacksLikeASmartPointer = cxxRecordDecl(
207*13fbcb42Sjoerg       hasMethod(cxxMethodDecl(hasOverloadedOperatorName("->"),
208*13fbcb42Sjoerg                               returns(qualType(pointsTo(type()))))),
209*13fbcb42Sjoerg       hasMethod(cxxMethodDecl(hasOverloadedOperatorName("*"),
210*13fbcb42Sjoerg                               returns(qualType(references(type()))))));
211*13fbcb42Sjoerg   const auto SmartPointer = qualType(hasDeclaration(
212*13fbcb42Sjoerg       cxxRecordDecl(anyOf(KnownSmartPointer, QuacksLikeASmartPointer))));
213*13fbcb42Sjoerg   return match(SmartPointer, Ty, Context).size() > 0;
214*13fbcb42Sjoerg }
215*13fbcb42Sjoerg 
evalData(const UnaryOperationData & Data,const MatchFinder::MatchResult & Match,std::string * Result)21606f32e7eSjoerg Error evalData(const UnaryOperationData &Data,
21706f32e7eSjoerg                const MatchFinder::MatchResult &Match, std::string *Result) {
218*13fbcb42Sjoerg   // The `Describe` operation can be applied to any node, not just expressions,
219*13fbcb42Sjoerg   // so it is handled here, separately.
220*13fbcb42Sjoerg   if (Data.Op == UnaryNodeOperator::Describe)
221*13fbcb42Sjoerg     return printNode(Data.Id, Match, Result);
222*13fbcb42Sjoerg 
22306f32e7eSjoerg   const auto *E = Match.Nodes.getNodeAs<Expr>(Data.Id);
22406f32e7eSjoerg   if (E == nullptr)
22506f32e7eSjoerg     return llvm::make_error<StringError>(
22606f32e7eSjoerg         errc::invalid_argument, "Id not bound or not Expr: " + Data.Id);
22706f32e7eSjoerg   llvm::Optional<std::string> Source;
22806f32e7eSjoerg   switch (Data.Op) {
22906f32e7eSjoerg   case UnaryNodeOperator::Parens:
23006f32e7eSjoerg     Source = tooling::buildParens(*E, *Match.Context);
23106f32e7eSjoerg     break;
23206f32e7eSjoerg   case UnaryNodeOperator::Deref:
23306f32e7eSjoerg     Source = tooling::buildDereference(*E, *Match.Context);
23406f32e7eSjoerg     break;
235*13fbcb42Sjoerg   case UnaryNodeOperator::MaybeDeref:
236*13fbcb42Sjoerg     if (E->getType()->isAnyPointerType() ||
237*13fbcb42Sjoerg         isSmartPointerType(E->getType(), *Match.Context)) {
238*13fbcb42Sjoerg       // Strip off any operator->. This can only occur inside an actual arrow
239*13fbcb42Sjoerg       // member access, so we treat it as equivalent to an actual object
240*13fbcb42Sjoerg       // expression.
241*13fbcb42Sjoerg       if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
242*13fbcb42Sjoerg         if (OpCall->getOperator() == clang::OO_Arrow &&
243*13fbcb42Sjoerg             OpCall->getNumArgs() == 1) {
244*13fbcb42Sjoerg           E = OpCall->getArg(0);
245*13fbcb42Sjoerg         }
246*13fbcb42Sjoerg       }
247*13fbcb42Sjoerg       Source = tooling::buildDereference(*E, *Match.Context);
248*13fbcb42Sjoerg       break;
249*13fbcb42Sjoerg     }
250*13fbcb42Sjoerg     *Result += tooling::getText(*E, *Match.Context);
251*13fbcb42Sjoerg     return Error::success();
252*13fbcb42Sjoerg   case UnaryNodeOperator::AddressOf:
25306f32e7eSjoerg     Source = tooling::buildAddressOf(*E, *Match.Context);
25406f32e7eSjoerg     break;
255*13fbcb42Sjoerg   case UnaryNodeOperator::MaybeAddressOf:
256*13fbcb42Sjoerg     if (E->getType()->isAnyPointerType() ||
257*13fbcb42Sjoerg         isSmartPointerType(E->getType(), *Match.Context)) {
258*13fbcb42Sjoerg       // Strip off any operator->. This can only occur inside an actual arrow
259*13fbcb42Sjoerg       // member access, so we treat it as equivalent to an actual object
260*13fbcb42Sjoerg       // expression.
261*13fbcb42Sjoerg       if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
262*13fbcb42Sjoerg         if (OpCall->getOperator() == clang::OO_Arrow &&
263*13fbcb42Sjoerg             OpCall->getNumArgs() == 1) {
264*13fbcb42Sjoerg           E = OpCall->getArg(0);
265*13fbcb42Sjoerg         }
266*13fbcb42Sjoerg       }
267*13fbcb42Sjoerg       *Result += tooling::getText(*E, *Match.Context);
268*13fbcb42Sjoerg       return Error::success();
269*13fbcb42Sjoerg     }
270*13fbcb42Sjoerg     Source = tooling::buildAddressOf(*E, *Match.Context);
271*13fbcb42Sjoerg     break;
272*13fbcb42Sjoerg   case UnaryNodeOperator::Describe:
273*13fbcb42Sjoerg     llvm_unreachable("This case is handled at the start of the function");
27406f32e7eSjoerg   }
27506f32e7eSjoerg   if (!Source)
27606f32e7eSjoerg     return llvm::make_error<StringError>(
27706f32e7eSjoerg         errc::invalid_argument,
27806f32e7eSjoerg         "Could not construct expression source from ID: " + Data.Id);
27906f32e7eSjoerg   *Result += *Source;
28006f32e7eSjoerg   return Error::success();
28106f32e7eSjoerg }
28206f32e7eSjoerg 
evalData(const SelectorData & Data,const MatchFinder::MatchResult & Match,std::string * Result)28306f32e7eSjoerg Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match,
28406f32e7eSjoerg                std::string *Result) {
285*13fbcb42Sjoerg   auto RawRange = Data.Selector(Match);
286*13fbcb42Sjoerg   if (!RawRange)
287*13fbcb42Sjoerg     return RawRange.takeError();
288*13fbcb42Sjoerg   CharSourceRange Range = Lexer::makeFileCharRange(
289*13fbcb42Sjoerg       *RawRange, *Match.SourceManager, Match.Context->getLangOpts());
290*13fbcb42Sjoerg   if (Range.isInvalid()) {
291*13fbcb42Sjoerg     // Validate the original range to attempt to get a meaningful error message.
292*13fbcb42Sjoerg     // If it's valid, then something else is the cause and we just return the
293*13fbcb42Sjoerg     // generic failure message.
294*13fbcb42Sjoerg     if (auto Err = tooling::validateEditRange(*RawRange, *Match.SourceManager))
295*13fbcb42Sjoerg       return handleErrors(std::move(Err), [](std::unique_ptr<StringError> E) {
296*13fbcb42Sjoerg         assert(E->convertToErrorCode() ==
297*13fbcb42Sjoerg                    llvm::make_error_code(errc::invalid_argument) &&
298*13fbcb42Sjoerg                "Validation errors must carry the invalid_argument code");
299*13fbcb42Sjoerg         return llvm::createStringError(
300*13fbcb42Sjoerg             errc::invalid_argument,
301*13fbcb42Sjoerg             "selected range could not be resolved to a valid source range; " +
302*13fbcb42Sjoerg                 E->getMessage());
303*13fbcb42Sjoerg       });
304*13fbcb42Sjoerg     return llvm::createStringError(
305*13fbcb42Sjoerg         errc::invalid_argument,
306*13fbcb42Sjoerg         "selected range could not be resolved to a valid source range");
307*13fbcb42Sjoerg   }
308*13fbcb42Sjoerg   // Validate `Range`, because `makeFileCharRange` accepts some ranges that
309*13fbcb42Sjoerg   // `validateEditRange` rejects.
310*13fbcb42Sjoerg   if (auto Err = tooling::validateEditRange(Range, *Match.SourceManager))
311*13fbcb42Sjoerg     return joinErrors(
312*13fbcb42Sjoerg         llvm::createStringError(errc::invalid_argument,
313*13fbcb42Sjoerg                                 "selected range is not valid for editing"),
314*13fbcb42Sjoerg         std::move(Err));
315*13fbcb42Sjoerg   *Result += tooling::getText(Range, *Match.Context);
31606f32e7eSjoerg   return Error::success();
31706f32e7eSjoerg }
31806f32e7eSjoerg 
evalData(const AccessData & Data,const MatchFinder::MatchResult & Match,std::string * Result)31906f32e7eSjoerg Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match,
32006f32e7eSjoerg                std::string *Result) {
32106f32e7eSjoerg   const auto *E = Match.Nodes.getNodeAs<Expr>(Data.BaseId);
32206f32e7eSjoerg   if (E == nullptr)
32306f32e7eSjoerg     return llvm::make_error<StringError>(errc::invalid_argument,
32406f32e7eSjoerg                                          "Id not bound: " + Data.BaseId);
32506f32e7eSjoerg   if (!E->isImplicitCXXThis()) {
326*13fbcb42Sjoerg     llvm::Optional<std::string> S;
327*13fbcb42Sjoerg     if (E->getType()->isAnyPointerType() ||
328*13fbcb42Sjoerg         isSmartPointerType(E->getType(), *Match.Context)) {
329*13fbcb42Sjoerg       // Strip off any operator->. This can only occur inside an actual arrow
330*13fbcb42Sjoerg       // member access, so we treat it as equivalent to an actual object
331*13fbcb42Sjoerg       // expression.
332*13fbcb42Sjoerg       if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
333*13fbcb42Sjoerg         if (OpCall->getOperator() == clang::OO_Arrow &&
334*13fbcb42Sjoerg             OpCall->getNumArgs() == 1) {
335*13fbcb42Sjoerg           E = OpCall->getArg(0);
336*13fbcb42Sjoerg         }
337*13fbcb42Sjoerg       }
338*13fbcb42Sjoerg       S = tooling::buildArrow(*E, *Match.Context);
339*13fbcb42Sjoerg     } else {
340*13fbcb42Sjoerg       S = tooling::buildDot(*E, *Match.Context);
341*13fbcb42Sjoerg     }
342*13fbcb42Sjoerg     if (S.hasValue())
34306f32e7eSjoerg       *Result += *S;
34406f32e7eSjoerg     else
34506f32e7eSjoerg       return llvm::make_error<StringError>(
34606f32e7eSjoerg           errc::invalid_argument,
34706f32e7eSjoerg           "Could not construct object text from ID: " + Data.BaseId);
34806f32e7eSjoerg   }
349*13fbcb42Sjoerg   return Data.Member->eval(Match, Result);
35006f32e7eSjoerg }
35106f32e7eSjoerg 
evalData(const IfBoundData & Data,const MatchFinder::MatchResult & Match,std::string * Result)35206f32e7eSjoerg Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match,
35306f32e7eSjoerg                std::string *Result) {
35406f32e7eSjoerg   auto &M = Match.Nodes.getMap();
355*13fbcb42Sjoerg   return (M.find(Data.Id) != M.end() ? Data.TrueStencil : Data.FalseStencil)
356*13fbcb42Sjoerg       ->eval(Match, Result);
35706f32e7eSjoerg }
35806f32e7eSjoerg 
evalData(const MatchConsumer<std::string> & Fn,const MatchFinder::MatchResult & Match,std::string * Result)35906f32e7eSjoerg Error evalData(const MatchConsumer<std::string> &Fn,
36006f32e7eSjoerg                const MatchFinder::MatchResult &Match, std::string *Result) {
36106f32e7eSjoerg   Expected<std::string> Value = Fn(Match);
36206f32e7eSjoerg   if (!Value)
36306f32e7eSjoerg     return Value.takeError();
36406f32e7eSjoerg   *Result += *Value;
36506f32e7eSjoerg   return Error::success();
36606f32e7eSjoerg }
36706f32e7eSjoerg 
evalData(const SequenceData & Data,const MatchFinder::MatchResult & Match,std::string * Result)368*13fbcb42Sjoerg Error evalData(const SequenceData &Data, const MatchFinder::MatchResult &Match,
369*13fbcb42Sjoerg                std::string *Result) {
370*13fbcb42Sjoerg   for (const auto &S : Data.Stencils)
371*13fbcb42Sjoerg     if (auto Err = S->eval(Match, Result))
372*13fbcb42Sjoerg       return Err;
373*13fbcb42Sjoerg   return Error::success();
374*13fbcb42Sjoerg }
375*13fbcb42Sjoerg 
376*13fbcb42Sjoerg template <typename T> class StencilImpl : public StencilInterface {
37706f32e7eSjoerg   T Data;
37806f32e7eSjoerg 
37906f32e7eSjoerg public:
38006f32e7eSjoerg   template <typename... Ps>
StencilImpl(Ps &&...Args)381*13fbcb42Sjoerg   explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
38206f32e7eSjoerg 
eval(const MatchFinder::MatchResult & Match,std::string * Result) const38306f32e7eSjoerg   Error eval(const MatchFinder::MatchResult &Match,
38406f32e7eSjoerg              std::string *Result) const override {
38506f32e7eSjoerg     return evalData(Data, Match, Result);
38606f32e7eSjoerg   }
38706f32e7eSjoerg 
toString() const38806f32e7eSjoerg   std::string toString() const override { return toStringData(Data); }
38906f32e7eSjoerg };
39006f32e7eSjoerg } // namespace
39106f32e7eSjoerg 
makeStencil(StringRef Text)392*13fbcb42Sjoerg Stencil transformer::detail::makeStencil(StringRef Text) {
393*13fbcb42Sjoerg   return std::make_shared<StencilImpl<RawTextData>>(std::string(Text));
39406f32e7eSjoerg }
39506f32e7eSjoerg 
makeStencil(RangeSelector Selector)396*13fbcb42Sjoerg Stencil transformer::detail::makeStencil(RangeSelector Selector) {
397*13fbcb42Sjoerg   return std::make_shared<StencilImpl<SelectorData>>(std::move(Selector));
39806f32e7eSjoerg }
39906f32e7eSjoerg 
dPrint(StringRef Id)400*13fbcb42Sjoerg Stencil transformer::dPrint(StringRef Id) {
401*13fbcb42Sjoerg   return std::make_shared<StencilImpl<DebugPrintNodeData>>(std::string(Id));
40206f32e7eSjoerg }
40306f32e7eSjoerg 
expression(llvm::StringRef Id)404*13fbcb42Sjoerg Stencil transformer::expression(llvm::StringRef Id) {
405*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
406*13fbcb42Sjoerg       UnaryNodeOperator::Parens, std::string(Id));
40706f32e7eSjoerg }
40806f32e7eSjoerg 
deref(llvm::StringRef ExprId)409*13fbcb42Sjoerg Stencil transformer::deref(llvm::StringRef ExprId) {
410*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
411*13fbcb42Sjoerg       UnaryNodeOperator::Deref, std::string(ExprId));
41206f32e7eSjoerg }
41306f32e7eSjoerg 
maybeDeref(llvm::StringRef ExprId)414*13fbcb42Sjoerg Stencil transformer::maybeDeref(llvm::StringRef ExprId) {
415*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
416*13fbcb42Sjoerg       UnaryNodeOperator::MaybeDeref, std::string(ExprId));
41706f32e7eSjoerg }
41806f32e7eSjoerg 
addressOf(llvm::StringRef ExprId)419*13fbcb42Sjoerg Stencil transformer::addressOf(llvm::StringRef ExprId) {
420*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
421*13fbcb42Sjoerg       UnaryNodeOperator::AddressOf, std::string(ExprId));
42206f32e7eSjoerg }
42306f32e7eSjoerg 
maybeAddressOf(llvm::StringRef ExprId)424*13fbcb42Sjoerg Stencil transformer::maybeAddressOf(llvm::StringRef ExprId) {
425*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
426*13fbcb42Sjoerg       UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
42706f32e7eSjoerg }
42806f32e7eSjoerg 
describe(StringRef Id)429*13fbcb42Sjoerg Stencil transformer::describe(StringRef Id) {
430*13fbcb42Sjoerg   return std::make_shared<StencilImpl<UnaryOperationData>>(
431*13fbcb42Sjoerg       UnaryNodeOperator::Describe, std::string(Id));
43206f32e7eSjoerg }
43306f32e7eSjoerg 
access(StringRef BaseId,Stencil Member)434*13fbcb42Sjoerg Stencil transformer::access(StringRef BaseId, Stencil Member) {
435*13fbcb42Sjoerg   return std::make_shared<StencilImpl<AccessData>>(BaseId, std::move(Member));
43606f32e7eSjoerg }
43706f32e7eSjoerg 
ifBound(StringRef Id,Stencil TrueStencil,Stencil FalseStencil)438*13fbcb42Sjoerg Stencil transformer::ifBound(StringRef Id, Stencil TrueStencil,
439*13fbcb42Sjoerg                              Stencil FalseStencil) {
440*13fbcb42Sjoerg   return std::make_shared<StencilImpl<IfBoundData>>(Id, std::move(TrueStencil),
441*13fbcb42Sjoerg                                                     std::move(FalseStencil));
44206f32e7eSjoerg }
44306f32e7eSjoerg 
run(MatchConsumer<std::string> Fn)444*13fbcb42Sjoerg Stencil transformer::run(MatchConsumer<std::string> Fn) {
445*13fbcb42Sjoerg   return std::make_shared<StencilImpl<MatchConsumer<std::string>>>(
446*13fbcb42Sjoerg       std::move(Fn));
44706f32e7eSjoerg }
44806f32e7eSjoerg 
catVector(std::vector<Stencil> Parts)449*13fbcb42Sjoerg Stencil transformer::catVector(std::vector<Stencil> Parts) {
450*13fbcb42Sjoerg   // Only one argument, so don't wrap in sequence.
451*13fbcb42Sjoerg   if (Parts.size() == 1)
452*13fbcb42Sjoerg     return std::move(Parts[0]);
453*13fbcb42Sjoerg   return std::make_shared<StencilImpl<SequenceData>>(std::move(Parts));
45406f32e7eSjoerg }
455