aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Tooling/Transformer
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Tooling/Transformer')
-rw-r--r--contrib/llvm-project/clang/include/clang/Tooling/Transformer/MatchConsumer.h6
-rw-r--r--contrib/llvm-project/clang/include/clang/Tooling/Transformer/RangeSelector.h29
-rw-r--r--contrib/llvm-project/clang/include/clang/Tooling/Transformer/RewriteRule.h290
-rw-r--r--contrib/llvm-project/clang/include/clang/Tooling/Transformer/Stencil.h11
4 files changed, 222 insertions, 114 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/MatchConsumer.h b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/MatchConsumer.h
index f407ffce3d25..cb0a5f684b7d 100644
--- a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/MatchConsumer.h
+++ b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/MatchConsumer.h
@@ -99,11 +99,5 @@ llvm::Expected<T> MatchComputation<T>::eval(
return Output;
}
} // namespace transformer
-
-namespace tooling {
-// DEPRECATED: Temporary alias supporting client migration to the `transformer`
-// namespace.
-using transformer::ifBound;
-} // namespace tooling
} // namespace clang
#endif // LLVM_CLANG_TOOLING_TRANSFORMER_MATCH_CONSUMER_H_
diff --git a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RangeSelector.h b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RangeSelector.h
index 2807037bc208..f17fb8c7b5c6 100644
--- a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RangeSelector.h
+++ b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RangeSelector.h
@@ -56,8 +56,13 @@ RangeSelector before(RangeSelector Selector);
/// * the TokenRange [B,E'] where the token at E' spans the range [E',E).
RangeSelector after(RangeSelector Selector);
-/// Selects a node, including trailing semicolon (for non-expression
-/// statements). \p ID is the node's binding in the match result.
+/// Selects the range between `R1` and `R2.
+inline RangeSelector between(RangeSelector R1, RangeSelector R2) {
+ return enclose(after(std::move(R1)), before(std::move(R2)));
+}
+
+/// Selects a node, including trailing semicolon, if any (for declarations and
+/// non-expression statements). \p ID is the node's binding in the match result.
RangeSelector node(std::string ID);
/// Selects a node, including trailing semicolon (always). Useful for selecting
@@ -98,26 +103,6 @@ RangeSelector elseBranch(std::string ID);
/// `SourceManager::getExpansionRange`.
RangeSelector expansion(RangeSelector S);
} // namespace transformer
-
-namespace tooling {
-// DEPRECATED: These are temporary aliases supporting client migration to the
-// `transformer` namespace.
-using RangeSelector = transformer::RangeSelector;
-
-using transformer::after;
-using transformer::before;
-using transformer::callArgs;
-using transformer::charRange;
-using transformer::elseBranch;
-using transformer::expansion;
-using transformer::initListElements;
-using transformer::member;
-using transformer::name;
-using transformer::node;
-using transformer::range;
-using transformer::statement;
-using transformer::statements;
-} // namespace tooling
} // namespace clang
#endif // LLVM_CLANG_TOOLING_REFACTOR_RANGE_SELECTOR_H_
diff --git a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RewriteRule.h b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RewriteRule.h
index d9e68717d5c8..ac93db8446df 100644
--- a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RewriteRule.h
+++ b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/RewriteRule.h
@@ -31,14 +31,30 @@
namespace clang {
namespace transformer {
+// Specifies how to interpret an edit.
+enum class EditKind {
+ // Edits a source range in the file.
+ Range,
+ // Inserts an include in the file. The `Replacement` field is the name of the
+ // newly included file.
+ AddInclude,
+};
+
/// A concrete description of a source edit, represented by a character range in
/// the source to be replaced and a corresponding replacement string.
struct Edit {
+ EditKind Kind = EditKind::Range;
CharSourceRange Range;
std::string Replacement;
llvm::Any Metadata;
};
+/// Format of the path in an include directive -- angle brackets or quotes.
+enum class IncludeFormat {
+ Quoted,
+ Angled,
+};
+
/// Maps a match result to a list of concrete edits (with possible
/// failure). This type is a building block of rewrite rules, but users will
/// generally work in terms of `ASTEdit`s (below) rather than directly in terms
@@ -47,6 +63,8 @@ using EditGenerator = MatchConsumer<llvm::SmallVector<Edit, 1>>;
using TextGenerator = std::shared_ptr<MatchComputation<std::string>>;
+using AnyGenerator = MatchConsumer<llvm::Any>;
+
// Description of a source-code edit, expressed in terms of an AST node.
// Includes: an ID for the (bound) node, a selector for source related to the
// node, a replacement and, optionally, an explanation for the edit.
@@ -84,12 +102,21 @@ using TextGenerator = std::shared_ptr<MatchComputation<std::string>>;
// changeTo(cat("different_expr"))
// \endcode
struct ASTEdit {
+ EditKind Kind = EditKind::Range;
RangeSelector TargetRange;
TextGenerator Replacement;
TextGenerator Note;
- llvm::Any Metadata;
+ // Not all transformations will want or need to attach metadata and therefore
+ // should not be required to do so.
+ AnyGenerator Metadata = [](const ast_matchers::MatchFinder::MatchResult &)
+ -> llvm::Expected<llvm::Any> {
+ return llvm::Expected<llvm::Any>(llvm::Any());
+ };
};
+/// Generates a single (specified) edit.
+EditGenerator edit(ASTEdit E);
+
/// Lifts a list of `ASTEdit`s into an `EditGenerator`.
///
/// The `EditGenerator` will return an empty vector if any of the edits apply to
@@ -100,14 +127,130 @@ struct ASTEdit {
/// clients. We recommend use of the \c AtomicChange or \c Replacements classes
/// for assistance in detecting such conflicts.
EditGenerator editList(llvm::SmallVector<ASTEdit, 1> Edits);
-// Convenience form of `editList` for a single edit.
-EditGenerator edit(ASTEdit);
-/// Format of the path in an include directive -- angle brackets or quotes.
-enum class IncludeFormat {
- Quoted,
- Angled,
-};
+/// Generates no edits.
+inline EditGenerator noEdits() { return editList({}); }
+
+/// Generates a single, no-op edit anchored at the start location of the
+/// specified range. A `noopEdit` may be preferred over `noEdits` to associate a
+/// diagnostic `Explanation` with the rule.
+EditGenerator noopEdit(RangeSelector Anchor);
+
+/// Version of `ifBound` specialized to `ASTEdit`.
+inline EditGenerator ifBound(std::string ID, ASTEdit TrueEdit,
+ ASTEdit FalseEdit) {
+ return ifBound(std::move(ID), edit(std::move(TrueEdit)),
+ edit(std::move(FalseEdit)));
+}
+
+/// Version of `ifBound` that has no "False" branch. If the node is not bound,
+/// then no edits are produced.
+inline EditGenerator ifBound(std::string ID, ASTEdit TrueEdit) {
+ return ifBound(std::move(ID), edit(std::move(TrueEdit)), noEdits());
+}
+
+/// Flattens a list of generators into a single generator whose elements are the
+/// concatenation of the results of the argument generators.
+EditGenerator flattenVector(SmallVector<EditGenerator, 2> Generators);
+
+namespace detail {
+/// Helper function to construct an \c EditGenerator. Overloaded for common
+/// cases so that user doesn't need to specify which factory function to
+/// use. This pattern gives benefits similar to implicit constructors, while
+/// maintaing a higher degree of explicitness.
+inline EditGenerator injectEdits(ASTEdit E) { return edit(std::move(E)); }
+inline EditGenerator injectEdits(EditGenerator G) { return G; }
+} // namespace detail
+
+template <typename... Ts> EditGenerator flatten(Ts &&...Edits) {
+ return flattenVector({detail::injectEdits(std::forward<Ts>(Edits))...});
+}
+
+// Every rewrite rule is triggered by a match against some AST node.
+// Transformer guarantees that this ID is bound to the triggering node whenever
+// a rewrite rule is applied.
+extern const char RootID[];
+
+/// Replaces a portion of the source text with \p Replacement.
+ASTEdit changeTo(RangeSelector Target, TextGenerator Replacement);
+/// DEPRECATED: use \c changeTo.
+inline ASTEdit change(RangeSelector Target, TextGenerator Replacement) {
+ return changeTo(std::move(Target), std::move(Replacement));
+}
+
+/// Replaces the entirety of a RewriteRule's match with \p Replacement. For
+/// example, to replace a function call, one could write:
+/// \code
+/// makeRule(callExpr(callee(functionDecl(hasName("foo")))),
+/// changeTo(cat("bar()")))
+/// \endcode
+inline ASTEdit changeTo(TextGenerator Replacement) {
+ return changeTo(node(RootID), std::move(Replacement));
+}
+/// DEPRECATED: use \c changeTo.
+inline ASTEdit change(TextGenerator Replacement) {
+ return changeTo(std::move(Replacement));
+}
+
+/// Inserts \p Replacement before \p S, leaving the source selected by \S
+/// unchanged.
+inline ASTEdit insertBefore(RangeSelector S, TextGenerator Replacement) {
+ return changeTo(before(std::move(S)), std::move(Replacement));
+}
+
+/// Inserts \p Replacement after \p S, leaving the source selected by \S
+/// unchanged.
+inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) {
+ return changeTo(after(std::move(S)), std::move(Replacement));
+}
+
+/// Removes the source selected by \p S.
+ASTEdit remove(RangeSelector S);
+
+/// Adds an include directive for the given header to the file of `Target`. The
+/// particular location specified by `Target` is ignored.
+ASTEdit addInclude(RangeSelector Target, StringRef Header,
+ IncludeFormat Format = IncludeFormat::Quoted);
+
+/// Adds an include directive for the given header to the file associated with
+/// `RootID`. If `RootID` matches inside a macro expansion, will add the
+/// directive to the file in which the macro was expanded (as opposed to the
+/// file in which the macro is defined).
+inline ASTEdit addInclude(StringRef Header,
+ IncludeFormat Format = IncludeFormat::Quoted) {
+ return addInclude(expansion(node(RootID)), Header, Format);
+}
+
+// FIXME: If `Metadata` returns an `llvm::Expected<T>` the `AnyGenerator` will
+// construct an `llvm::Expected<llvm::Any>` where no error is present but the
+// `llvm::Any` holds the error. This is unlikely but potentially surprising.
+// Perhaps the `llvm::Expected` should be unwrapped, or perhaps this should be a
+// compile-time error. No solution here is perfect.
+//
+// Note: This function template accepts any type callable with a MatchResult
+// rather than a `std::function` because the return-type needs to be deduced. If
+// it accepted a `std::function<R(MatchResult)>`, lambdas or other callable
+// types would not be able to deduce `R`, and users would be forced to specify
+// explicitly the type they intended to return by wrapping the lambda at the
+// call-site.
+template <typename Callable>
+inline ASTEdit withMetadata(ASTEdit Edit, Callable Metadata) {
+ Edit.Metadata =
+ [Gen = std::move(Metadata)](
+ const ast_matchers::MatchFinder::MatchResult &R) -> llvm::Any {
+ return Gen(R);
+ };
+
+ return Edit;
+}
+
+/// Assuming that the inner range is enclosed by the outer range, creates
+/// precision edits to remove the parts of the outer range that are not included
+/// in the inner range.
+inline EditGenerator shrinkTo(RangeSelector outer, RangeSelector inner) {
+ return editList({remove(enclose(before(outer), before(inner))),
+ remove(enclose(after(inner), after(outer)))});
+}
/// Description of a source-code transformation.
//
@@ -137,25 +280,19 @@ struct RewriteRule {
ast_matchers::internal::DynTypedMatcher Matcher;
EditGenerator Edits;
TextGenerator Explanation;
- // Include paths to add to the file affected by this case. These are
- // bundled with the `Case`, rather than the `RewriteRule`, because each case
- // might have different associated changes to the includes.
- std::vector<std::pair<std::string, IncludeFormat>> AddedIncludes;
};
// We expect RewriteRules will most commonly include only one case.
SmallVector<Case, 1> Cases;
- // ID used as the default target of each match. The node described by the
- // matcher is should always be bound to this id.
- static constexpr llvm::StringLiteral RootID = "___root___";
+ /// DEPRECATED: use `::clang::transformer::RootID` instead.
+ static const llvm::StringRef RootID;
};
-/// Convenience function for constructing a simple \c RewriteRule.
+/// Constructs a simple \c RewriteRule.
RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
EditGenerator Edits, TextGenerator Explanation = nullptr);
-/// Convenience function for constructing a \c RewriteRule from multiple
-/// `ASTEdit`s.
+/// Constructs a \c RewriteRule from multiple `ASTEdit`s.
inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
llvm::SmallVector<ASTEdit, 1> Edits,
TextGenerator Explanation = nullptr) {
@@ -163,7 +300,7 @@ inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
std::move(Explanation));
}
-/// Convenience overload of \c makeRule for common case of only one edit.
+/// Overload of \c makeRule for common case of only one edit.
inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
ASTEdit Edit,
TextGenerator Explanation = nullptr) {
@@ -177,8 +314,8 @@ inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
/// \code
/// auto R = makeRule(callExpr(callee(functionDecl(hasName("foo")))),
/// changeTo(cat("bar()")));
-/// AddInclude(R, "path/to/bar_header.h");
-/// AddInclude(R, "vector", IncludeFormat::Angled);
+/// addInclude(R, "path/to/bar_header.h");
+/// addInclude(R, "vector", IncludeFormat::Angled);
/// \endcode
void addInclude(RewriteRule &Rule, llvm::StringRef Header,
IncludeFormat Format = IncludeFormat::Quoted);
@@ -224,47 +361,22 @@ void addInclude(RewriteRule &Rule, llvm::StringRef Header,
// ```
RewriteRule applyFirst(ArrayRef<RewriteRule> Rules);
-/// Replaces a portion of the source text with \p Replacement.
-ASTEdit changeTo(RangeSelector Target, TextGenerator Replacement);
-/// DEPRECATED: use \c changeTo.
-inline ASTEdit change(RangeSelector Target, TextGenerator Replacement) {
- return changeTo(std::move(Target), std::move(Replacement));
-}
-
-/// Replaces the entirety of a RewriteRule's match with \p Replacement. For
-/// example, to replace a function call, one could write:
-/// \code
-/// makeRule(callExpr(callee(functionDecl(hasName("foo")))),
-/// changeTo(cat("bar()")))
-/// \endcode
-inline ASTEdit changeTo(TextGenerator Replacement) {
- return changeTo(node(std::string(RewriteRule::RootID)),
- std::move(Replacement));
-}
-/// DEPRECATED: use \c changeTo.
-inline ASTEdit change(TextGenerator Replacement) {
- return changeTo(std::move(Replacement));
-}
-
-/// Inserts \p Replacement before \p S, leaving the source selected by \S
-/// unchanged.
-inline ASTEdit insertBefore(RangeSelector S, TextGenerator Replacement) {
- return changeTo(before(std::move(S)), std::move(Replacement));
-}
-
-/// Inserts \p Replacement after \p S, leaving the source selected by \S
-/// unchanged.
-inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) {
- return changeTo(after(std::move(S)), std::move(Replacement));
-}
-
-/// Removes the source selected by \p S.
-ASTEdit remove(RangeSelector S);
-
-inline ASTEdit withMetadata(ASTEdit edit, llvm::Any Metadata) {
- edit.Metadata = std::move(Metadata);
- return edit;
-}
+/// Applies `Rule` to all descendants of the node bound to `NodeId`. `Rule` can
+/// refer to nodes bound by the calling rule. `Rule` is not applied to the node
+/// itself.
+///
+/// For example,
+/// ```
+/// auto InlineX =
+/// makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+/// makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
+/// flatten(
+/// changeTo(name("f"), cat("newName")),
+/// rewriteDescendants("body", InlineX)));
+/// ```
+/// Here, we find the function `f`, change its name to `newName` and change all
+/// appearances of `x` in its body to `3`.
+EditGenerator rewriteDescendants(std::string NodeId, RewriteRule Rule);
/// The following three functions are a low-level part of the RewriteRule
/// API. We expose them for use in implementing the fixtures that interpret
@@ -275,6 +387,38 @@ inline ASTEdit withMetadata(ASTEdit edit, llvm::Any Metadata) {
// RewriteRule API. Recast them as such. Or, just declare these functions
// public and well-supported and move them out of `detail`.
namespace detail {
+/// The following overload set is a version of `rewriteDescendants` that
+/// operates directly on the AST, rather than generating a Transformer
+/// combinator. It applies `Rule` to all descendants of `Node`, although not
+/// `Node` itself. `Rule` can refer to nodes bound in `Result`.
+///
+/// For example, assuming that "body" is bound to a function body in MatchResult
+/// `Results`, this will produce edits to change all appearances of `x` in that
+/// body to `3`.
+/// ```
+/// auto InlineX =
+/// makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+/// const auto *Node = Results.Nodes.getNodeAs<Stmt>("body");
+/// auto Edits = rewriteDescendants(*Node, InlineX, Results);
+/// ```
+/// @{
+llvm::Expected<SmallVector<Edit, 1>>
+rewriteDescendants(const Decl &Node, RewriteRule Rule,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+
+llvm::Expected<SmallVector<Edit, 1>>
+rewriteDescendants(const Stmt &Node, RewriteRule Rule,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+
+llvm::Expected<SmallVector<Edit, 1>>
+rewriteDescendants(const TypeLoc &Node, RewriteRule Rule,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+
+llvm::Expected<SmallVector<Edit, 1>>
+rewriteDescendants(const DynTypedNode &Node, RewriteRule Rule,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+/// @}
+
/// Builds a single matcher for the rule, covering all of the rule's cases.
/// Only supports Rules whose cases' matchers share the same base "kind"
/// (`Stmt`, `Decl`, etc.) Deprecated: use `buildMatchers` instead, which
@@ -304,28 +448,6 @@ findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result,
const RewriteRule &Rule);
} // namespace detail
} // namespace transformer
-
-namespace tooling {
-// DEPRECATED: These are temporary aliases supporting client migration to the
-// `transformer` namespace.
-/// Wraps a string as a TextGenerator.
-using TextGenerator = transformer::TextGenerator;
-
-TextGenerator text(std::string M);
-
-using transformer::addInclude;
-using transformer::applyFirst;
-using transformer::change;
-using transformer::insertAfter;
-using transformer::insertBefore;
-using transformer::makeRule;
-using transformer::remove;
-using transformer::RewriteRule;
-using transformer::IncludeFormat;
-namespace detail {
-using namespace transformer::detail;
-} // namespace detail
-} // namespace tooling
} // namespace clang
#endif // LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_
diff --git a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/Stencil.h b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/Stencil.h
index 1b50a670f70b..1b7495eb0262 100644
--- a/contrib/llvm-project/clang/include/clang/Tooling/Transformer/Stencil.h
+++ b/contrib/llvm-project/clang/include/clang/Tooling/Transformer/Stencil.h
@@ -82,7 +82,6 @@ Stencil deref(llvm::StringRef ExprId);
/// If \p ExprId is of pointer type, constructs an idiomatic dereferencing of
/// the expression bound to \p ExprId, including wrapping it in parentheses, if
/// needed. Otherwise, generates the original expression source.
-/// FIXME: Identify smart-pointers as pointer types.
Stencil maybeDeref(llvm::StringRef ExprId);
/// Constructs an expression that idiomatically takes the address of the
@@ -94,7 +93,6 @@ Stencil addressOf(llvm::StringRef ExprId);
/// idiomatically takes the address of the expression bound to \p ExprId,
/// including wrapping \p ExprId in parentheses, if needed. Otherwise, generates
/// the original expression source.
-/// FIXME: Identify smart-pointers as pointer types.
Stencil maybeAddressOf(llvm::StringRef ExprId);
/// Constructs a `MemberExpr` that accesses the named member (\p Member) of the
@@ -123,6 +121,15 @@ inline Stencil ifBound(llvm::StringRef Id, llvm::StringRef TrueText,
/// Stencil. This supports user-defined extensions to the \c Stencil language.
Stencil run(MatchConsumer<std::string> C);
+/// Produces a human-readable rendering of the node bound to `Id`, suitable for
+/// diagnostics and debugging. This operator can be applied to any node, but is
+/// targeted at those whose source cannot be printed directly, including:
+///
+/// * Types. represented based on their structure. Note that namespace
+/// qualifiers are always printed, with the anonymous namespace represented
+/// explicitly. No desugaring or canonicalization is applied.
+Stencil describe(llvm::StringRef Id);
+
/// For debug use only; semantics are not guaranteed.
///
/// \returns the string resulting from calling the node's print() method.