clang  19.0.0git
Transformer.h
Go to the documentation of this file.
1 //===--- Transformer.h - Transformer 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 #ifndef LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
10 #define LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
11 
15 #include "llvm/Support/Error.h"
16 #include <functional>
17 #include <utility>
18 
19 namespace clang {
20 namespace tooling {
21 
22 namespace detail {
23 /// Implementation details of \c Transformer with type erasure around
24 /// \c RewriteRule<T> as well as the corresponding consumers.
26 public:
27  virtual ~TransformerImpl() = default;
28 
30 
31  virtual std::vector<ast_matchers::internal::DynTypedMatcher>
32  buildMatchers() const = 0;
33 
34 protected:
35  /// Converts a set of \c Edit into a \c AtomicChange per file modified.
36  /// Returns an error if the edits fail to compose, e.g. overlapping edits.
40 
41 private:
42  virtual void
43  onMatchImpl(const ast_matchers::MatchFinder::MatchResult &Result) = 0;
44 };
45 
46 // FIXME: Use std::type_identity or backport when available.
47 template <class T> struct type_identity {
48  using type = T;
49 };
50 } // namespace detail
51 
52 template <typename T> struct TransformerResult {
55 };
56 
57 template <> struct TransformerResult<void> {
59 };
60 
61 /// Handles the matcher and callback registration for a single `RewriteRule`, as
62 /// defined by the arguments of the constructor.
64 public:
65  /// Provides the set of changes to the consumer. The callback is free to move
66  /// or destructively consume the changes as needed.
67  ///
68  /// We use \c MutableArrayRef as an abstraction to provide decoupling, and we
69  /// expect the majority of consumers to copy or move the individual values
70  /// into a separate data structure.
71  using ChangeSetConsumer = std::function<void(
73 
74  /// \param Consumer receives all rewrites for a single match, or an error.
75  /// Will not necessarily be called for each match; for example, if the rule
76  /// generates no edits but does not fail. Note that clients are responsible
77  /// for handling the case that independent \c AtomicChanges conflict with each
78  /// other.
80  ChangeSetConsumer Consumer)
81  : Transformer(std::move(Rule),
82  [Consumer = std::move(Consumer)](
83  llvm::Expected<TransformerResult<void>> Result) {
84  if (Result)
85  Consumer(Result->Changes);
86  else
87  Consumer(Result.takeError());
88  }) {}
89 
90  /// \param Consumer receives all rewrites and the associated metadata for a
91  /// single match, or an error. Will always be called for each match, even if
92  /// the rule generates no edits. Note that clients are responsible for
93  /// handling the case that independent \c AtomicChanges conflict with each
94  /// other.
95  template <typename MetadataT>
96  explicit Transformer(
98  std::function<void(llvm::Expected<TransformerResult<
100  Consumer);
101 
102  /// N.B. Passes `this` pointer to `MatchFinder`. So, this object should not
103  /// be moved after this call.
105 
106  /// Not called directly by users -- called by the framework, via base class
107  /// pointer.
108  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
109 
110 private:
111  std::unique_ptr<detail::TransformerImpl> Impl;
112 };
113 
114 namespace detail {
115 /// Runs the metadata generator on \c Rule and stuffs it into \c Result.
116 /// @{
117 template <typename T>
118 llvm::Error
120  size_t SelectedCase,
122  TransformerResult<T> &Result) {
123  // Silence a false positive GCC -Wunused-but-set-parameter warning in constexpr
124  // cases, by marking SelectedCase as used. See
125  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85827 for details. The issue is
126  // fixed in GCC 10.
127  (void)SelectedCase;
128  if constexpr (!std::is_void_v<T>) {
129  auto Metadata = Rule.Metadata[SelectedCase]->eval(Match);
130  if (!Metadata)
131  return Metadata.takeError();
132  Result.Metadata = std::move(*Metadata);
133  }
134  return llvm::Error::success();
135 }
136 /// @}
137 
138 /// Implementation when metadata is generated as a part of the rewrite. This
139 /// happens when we have a \c RewriteRuleWith<T>.
140 template <typename T> class WithMetadataImpl final : public TransformerImpl {
142  std::function<void(llvm::Expected<TransformerResult<T>>)> Consumer;
143 
144 public:
147  std::function<void(llvm::Expected<TransformerResult<T>>)> Consumer)
148  : Rule(std::move(R)), Consumer(std::move(Consumer)) {
149  assert(llvm::all_of(Rule.Cases,
150  [](const transformer::RewriteRuleBase::Case &Case)
151  -> bool { return !!Case.Edits; }) &&
152  "edit generator must be provided for each rule");
153  if constexpr (!std::is_void_v<T>)
154  assert(llvm::all_of(Rule.Metadata,
155  [](const typename transformer::Generator<T> &Metadata)
156  -> bool { return !!Metadata; }) &&
157  "metadata generator must be provided for each rule");
158  }
159 
160 private:
161  void onMatchImpl(const ast_matchers::MatchFinder::MatchResult &Result) final {
162  size_t I = transformer::detail::findSelectedCase(Result, Rule);
163  auto Transformations = Rule.Cases[I].Edits(Result);
164  if (!Transformations) {
165  Consumer(Transformations.takeError());
166  return;
167  }
168 
170  if (!Transformations->empty()) {
171  auto C = convertToAtomicChanges(*Transformations, Result);
172  if (C) {
173  Changes = std::move(*C);
174  } else {
175  Consumer(C.takeError());
176  return;
177  }
178  } else if (std::is_void<T>::value) {
179  // If we don't have metadata and we don't have any edits, skip.
180  return;
181  }
182 
183  TransformerResult<T> RewriteResult;
184  if (auto E = populateMetadata(Rule, I, Result, RewriteResult)) {
185  Consumer(std::move(E));
186  return;
187  }
188 
189  RewriteResult.Changes = llvm::MutableArrayRef<AtomicChange>(Changes);
190  Consumer(std::move(RewriteResult));
191  }
192 
193  std::vector<ast_matchers::internal::DynTypedMatcher>
194  buildMatchers() const final {
196  }
197 };
198 } // namespace detail
199 
200 template <typename MetadataT>
203  std::function<void(llvm::Expected<TransformerResult<
205  Consumer)
206  : Impl(std::make_unique<detail::WithMetadataImpl<MetadataT>>(
207  std::move(Rule), std::move(Consumer))) {}
208 
209 } // namespace tooling
210 } // namespace clang
211 
212 #endif // LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
Defines the RewriteRule class and related functions for creating, modifying and interpreting RewriteR...
Called when the Match registered for it was successfully found in the AST.
A class to allow finding matches over the Clang AST.
Handles the matcher and callback registration for a single RewriteRule, as defined by the arguments o...
Definition: Transformer.h:63
std::function< void(Expected< llvm::MutableArrayRef< AtomicChange > > Changes)> ChangeSetConsumer
Provides the set of changes to the consumer.
Definition: Transformer.h:72
void registerMatchers(ast_matchers::MatchFinder *MatchFinder)
N.B.
Definition: Transformer.cpp:71
void run(const ast_matchers::MatchFinder::MatchResult &Result) override
Not called directly by users – called by the framework, via base class pointer.
Definition: Transformer.cpp:76
Transformer(transformer::RewriteRuleWith< void > Rule, ChangeSetConsumer Consumer)
Definition: Transformer.h:79
Implementation details of Transformer with type erasure around RewriteRule<T> as well as the correspo...
Definition: Transformer.h:25
virtual std::vector< ast_matchers::internal::DynTypedMatcher > buildMatchers() const =0
static llvm::Expected< llvm::SmallVector< AtomicChange, 1 > > convertToAtomicChanges(const llvm::SmallVectorImpl< transformer::Edit > &Edits, const ast_matchers::MatchFinder::MatchResult &Result)
Converts a set of Edit into a AtomicChange per file modified.
Definition: Transformer.cpp:35
void onMatch(const ast_matchers::MatchFinder::MatchResult &Result)
Definition: Transformer.cpp:26
Implementation when metadata is generated as a part of the rewrite.
Definition: Transformer.h:140
WithMetadataImpl(transformer::RewriteRuleWith< T > R, std::function< void(llvm::Expected< TransformerResult< T >>)> Consumer)
Definition: Transformer.h:145
llvm::Error populateMetadata(const transformer::RewriteRuleWith< T > &Rule, size_t SelectedCase, const ast_matchers::MatchFinder::MatchResult &Match, TransformerResult< T > &Result)
Runs the metadata generator on Rule and stuffs it into Result.
Definition: Transformer.h:119
size_t findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, const RewriteRuleBase &Rule)
Returns the index of the Case of Rule that was selected in the match result.
std::vector< ast_matchers::internal::DynTypedMatcher > buildMatchers(const RewriteRuleBase &Rule)
Builds a set of matchers that cover the rule.
std::shared_ptr< MatchComputation< T > > Generator
Definition: RewriteRule.h:65
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
Definition: Format.h:5433
Contains all information for a given match.
llvm::MutableArrayRef< AtomicChange > Changes
Definition: Transformer.h:58
llvm::MutableArrayRef< AtomicChange > Changes
Definition: Transformer.h:53
A source-code transformation with accompanying metadata.
Definition: RewriteRule.h:295
SmallVector< Generator< MetadataT >, 1 > Metadata
Definition: RewriteRule.h:296