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:
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:
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();
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");
252 llvm::createStringError(errc::invalid_argument,
253 "selected range is not valid for editing"),
256 return Error::success();
266 AccessStencil(StringRef BaseId,
Stencil Member)
269 std::string
toString()
const override {
270 return (llvm::Twine(
"access(\"") + BaseId +
"\", " +
Member->toString() +
276 std::string *Result)
const override {
279 return llvm::make_error<StringError>(errc::invalid_argument,
280 "Id not bound: " + BaseId);
283 return llvm::make_error<StringError>(
284 errc::invalid_argument,
285 "Could not construct object text from ID: " + BaseId);
287 return Member->eval(Match, Result);
297 IfBoundStencil(StringRef Id,
Stencil TrueStencil,
Stencil FalseStencil)
298 :
Id(
std::string(
Id)), TrueStencil(
std::move(TrueStencil)),
299 FalseStencil(
std::move(FalseStencil)) {}
301 std::string
toString()
const override {
302 return (llvm::Twine(
"ifBound(\"") + Id +
"\", " + TrueStencil->toString() +
303 ", " + FalseStencil->toString() +
")")
308 std::string *Result)
const override {
310 return (M.find(Id) != M.end() ? TrueStencil : FalseStencil)
311 ->eval(Match, Result);
316 static bool containsNoNullStencils(
317 const std::vector<std::pair<std::string, Stencil>> &Cases) {
318 for (
const auto &S : Cases)
319 if (S.second ==
nullptr)
325 SelectBoundStencil(std::vector<std::pair<std::string, Stencil>> Cases,
327 : CaseStencils(
std::move(Cases)), DefaultStencil(
std::move(
Default)) {
328 assert(containsNoNullStencils(CaseStencils) &&
329 "cases of selectBound may not be null");
331 ~SelectBoundStencil()
override {}
334 std::string *result)
const override {
336 for (
const auto &S : CaseStencils) {
337 if (NodeMap.count(S.first) > 0) {
338 return S.second->eval(
match, result);
342 if (DefaultStencil !=
nullptr) {
343 return DefaultStencil->eval(
match, result);
347 CaseIDs.reserve(CaseStencils.size());
348 for (
const auto &S : CaseStencils)
349 CaseIDs.emplace_back(S.first);
351 return llvm::createStringError(
352 errc::result_out_of_range,
353 llvm::Twine(
"selectBound failed: no cases bound and no default: {") +
354 llvm::join(CaseIDs,
", ") +
"}");
357 std::string
toString()
const override {
359 llvm::raw_string_ostream Stream(Buffer);
360 Stream <<
"selectBound({";
362 for (
const auto &S : CaseStencils) {
367 Stream <<
"{\"" << S.first <<
"\", " << S.second->toString();
370 if (DefaultStencil !=
nullptr) {
371 Stream <<
", " << DefaultStencil->toString();
378 std::vector<std::pair<std::string, Stencil>> CaseStencils;
383 std::vector<Stencil> Stencils;
386 SequenceStencil(std::vector<Stencil> Stencils)
387 : Stencils(
std::move(Stencils)) {}
389 std::string
toString()
const override {
391 Parts.reserve(Stencils.size());
392 for (
const auto &S : Stencils)
393 Parts.push_back(S->toString());
394 return (llvm::Twine(
"seq(") + llvm::join(Parts,
", ") +
")").str();
398 std::string *Result)
const override {
399 for (
const auto &S : Stencils)
400 if (
auto Err = S->eval(Match, Result))
402 return Error::success();
412 std::string
toString()
const override {
return "run(...)"; }
415 std::string *Result)
const override {
419 return Value.takeError();
421 return Error::success();
427 return std::make_shared<RawTextStencil>(std::string(
Text));
431 return std::make_shared<SelectorStencil>(std::move(
Selector));
435 return std::make_shared<DebugPrintNodeStencil>(std::string(
Id));
439 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Parens,
444 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Deref,
445 std::string(ExprId));
449 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::MaybeDeref,
450 std::string(ExprId));
454 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::AddressOf,
455 std::string(ExprId));
459 return std::make_shared<UnaryOperationStencil>(
460 UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
464 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Describe,
469 return std::make_shared<AccessStencil>(BaseId, std::move(
Member));
474 return std::make_shared<IfBoundStencil>(
Id, std::move(TrueStencil),
475 std::move(FalseStencil));
479 std::vector<std::pair<std::string, Stencil>> CaseStencils,
481 return std::make_shared<SelectBoundStencil>(std::move(CaseStencils),
482 std::move(DefaultStencil));
486 return std::make_shared<RunStencil>(std::move(Fn));
491 if (Parts.size() == 1)
492 return std::move(Parts[0]);
493 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.
bool isAnyPointerType() const
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.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Parens
New-expression has a C++98 paren-delimited initializer.
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.