|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 | 9 | #include "clang/Tooling/Transformer/RewriteRule.h"
|
| 10 | +#include "clang/AST/ASTTypeTraits.h" |
| 11 | +#include "clang/AST/Stmt.h" |
10 | 12 | #include "clang/ASTMatchers/ASTMatchFinder.h"
|
11 | 13 | #include "clang/ASTMatchers/ASTMatchers.h"
|
12 | 14 | #include "clang/Basic/SourceLocation.h"
|
@@ -115,15 +117,144 @@ ASTEdit transformer::remove(RangeSelector S) {
|
115 | 117 | return change(std::move(S), std::make_shared<SimpleTextGenerator>(""));
|
116 | 118 | }
|
117 | 119 |
|
118 |
| -RewriteRule transformer::makeRule(ast_matchers::internal::DynTypedMatcher M, |
119 |
| - EditGenerator Edits, |
| 120 | +RewriteRule transformer::makeRule(DynTypedMatcher M, EditGenerator Edits, |
120 | 121 | TextGenerator Explanation) {
|
121 | 122 | return RewriteRule{{RewriteRule::Case{
|
122 | 123 | std::move(M), std::move(Edits), std::move(Explanation), {}}}};
|
123 | 124 | }
|
124 | 125 |
|
| 126 | +namespace { |
| 127 | + |
| 128 | +/// Unconditionally binds the given node set before trying `InnerMatcher` and |
| 129 | +/// keeps the bound nodes on a successful match. |
| 130 | +template <typename T> |
| 131 | +class BindingsMatcher : public ast_matchers::internal::MatcherInterface<T> { |
| 132 | + ast_matchers::BoundNodes Nodes; |
| 133 | + const ast_matchers::internal::Matcher<T> InnerMatcher; |
| 134 | + |
| 135 | +public: |
| 136 | + explicit BindingsMatcher(ast_matchers::BoundNodes Nodes, |
| 137 | + ast_matchers::internal::Matcher<T> InnerMatcher) |
| 138 | + : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {} |
| 139 | + |
| 140 | + bool matches( |
| 141 | + const T &Node, ast_matchers::internal::ASTMatchFinder *Finder, |
| 142 | + ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override { |
| 143 | + ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); |
| 144 | + for (const auto &N : Nodes.getMap()) |
| 145 | + Result.setBinding(N.first, N.second); |
| 146 | + if (InnerMatcher.matches(Node, Finder, &Result)) { |
| 147 | + *Builder = std::move(Result); |
| 148 | + return true; |
| 149 | + } |
| 150 | + return false; |
| 151 | + } |
| 152 | +}; |
| 153 | + |
| 154 | +/// Matches nodes of type T that have at least one descendant node for which the |
| 155 | +/// given inner matcher matches. Will match for each descendant node that |
| 156 | +/// matches. Based on ForEachDescendantMatcher, but takes a dynamic matcher, |
| 157 | +/// instead of a static one, because it is used by RewriteRule, which carries |
| 158 | +/// (only top-level) dynamic matchers. |
| 159 | +template <typename T> |
| 160 | +class DynamicForEachDescendantMatcher |
| 161 | + : public ast_matchers::internal::MatcherInterface<T> { |
| 162 | + const DynTypedMatcher DescendantMatcher; |
| 163 | + |
| 164 | +public: |
| 165 | + explicit DynamicForEachDescendantMatcher(DynTypedMatcher DescendantMatcher) |
| 166 | + : DescendantMatcher(std::move(DescendantMatcher)) {} |
| 167 | + |
| 168 | + bool matches( |
| 169 | + const T &Node, ast_matchers::internal::ASTMatchFinder *Finder, |
| 170 | + ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override { |
| 171 | + return Finder->matchesDescendantOf( |
| 172 | + Node, this->DescendantMatcher, Builder, |
| 173 | + ast_matchers::internal::ASTMatchFinder::BK_All); |
| 174 | + } |
| 175 | +}; |
| 176 | + |
| 177 | +template <typename T> |
| 178 | +ast_matchers::internal::Matcher<T> |
| 179 | +forEachDescendantDynamically(ast_matchers::BoundNodes Nodes, |
| 180 | + DynTypedMatcher M) { |
| 181 | + return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>( |
| 182 | + std::move(Nodes), |
| 183 | + ast_matchers::internal::makeMatcher( |
| 184 | + new DynamicForEachDescendantMatcher<T>(std::move(M))))); |
| 185 | +} |
| 186 | + |
| 187 | +class ApplyRuleCallback : public MatchFinder::MatchCallback { |
| 188 | +public: |
| 189 | + ApplyRuleCallback(RewriteRule Rule) : Rule(std::move(Rule)) {} |
| 190 | + |
| 191 | + template <typename T> |
| 192 | + void registerMatchers(const ast_matchers::BoundNodes &Nodes, |
| 193 | + MatchFinder *MF) { |
| 194 | + for (auto &Matcher : transformer::detail::buildMatchers(Rule)) |
| 195 | + MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this); |
| 196 | + } |
| 197 | + |
| 198 | + void run(const MatchFinder::MatchResult &Result) override { |
| 199 | + if (!Edits) |
| 200 | + return; |
| 201 | + transformer::RewriteRule::Case Case = |
| 202 | + transformer::detail::findSelectedCase(Result, Rule); |
| 203 | + auto Transformations = Case.Edits(Result); |
| 204 | + if (!Transformations) { |
| 205 | + Edits = Transformations.takeError(); |
| 206 | + return; |
| 207 | + } |
| 208 | + Edits->append(Transformations->begin(), Transformations->end()); |
| 209 | + } |
| 210 | + |
| 211 | + RewriteRule Rule; |
| 212 | + |
| 213 | + // Initialize to a non-error state. |
| 214 | + Expected<SmallVector<Edit, 1>> Edits = SmallVector<Edit, 1>(); |
| 215 | +}; |
| 216 | +} // namespace |
| 217 | + |
| 218 | +template <typename T> |
| 219 | +llvm::Expected<SmallVector<clang::transformer::Edit, 1>> |
| 220 | +rewriteDescendantsImpl(const T &Node, RewriteRule Rule, |
| 221 | + const MatchResult &Result) { |
| 222 | + ApplyRuleCallback Callback(std::move(Rule)); |
| 223 | + MatchFinder Finder; |
| 224 | + Callback.registerMatchers<T>(Result.Nodes, &Finder); |
| 225 | + Finder.match(Node, *Result.Context); |
| 226 | + return std::move(Callback.Edits); |
| 227 | +} |
| 228 | + |
| 229 | +EditGenerator transformer::rewriteDescendants(std::string NodeId, |
| 230 | + RewriteRule Rule) { |
| 231 | + // FIXME: warn or return error if `Rule` contains any `AddedIncludes`, since |
| 232 | + // these will be dropped. |
| 233 | + return [NodeId = std::move(NodeId), |
| 234 | + Rule = std::move(Rule)](const MatchResult &Result) |
| 235 | + -> llvm::Expected<SmallVector<clang::transformer::Edit, 1>> { |
| 236 | + const ast_matchers::BoundNodes::IDToNodeMap &NodesMap = |
| 237 | + Result.Nodes.getMap(); |
| 238 | + auto It = NodesMap.find(NodeId); |
| 239 | + if (It == NodesMap.end()) |
| 240 | + return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, |
| 241 | + "ID not bound: " + NodeId); |
| 242 | + if (auto *Node = It->second.get<Decl>()) |
| 243 | + return rewriteDescendantsImpl(*Node, std::move(Rule), Result); |
| 244 | + if (auto *Node = It->second.get<Stmt>()) |
| 245 | + return rewriteDescendantsImpl(*Node, std::move(Rule), Result); |
| 246 | + if (auto *Node = It->second.get<TypeLoc>()) |
| 247 | + return rewriteDescendantsImpl(*Node, std::move(Rule), Result); |
| 248 | + |
| 249 | + return llvm::make_error<llvm::StringError>( |
| 250 | + llvm::errc::invalid_argument, |
| 251 | + "type unsupported for recursive rewriting, ID=\"" + NodeId + |
| 252 | + "\", Kind=" + It->second.getNodeKind().asStringRef()); |
| 253 | + }; |
| 254 | +} |
| 255 | + |
125 | 256 | void transformer::addInclude(RewriteRule &Rule, StringRef Header,
|
126 |
| - IncludeFormat Format) { |
| 257 | + IncludeFormat Format) { |
127 | 258 | for (auto &Case : Rule.Cases)
|
128 | 259 | Case.AddedIncludes.emplace_back(Header.str(), Format);
|
129 | 260 | }
|
|
0 commit comments