18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/Support/Errc.h"
21#include "llvm/Support/Error.h"
33using llvm::StringError;
37 auto &NodesMap = Nodes.
getMap();
38 auto It = NodesMap.find(Id);
39 if (It == NodesMap.end())
40 return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
41 "Id not bound: " + Id);
46 std::string *Result) {
48 llvm::raw_string_ostream Os(Output);
50 if (
auto Err = NodeOrErr.takeError())
53 if (
const auto *ND = NodeOrErr->get<
NamedDecl>()) {
55 ND->getNameForDiagnostic(Os, PP,
false);
57 NodeOrErr->print(Os, PP);
60 return Error::success();
69 explicit RawTextStencil(std::string
T) : Text(std::move(
T)) {}
71 std::string
toString()
const override {
75 OS.write_escaped(Text);
80 Error eval(
const MatchFinder::MatchResult &
Match,
81 std::string *
Result)
const override {
83 return Error::success();
92 explicit DebugPrintNodeStencil(std::string S) : Id(std::move(S)) {}
94 std::string
toString()
const override {
95 return (llvm::Twine(
"dPrint(\"") + Id +
"\")").str();
98 Error eval(
const MatchFinder::MatchResult &
Match,
99 std::string *
Result)
const override {
105enum class UnaryNodeOperator {
116 UnaryNodeOperator Op;
120 UnaryOperationStencil(UnaryNodeOperator Op, std::string Id)
121 : Op(Op), Id(std::move(Id)) {}
123 std::string
toString()
const override {
126 case UnaryNodeOperator::Parens:
127 OpName =
"expression";
129 case UnaryNodeOperator::Deref:
132 case UnaryNodeOperator::MaybeDeref:
133 OpName =
"maybeDeref";
135 case UnaryNodeOperator::AddressOf:
136 OpName =
"addressOf";
138 case UnaryNodeOperator::MaybeAddressOf:
139 OpName =
"maybeAddressOf";
141 case UnaryNodeOperator::Describe:
145 return (OpName +
"(\"" + Id +
"\")").str();
148 Error eval(
const MatchFinder::MatchResult &
Match,
149 std::string *
Result)
const override {
152 if (Op == UnaryNodeOperator::Describe)
155 const auto *E =
Match.Nodes.getNodeAs<Expr>(Id);
157 return llvm::make_error<StringError>(errc::invalid_argument,
158 "Id not bound or not Expr: " + Id);
159 std::optional<std::string> Source;
161 case UnaryNodeOperator::Parens:
164 case UnaryNodeOperator::Deref:
167 case UnaryNodeOperator::MaybeDeref:
168 if (E->getType()->isAnyPointerType() ||
173 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
174 if (OpCall->getOperator() == clang::OO_Arrow &&
175 OpCall->getNumArgs() == 1) {
176 E = OpCall->getArg(0);
183 return Error::success();
184 case UnaryNodeOperator::AddressOf:
187 case UnaryNodeOperator::MaybeAddressOf:
188 if (E->getType()->isAnyPointerType() ||
193 if (
const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) {
194 if (OpCall->getOperator() == clang::OO_Arrow &&
195 OpCall->getNumArgs() == 1) {
196 E = OpCall->getArg(0);
200 return Error::success();
204 case UnaryNodeOperator::Describe:
205 llvm_unreachable(
"This case is handled at the start of the function");
208 return llvm::make_error<StringError>(
209 errc::invalid_argument,
210 "Could not construct expression source from ID: " + Id);
212 return Error::success();
221 explicit SelectorStencil(
RangeSelector S) : Selector(std::move(S)) {}
223 std::string
toString()
const override {
return "selection(...)"; }
225 Error eval(
const MatchFinder::MatchResult &
Match,
226 std::string *
Result)
const override {
227 auto RawRange = Selector(
Match);
229 return RawRange.takeError();
231 *RawRange, *
Match.SourceManager,
Match.Context->getLangOpts());
232 if (
Range.isInvalid()) {
238 return handleErrors(std::move(Err), [](std::unique_ptr<StringError> E) {
239 assert(E->convertToErrorCode() ==
240 llvm::make_error_code(errc::invalid_argument) &&
241 "Validation errors must carry the invalid_argument code");
242 return llvm::createStringError(
243 errc::invalid_argument,
244 "selected range could not be resolved to a valid source range; " +
247 return llvm::createStringError(
248 errc::invalid_argument,
249 "selected range could not be resolved to a valid source range");
256 llvm::createStringError(errc::invalid_argument,
257 "selected range is not valid for editing"),
260 return Error::success();
270 AccessStencil(StringRef BaseId,
Stencil Member)
271 : BaseId(std::string(BaseId)), Member(std::move(Member)) {}
273 std::string
toString()
const override {
274 return (llvm::Twine(
"access(\"") + BaseId +
"\", " + Member->toString() +
279 Error eval(
const MatchFinder::MatchResult &
Match,
280 std::string *
Result)
const override {
281 const auto *E =
Match.Nodes.getNodeAs<Expr>(BaseId);
283 return llvm::make_error<StringError>(errc::invalid_argument,
284 "Id not bound: " + BaseId);
287 return llvm::make_error<StringError>(
288 errc::invalid_argument,
289 "Could not construct object text from ID: " + BaseId);
301 IfBoundStencil(StringRef Id,
Stencil TrueStencil,
Stencil FalseStencil)
302 : Id(std::string(Id)), TrueStencil(std::move(TrueStencil)),
303 FalseStencil(std::move(FalseStencil)) {}
305 std::string
toString()
const override {
306 return (llvm::Twine(
"ifBound(\"") + Id +
"\", " + TrueStencil->toString() +
307 ", " + FalseStencil->toString() +
")")
311 Error eval(
const MatchFinder::MatchResult &
Match,
312 std::string *
Result)
const override {
313 auto &M =
Match.Nodes.getMap();
314 return (M.find(Id) != M.end() ? TrueStencil : FalseStencil)
320 static bool containsNoNullStencils(
321 const std::vector<std::pair<std::string, Stencil>> &Cases) {
322 for (
const auto &S : Cases)
323 if (S.second ==
nullptr)
329 SelectBoundStencil(std::vector<std::pair<std::string, Stencil>> Cases,
331 : CaseStencils(std::move(Cases)), DefaultStencil(std::move(
Default)) {
332 assert(containsNoNullStencils(CaseStencils) &&
333 "cases of selectBound may not be null");
335 ~SelectBoundStencil()
override {}
337 llvm::Error eval(
const MatchFinder::MatchResult &
match,
338 std::string *result)
const override {
340 for (
const auto &S : CaseStencils) {
341 if (NodeMap.count(S.first) > 0) {
342 return S.second->eval(
match, result);
346 if (DefaultStencil !=
nullptr) {
347 return DefaultStencil->eval(
match, result);
350 llvm::SmallVector<llvm::StringRef, 2> CaseIDs;
351 CaseIDs.reserve(CaseStencils.size());
352 for (
const auto &S : CaseStencils)
353 CaseIDs.emplace_back(S.first);
355 return llvm::createStringError(
356 errc::result_out_of_range,
357 llvm::Twine(
"selectBound failed: no cases bound and no default: {") +
358 llvm::join(CaseIDs,
", ") +
"}");
361 std::string
toString()
const override {
363 llvm::raw_string_ostream Stream(Buffer);
364 Stream <<
"selectBound({";
366 for (
const auto &S : CaseStencils) {
371 Stream <<
"{\"" << S.first <<
"\", " << S.second->toString();
374 if (DefaultStencil !=
nullptr) {
375 Stream <<
", " << DefaultStencil->toString();
382 std::vector<std::pair<std::string, Stencil>> CaseStencils;
387 std::vector<Stencil> Stencils;
390 SequenceStencil(std::vector<Stencil> Stencils)
391 : Stencils(std::move(Stencils)) {}
393 std::string
toString()
const override {
394 llvm::SmallVector<std::string, 2> Parts;
395 Parts.reserve(Stencils.size());
396 for (
const auto &S : Stencils)
397 Parts.push_back(S->toString());
398 return (llvm::Twine(
"seq(") + llvm::join(Parts,
", ") +
")").str();
401 Error eval(
const MatchFinder::MatchResult &
Match,
402 std::string *
Result)
const override {
403 for (
const auto &S : Stencils)
406 return Error::success();
416 std::string
toString()
const override {
return "run(...)"; }
418 Error eval(
const MatchFinder::MatchResult &
Match,
419 std::string *
Result)
const override {
421 Expected<std::string>
Value = Consumer(
Match);
423 return Value.takeError();
425 return Error::success();
431 return std::make_shared<RawTextStencil>(std::string(
Text));
435 return std::make_shared<SelectorStencil>(std::move(
Selector));
439 return std::make_shared<DebugPrintNodeStencil>(std::string(Id));
443 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Parens,
448 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Deref,
449 std::string(ExprId));
453 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::MaybeDeref,
454 std::string(ExprId));
458 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::AddressOf,
459 std::string(ExprId));
463 return std::make_shared<UnaryOperationStencil>(
464 UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
468 return std::make_shared<UnaryOperationStencil>(UnaryNodeOperator::Describe,
473 return std::make_shared<AccessStencil>(BaseId, std::move(
Member));
478 return std::make_shared<IfBoundStencil>(Id, std::move(TrueStencil),
479 std::move(FalseStencil));
483 std::vector<std::pair<std::string, Stencil>> CaseStencils,
485 return std::make_shared<SelectBoundStencil>(std::move(CaseStencils),
486 std::move(DefaultStencil));
490 return std::make_shared<RunStencil>(std::move(Fn));
495 if (Parts.size() == 1)
496 return std::move(Parts[0]);
497 return std::make_shared<SequenceStencil>(std::move(Parts));
Defines the clang::ASTContext interface.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
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...
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.
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.
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.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
@ 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.