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"
17 #include "llvm/Support/Errc.h"
18 #include <atomic>
19 #include <memory>
20 #include <string>
21 
22 using namespace clang;
23 using namespace tooling;
24 
26 using llvm::Error;
27 
28 // A down_cast function to safely down cast a StencilPartInterface to a subclass
29 // D. Returns nullptr if P is not an instance of D.
30 template <typename D> const D *down_cast(const StencilPartInterface *P) {
31  if (P == nullptr || D::typeId() != P->typeId())
32  return nullptr;
33  return static_cast<const D *>(P);
34 }
35 
38  auto &NodesMap = Nodes.getMap();
39  auto It = NodesMap.find(Id);
40  if (It == NodesMap.end())
41  return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
42  "Id not bound: " + Id);
43  return It->second;
44 }
45 
46 namespace {
47 // An arbitrary fragment of code within a stencil.
48 struct RawTextData {
49  explicit RawTextData(std::string T) : Text(std::move(T)) {}
50  std::string Text;
51 };
52 
53 // A debugging operation to dump the AST for a particular (bound) AST node.
54 struct DebugPrintNodeOpData {
55  explicit DebugPrintNodeOpData(std::string S) : Id(std::move(S)) {}
56  std::string Id;
57 };
58 
59 // The fragment of code corresponding to the selected range.
60 struct SelectorOpData {
61  explicit SelectorOpData(RangeSelector S) : Selector(std::move(S)) {}
63 };
64 } // namespace
65 
66 bool isEqualData(const RawTextData &A, const RawTextData &B) {
67  return A.Text == B.Text;
68 }
69 
70 bool isEqualData(const DebugPrintNodeOpData &A, const DebugPrintNodeOpData &B) {
71  return A.Id == B.Id;
72 }
73 
74 // Equality is not (yet) defined for \c RangeSelector.
75 bool isEqualData(const SelectorOpData &, const SelectorOpData &) { return false; }
76 
77 // The `evalData()` overloads evaluate the given stencil data to a string, given
78 // the match result, and append it to `Result`. We define an overload for each
79 // type of stencil data.
80 
81 Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
82  std::string *Result) {
83  Result->append(Data.Text);
84  return Error::success();
85 }
86 
87 Error evalData(const DebugPrintNodeOpData &Data,
88  const MatchFinder::MatchResult &Match, std::string *Result) {
89  std::string Output;
90  llvm::raw_string_ostream Os(Output);
91  auto NodeOrErr = getNode(Match.Nodes, Data.Id);
92  if (auto Err = NodeOrErr.takeError())
93  return Err;
94  NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
95  *Result += Os.str();
96  return Error::success();
97 }
98 
99 Error evalData(const SelectorOpData &Data, const MatchFinder::MatchResult &Match,
100  std::string *Result) {
101  auto Range = Data.Selector(Match);
102  if (!Range)
103  return Range.takeError();
104  *Result += getText(*Range, *Match.Context);
105  return Error::success();
106 }
107 
108 template <typename T>
110  T Data;
111 
112 public:
113  template <typename... Ps>
114  explicit StencilPartImpl(Ps &&... Args)
116  Data(std::forward<Ps>(Args)...) {}
117 
118  // Generates a unique identifier for this class (specifically, one per
119  // instantiation of the template).
120  static const void* typeId() {
121  static bool b;
122  return &b;
123  }
124 
126  std::string *Result) const override {
127  return evalData(Data, Match, Result);
128  }
129 
130  bool isEqual(const StencilPartInterface &Other) const override {
131  if (const auto *OtherPtr = down_cast<StencilPartImpl>(&Other))
132  return isEqualData(Data, OtherPtr->Data);
133  return false;
134  }
135 };
136 
137 namespace {
138 using RawText = StencilPartImpl<RawTextData>;
139 using DebugPrintNodeOp = StencilPartImpl<DebugPrintNodeOpData>;
140 using SelectorOp = StencilPartImpl<SelectorOpData>;
141 } // namespace
142 
143 StencilPart Stencil::wrap(StringRef Text) {
144  return stencil::text(Text);
145 }
146 
147 StencilPart Stencil::wrap(RangeSelector Selector) {
148  return stencil::selection(std::move(Selector));
149 }
150 
151 void Stencil::append(Stencil OtherStencil) {
152  for (auto &Part : OtherStencil.Parts)
153  Parts.push_back(std::move(Part));
154 }
155 
158  std::string Result;
159  for (const auto &Part : Parts)
160  if (auto Err = Part.eval(Match, &Result))
161  return std::move(Err);
162  return Result;
163 }
164 
165 StencilPart stencil::text(StringRef Text) {
166  return StencilPart(std::make_shared<RawText>(Text));
167 }
168 
170  return StencilPart(std::make_shared<SelectorOp>(std::move(Selector)));
171 }
172 
173 StencilPart stencil::dPrint(StringRef Id) {
174  return StencilPart(std::make_shared<DebugPrintNodeOp>(Id));
175 }
A class to allow finding matches over the Clang AST.
Defines the clang::ASTContext interface.
A stencil is represented as a sequence of "parts" that can each individually generate a code string b...
Definition: Stencil.h:41
Smart pointer class that efficiently represents Objective-C method names.
A sequence of code fragments, references to parameters and code-generation operations that together c...
Definition: Stencil.h:95
const D * down_cast(const StencilPartInterface *P)
Definition: Stencil.cpp:30
StringRef P
static llvm::Expected< ast_type_traits::DynTypedNode > getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id)
Definition: Stencil.cpp:37
StringRef getText(CharSourceRange Range, const ASTContext &Context)
Returns the source-code text in the specified range.
Definition: SourceCode.cpp:17
MatchFinder::MatchResult MatchResult
Describes how types, statements, expressions, and declarations should be printed. ...
Definition: PrettyPrinter.h:37
BoundNodesTreeBuilder Nodes
llvm::Expected< std::string > eval(const ast_matchers::MatchFinder::MatchResult &Match) const
Definition: Stencil.cpp:157
const IDToNodeMap & getMap() const
Retrieve mapping from binding identifiers to bound nodes.
Definition: ASTMatchers.h:120
Definition: Format.h:2327
std::function< Expected< CharSourceRange >(const ast_matchers::MatchFinder::MatchResult &)> RangeSelector
Definition: RangeSelector.h:27
StencilPartImpl(Ps &&... Args)
Definition: Stencil.cpp:114
bool isEqualData(const RawTextData &A, const RawTextData &B)
Definition: Stencil.cpp:66
static const void * typeId()
Definition: Stencil.cpp:120
llvm::Error Error
Error eval(const MatchFinder::MatchResult &Match, std::string *Result) const override
Definition: Stencil.cpp:125
A source range independent of the SourceManager.
Definition: Replacement.h:44
A copyable facade for a std::unique_ptr<StencilPartInterface>.
Definition: Stencil.h:69
int Id
Definition: ASTDiff.cpp:190
Contains all information for a given match.
Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &, std::string *Result)
Definition: Stencil.cpp:81
StencilPart selection(RangeSelector Selector)
Definition: Stencil.cpp:169
Maps string IDs to AST nodes matched by parts of a matcher.
Definition: ASTMatchers.h:103
clang::ASTContext *const Context
Utilities for interpreting the matched AST structures.
void append(Stencil OtherStencil)
Appends data from a OtherStencil to this stencil.
Definition: Stencil.cpp:151
const BoundNodes Nodes
Contains the nodes bound on the current match.
Dataflow Directional Tag Classes.
StencilPart dPrint(llvm::StringRef Id)
For debug use only; semantics are not guaranteed.
StencilPart text(llvm::StringRef Text)
StringRef Text
Definition: Format.cpp:1757
const LangOptions & getLangOpts() const
Definition: ASTContext.h:720
const void * typeId() const
Definition: Stencil.h:52
bool isEqual(const StencilPartInterface &Other) const override
Definition: Stencil.cpp:130