]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/include/clang/Tooling/Refactoring/Stencil.h
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / include / clang / Tooling / Refactoring / Stencil.h
1 //===--- Stencil.h - Stencil class ------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// /file
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.
13 ///
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.
17 ///
18 //===----------------------------------------------------------------------===//
19
20 #ifndef LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
21 #define LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
22
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"
29 #include <string>
30 #include <vector>
31
32 namespace clang {
33 namespace tooling {
34
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
38 /// on bound nodes.
39 ///
40 /// Users can create custom Stencil operations by implementing this interface.
41 class StencilPartInterface {
42 public:
43   virtual ~StencilPartInterface() = default;
44
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;
49
50   virtual bool isEqual(const StencilPartInterface &other) const = 0;
51
52   const void *typeId() const { return TypeId; }
53
54 protected:
55   StencilPartInterface(const void *DerivedId) : TypeId(DerivedId) {}
56
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;
61
62   /// Unique identifier of the concrete type of this instance.  Supports safe
63   /// downcasting.
64   const void *TypeId;
65 };
66
67 /// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result
68 /// in a copy of the underlying pointee object.
69 class StencilPart {
70 public:
71   explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl)
72       : Impl(std::move(Impl)) {}
73
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);
78   }
79
80   bool operator==(const StencilPart &Other) const {
81     if (Impl == Other.Impl)
82       return true;
83     if (Impl == nullptr || Other.Impl == nullptr)
84       return false;
85     return Impl->isEqual(*Other.Impl);
86   }
87
88 private:
89   std::shared_ptr<StencilPartInterface> Impl;
90 };
91
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.
95 class Stencil {
96 public:
97   Stencil() = default;
98
99   /// Composes a stencil from a series of parts.
100   template <typename... Ts> static Stencil cat(Ts &&... Parts) {
101     Stencil S;
102     S.Parts = {wrap(std::forward<Ts>(Parts))...};
103     return S;
104   }
105
106   /// Appends data from a \p OtherStencil to this stencil.
107   void append(Stencil OtherStencil);
108
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;
114
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 {
119     return eval(Result);
120   }
121
122 private:
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; }
127
128   std::vector<StencilPart> Parts;
129 };
130
131 inline bool operator==(const Stencil &A, const Stencil &B) {
132   return A.Parts == B.Parts;
133 }
134
135 inline bool operator!=(const Stencil &A, const Stencil &B) { return !(A == B); }
136
137 // Functions for conveniently building stencils.
138 namespace stencil {
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)...);
142 }
143
144 /// \returns exactly the text provided.
145 StencilPart text(llvm::StringRef Text);
146
147 /// \returns the source corresponding to the selected range.
148 StencilPart selection(RangeSelector Selector);
149
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));
154 }
155
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
160 /// statement.
161 /// FIXME: Deprecated. Write `selection(statement(Id))` instead.
162 inline StencilPart sNode(llvm::StringRef Id) {
163   return selection(tooling::statement(Id));
164 }
165
166 /// For debug use only; semantics are not guaranteed.
167 ///
168 /// \returns the string resulting from calling the node's print() method.
169 StencilPart dPrint(llvm::StringRef Id);
170 } // namespace stencil
171 } // namespace tooling
172 } // namespace clang
173 #endif // LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_