18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/Support/Errc.h"
21#include "llvm/Support/Error.h"
27using namespace transformer;
34using llvm::StringError;
38 auto &NodesMap =
Nodes.getMap();
39 auto It = NodesMap.find(
Id);
40 if (It == NodesMap.end())
41 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
42 "Id not bound: " +
Id);
47 std::string *Result) {
49 llvm::raw_string_ostream Os(Output);
51 if (
auto Err = NodeOrErr.takeError())
55 return Error::success();
64 explicit RawTextStencil(std::string T) :
Text(
std::move(T)) {}
66 std::string
toString()
const override {
68 llvm::raw_string_ostream OS(Result);
70 OS.write_escaped(Text);
77 std::string *Result)
const override {
79 return Error::success();
88 explicit DebugPrintNodeStencil(std::string S) :
Id(
std::move(S)) {}
90 std::string
toString()
const override {
91 return (llvm::Twine(
"dPrint(\"") + Id +
"\")").str();
95 std::string *Result)
const override {
101enum class UnaryNodeOperator {
112 UnaryNodeOperator Op;
116 UnaryOperationStencil(UnaryNodeOperator Op, std::string Id)
119 std::string
toString()
const override {
122 case UnaryNodeOperator::Parens:
123 OpName =
"expression";
125 case UnaryNodeOperator::Deref:
128 case UnaryNodeOperator::MaybeDeref:
129 OpName =
"maybeDeref";
131 case UnaryNodeOperator::AddressOf:
132 OpName =
"addressOf";
134 case UnaryNodeOperator::MaybeAddressOf:
135 OpName =
"maybeAddressOf";
137 case UnaryNodeOperator::Describe:
141 return (OpName +
"(\"" + Id +
"\")").str();
145 std::string *Result)
const override {
148 if (Op == UnaryNodeOperator::Describe)
153 return llvm::make_error<StringError>(errc::invalid_argument,
154 "Id not bound or not Expr: " + Id);
155 std::optional<std::string> Source;
157 case UnaryNodeOperator::Parens:
160 case UnaryNodeOperator::Deref:
163 case UnaryNodeOperator::MaybeDeref:
164 if (E->getType()->isAnyPointerType() ||
169 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
170 if (OpCall->getOperator() == clang::OO_Arrow &&
171 OpCall->getNumArgs() == 1) {
172 E = OpCall->getArg(0);
179 return Error::success();
180 case UnaryNodeOperator::AddressOf:
183 case UnaryNodeOperator::MaybeAddressOf:
184 if (E->getType()->isAnyPointerType() ||
189 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
190 if (OpCall->getOperator() == clang::OO_Arrow &&
191 OpCall->getNumArgs() == 1) {
192 E = OpCall->getArg(0);
196 return Error::success();
200 case UnaryNodeOperator::Describe:
201 llvm_unreachable(
"This case is handled at the start of the function");
204 return llvm::make_error<StringError>(
205 errc::invalid_argument,
206 "Could not construct expression source from ID: " + Id);
208 return Error::success();
219 std::string
toString()
const override {
return "selection(...)"; }
222 std::string *Result)
const override {
225 return RawRange.takeError();
228 if (
Range.isInvalid()) {
234 return handleErrors(std::move(Err), [](std::unique_ptr<StringError> E) {
235 assert(E->convertToErrorCode() ==
236 llvm::make_error_code(errc::invalid_argument) &&
237 "Validation errors must carry the invalid_argument code");
238 return llvm::createStringError(
239 errc::invalid_argument,
240 "selected range could not be resolved to a valid source range; " +
243 return llvm::createStringError(
244 errc::invalid_argument,
245 "selected range could not be resolved to a valid source range");
251 llvm::createStringError(errc::invalid_argument,
252 "selected range is not valid for editing"),
255 return Error::success();
265 AccessStencil(StringRef BaseId,
Stencil Member)
268 std::string
toString()
const override {
269 return (llvm::Twine(
"access(\"") + BaseId +
"\", " +
Member->toString() +
275 std::string *Result)
const override {
278 return llvm::make_error<StringError>(errc::invalid_argument,
279 "Id not bound: " + BaseId);
282 return llvm::make_error<StringError>(
283 errc::invalid_argument,
284 "Could not construct object text from ID: " + BaseId);
286 return Member->eval(Match, Result);
296 IfBoundStencil(StringRef Id,
Stencil TrueStencil,
Stencil FalseStencil)
297 :
Id(
std::string(
Id)), TrueStencil(
std::move(TrueStencil)),
298 FalseStencil(
std::move(FalseStencil)) {}
300 std::string
toString()
const override {
301 return (llvm::Twine(
"ifBound(\"") + Id +
"\", " + TrueStencil->toString() +
302 ", " + FalseStencil->toString() +
")")
307 std::string *Result)
const override {
309 return (M.find(Id) != M.end() ? TrueStencil : FalseStencil)
310 ->eval(Match, Result);
315 static bool containsNoNullStencils(
316 const std::vector<std::pair<std::string, Stencil>> &Cases) {
317 for (
const auto &S : Cases)
318 if (S.second ==
nullptr)
324 SelectBoundStencil(std::vector<std::pair<std::string, Stencil>> Cases,
326 : CaseStencils(
std::move(Cases)), DefaultStencil(
std::move(
Default)) {
327 assert(containsNoNullStencils(CaseStencils) &&
328 "cases of selectBound may not be null");
330 ~SelectBoundStencil()
override{};
333 std::string *result)
const override {
335 for (
const auto &S : CaseStencils) {
336 if (NodeMap.count(S.first) > 0) {
337 return S.second->eval(
match, result);
341 if (DefaultStencil !=
nullptr) {
342 return DefaultStencil->eval(
match, result);
346 CaseIDs.reserve(CaseStencils.size());
347 for (
const auto &S : CaseStencils)
348 CaseIDs.emplace_back(S.first);
350 return llvm::createStringError(
351 errc::result_out_of_range,
352 llvm::Twine(
"selectBound failed: no cases bound and no default: {") +
353 llvm::join(CaseIDs,
", ") +
"}");
356 std::string
toString()
const override {
358 llvm::raw_string_ostream Stream(Buffer);
359 Stream <<
"selectBound({";
361 for (
const auto &S : CaseStencils) {
366 Stream <<
"{\"" << S.first <<
"\", " << S.second->toString();
369 if (DefaultStencil !=
nullptr) {
370 Stream <<
", " << DefaultStencil->toString();
377 std::vector<std::pair<std::string, Stencil>> CaseStencils;
382 std::vector<Stencil> Stencils;
385 SequenceStencil(std::vector<Stencil> Stencils)
386 : Stencils(
std::move(Stencils)) {}
388 std::string
toString()
const override {
390 Parts.reserve(Stencils.size());
391 for (
const auto &S : Stencils)
392 Parts.push_back(S->toString());
393 return (llvm::Twine(
"seq(") + llvm::join(Parts,
", ") +
")").str();
397 std::string *Result)
const override {
398 for (
const auto &S : Stencils)
399 if (
auto Err = S->eval(Match, Result))
401 return Error::success();
411 std::string
toString()
const override {
return "run(...)"; }
414 std::string *Result)
const override {
418 return Value.takeError();
420 return Error::success();
426 return std::make_shared<RawTextStencil>(std::string(
Text));
430 return std::make_shared<SelectorStencil>(std::move(
Selector));
434 return std::make_shared<DebugPrintNodeStencil>(std::string(
Id));
438 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Parens,
443 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Deref,
444 std::string(ExprId));
448 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::MaybeDeref,
449 std::string(ExprId));
453 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::AddressOf,
454 std::string(ExprId));
458 return std::make_shared<UnaryOperationStencil>(
459 UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
463 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Describe,
468 return std::make_shared<AccessStencil>(BaseId, std::move(
Member));
473 return std::make_shared<IfBoundStencil>(
Id, std::move(TrueStencil),
474 std::move(FalseStencil));
478 std::vector<std::pair<std::string, Stencil>> CaseStencils,
480 return std::make_shared<SelectBoundStencil>(std::move(CaseStencils),
481 std::move(DefaultStencil));
485 return std::make_shared<RunStencil>(std::move(Fn));
490 if (Parts.size() == 1)
491 return std::move(Parts[0]);
492 return std::make_shared<SequenceStencil>(std::move(Parts));
Defines the clang::ASTContext interface.
BoundNodesTreeBuilder Nodes
This file collects facilities for generating source code strings.
Defines the clang::SourceLocation class and associated facilities.
static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match, std::string *Result)
static llvm::Expected< DynTypedNode > getNode(const BoundNodes &Nodes, StringRef Id)
This file defines the Stencil abstraction: a code-generating object, parameterized by named reference...
const LangOptions & getLangOpts() const
Represents a character-granular source range.
This represents one expression.
static CharSourceRange makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Accepts a range and returns a character range with file locations.
Smart pointer class that efficiently represents Objective-C method names.
Maps string IDs to AST nodes matched by parts of a matcher.
internal::BoundNodesMap::IDToNodeMap IDToNodeMap
Type of mapping from binding identifiers to bound nodes.
const IDToNodeMap & getMap() const
Retrieve mapping from binding identifiers to bound nodes.
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
A class to allow finding matches over the Clang AST.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.
Describes how types, statements, expressions, and declarations should be printed.
Contains all information for a given match.
clang::SourceManager *const SourceManager
const BoundNodes Nodes
Contains the nodes bound on the current match.
clang::ASTContext *const Context
Utilities for interpreting the matched AST structures.