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())
54 if (
const auto *ND = NodeOrErr->get<
NamedDecl>()) {
56 ND->getNameForDiagnostic(Os, PP,
false);
58 NodeOrErr->print(Os, PP);
61 return Error::success();
70 explicit RawTextStencil(std::string
T) :
Text(
std::move(
T)) {}
72 std::string
toString()
const override {
74 llvm::raw_string_ostream OS(Result);
76 OS.write_escaped(Text);
82 std::string *Result)
const override {
84 return Error::success();
93 explicit DebugPrintNodeStencil(std::string S) :
Id(
std::move(S)) {}
95 std::string
toString()
const override {
96 return (llvm::Twine(
"dPrint(\"") + Id +
"\")").str();
100 std::string *Result)
const override {
106enum class UnaryNodeOperator {
117 UnaryNodeOperator Op;
121 UnaryOperationStencil(UnaryNodeOperator Op, std::string Id)
124 std::string
toString()
const override {
127 case UnaryNodeOperator::Parens:
128 OpName =
"expression";
130 case UnaryNodeOperator::Deref:
133 case UnaryNodeOperator::MaybeDeref:
134 OpName =
"maybeDeref";
136 case UnaryNodeOperator::AddressOf:
137 OpName =
"addressOf";
139 case UnaryNodeOperator::MaybeAddressOf:
140 OpName =
"maybeAddressOf";
142 case UnaryNodeOperator::Describe:
146 return (OpName +
"(\"" + Id +
"\")").str();
150 std::string *Result)
const override {
153 if (Op == UnaryNodeOperator::Describe)
158 return llvm::make_error<StringError>(errc::invalid_argument,
159 "Id not bound or not Expr: " + Id);
160 std::optional<std::string> Source;
162 case UnaryNodeOperator::Parens:
165 case UnaryNodeOperator::Deref:
168 case UnaryNodeOperator::MaybeDeref:
174 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(
E)) {
175 if (OpCall->getOperator() == clang::OO_Arrow &&
176 OpCall->getNumArgs() == 1) {
177 E = OpCall->getArg(0);
184 return Error::success();
185 case UnaryNodeOperator::AddressOf:
188 case UnaryNodeOperator::MaybeAddressOf:
194 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(
E)) {
195 if (OpCall->getOperator() == clang::OO_Arrow &&
196 OpCall->getNumArgs() == 1) {
197 E = OpCall->getArg(0);
201 return Error::success();
205 case UnaryNodeOperator::Describe:
206 llvm_unreachable(
"This case is handled at the start of the function");
209 return llvm::make_error<StringError>(
210 errc::invalid_argument,
211 "Could not construct expression source from ID: " + Id);
213 return Error::success();
224 std::string
toString()
const override {
return "selection(...)"; }
227 std::string *Result)
const override {
230 return RawRange.takeError();
239 return handleErrors(std::move(Err), [](std::unique_ptr<StringError>
E) {
240 assert(
E->convertToErrorCode() ==
241 llvm::make_error_code(errc::invalid_argument) &&
242 "Validation errors must carry the invalid_argument code");
243 return llvm::createStringError(
244 errc::invalid_argument,
245 "selected range could not be resolved to a valid source range; " +
248 return llvm::createStringError(
249 errc::invalid_argument,
250 "selected range could not be resolved to a valid source range");
257 llvm::createStringError(errc::invalid_argument,
258 "selected range is not valid for editing"),
261 return Error::success();
271 AccessStencil(StringRef BaseId,
Stencil Member)
274 std::string
toString()
const override {
275 return (llvm::Twine(
"access(\"") + BaseId +
"\", " +
Member->toString() +
281 std::string *Result)
const override {
284 return llvm::make_error<StringError>(errc::invalid_argument,
285 "Id not bound: " + BaseId);
288 return llvm::make_error<StringError>(
289 errc::invalid_argument,
290 "Could not construct object text from ID: " + BaseId);
292 return Member->eval(Match, Result);
302 IfBoundStencil(StringRef Id,
Stencil TrueStencil,
Stencil FalseStencil)
303 :
Id(
std::string(
Id)), TrueStencil(
std::move(TrueStencil)),
304 FalseStencil(
std::move(FalseStencil)) {}
306 std::string
toString()
const override {
307 return (llvm::Twine(
"ifBound(\"") + Id +
"\", " + TrueStencil->toString() +
308 ", " + FalseStencil->toString() +
")")
313 std::string *Result)
const override {
315 return (M.find(Id) != M.end() ? TrueStencil : FalseStencil)
316 ->eval(Match, Result);
321 static bool containsNoNullStencils(
322 const std::vector<std::pair<std::string, Stencil>> &Cases) {
323 for (
const auto &S : Cases)
324 if (S.second ==
nullptr)
330 SelectBoundStencil(std::vector<std::pair<std::string, Stencil>> Cases,
332 : CaseStencils(
std::move(Cases)), DefaultStencil(
std::move(
Default)) {
333 assert(containsNoNullStencils(CaseStencils) &&
334 "cases of selectBound may not be null");
336 ~SelectBoundStencil()
override {}
339 std::string *result)
const override {
341 for (
const auto &S : CaseStencils) {
342 if (NodeMap.count(S.first) > 0) {
343 return S.second->eval(
match, result);
347 if (DefaultStencil !=
nullptr) {
348 return DefaultStencil->eval(
match, result);
352 CaseIDs.reserve(CaseStencils.size());
353 for (
const auto &S : CaseStencils)
354 CaseIDs.emplace_back(S.first);
356 return llvm::createStringError(
357 errc::result_out_of_range,
358 llvm::Twine(
"selectBound failed: no cases bound and no default: {") +
359 llvm::join(CaseIDs,
", ") +
"}");
362 std::string
toString()
const override {
364 llvm::raw_string_ostream Stream(Buffer);
365 Stream <<
"selectBound({";
367 for (
const auto &S : CaseStencils) {
372 Stream <<
"{\"" << S.first <<
"\", " << S.second->toString();
375 if (DefaultStencil !=
nullptr) {
376 Stream <<
", " << DefaultStencil->toString();
383 std::vector<std::pair<std::string, Stencil>> CaseStencils;
388 std::vector<Stencil> Stencils;
391 SequenceStencil(std::vector<Stencil> Stencils)
392 : Stencils(
std::move(Stencils)) {}
394 std::string
toString()
const override {
396 Parts.reserve(Stencils.size());
397 for (
const auto &S : Stencils)
398 Parts.push_back(S->toString());
399 return (llvm::Twine(
"seq(") + llvm::join(Parts,
", ") +
")").str();
403 std::string *Result)
const override {
404 for (
const auto &S : Stencils)
405 if (
auto Err = S->eval(Match, Result))
407 return Error::success();
417 std::string
toString()
const override {
return "run(...)"; }
420 std::string *Result)
const override {
424 return Value.takeError();
426 return Error::success();
432 return std::make_shared<RawTextStencil>(std::string(
Text));
436 return std::make_shared<SelectorStencil>(std::move(
Selector));
440 return std::make_shared<DebugPrintNodeStencil>(std::string(
Id));
444 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Parens,
449 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Deref,
450 std::string(ExprId));
454 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::MaybeDeref,
455 std::string(ExprId));
459 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::AddressOf,
460 std::string(ExprId));
464 return std::make_shared<UnaryOperationStencil>(
465 UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
469 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Describe,
474 return std::make_shared<AccessStencil>(BaseId, std::move(
Member));
479 return std::make_shared<IfBoundStencil>(
Id, std::move(TrueStencil),
480 std::move(FalseStencil));
484 std::vector<std::pair<std::string, Stencil>> CaseStencils,
486 return std::make_shared<SelectBoundStencil>(std::move(CaseStencils),
487 std::move(DefaultStencil));
491 return std::make_shared<RunStencil>(std::move(Fn));
496 if (Parts.size() == 1)
497 return std::move(Parts[0]);
498 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.
This represents a decl that may have a name.
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.