clang  10.0.0svn
Stencil.cpp
Go to the documentation of this file.
1 //===--- Stencil.cpp - Stencil implementation -------------------*- 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 
10 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Expr.h"
15 #include "clang/Lex/Lexer.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/Errc.h"
20 #include <atomic>
21 #include <memory>
22 #include <string>
23 
24 using namespace clang;
25 using namespace transformer;
26 
29 using llvm::errc;
30 using llvm::Error;
31 using llvm::Expected;
32 using llvm::StringError;
33 
36  auto &NodesMap = Nodes.getMap();
37  auto It = NodesMap.find(Id);
38  if (It == NodesMap.end())
39  return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
40  "Id not bound: " + Id);
41  return It->second;
42 }
43 
44 namespace {
45 // An arbitrary fragment of code within a stencil.
46 struct RawTextData {
47  explicit RawTextData(std::string T) : Text(std::move(T)) {}
48  std::string Text;
49 };
50 
51 // A debugging operation to dump the AST for a particular (bound) AST node.
52 struct DebugPrintNodeData {
53  explicit DebugPrintNodeData(std::string S) : Id(std::move(S)) {}
54  std::string Id;
55 };
56 
57 // Operators that take a single node Id as an argument.
58 enum class UnaryNodeOperator {
59  Parens,
60  Deref,
61  Address,
62 };
63 
64 // Generic container for stencil operations with a (single) node-id argument.
65 struct UnaryOperationData {
66  UnaryOperationData(UnaryNodeOperator Op, std::string Id)
67  : Op(Op), Id(std::move(Id)) {}
69  std::string Id;
70 };
71 
72 // The fragment of code corresponding to the selected range.
73 struct SelectorData {
74  explicit SelectorData(RangeSelector S) : Selector(std::move(S)) {}
76 };
77 
78 // A stencil operation to build a member access `e.m` or `e->m`, as appropriate.
79 struct AccessData {
80  AccessData(StringRef BaseId, StencilPart Member)
81  : BaseId(BaseId), Member(std::move(Member)) {}
82  std::string BaseId;
83  StencilPart Member;
84 };
85 
86 struct IfBoundData {
87  IfBoundData(StringRef Id, StencilPart TruePart, StencilPart FalsePart)
88  : Id(Id), TruePart(std::move(TruePart)), FalsePart(std::move(FalsePart)) {
89  }
90  std::string Id;
91  StencilPart TruePart;
92  StencilPart FalsePart;
93 };
94 
95 std::string toStringData(const RawTextData &Data) {
96  std::string Result;
97  llvm::raw_string_ostream OS(Result);
98  OS << "\"";
99  OS.write_escaped(Data.Text);
100  OS << "\"";
101  OS.flush();
102  return Result;
103 }
104 
105 std::string toStringData(const DebugPrintNodeData &Data) {
106  return (llvm::Twine("dPrint(\"") + Data.Id + "\")").str();
107 }
108 
109 std::string toStringData(const UnaryOperationData &Data) {
110  StringRef OpName;
111  switch (Data.Op) {
112  case UnaryNodeOperator::Parens:
113  OpName = "expression";
114  break;
115  case UnaryNodeOperator::Deref:
116  OpName = "deref";
117  break;
118  case UnaryNodeOperator::Address:
119  OpName = "addressOf";
120  break;
121  }
122  return (OpName + "(\"" + Data.Id + "\")").str();
123 }
124 
125 std::string toStringData(const SelectorData &) { return "selection(...)"; }
126 
127 std::string toStringData(const AccessData &Data) {
128  return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
129  Data.Member.toString() + ")")
130  .str();
131 }
132 
133 std::string toStringData(const IfBoundData &Data) {
134  return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
135  Data.TruePart.toString() + ", " + Data.FalsePart.toString() + ")")
136  .str();
137 }
138 
139 std::string toStringData(const MatchConsumer<std::string> &) {
140  return "run(...)";
141 }
142 
143 // The `evalData()` overloads evaluate the given stencil data to a string, given
144 // the match result, and append it to `Result`. We define an overload for each
145 // type of stencil data.
146 
147 Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
148  std::string *Result) {
149  Result->append(Data.Text);
150  return Error::success();
151 }
152 
153 Error evalData(const DebugPrintNodeData &Data,
154  const MatchFinder::MatchResult &Match, std::string *Result) {
155  std::string Output;
156  llvm::raw_string_ostream Os(Output);
157  auto NodeOrErr = getNode(Match.Nodes, Data.Id);
158  if (auto Err = NodeOrErr.takeError())
159  return Err;
160  NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
161  *Result += Os.str();
162  return Error::success();
163 }
164 
165 Error evalData(const UnaryOperationData &Data,
166  const MatchFinder::MatchResult &Match, std::string *Result) {
167  const auto *E = Match.Nodes.getNodeAs<Expr>(Data.Id);
168  if (E == nullptr)
169  return llvm::make_error<StringError>(
170  errc::invalid_argument, "Id not bound or not Expr: " + Data.Id);
172  switch (Data.Op) {
173  case UnaryNodeOperator::Parens:
174  Source = tooling::buildParens(*E, *Match.Context);
175  break;
176  case UnaryNodeOperator::Deref:
177  Source = tooling::buildDereference(*E, *Match.Context);
178  break;
179  case UnaryNodeOperator::Address:
180  Source = tooling::buildAddressOf(*E, *Match.Context);
181  break;
182  }
183  if (!Source)
184  return llvm::make_error<StringError>(
185  errc::invalid_argument,
186  "Could not construct expression source from ID: " + Data.Id);
187  *Result += *Source;
188  return Error::success();
189 }
190 
191 Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match,
192  std::string *Result) {
193  auto Range = Data.Selector(Match);
194  if (!Range)
195  return Range.takeError();
196  *Result += tooling::getText(*Range, *Match.Context);
197  return Error::success();
198 }
199 
200 Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match,
201  std::string *Result) {
202  const auto *E = Match.Nodes.getNodeAs<Expr>(Data.BaseId);
203  if (E == nullptr)
204  return llvm::make_error<StringError>(errc::invalid_argument,
205  "Id not bound: " + Data.BaseId);
206  if (!E->isImplicitCXXThis()) {
208  E->getType()->isAnyPointerType()
209  ? tooling::buildArrow(*E, *Match.Context)
210  : tooling::buildDot(*E, *Match.Context))
211  *Result += *S;
212  else
213  return llvm::make_error<StringError>(
214  errc::invalid_argument,
215  "Could not construct object text from ID: " + Data.BaseId);
216  }
217  return Data.Member.eval(Match, Result);
218 }
219 
220 Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match,
221  std::string *Result) {
222  auto &M = Match.Nodes.getMap();
223  return (M.find(Data.Id) != M.end() ? Data.TruePart : Data.FalsePart)
224  .eval(Match, Result);
225 }
226 
227 Error evalData(const MatchConsumer<std::string> &Fn,
228  const MatchFinder::MatchResult &Match, std::string *Result) {
229  Expected<std::string> Value = Fn(Match);
230  if (!Value)
231  return Value.takeError();
232  *Result += *Value;
233  return Error::success();
234 }
235 
236 template <typename T>
237 class StencilPartImpl : public StencilPartInterface {
238  T Data;
239 
240 public:
241  template <typename... Ps>
242  explicit StencilPartImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
243 
244  Error eval(const MatchFinder::MatchResult &Match,
245  std::string *Result) const override {
246  return evalData(Data, Match, Result);
247  }
248 
249  std::string toString() const override { return toStringData(Data); }
250 };
251 } // namespace
252 
253 StencilPart Stencil::wrap(StringRef Text) {
254  return transformer::text(Text);
255 }
256 
257 StencilPart Stencil::wrap(RangeSelector Selector) {
258  return transformer::selection(std::move(Selector));
259 }
260 
261 void Stencil::append(Stencil OtherStencil) {
262  for (auto &Part : OtherStencil.Parts)
263  Parts.push_back(std::move(Part));
264 }
265 
268  std::string Result;
269  for (const auto &Part : Parts)
270  if (auto Err = Part.eval(Match, &Result))
271  return std::move(Err);
272  return Result;
273 }
274 
276  return StencilPart(std::make_shared<StencilPartImpl<RawTextData>>(Text));
277 }
278 
280  return StencilPart(
281  std::make_shared<StencilPartImpl<SelectorData>>(std::move(Selector)));
282 }
283 
285  return StencilPart(std::make_shared<StencilPartImpl<DebugPrintNodeData>>(Id));
286 }
287 
289  return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
290  UnaryNodeOperator::Parens, Id));
291 }
292 
293 StencilPart transformer::deref(llvm::StringRef ExprId) {
294  return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
295  UnaryNodeOperator::Deref, ExprId));
296 }
297 
298 StencilPart transformer::addressOf(llvm::StringRef ExprId) {
299  return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
300  UnaryNodeOperator::Address, ExprId));
301 }
302 
303 StencilPart transformer::access(StringRef BaseId, StencilPart Member) {
304  return StencilPart(
305  std::make_shared<StencilPartImpl<AccessData>>(BaseId, std::move(Member)));
306 }
307 
308 StencilPart transformer::ifBound(StringRef Id, StencilPart TruePart,
309  StencilPart FalsePart) {
310  return StencilPart(std::make_shared<StencilPartImpl<IfBoundData>>(
311  Id, std::move(TruePart), std::move(FalsePart)));
312 }
313 
315  return StencilPart(
316  std::make_shared<StencilPartImpl<MatchConsumer<std::string>>>(
317  std::move(Fn)));
318 }
A class to allow finding matches over the Clang AST.
Defines the clang::ASTContext interface.
Smart pointer class that efficiently represents Objective-C method names.
StencilPart selection(RangeSelector Selector)
Definition: Stencil.cpp:279
MatchConsumer< T > ifBound(std::string ID, MatchConsumer< T > TrueC, MatchConsumer< T > FalseC)
Chooses between the two consumers, based on whether ID is bound in the match.
Definition: MatchConsumer.h:47
A sequence of code fragments, references to parameters and code-generation operations that together c...
Definition: Stencil.h:90
llvm::Expected< T > Expected
llvm::Optional< std::string > buildDereference(const Expr &E, const ASTContext &Context)
Builds idiomatic source for the dereferencing of E: prefix with * but simplify when it already begins...
StringRef getText(CharSourceRange Range, const ASTContext &Context)
Returns the source-code text in the specified range.
Definition: SourceCode.cpp:17
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:37
BoundNodesTreeBuilder Nodes
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
const IDToNodeMap & getMap() const
Retrieve mapping from binding identifiers to bound nodes.
Definition: ASTMatchers.h:120
void append(Stencil OtherStencil)
Appends data from a OtherStencil to this stencil.
Definition: Stencil.cpp:261
llvm::Expected< std::string > eval(const ast_matchers::MatchFinder::MatchResult &Match) const
Definition: Stencil.cpp:267
UnaryNodeOperator
Definition: Stencil.cpp:58
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
Definition: ASTMatchers.h:110
StencilPart deref(llvm::StringRef ExprId)
Constructs an idiomatic dereferencing of the expression bound to ExprId.
Definition: Stencil.cpp:293
llvm::Error Error
StencilPart dPrint(llvm::StringRef Id)
For debug use only; semantics are not guaranteed.
This file defines the Stencil abstraction: a code-generating object, parameterized by named reference...
llvm::Optional< std::string > buildArrow(const Expr &E, const ASTContext &Context)
Adds an arrow to the end of the given expression, but adds parentheses when needed by the syntax...
transformer::StencilPart StencilPart
Definition: Stencil.h:201
StencilPart expression(llvm::StringRef Id)
Generates the source of the expression bound to Id, wrapping it in parentheses if it may parse differ...
Definition: Stencil.cpp:288
This represents one expression.
Definition: Expr.h:108
int Id
Definition: ASTDiff.cpp:190
StencilPart addressOf(llvm::StringRef ExprId)
Constructs an expression that idiomatically takes the address of the expression bound to ExprId...
Definition: Stencil.cpp:298
StencilPart run(MatchConsumer< std::string > C)
Wraps a MatchConsumer in a StencilPart, so that it can be used in a Stencil.
Definition: Stencil.cpp:314
A copyable facade for a std::unique_ptr<StencilPartInterface>.
Definition: Stencil.h:66
Contains all information for a given match.
This file collects facilities for generating source code strings.
MatchConsumer< CharSourceRange > RangeSelector
Definition: RangeSelector.h:27
Maps string IDs to AST nodes matched by parts of a matcher.
Definition: ASTMatchers.h:103
llvm::Optional< std::string > buildAddressOf(const Expr &E, const ASTContext &Context)
Builds idiomatic source for taking the address of E: prefix with & but simplify when it already begin...
std::function< Expected< T >(const ast_matchers::MatchFinder::MatchResult &)> MatchConsumer
A failable computation over nodes bound by AST matchers.
Definition: MatchConsumer.h:35
clang::ASTContext *const Context
Utilities for interpreting the matched AST structures.
llvm::Optional< std::string > buildParens(const Expr &E, const ASTContext &Context)
Builds source for an expression, adding parens if needed for unambiguous parsing. ...
static llvm::Expected< DynTypedNode > getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id)
Definition: Stencil.cpp:35
llvm::Optional< std::string > buildDot(const Expr &E, const ASTContext &Context)
Adds a dot to the end of the given expression, but adds parentheses when needed by the syntax...
ast_type_traits::DynTypedNode DynTypedNode
const BoundNodes Nodes
Contains the nodes bound on the current match.
Dataflow Directional Tag Classes.
StencilPart text(llvm::StringRef Text)
A stencil is represented as a sequence of "parts" that can each individually generate a code string b...
Definition: Stencil.h:41
StencilPart access(llvm::StringRef BaseId, StencilPart Member)
Constructs a MemberExpr that accesses the named member (Member) of the object bound to BaseId...
StringRef Text
Definition: Format.cpp:1808
const LangOptions & getLangOpts() const
Definition: ASTContext.h:723