xref: /llvm-project/clang/lib/Tooling/Transformer/RewriteRule.cpp (revision 2307029b1a43a86aa6614c33aa198addf82d486b)
1e38c36b7SYitzhak Mandelbaum //===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
2e38c36b7SYitzhak Mandelbaum //
3e38c36b7SYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e38c36b7SYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information.
5e38c36b7SYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e38c36b7SYitzhak Mandelbaum //
7e38c36b7SYitzhak Mandelbaum //===----------------------------------------------------------------------===//
8e38c36b7SYitzhak Mandelbaum 
9e38c36b7SYitzhak Mandelbaum #include "clang/Tooling/Transformer/RewriteRule.h"
10c332a984SYitzhak Mandelbaum #include "clang/AST/ASTTypeTraits.h"
11c332a984SYitzhak Mandelbaum #include "clang/AST/Stmt.h"
12e38c36b7SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchFinder.h"
13e38c36b7SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h"
14e38c36b7SYitzhak Mandelbaum #include "clang/Basic/SourceLocation.h"
15e38c36b7SYitzhak Mandelbaum #include "clang/Tooling/Transformer/SourceCode.h"
16e38c36b7SYitzhak Mandelbaum #include "llvm/ADT/StringRef.h"
17e38c36b7SYitzhak Mandelbaum #include "llvm/Support/Errc.h"
18e38c36b7SYitzhak Mandelbaum #include "llvm/Support/Error.h"
19e38c36b7SYitzhak Mandelbaum #include <map>
20e38c36b7SYitzhak Mandelbaum #include <string>
21e38c36b7SYitzhak Mandelbaum #include <utility>
22e38c36b7SYitzhak Mandelbaum #include <vector>
23e38c36b7SYitzhak Mandelbaum 
24e38c36b7SYitzhak Mandelbaum using namespace clang;
258bb47cd8SYitzhak Mandelbaum using namespace transformer;
26e38c36b7SYitzhak Mandelbaum 
27e38c36b7SYitzhak Mandelbaum using ast_matchers::MatchFinder;
28e38c36b7SYitzhak Mandelbaum using ast_matchers::internal::DynTypedMatcher;
29e38c36b7SYitzhak Mandelbaum 
30e38c36b7SYitzhak Mandelbaum using MatchResult = MatchFinder::MatchResult;
31e38c36b7SYitzhak Mandelbaum 
32645dd1b3SYitzhak Mandelbaum const char transformer::RootID[] = "___root___";
33645dd1b3SYitzhak Mandelbaum 
345e5d3667SYitzhak Mandelbaum static Expected<SmallVector<transformer::Edit, 1>>
translateEdits(const MatchResult & Result,ArrayRef<ASTEdit> ASTEdits)355e5d3667SYitzhak Mandelbaum translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
365e5d3667SYitzhak Mandelbaum   SmallVector<transformer::Edit, 1> Edits;
375e5d3667SYitzhak Mandelbaum   for (const auto &E : ASTEdits) {
385e5d3667SYitzhak Mandelbaum     Expected<CharSourceRange> Range = E.TargetRange(Result);
39e38c36b7SYitzhak Mandelbaum     if (!Range)
40e38c36b7SYitzhak Mandelbaum       return Range.takeError();
41b0de3630SFangrui Song     std::optional<CharSourceRange> EditRange =
42*2307029bSEric Li         tooling::getFileRangeForEdit(*Range, *Result.Context);
43e38c36b7SYitzhak Mandelbaum     // FIXME: let user specify whether to treat this case as an error or ignore
441fabe6e5SYitzhak Mandelbaum     // it as is currently done. This behavior is problematic in that it hides
451fabe6e5SYitzhak Mandelbaum     // failures from bad ranges. Also, the behavior here differs from
461fabe6e5SYitzhak Mandelbaum     // `flatten`. Here, we abort (without error), whereas flatten, if it hits an
471fabe6e5SYitzhak Mandelbaum     // empty list, does not abort. As a result, `editList({A,B})` is not
481fabe6e5SYitzhak Mandelbaum     // equivalent to `flatten(edit(A), edit(B))`. The former will abort if `A`
491fabe6e5SYitzhak Mandelbaum     // produces a bad range, whereas the latter will simply ignore A.
50e38c36b7SYitzhak Mandelbaum     if (!EditRange)
515e5d3667SYitzhak Mandelbaum       return SmallVector<Edit, 0>();
525e5d3667SYitzhak Mandelbaum     transformer::Edit T;
53d8c1f43dSYitzhak Mandelbaum     T.Kind = E.Kind;
54e38c36b7SYitzhak Mandelbaum     T.Range = *EditRange;
555331e122SClement Courbet     if (E.Replacement) {
565331e122SClement Courbet       auto Replacement = E.Replacement->eval(Result);
575331e122SClement Courbet       if (!Replacement)
585331e122SClement Courbet         return Replacement.takeError();
59e38c36b7SYitzhak Mandelbaum       T.Replacement = std::move(*Replacement);
605331e122SClement Courbet     }
61156c0754SClement Courbet     if (E.Note) {
62156c0754SClement Courbet       auto Note = E.Note->eval(Result);
63156c0754SClement Courbet       if (!Note)
64156c0754SClement Courbet         return Note.takeError();
65156c0754SClement Courbet       T.Note = std::move(*Note);
66156c0754SClement Courbet     }
675331e122SClement Courbet     if (E.Metadata) {
685331e122SClement Courbet       auto Metadata = E.Metadata(Result);
695331e122SClement Courbet       if (!Metadata)
705331e122SClement Courbet         return Metadata.takeError();
71e5b3202bSAndy Soffer       T.Metadata = std::move(*Metadata);
725331e122SClement Courbet     }
735e5d3667SYitzhak Mandelbaum     Edits.push_back(std::move(T));
74e38c36b7SYitzhak Mandelbaum   }
755e5d3667SYitzhak Mandelbaum   return Edits;
76e38c36b7SYitzhak Mandelbaum }
77e38c36b7SYitzhak Mandelbaum 
editList(SmallVector<ASTEdit,1> Edits)785e5d3667SYitzhak Mandelbaum EditGenerator transformer::editList(SmallVector<ASTEdit, 1> Edits) {
795e5d3667SYitzhak Mandelbaum   return [Edits = std::move(Edits)](const MatchResult &Result) {
805e5d3667SYitzhak Mandelbaum     return translateEdits(Result, Edits);
815e5d3667SYitzhak Mandelbaum   };
825e5d3667SYitzhak Mandelbaum }
835e5d3667SYitzhak Mandelbaum 
edit(ASTEdit Edit)845e5d3667SYitzhak Mandelbaum EditGenerator transformer::edit(ASTEdit Edit) {
855e5d3667SYitzhak Mandelbaum   return [Edit = std::move(Edit)](const MatchResult &Result) {
865e5d3667SYitzhak Mandelbaum     return translateEdits(Result, {Edit});
875e5d3667SYitzhak Mandelbaum   };
885e5d3667SYitzhak Mandelbaum }
895e5d3667SYitzhak Mandelbaum 
noopEdit(RangeSelector Anchor)906f8f5cb7SYitzhak Mandelbaum EditGenerator transformer::noopEdit(RangeSelector Anchor) {
916f8f5cb7SYitzhak Mandelbaum   return [Anchor = std::move(Anchor)](const MatchResult &Result)
926f8f5cb7SYitzhak Mandelbaum              -> Expected<SmallVector<transformer::Edit, 1>> {
936f8f5cb7SYitzhak Mandelbaum     Expected<CharSourceRange> Range = Anchor(Result);
946f8f5cb7SYitzhak Mandelbaum     if (!Range)
956f8f5cb7SYitzhak Mandelbaum       return Range.takeError();
966f8f5cb7SYitzhak Mandelbaum     // In case the range is inside a macro expansion, map the location back to a
976f8f5cb7SYitzhak Mandelbaum     // "real" source location.
986f8f5cb7SYitzhak Mandelbaum     SourceLocation Begin =
996f8f5cb7SYitzhak Mandelbaum         Result.SourceManager->getSpellingLoc(Range->getBegin());
1006f8f5cb7SYitzhak Mandelbaum     Edit E;
1016f8f5cb7SYitzhak Mandelbaum     // Implicitly, leave `E.Replacement` as the empty string.
1026f8f5cb7SYitzhak Mandelbaum     E.Kind = EditKind::Range;
1036f8f5cb7SYitzhak Mandelbaum     E.Range = CharSourceRange::getCharRange(Begin, Begin);
1046f8f5cb7SYitzhak Mandelbaum     return SmallVector<Edit, 1>{E};
1056f8f5cb7SYitzhak Mandelbaum   };
1066f8f5cb7SYitzhak Mandelbaum }
1076f8f5cb7SYitzhak Mandelbaum 
108cf428778SYitzhak Mandelbaum EditGenerator
flattenVector(SmallVector<EditGenerator,2> Generators)109cf428778SYitzhak Mandelbaum transformer::flattenVector(SmallVector<EditGenerator, 2> Generators) {
110cf428778SYitzhak Mandelbaum   if (Generators.size() == 1)
111cf428778SYitzhak Mandelbaum     return std::move(Generators[0]);
112cf428778SYitzhak Mandelbaum   return
113cf428778SYitzhak Mandelbaum       [Gs = std::move(Generators)](
114cf428778SYitzhak Mandelbaum           const MatchResult &Result) -> llvm::Expected<SmallVector<Edit, 1>> {
115cf428778SYitzhak Mandelbaum         SmallVector<Edit, 1> AllEdits;
116cf428778SYitzhak Mandelbaum         for (const auto &G : Gs) {
117cf428778SYitzhak Mandelbaum           llvm::Expected<SmallVector<Edit, 1>> Edits = G(Result);
118cf428778SYitzhak Mandelbaum           if (!Edits)
119cf428778SYitzhak Mandelbaum             return Edits.takeError();
120cf428778SYitzhak Mandelbaum           AllEdits.append(Edits->begin(), Edits->end());
121cf428778SYitzhak Mandelbaum         }
122cf428778SYitzhak Mandelbaum         return AllEdits;
123cf428778SYitzhak Mandelbaum       };
124cf428778SYitzhak Mandelbaum }
125cf428778SYitzhak Mandelbaum 
changeTo(RangeSelector Target,TextGenerator Replacement)1265e5d3667SYitzhak Mandelbaum ASTEdit transformer::changeTo(RangeSelector Target, TextGenerator Replacement) {
127e38c36b7SYitzhak Mandelbaum   ASTEdit E;
1285e5d3667SYitzhak Mandelbaum   E.TargetRange = std::move(Target);
129e38c36b7SYitzhak Mandelbaum   E.Replacement = std::move(Replacement);
130e38c36b7SYitzhak Mandelbaum   return E;
131e38c36b7SYitzhak Mandelbaum }
132e38c36b7SYitzhak Mandelbaum 
note(RangeSelector Anchor,TextGenerator Note)133156c0754SClement Courbet ASTEdit transformer::note(RangeSelector Anchor, TextGenerator Note) {
134156c0754SClement Courbet   ASTEdit E;
135156c0754SClement Courbet   E.TargetRange = transformer::before(Anchor);
136156c0754SClement Courbet   E.Note = std::move(Note);
137156c0754SClement Courbet   return E;
138156c0754SClement Courbet }
139156c0754SClement Courbet 
140489449c2SYitzhak Mandelbaum namespace {
141489449c2SYitzhak Mandelbaum /// A \c TextGenerator that always returns a fixed string.
142489449c2SYitzhak Mandelbaum class SimpleTextGenerator : public MatchComputation<std::string> {
143489449c2SYitzhak Mandelbaum   std::string S;
144489449c2SYitzhak Mandelbaum 
145489449c2SYitzhak Mandelbaum public:
SimpleTextGenerator(std::string S)146489449c2SYitzhak Mandelbaum   SimpleTextGenerator(std::string S) : S(std::move(S)) {}
eval(const ast_matchers::MatchFinder::MatchResult &,std::string * Result) const147489449c2SYitzhak Mandelbaum   llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
148489449c2SYitzhak Mandelbaum                    std::string *Result) const override {
149489449c2SYitzhak Mandelbaum     Result->append(S);
150489449c2SYitzhak Mandelbaum     return llvm::Error::success();
151489449c2SYitzhak Mandelbaum   }
toString() const152489449c2SYitzhak Mandelbaum   std::string toString() const override {
153489449c2SYitzhak Mandelbaum     return (llvm::Twine("text(\"") + S + "\")").str();
154489449c2SYitzhak Mandelbaum   }
155489449c2SYitzhak Mandelbaum };
156489449c2SYitzhak Mandelbaum } // namespace
157489449c2SYitzhak Mandelbaum 
makeText(std::string S)158d8c1f43dSYitzhak Mandelbaum static TextGenerator makeText(std::string S) {
159d8c1f43dSYitzhak Mandelbaum   return std::make_shared<SimpleTextGenerator>(std::move(S));
160d8c1f43dSYitzhak Mandelbaum }
161d8c1f43dSYitzhak Mandelbaum 
remove(RangeSelector S)162489449c2SYitzhak Mandelbaum ASTEdit transformer::remove(RangeSelector S) {
163d8c1f43dSYitzhak Mandelbaum   return change(std::move(S), makeText(""));
164d8c1f43dSYitzhak Mandelbaum }
165d8c1f43dSYitzhak Mandelbaum 
formatHeaderPath(StringRef Header,IncludeFormat Format)166d8c1f43dSYitzhak Mandelbaum static std::string formatHeaderPath(StringRef Header, IncludeFormat Format) {
167d8c1f43dSYitzhak Mandelbaum   switch (Format) {
168d8c1f43dSYitzhak Mandelbaum   case transformer::IncludeFormat::Quoted:
169d8c1f43dSYitzhak Mandelbaum     return Header.str();
170d8c1f43dSYitzhak Mandelbaum   case transformer::IncludeFormat::Angled:
171d8c1f43dSYitzhak Mandelbaum     return ("<" + Header + ">").str();
172d8c1f43dSYitzhak Mandelbaum   }
173b9aaf32fSSimon Pilgrim   llvm_unreachable("Unknown transformer::IncludeFormat enum");
174d8c1f43dSYitzhak Mandelbaum }
175d8c1f43dSYitzhak Mandelbaum 
addInclude(RangeSelector Target,StringRef Header,IncludeFormat Format)176d8c1f43dSYitzhak Mandelbaum ASTEdit transformer::addInclude(RangeSelector Target, StringRef Header,
177d8c1f43dSYitzhak Mandelbaum                                 IncludeFormat Format) {
178d8c1f43dSYitzhak Mandelbaum   ASTEdit E;
179d8c1f43dSYitzhak Mandelbaum   E.Kind = EditKind::AddInclude;
180d8c1f43dSYitzhak Mandelbaum   E.TargetRange = Target;
181d8c1f43dSYitzhak Mandelbaum   E.Replacement = makeText(formatHeaderPath(Header, Format));
182d8c1f43dSYitzhak Mandelbaum   return E;
183489449c2SYitzhak Mandelbaum }
184489449c2SYitzhak Mandelbaum 
1859edeceaeSEric Li EditGenerator
makeEditGenerator(llvm::SmallVector<ASTEdit,1> Edits)1869edeceaeSEric Li transformer::detail::makeEditGenerator(llvm::SmallVector<ASTEdit, 1> Edits) {
1879edeceaeSEric Li   return editList(std::move(Edits));
1889edeceaeSEric Li }
1899edeceaeSEric Li 
makeEditGenerator(ASTEdit Edit)1909edeceaeSEric Li EditGenerator transformer::detail::makeEditGenerator(ASTEdit Edit) {
1919edeceaeSEric Li   return edit(std::move(Edit));
1929edeceaeSEric Li }
1939edeceaeSEric Li 
makeRule(DynTypedMatcher M,EditGenerator Edits)1949edeceaeSEric Li RewriteRule transformer::detail::makeRule(DynTypedMatcher M,
1959edeceaeSEric Li                                           EditGenerator Edits) {
1969edeceaeSEric Li   RewriteRule R;
1979edeceaeSEric Li   R.Cases = {{std::move(M), std::move(Edits)}};
1989edeceaeSEric Li   return R;
1999edeceaeSEric Li }
2009edeceaeSEric Li 
makeRule(ast_matchers::internal::DynTypedMatcher M,std::initializer_list<ASTEdit> Edits)2019edeceaeSEric Li RewriteRule transformer::makeRule(ast_matchers::internal::DynTypedMatcher M,
2029edeceaeSEric Li                                   std::initializer_list<ASTEdit> Edits) {
2039edeceaeSEric Li   return detail::makeRule(std::move(M),
2049edeceaeSEric Li                           detail::makeEditGenerator(std::move(Edits)));
205e38c36b7SYitzhak Mandelbaum }
206e38c36b7SYitzhak Mandelbaum 
207c332a984SYitzhak Mandelbaum namespace {
208c332a984SYitzhak Mandelbaum 
209c332a984SYitzhak Mandelbaum /// Unconditionally binds the given node set before trying `InnerMatcher` and
210c332a984SYitzhak Mandelbaum /// keeps the bound nodes on a successful match.
211c332a984SYitzhak Mandelbaum template <typename T>
212c332a984SYitzhak Mandelbaum class BindingsMatcher : public ast_matchers::internal::MatcherInterface<T> {
213c332a984SYitzhak Mandelbaum   ast_matchers::BoundNodes Nodes;
214c332a984SYitzhak Mandelbaum   const ast_matchers::internal::Matcher<T> InnerMatcher;
215c332a984SYitzhak Mandelbaum 
216c332a984SYitzhak Mandelbaum public:
BindingsMatcher(ast_matchers::BoundNodes Nodes,ast_matchers::internal::Matcher<T> InnerMatcher)217c332a984SYitzhak Mandelbaum   explicit BindingsMatcher(ast_matchers::BoundNodes Nodes,
218c332a984SYitzhak Mandelbaum                            ast_matchers::internal::Matcher<T> InnerMatcher)
219c332a984SYitzhak Mandelbaum       : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}
220c332a984SYitzhak Mandelbaum 
matches(const T & Node,ast_matchers::internal::ASTMatchFinder * Finder,ast_matchers::internal::BoundNodesTreeBuilder * Builder) const221c332a984SYitzhak Mandelbaum   bool matches(
222c332a984SYitzhak Mandelbaum       const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,
223c332a984SYitzhak Mandelbaum       ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
224c332a984SYitzhak Mandelbaum     ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
225c332a984SYitzhak Mandelbaum     for (const auto &N : Nodes.getMap())
226c332a984SYitzhak Mandelbaum       Result.setBinding(N.first, N.second);
227c332a984SYitzhak Mandelbaum     if (InnerMatcher.matches(Node, Finder, &Result)) {
228c332a984SYitzhak Mandelbaum       *Builder = std::move(Result);
229c332a984SYitzhak Mandelbaum       return true;
230c332a984SYitzhak Mandelbaum     }
231c332a984SYitzhak Mandelbaum     return false;
232c332a984SYitzhak Mandelbaum   }
233c332a984SYitzhak Mandelbaum };
234c332a984SYitzhak Mandelbaum 
235c332a984SYitzhak Mandelbaum /// Matches nodes of type T that have at least one descendant node for which the
236c332a984SYitzhak Mandelbaum /// given inner matcher matches.  Will match for each descendant node that
237c332a984SYitzhak Mandelbaum /// matches.  Based on ForEachDescendantMatcher, but takes a dynamic matcher,
238c332a984SYitzhak Mandelbaum /// instead of a static one, because it is used by RewriteRule, which carries
239c332a984SYitzhak Mandelbaum /// (only top-level) dynamic matchers.
240c332a984SYitzhak Mandelbaum template <typename T>
241c332a984SYitzhak Mandelbaum class DynamicForEachDescendantMatcher
242c332a984SYitzhak Mandelbaum     : public ast_matchers::internal::MatcherInterface<T> {
243c332a984SYitzhak Mandelbaum   const DynTypedMatcher DescendantMatcher;
244c332a984SYitzhak Mandelbaum 
245c332a984SYitzhak Mandelbaum public:
DynamicForEachDescendantMatcher(DynTypedMatcher DescendantMatcher)246c332a984SYitzhak Mandelbaum   explicit DynamicForEachDescendantMatcher(DynTypedMatcher DescendantMatcher)
247c332a984SYitzhak Mandelbaum       : DescendantMatcher(std::move(DescendantMatcher)) {}
248c332a984SYitzhak Mandelbaum 
matches(const T & Node,ast_matchers::internal::ASTMatchFinder * Finder,ast_matchers::internal::BoundNodesTreeBuilder * Builder) const249c332a984SYitzhak Mandelbaum   bool matches(
250c332a984SYitzhak Mandelbaum       const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,
251c332a984SYitzhak Mandelbaum       ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
252c332a984SYitzhak Mandelbaum     return Finder->matchesDescendantOf(
253c332a984SYitzhak Mandelbaum         Node, this->DescendantMatcher, Builder,
254c332a984SYitzhak Mandelbaum         ast_matchers::internal::ASTMatchFinder::BK_All);
255c332a984SYitzhak Mandelbaum   }
256c332a984SYitzhak Mandelbaum };
257c332a984SYitzhak Mandelbaum 
258c332a984SYitzhak Mandelbaum template <typename T>
259c332a984SYitzhak Mandelbaum ast_matchers::internal::Matcher<T>
forEachDescendantDynamically(ast_matchers::BoundNodes Nodes,DynTypedMatcher M)260c332a984SYitzhak Mandelbaum forEachDescendantDynamically(ast_matchers::BoundNodes Nodes,
261c332a984SYitzhak Mandelbaum                              DynTypedMatcher M) {
262c332a984SYitzhak Mandelbaum   return ast_matchers::internal::makeMatcher(new BindingsMatcher<T>(
263c332a984SYitzhak Mandelbaum       std::move(Nodes),
264c332a984SYitzhak Mandelbaum       ast_matchers::internal::makeMatcher(
265c332a984SYitzhak Mandelbaum           new DynamicForEachDescendantMatcher<T>(std::move(M)))));
266c332a984SYitzhak Mandelbaum }
267c332a984SYitzhak Mandelbaum 
268c332a984SYitzhak Mandelbaum class ApplyRuleCallback : public MatchFinder::MatchCallback {
269c332a984SYitzhak Mandelbaum public:
ApplyRuleCallback(RewriteRule Rule)270c332a984SYitzhak Mandelbaum   ApplyRuleCallback(RewriteRule Rule) : Rule(std::move(Rule)) {}
271c332a984SYitzhak Mandelbaum 
272c332a984SYitzhak Mandelbaum   template <typename T>
registerMatchers(const ast_matchers::BoundNodes & Nodes,MatchFinder * MF)273c332a984SYitzhak Mandelbaum   void registerMatchers(const ast_matchers::BoundNodes &Nodes,
274c332a984SYitzhak Mandelbaum                         MatchFinder *MF) {
275c332a984SYitzhak Mandelbaum     for (auto &Matcher : transformer::detail::buildMatchers(Rule))
276c332a984SYitzhak Mandelbaum       MF->addMatcher(forEachDescendantDynamically<T>(Nodes, Matcher), this);
277c332a984SYitzhak Mandelbaum   }
278c332a984SYitzhak Mandelbaum 
run(const MatchFinder::MatchResult & Result)279c332a984SYitzhak Mandelbaum   void run(const MatchFinder::MatchResult &Result) override {
280c332a984SYitzhak Mandelbaum     if (!Edits)
281c332a984SYitzhak Mandelbaum       return;
2829edeceaeSEric Li     size_t I = transformer::detail::findSelectedCase(Result, Rule);
2839edeceaeSEric Li     auto Transformations = Rule.Cases[I].Edits(Result);
284c332a984SYitzhak Mandelbaum     if (!Transformations) {
285c332a984SYitzhak Mandelbaum       Edits = Transformations.takeError();
286c332a984SYitzhak Mandelbaum       return;
287c332a984SYitzhak Mandelbaum     }
288c332a984SYitzhak Mandelbaum     Edits->append(Transformations->begin(), Transformations->end());
289c332a984SYitzhak Mandelbaum   }
290c332a984SYitzhak Mandelbaum 
291c332a984SYitzhak Mandelbaum   RewriteRule Rule;
292c332a984SYitzhak Mandelbaum 
293c332a984SYitzhak Mandelbaum   // Initialize to a non-error state.
294c332a984SYitzhak Mandelbaum   Expected<SmallVector<Edit, 1>> Edits = SmallVector<Edit, 1>();
295c332a984SYitzhak Mandelbaum };
296c332a984SYitzhak Mandelbaum } // namespace
297c332a984SYitzhak Mandelbaum 
298c332a984SYitzhak Mandelbaum template <typename T>
299d4f39031SYitzhak Mandelbaum llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
rewriteDescendantsImpl(const T & Node,RewriteRule Rule,const MatchResult & Result)300c332a984SYitzhak Mandelbaum rewriteDescendantsImpl(const T &Node, RewriteRule Rule,
301c332a984SYitzhak Mandelbaum                        const MatchResult &Result) {
302c332a984SYitzhak Mandelbaum   ApplyRuleCallback Callback(std::move(Rule));
303c332a984SYitzhak Mandelbaum   MatchFinder Finder;
304c332a984SYitzhak Mandelbaum   Callback.registerMatchers<T>(Result.Nodes, &Finder);
305c332a984SYitzhak Mandelbaum   Finder.match(Node, *Result.Context);
306c332a984SYitzhak Mandelbaum   return std::move(Callback.Edits);
307c332a984SYitzhak Mandelbaum }
308c332a984SYitzhak Mandelbaum 
309d4f39031SYitzhak Mandelbaum llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
rewriteDescendants(const Decl & Node,RewriteRule Rule,const MatchResult & Result)310d4f39031SYitzhak Mandelbaum transformer::detail::rewriteDescendants(const Decl &Node, RewriteRule Rule,
311d4f39031SYitzhak Mandelbaum                                         const MatchResult &Result) {
312d4f39031SYitzhak Mandelbaum   return rewriteDescendantsImpl(Node, std::move(Rule), Result);
313d4f39031SYitzhak Mandelbaum }
314d4f39031SYitzhak Mandelbaum 
315d4f39031SYitzhak Mandelbaum llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
rewriteDescendants(const Stmt & Node,RewriteRule Rule,const MatchResult & Result)316d4f39031SYitzhak Mandelbaum transformer::detail::rewriteDescendants(const Stmt &Node, RewriteRule Rule,
317d4f39031SYitzhak Mandelbaum                                         const MatchResult &Result) {
318d4f39031SYitzhak Mandelbaum   return rewriteDescendantsImpl(Node, std::move(Rule), Result);
319d4f39031SYitzhak Mandelbaum }
320d4f39031SYitzhak Mandelbaum 
321d4f39031SYitzhak Mandelbaum llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
rewriteDescendants(const TypeLoc & Node,RewriteRule Rule,const MatchResult & Result)322d4f39031SYitzhak Mandelbaum transformer::detail::rewriteDescendants(const TypeLoc &Node, RewriteRule Rule,
323d4f39031SYitzhak Mandelbaum                                         const MatchResult &Result) {
324d4f39031SYitzhak Mandelbaum   return rewriteDescendantsImpl(Node, std::move(Rule), Result);
325d4f39031SYitzhak Mandelbaum }
326d4f39031SYitzhak Mandelbaum 
327d4f39031SYitzhak Mandelbaum llvm::Expected<SmallVector<clang::transformer::Edit, 1>>
rewriteDescendants(const DynTypedNode & DNode,RewriteRule Rule,const MatchResult & Result)328d4f39031SYitzhak Mandelbaum transformer::detail::rewriteDescendants(const DynTypedNode &DNode,
329d4f39031SYitzhak Mandelbaum                                         RewriteRule Rule,
330d4f39031SYitzhak Mandelbaum                                         const MatchResult &Result) {
331d4f39031SYitzhak Mandelbaum   if (const auto *Node = DNode.get<Decl>())
332d4f39031SYitzhak Mandelbaum     return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
333d4f39031SYitzhak Mandelbaum   if (const auto *Node = DNode.get<Stmt>())
334d4f39031SYitzhak Mandelbaum     return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
335d4f39031SYitzhak Mandelbaum   if (const auto *Node = DNode.get<TypeLoc>())
336d4f39031SYitzhak Mandelbaum     return rewriteDescendantsImpl(*Node, std::move(Rule), Result);
337d4f39031SYitzhak Mandelbaum 
338d4f39031SYitzhak Mandelbaum   return llvm::make_error<llvm::StringError>(
339d4f39031SYitzhak Mandelbaum       llvm::errc::invalid_argument,
340d4f39031SYitzhak Mandelbaum       "type unsupported for recursive rewriting, Kind=" +
341d4f39031SYitzhak Mandelbaum           DNode.getNodeKind().asStringRef());
342d4f39031SYitzhak Mandelbaum }
343d4f39031SYitzhak Mandelbaum 
rewriteDescendants(std::string NodeId,RewriteRule Rule)344c332a984SYitzhak Mandelbaum EditGenerator transformer::rewriteDescendants(std::string NodeId,
345c332a984SYitzhak Mandelbaum                                               RewriteRule Rule) {
346c332a984SYitzhak Mandelbaum   return [NodeId = std::move(NodeId),
347c332a984SYitzhak Mandelbaum           Rule = std::move(Rule)](const MatchResult &Result)
348c332a984SYitzhak Mandelbaum              -> llvm::Expected<SmallVector<clang::transformer::Edit, 1>> {
349c332a984SYitzhak Mandelbaum     const ast_matchers::BoundNodes::IDToNodeMap &NodesMap =
350c332a984SYitzhak Mandelbaum         Result.Nodes.getMap();
351c332a984SYitzhak Mandelbaum     auto It = NodesMap.find(NodeId);
352c332a984SYitzhak Mandelbaum     if (It == NodesMap.end())
353c332a984SYitzhak Mandelbaum       return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
354c332a984SYitzhak Mandelbaum                                                  "ID not bound: " + NodeId);
355d4f39031SYitzhak Mandelbaum     return detail::rewriteDescendants(It->second, std::move(Rule), Result);
356c332a984SYitzhak Mandelbaum   };
357c332a984SYitzhak Mandelbaum }
358c332a984SYitzhak Mandelbaum 
addInclude(RewriteRuleBase & Rule,StringRef Header,IncludeFormat Format)3599edeceaeSEric Li void transformer::addInclude(RewriteRuleBase &Rule, StringRef Header,
360e38c36b7SYitzhak Mandelbaum                              IncludeFormat Format) {
361e38c36b7SYitzhak Mandelbaum   for (auto &Case : Rule.Cases)
362d8c1f43dSYitzhak Mandelbaum     Case.Edits = flatten(std::move(Case.Edits), addInclude(Header, Format));
363e38c36b7SYitzhak Mandelbaum }
364e38c36b7SYitzhak Mandelbaum 
365e38c36b7SYitzhak Mandelbaum #ifndef NDEBUG
366e38c36b7SYitzhak Mandelbaum // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
367e38c36b7SYitzhak Mandelbaum // (all node matcher types except for `QualType` and `Type`), rather than just
368e38c36b7SYitzhak Mandelbaum // banning `QualType` and `Type`.
hasValidKind(const DynTypedMatcher & M)369e38c36b7SYitzhak Mandelbaum static bool hasValidKind(const DynTypedMatcher &M) {
370e38c36b7SYitzhak Mandelbaum   return !M.canConvertTo<QualType>();
371e38c36b7SYitzhak Mandelbaum }
372e38c36b7SYitzhak Mandelbaum #endif
373e38c36b7SYitzhak Mandelbaum 
374e38c36b7SYitzhak Mandelbaum // Binds each rule's matcher to a unique (and deterministic) tag based on
375ce5780b8SYitzhak Mandelbaum // `TagBase` and the id paired with the case. All of the returned matchers have
376ce5780b8SYitzhak Mandelbaum // their traversal kind explicitly set, either based on a pre-set kind or to the
377ce5780b8SYitzhak Mandelbaum // provided `DefaultTraversalKind`.
taggedMatchers(StringRef TagBase,const SmallVectorImpl<std::pair<size_t,RewriteRule::Case>> & Cases,TraversalKind DefaultTraversalKind)378e38c36b7SYitzhak Mandelbaum static std::vector<DynTypedMatcher> taggedMatchers(
379e38c36b7SYitzhak Mandelbaum     StringRef TagBase,
380ce5780b8SYitzhak Mandelbaum     const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases,
381027899daSAlexander Kornienko     TraversalKind DefaultTraversalKind) {
382e38c36b7SYitzhak Mandelbaum   std::vector<DynTypedMatcher> Matchers;
383e38c36b7SYitzhak Mandelbaum   Matchers.reserve(Cases.size());
384e38c36b7SYitzhak Mandelbaum   for (const auto &Case : Cases) {
385e38c36b7SYitzhak Mandelbaum     std::string Tag = (TagBase + Twine(Case.first)).str();
386e38c36b7SYitzhak Mandelbaum     // HACK: Many matchers are not bindable, so ensure that tryBind will work.
387e38c36b7SYitzhak Mandelbaum     DynTypedMatcher BoundMatcher(Case.second.Matcher);
388e38c36b7SYitzhak Mandelbaum     BoundMatcher.setAllowBind(true);
389ce5780b8SYitzhak Mandelbaum     auto M = *BoundMatcher.tryBind(Tag);
390ce5780b8SYitzhak Mandelbaum     Matchers.push_back(!M.getTraversalKind()
391ce5780b8SYitzhak Mandelbaum                            ? M.withTraversalKind(DefaultTraversalKind)
392ce5780b8SYitzhak Mandelbaum                            : std::move(M));
393e38c36b7SYitzhak Mandelbaum   }
394e38c36b7SYitzhak Mandelbaum   return Matchers;
395e38c36b7SYitzhak Mandelbaum }
396e38c36b7SYitzhak Mandelbaum 
397e38c36b7SYitzhak Mandelbaum // Simply gathers the contents of the various rules into a single rule. The
398e38c36b7SYitzhak Mandelbaum // actual work to combine these into an ordered choice is deferred to matcher
399e38c36b7SYitzhak Mandelbaum // registration.
4009edeceaeSEric Li template <>
4019edeceaeSEric Li RewriteRuleWith<void>
applyFirst(ArrayRef<RewriteRuleWith<void>> Rules)4029edeceaeSEric Li transformer::applyFirst(ArrayRef<RewriteRuleWith<void>> Rules) {
403e38c36b7SYitzhak Mandelbaum   RewriteRule R;
404e38c36b7SYitzhak Mandelbaum   for (auto &Rule : Rules)
405e38c36b7SYitzhak Mandelbaum     R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
406e38c36b7SYitzhak Mandelbaum   return R;
407e38c36b7SYitzhak Mandelbaum }
408e38c36b7SYitzhak Mandelbaum 
409e38c36b7SYitzhak Mandelbaum std::vector<DynTypedMatcher>
buildMatchers(const RewriteRuleBase & Rule)4109edeceaeSEric Li transformer::detail::buildMatchers(const RewriteRuleBase &Rule) {
411e38c36b7SYitzhak Mandelbaum   // Map the cases into buckets of matchers -- one for each "root" AST kind,
412e38c36b7SYitzhak Mandelbaum   // which guarantees that they can be combined in a single anyOf matcher. Each
413e38c36b7SYitzhak Mandelbaum   // case is paired with an identifying number that is converted to a string id
414e38c36b7SYitzhak Mandelbaum   // in `taggedMatchers`.
4159edeceaeSEric Li   std::map<ASTNodeKind,
4169edeceaeSEric Li            SmallVector<std::pair<size_t, RewriteRuleBase::Case>, 1>>
417e38c36b7SYitzhak Mandelbaum       Buckets;
418e38c36b7SYitzhak Mandelbaum   const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
419e38c36b7SYitzhak Mandelbaum   for (int I = 0, N = Cases.size(); I < N; ++I) {
420e38c36b7SYitzhak Mandelbaum     assert(hasValidKind(Cases[I].Matcher) &&
421e38c36b7SYitzhak Mandelbaum            "Matcher must be non-(Qual)Type node matcher");
422e38c36b7SYitzhak Mandelbaum     Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
423e38c36b7SYitzhak Mandelbaum   }
424e38c36b7SYitzhak Mandelbaum 
425ce5780b8SYitzhak Mandelbaum   // Each anyOf explicitly controls the traversal kind. The anyOf itself is set
426ce5780b8SYitzhak Mandelbaum   // to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to the kind
427ce5780b8SYitzhak Mandelbaum   // of the branches. Then, each branch is either left as is, if the kind is
4286f0a3711SYitzhak Mandelbaum   // already set, or explicitly set to `TK_AsIs`. We choose this setting because
4296f0a3711SYitzhak Mandelbaum   // it is the default interpretation of matchers.
430e38c36b7SYitzhak Mandelbaum   std::vector<DynTypedMatcher> Matchers;
431e38c36b7SYitzhak Mandelbaum   for (const auto &Bucket : Buckets) {
432e38c36b7SYitzhak Mandelbaum     DynTypedMatcher M = DynTypedMatcher::constructVariadic(
433e38c36b7SYitzhak Mandelbaum         DynTypedMatcher::VO_AnyOf, Bucket.first,
4346f0a3711SYitzhak Mandelbaum         taggedMatchers("Tag", Bucket.second, TK_AsIs));
435e38c36b7SYitzhak Mandelbaum     M.setAllowBind(true);
436e38c36b7SYitzhak Mandelbaum     // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
437645dd1b3SYitzhak Mandelbaum     Matchers.push_back(M.tryBind(RootID)->withTraversalKind(TK_AsIs));
438e38c36b7SYitzhak Mandelbaum   }
439e38c36b7SYitzhak Mandelbaum   return Matchers;
440e38c36b7SYitzhak Mandelbaum }
441e38c36b7SYitzhak Mandelbaum 
buildMatcher(const RewriteRuleBase & Rule)4429edeceaeSEric Li DynTypedMatcher transformer::detail::buildMatcher(const RewriteRuleBase &Rule) {
443e38c36b7SYitzhak Mandelbaum   std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
444e38c36b7SYitzhak Mandelbaum   assert(Ms.size() == 1 && "Cases must have compatible matchers.");
445e38c36b7SYitzhak Mandelbaum   return Ms[0];
446e38c36b7SYitzhak Mandelbaum }
447e38c36b7SYitzhak Mandelbaum 
getRuleMatchLoc(const MatchResult & Result)4488bb47cd8SYitzhak Mandelbaum SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
449e38c36b7SYitzhak Mandelbaum   auto &NodesMap = Result.Nodes.getMap();
450645dd1b3SYitzhak Mandelbaum   auto Root = NodesMap.find(RootID);
451e38c36b7SYitzhak Mandelbaum   assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
452*2307029bSEric Li   std::optional<CharSourceRange> RootRange = tooling::getFileRangeForEdit(
453e38c36b7SYitzhak Mandelbaum       CharSourceRange::getTokenRange(Root->second.getSourceRange()),
454e38c36b7SYitzhak Mandelbaum       *Result.Context);
455e38c36b7SYitzhak Mandelbaum   if (RootRange)
456e38c36b7SYitzhak Mandelbaum     return RootRange->getBegin();
457e38c36b7SYitzhak Mandelbaum   // The match doesn't have a coherent range, so fall back to the expansion
458e38c36b7SYitzhak Mandelbaum   // location as the "beginning" of the match.
459e38c36b7SYitzhak Mandelbaum   return Result.SourceManager->getExpansionLoc(
460e38c36b7SYitzhak Mandelbaum       Root->second.getSourceRange().getBegin());
461e38c36b7SYitzhak Mandelbaum }
462e38c36b7SYitzhak Mandelbaum 
463e38c36b7SYitzhak Mandelbaum // Finds the case that was "selected" -- that is, whose matcher triggered the
464e38c36b7SYitzhak Mandelbaum // `MatchResult`.
findSelectedCase(const MatchResult & Result,const RewriteRuleBase & Rule)4659edeceaeSEric Li size_t transformer::detail::findSelectedCase(const MatchResult &Result,
4669edeceaeSEric Li                                              const RewriteRuleBase &Rule) {
467e38c36b7SYitzhak Mandelbaum   if (Rule.Cases.size() == 1)
4689edeceaeSEric Li     return 0;
469e38c36b7SYitzhak Mandelbaum 
470e38c36b7SYitzhak Mandelbaum   auto &NodesMap = Result.Nodes.getMap();
471e38c36b7SYitzhak Mandelbaum   for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
472e38c36b7SYitzhak Mandelbaum     std::string Tag = ("Tag" + Twine(i)).str();
473e38c36b7SYitzhak Mandelbaum     if (NodesMap.find(Tag) != NodesMap.end())
4749edeceaeSEric Li       return i;
475e38c36b7SYitzhak Mandelbaum   }
476e38c36b7SYitzhak Mandelbaum   llvm_unreachable("No tag found for this rule.");
477e38c36b7SYitzhak Mandelbaum }
478