1 //===--- Stencil.h - Stencil class ------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file defines the *Stencil* abstraction: a code-generating object,
11 /// parameterized by named references to (bound) AST nodes. Given a match
12 /// result, a stencil can be evaluated to a string of source code.
14 /// A stencil is similar in spirit to a format string: it is composed of a
15 /// series of raw text strings, references to nodes (the parameters) and helper
16 /// code-generation operations.
18 //===----------------------------------------------------------------------===//
20 #ifndef LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
21 #define LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
23 #include "clang/AST/ASTContext.h"
24 #include "clang/AST/ASTTypeTraits.h"
25 #include "clang/ASTMatchers/ASTMatchFinder.h"
26 #include "clang/Tooling/Refactoring/RangeSelector.h"
27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/Support/Error.h"
35 /// A stencil is represented as a sequence of "parts" that can each individually
36 /// generate a code string based on a match result. The different kinds of
37 /// parts include (raw) text, references to bound nodes and assorted operations
40 /// Users can create custom Stencil operations by implementing this interface.
41 class StencilPartInterface {
43 virtual ~StencilPartInterface() = default;
45 /// Evaluates this part to a string and appends it to \c Result. \c Result is
46 /// undefined in the case of an error.
47 virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
48 std::string *Result) const = 0;
50 virtual bool isEqual(const StencilPartInterface &other) const = 0;
52 const void *typeId() const { return TypeId; }
55 StencilPartInterface(const void *DerivedId) : TypeId(DerivedId) {}
57 // Since this is an abstract class, copying/assigning only make sense for
58 // derived classes implementing `clone()`.
59 StencilPartInterface(const StencilPartInterface &) = default;
60 StencilPartInterface &operator=(const StencilPartInterface &) = default;
62 /// Unique identifier of the concrete type of this instance. Supports safe
67 /// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result
68 /// in a copy of the underlying pointee object.
71 explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl)
72 : Impl(std::move(Impl)) {}
74 /// See `StencilPartInterface::eval()`.
75 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
76 std::string *Result) const {
77 return Impl->eval(Match, Result);
80 bool operator==(const StencilPart &Other) const {
81 if (Impl == Other.Impl)
83 if (Impl == nullptr || Other.Impl == nullptr)
85 return Impl->isEqual(*Other.Impl);
89 std::shared_ptr<StencilPartInterface> Impl;
92 /// A sequence of code fragments, references to parameters and code-generation
93 /// operations that together can be evaluated to (a fragment of) source code,
94 /// given a match result.
99 /// Composes a stencil from a series of parts.
100 template <typename... Ts> static Stencil cat(Ts &&... Parts) {
102 S.Parts = {wrap(std::forward<Ts>(Parts))...};
106 /// Appends data from a \p OtherStencil to this stencil.
107 void append(Stencil OtherStencil);
109 // Evaluates the stencil given a match result. Requires that the nodes in the
110 // result includes any ids referenced in the stencil. References to missing
111 // nodes will result in an invalid_argument error.
112 llvm::Expected<std::string>
113 eval(const ast_matchers::MatchFinder::MatchResult &Match) const;
115 // Allow Stencils to operate as std::function, for compatibility with
116 // Transformer's TextGenerator.
117 llvm::Expected<std::string>
118 operator()(const ast_matchers::MatchFinder::MatchResult &Result) const {
123 friend bool operator==(const Stencil &A, const Stencil &B);
124 static StencilPart wrap(llvm::StringRef Text);
125 static StencilPart wrap(RangeSelector Selector);
126 static StencilPart wrap(StencilPart Part) { return Part; }
128 std::vector<StencilPart> Parts;
131 inline bool operator==(const Stencil &A, const Stencil &B) {
132 return A.Parts == B.Parts;
135 inline bool operator!=(const Stencil &A, const Stencil &B) { return !(A == B); }
137 // Functions for conveniently building stencils.
139 /// Convenience wrapper for Stencil::cat that can be imported with a using decl.
140 template <typename... Ts> Stencil cat(Ts &&... Parts) {
141 return Stencil::cat(std::forward<Ts>(Parts)...);
144 /// \returns exactly the text provided.
145 StencilPart text(llvm::StringRef Text);
147 /// \returns the source corresponding to the selected range.
148 StencilPart selection(RangeSelector Selector);
150 /// \returns the source corresponding to the identified node.
151 /// FIXME: Deprecated. Write `selection(node(Id))` instead.
152 inline StencilPart node(llvm::StringRef Id) {
153 return selection(tooling::node(Id));
156 /// Variant of \c node() that identifies the node as a statement, for purposes
157 /// of deciding whether to include any trailing semicolon. Only relevant for
158 /// Expr nodes, which, by default, are *not* considered as statements.
159 /// \returns the source corresponding to the identified node, considered as a
161 /// FIXME: Deprecated. Write `selection(statement(Id))` instead.
162 inline StencilPart sNode(llvm::StringRef Id) {
163 return selection(tooling::statement(Id));
166 /// For debug use only; semantics are not guaranteed.
168 /// \returns the string resulting from calling the node's print() method.
169 StencilPart dPrint(llvm::StringRef Id);
170 } // namespace stencil
171 } // namespace tooling
173 #endif // LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_