Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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_TRANSFORMER_STENCIL_H_ |
||
21 | #define LLVM_CLANG_TOOLING_TRANSFORMER_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/Transformer/MatchConsumer.h" |
||
27 | #include "clang/Tooling/Transformer/RangeSelector.h" |
||
28 | #include "llvm/ADT/StringRef.h" |
||
29 | #include "llvm/Support/Error.h" |
||
30 | #include <string> |
||
31 | #include <vector> |
||
32 | |||
33 | namespace clang { |
||
34 | namespace transformer { |
||
35 | |||
36 | using StencilInterface = MatchComputation<std::string>; |
||
37 | |||
38 | /// A sequence of code fragments, references to parameters and code-generation |
||
39 | /// operations that together can be evaluated to (a fragment of) source code or |
||
40 | /// a diagnostic message, given a match result. |
||
41 | /// |
||
42 | /// We use a `shared_ptr` to allow for easy and cheap copying of stencils. |
||
43 | /// Since `StencilInterface` is an immutable interface, the sharing doesn't |
||
44 | /// impose any risks. Otherwise, we would have to add a virtual `copy` method to |
||
45 | /// the API and implement it for all derived classes. |
||
46 | using Stencil = std::shared_ptr<StencilInterface>; |
||
47 | |||
48 | namespace detail { |
||
49 | /// Convenience function to construct a \c Stencil. Overloaded for common cases |
||
50 | /// so that user doesn't need to specify which factory function to use. This |
||
51 | /// pattern gives benefits similar to implicit constructors, while maintaing a |
||
52 | /// higher degree of explicitness. |
||
53 | Stencil makeStencil(llvm::StringRef Text); |
||
54 | Stencil makeStencil(RangeSelector Selector); |
||
55 | inline Stencil makeStencil(Stencil S) { return S; } |
||
56 | } // namespace detail |
||
57 | |||
58 | /// Constructs the string representing the concatenation of the given \p |
||
59 | /// Parts. If only one element is passed in \p Parts, returns that element. |
||
60 | Stencil catVector(std::vector<Stencil> Parts); |
||
61 | |||
62 | /// Concatenates 0+ stencil pieces into a single stencil. Arguments can be raw |
||
63 | /// text, ranges in the matched code (\p RangeSelector) or other `Stencil`s. |
||
64 | template <typename... Ts> Stencil cat(Ts &&... Parts) { |
||
65 | return catVector({detail::makeStencil(std::forward<Ts>(Parts))...}); |
||
66 | } |
||
67 | |||
68 | // |
||
69 | // Functions for conveniently building stencils. |
||
70 | // |
||
71 | |||
72 | /// Generates the source of the expression bound to \p Id, wrapping it in |
||
73 | /// parentheses if it may parse differently depending on context. For example, a |
||
74 | /// binary operation is always wrapped, while a variable reference is never |
||
75 | /// wrapped. |
||
76 | Stencil expression(llvm::StringRef Id); |
||
77 | |||
78 | /// Constructs an idiomatic dereferencing of the expression bound to \p ExprId. |
||
79 | /// \p ExprId is wrapped in parentheses, if needed. |
||
80 | Stencil deref(llvm::StringRef ExprId); |
||
81 | |||
82 | /// If \p ExprId is of pointer type, constructs an idiomatic dereferencing of |
||
83 | /// the expression bound to \p ExprId, including wrapping it in parentheses, if |
||
84 | /// needed. Otherwise, generates the original expression source. |
||
85 | Stencil maybeDeref(llvm::StringRef ExprId); |
||
86 | |||
87 | /// Constructs an expression that idiomatically takes the address of the |
||
88 | /// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if |
||
89 | /// needed. |
||
90 | Stencil addressOf(llvm::StringRef ExprId); |
||
91 | |||
92 | /// If \p ExprId is not a pointer type, constructs an expression that |
||
93 | /// idiomatically takes the address of the expression bound to \p ExprId, |
||
94 | /// including wrapping \p ExprId in parentheses, if needed. Otherwise, generates |
||
95 | /// the original expression source. |
||
96 | Stencil maybeAddressOf(llvm::StringRef ExprId); |
||
97 | |||
98 | /// Constructs a `MemberExpr` that accesses the named member (\p Member) of the |
||
99 | /// object bound to \p BaseId. The access is constructed idiomatically: if \p |
||
100 | /// BaseId is bound to `e` and \p Member identifies member `m`, then returns |
||
101 | /// `e->m`, when e is a pointer, `e2->m` when e = `*e2` and `e.m` otherwise. |
||
102 | /// Additionally, `e` is wrapped in parentheses, if needed. |
||
103 | Stencil access(llvm::StringRef BaseId, Stencil Member); |
||
104 | inline Stencil access(llvm::StringRef BaseId, llvm::StringRef Member) { |
||
105 | return access(BaseId, detail::makeStencil(Member)); |
||
106 | } |
||
107 | |||
108 | /// Chooses between the two stencil parts, based on whether \p ID is bound in |
||
109 | /// the match. |
||
110 | Stencil ifBound(llvm::StringRef Id, Stencil TrueStencil, Stencil FalseStencil); |
||
111 | |||
112 | /// Chooses between the two strings, based on whether \p ID is bound in the |
||
113 | /// match. |
||
114 | inline Stencil ifBound(llvm::StringRef Id, llvm::StringRef TrueText, |
||
115 | llvm::StringRef FalseText) { |
||
116 | return ifBound(Id, detail::makeStencil(TrueText), |
||
117 | detail::makeStencil(FalseText)); |
||
118 | } |
||
119 | |||
120 | /// Chooses between multiple stencils, based on the presence of bound nodes. \p |
||
121 | /// CaseStencils takes a vector of (ID, \c Stencil) pairs and checks each ID in |
||
122 | /// order to see if it's bound to a node. If so, the associated \c Stencil is |
||
123 | /// run and all other cases are ignored. An optional \p DefaultStencil can be |
||
124 | /// provided to be run if all cases are exhausted beacause none of the provided |
||
125 | /// IDs are bound. If no default case is provided and all cases are exhausted, |
||
126 | /// the stencil will fail with error `llvm::errc::result_out_of_range`. |
||
127 | /// |
||
128 | /// For example, say one matches a statement's type with: |
||
129 | /// anyOf( |
||
130 | /// qualType(isInteger()).bind("int"), |
||
131 | /// qualType(realFloatingPointType()).bind("float"), |
||
132 | /// qualType(isAnyCharacter()).bind("char"), |
||
133 | /// booleanType().bind("bool")) |
||
134 | /// |
||
135 | /// Then, one can decide in a stencil how to construct a literal. |
||
136 | /// cat("a = ", |
||
137 | /// selectBound( |
||
138 | /// {{"int", cat("0")}, |
||
139 | /// {"float", cat("0.0")}, |
||
140 | /// {"char", cat("'\\0'")}, |
||
141 | /// {"bool", cat("false")}})) |
||
142 | /// |
||
143 | /// In addition, one could supply a default case for all other types: |
||
144 | /// selectBound( |
||
145 | /// {{"int", cat("0")}, |
||
146 | /// ... |
||
147 | /// {"bool", cat("false")}}, |
||
148 | /// cat("{}")) |
||
149 | Stencil selectBound(std::vector<std::pair<std::string, Stencil>> CaseStencils, |
||
150 | Stencil DefaultStencil = nullptr); |
||
151 | |||
152 | /// Wraps a \c MatchConsumer in a \c Stencil, so that it can be used in a \c |
||
153 | /// Stencil. This supports user-defined extensions to the \c Stencil language. |
||
154 | Stencil run(MatchConsumer<std::string> C); |
||
155 | |||
156 | /// Produces a human-readable rendering of the node bound to `Id`, suitable for |
||
157 | /// diagnostics and debugging. This operator can be applied to any node, but is |
||
158 | /// targeted at those whose source cannot be printed directly, including: |
||
159 | /// |
||
160 | /// * Types. represented based on their structure. Note that namespace |
||
161 | /// qualifiers are always printed, with the anonymous namespace represented |
||
162 | /// explicitly. No desugaring or canonicalization is applied. |
||
163 | Stencil describe(llvm::StringRef Id); |
||
164 | |||
165 | /// For debug use only; semantics are not guaranteed. |
||
166 | /// |
||
167 | /// \returns the string resulting from calling the node's print() method. |
||
168 | Stencil dPrint(llvm::StringRef Id); |
||
169 | } // namespace transformer |
||
170 | } // namespace clang |
||
171 | #endif // LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_ |