File indexing completed on 2026-05-10 08:37:12
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
0010 #define LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
0011
0012 #include "clang/ASTMatchers/ASTMatchFinder.h"
0013 #include "clang/Tooling/Refactoring/AtomicChange.h"
0014 #include "clang/Tooling/Transformer/RewriteRule.h"
0015 #include "llvm/Support/Error.h"
0016 #include <functional>
0017 #include <utility>
0018
0019 namespace clang {
0020 namespace tooling {
0021
0022 namespace detail {
0023
0024
0025 class TransformerImpl {
0026 public:
0027 virtual ~TransformerImpl() = default;
0028
0029 void onMatch(const ast_matchers::MatchFinder::MatchResult &Result);
0030
0031 virtual std::vector<ast_matchers::internal::DynTypedMatcher>
0032 buildMatchers() const = 0;
0033
0034 protected:
0035
0036
0037 static llvm::Expected<llvm::SmallVector<AtomicChange, 1>>
0038 convertToAtomicChanges(const llvm::SmallVectorImpl<transformer::Edit> &Edits,
0039 const ast_matchers::MatchFinder::MatchResult &Result);
0040
0041 private:
0042 virtual void
0043 onMatchImpl(const ast_matchers::MatchFinder::MatchResult &Result) = 0;
0044 };
0045
0046
0047 template <class T> struct type_identity {
0048 using type = T;
0049 };
0050 }
0051
0052 template <typename T> struct TransformerResult {
0053 llvm::MutableArrayRef<AtomicChange> Changes;
0054 T Metadata;
0055 };
0056
0057 template <> struct TransformerResult<void> {
0058 llvm::MutableArrayRef<AtomicChange> Changes;
0059 };
0060
0061
0062
0063 class Transformer : public ast_matchers::MatchFinder::MatchCallback {
0064 public:
0065
0066
0067
0068
0069
0070
0071 using ChangeSetConsumer = std::function<void(
0072 Expected<llvm::MutableArrayRef<AtomicChange>> Changes)>;
0073
0074
0075
0076
0077
0078
0079 explicit Transformer(transformer::RewriteRuleWith<void> Rule,
0080 ChangeSetConsumer Consumer)
0081 : Transformer(std::move(Rule),
0082 [Consumer = std::move(Consumer)](
0083 llvm::Expected<TransformerResult<void>> Result) {
0084 if (Result)
0085 Consumer(Result->Changes);
0086 else
0087 Consumer(Result.takeError());
0088 }) {}
0089
0090
0091
0092
0093
0094
0095 template <typename MetadataT>
0096 explicit Transformer(
0097 transformer::RewriteRuleWith<MetadataT> Rule,
0098 std::function<void(llvm::Expected<TransformerResult<
0099 typename detail::type_identity<MetadataT>::type>>)>
0100 Consumer);
0101
0102
0103
0104 void registerMatchers(ast_matchers::MatchFinder *MatchFinder);
0105
0106
0107
0108 void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
0109
0110 private:
0111 std::unique_ptr<detail::TransformerImpl> Impl;
0112 };
0113
0114 namespace detail {
0115
0116
0117 template <typename T>
0118 llvm::Error
0119 populateMetadata(const transformer::RewriteRuleWith<T> &Rule,
0120 size_t SelectedCase,
0121 const ast_matchers::MatchFinder::MatchResult &Match,
0122 TransformerResult<T> &Result) {
0123
0124
0125
0126
0127 (void)SelectedCase;
0128 if constexpr (!std::is_void_v<T>) {
0129 auto Metadata = Rule.Metadata[SelectedCase]->eval(Match);
0130 if (!Metadata)
0131 return Metadata.takeError();
0132 Result.Metadata = std::move(*Metadata);
0133 }
0134 return llvm::Error::success();
0135 }
0136
0137
0138
0139
0140 template <typename T> class WithMetadataImpl final : public TransformerImpl {
0141 transformer::RewriteRuleWith<T> Rule;
0142 std::function<void(llvm::Expected<TransformerResult<T>>)> Consumer;
0143
0144 public:
0145 explicit WithMetadataImpl(
0146 transformer::RewriteRuleWith<T> R,
0147 std::function<void(llvm::Expected<TransformerResult<T>>)> Consumer)
0148 : Rule(std::move(R)), Consumer(std::move(Consumer)) {
0149 assert(llvm::all_of(Rule.Cases,
0150 [](const transformer::RewriteRuleBase::Case &Case)
0151 -> bool { return !!Case.Edits; }) &&
0152 "edit generator must be provided for each rule");
0153 if constexpr (!std::is_void_v<T>)
0154 assert(llvm::all_of(Rule.Metadata,
0155 [](const typename transformer::Generator<T> &Metadata)
0156 -> bool { return !!Metadata; }) &&
0157 "metadata generator must be provided for each rule");
0158 }
0159
0160 private:
0161 void onMatchImpl(const ast_matchers::MatchFinder::MatchResult &Result) final {
0162 size_t I = transformer::detail::findSelectedCase(Result, Rule);
0163 auto Transformations = Rule.Cases[I].Edits(Result);
0164 if (!Transformations) {
0165 Consumer(Transformations.takeError());
0166 return;
0167 }
0168
0169 llvm::SmallVector<AtomicChange, 1> Changes;
0170 if (!Transformations->empty()) {
0171 auto C = convertToAtomicChanges(*Transformations, Result);
0172 if (C) {
0173 Changes = std::move(*C);
0174 } else {
0175 Consumer(C.takeError());
0176 return;
0177 }
0178 } else if (std::is_void<T>::value) {
0179
0180 return;
0181 }
0182
0183 TransformerResult<T> RewriteResult;
0184 if (auto E = populateMetadata(Rule, I, Result, RewriteResult)) {
0185 Consumer(std::move(E));
0186 return;
0187 }
0188
0189 RewriteResult.Changes = llvm::MutableArrayRef<AtomicChange>(Changes);
0190 Consumer(std::move(RewriteResult));
0191 }
0192
0193 std::vector<ast_matchers::internal::DynTypedMatcher>
0194 buildMatchers() const final {
0195 return transformer::detail::buildMatchers(Rule);
0196 }
0197 };
0198 }
0199
0200 template <typename MetadataT>
0201 Transformer::Transformer(
0202 transformer::RewriteRuleWith<MetadataT> Rule,
0203 std::function<void(llvm::Expected<TransformerResult<
0204 typename detail::type_identity<MetadataT>::type>>)>
0205 Consumer)
0206 : Impl(std::make_unique<detail::WithMetadataImpl<MetadataT>>(
0207 std::move(Rule), std::move(Consumer))) {}
0208
0209 }
0210 }
0211
0212 #endif