xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/Transformer/RewriteRule.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1a7dea167SDimitry Andric //===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "clang/Tooling/Transformer/RewriteRule.h"
10a7dea167SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
11a7dea167SDimitry Andric #include "clang/ASTMatchers/ASTMatchers.h"
12a7dea167SDimitry Andric #include "clang/Basic/SourceLocation.h"
13a7dea167SDimitry Andric #include "clang/Tooling/Transformer/SourceCode.h"
14a7dea167SDimitry Andric #include "llvm/ADT/Optional.h"
15a7dea167SDimitry Andric #include "llvm/ADT/StringRef.h"
16a7dea167SDimitry Andric #include "llvm/Support/Errc.h"
17a7dea167SDimitry Andric #include "llvm/Support/Error.h"
18a7dea167SDimitry Andric #include <map>
19a7dea167SDimitry Andric #include <string>
20a7dea167SDimitry Andric #include <utility>
21a7dea167SDimitry Andric #include <vector>
22a7dea167SDimitry Andric 
23a7dea167SDimitry Andric using namespace clang;
24a7dea167SDimitry Andric using namespace transformer;
25a7dea167SDimitry Andric 
26a7dea167SDimitry Andric using ast_matchers::MatchFinder;
27a7dea167SDimitry Andric using ast_matchers::internal::DynTypedMatcher;
28a7dea167SDimitry Andric 
29a7dea167SDimitry Andric using MatchResult = MatchFinder::MatchResult;
30a7dea167SDimitry Andric 
31*5ffd83dbSDimitry Andric static Expected<SmallVector<transformer::Edit, 1>>
32*5ffd83dbSDimitry Andric translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
33*5ffd83dbSDimitry Andric   SmallVector<transformer::Edit, 1> Edits;
34*5ffd83dbSDimitry Andric   for (const auto &E : ASTEdits) {
35*5ffd83dbSDimitry Andric     Expected<CharSourceRange> Range = E.TargetRange(Result);
36a7dea167SDimitry Andric     if (!Range)
37a7dea167SDimitry Andric       return Range.takeError();
38a7dea167SDimitry Andric     llvm::Optional<CharSourceRange> EditRange =
39a7dea167SDimitry Andric         tooling::getRangeForEdit(*Range, *Result.Context);
40a7dea167SDimitry Andric     // FIXME: let user specify whether to treat this case as an error or ignore
41a7dea167SDimitry Andric     // it as is currently done.
42a7dea167SDimitry Andric     if (!EditRange)
43*5ffd83dbSDimitry Andric       return SmallVector<Edit, 0>();
44*5ffd83dbSDimitry Andric     auto Replacement = E.Replacement->eval(Result);
45a7dea167SDimitry Andric     if (!Replacement)
46a7dea167SDimitry Andric       return Replacement.takeError();
47*5ffd83dbSDimitry Andric     transformer::Edit T;
48a7dea167SDimitry Andric     T.Range = *EditRange;
49a7dea167SDimitry Andric     T.Replacement = std::move(*Replacement);
50*5ffd83dbSDimitry Andric     T.Metadata = E.Metadata;
51*5ffd83dbSDimitry Andric     Edits.push_back(std::move(T));
52a7dea167SDimitry Andric   }
53*5ffd83dbSDimitry Andric   return Edits;
54a7dea167SDimitry Andric }
55a7dea167SDimitry Andric 
56*5ffd83dbSDimitry Andric EditGenerator transformer::editList(SmallVector<ASTEdit, 1> Edits) {
57*5ffd83dbSDimitry Andric   return [Edits = std::move(Edits)](const MatchResult &Result) {
58*5ffd83dbSDimitry Andric     return translateEdits(Result, Edits);
59*5ffd83dbSDimitry Andric   };
60*5ffd83dbSDimitry Andric }
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric EditGenerator transformer::edit(ASTEdit Edit) {
63*5ffd83dbSDimitry Andric   return [Edit = std::move(Edit)](const MatchResult &Result) {
64*5ffd83dbSDimitry Andric     return translateEdits(Result, {Edit});
65*5ffd83dbSDimitry Andric   };
66*5ffd83dbSDimitry Andric }
67*5ffd83dbSDimitry Andric 
68*5ffd83dbSDimitry Andric ASTEdit transformer::changeTo(RangeSelector Target, TextGenerator Replacement) {
69a7dea167SDimitry Andric   ASTEdit E;
70*5ffd83dbSDimitry Andric   E.TargetRange = std::move(Target);
71a7dea167SDimitry Andric   E.Replacement = std::move(Replacement);
72a7dea167SDimitry Andric   return E;
73a7dea167SDimitry Andric }
74a7dea167SDimitry Andric 
75480093f4SDimitry Andric namespace {
76480093f4SDimitry Andric /// A \c TextGenerator that always returns a fixed string.
77480093f4SDimitry Andric class SimpleTextGenerator : public MatchComputation<std::string> {
78480093f4SDimitry Andric   std::string S;
79480093f4SDimitry Andric 
80480093f4SDimitry Andric public:
81480093f4SDimitry Andric   SimpleTextGenerator(std::string S) : S(std::move(S)) {}
82480093f4SDimitry Andric   llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
83480093f4SDimitry Andric                    std::string *Result) const override {
84480093f4SDimitry Andric     Result->append(S);
85480093f4SDimitry Andric     return llvm::Error::success();
86480093f4SDimitry Andric   }
87480093f4SDimitry Andric   std::string toString() const override {
88480093f4SDimitry Andric     return (llvm::Twine("text(\"") + S + "\")").str();
89480093f4SDimitry Andric   }
90480093f4SDimitry Andric };
91480093f4SDimitry Andric } // namespace
92480093f4SDimitry Andric 
93480093f4SDimitry Andric ASTEdit transformer::remove(RangeSelector S) {
94480093f4SDimitry Andric   return change(std::move(S), std::make_shared<SimpleTextGenerator>(""));
95480093f4SDimitry Andric }
96480093f4SDimitry Andric 
97*5ffd83dbSDimitry Andric RewriteRule transformer::makeRule(ast_matchers::internal::DynTypedMatcher M,
98*5ffd83dbSDimitry Andric                                   EditGenerator Edits,
99a7dea167SDimitry Andric                                   TextGenerator Explanation) {
100a7dea167SDimitry Andric   return RewriteRule{{RewriteRule::Case{
101a7dea167SDimitry Andric       std::move(M), std::move(Edits), std::move(Explanation), {}}}};
102a7dea167SDimitry Andric }
103a7dea167SDimitry Andric 
104a7dea167SDimitry Andric void transformer::addInclude(RewriteRule &Rule, StringRef Header,
105a7dea167SDimitry Andric                          IncludeFormat Format) {
106a7dea167SDimitry Andric   for (auto &Case : Rule.Cases)
107a7dea167SDimitry Andric     Case.AddedIncludes.emplace_back(Header.str(), Format);
108a7dea167SDimitry Andric }
109a7dea167SDimitry Andric 
110a7dea167SDimitry Andric #ifndef NDEBUG
111a7dea167SDimitry Andric // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
112a7dea167SDimitry Andric // (all node matcher types except for `QualType` and `Type`), rather than just
113a7dea167SDimitry Andric // banning `QualType` and `Type`.
114a7dea167SDimitry Andric static bool hasValidKind(const DynTypedMatcher &M) {
115a7dea167SDimitry Andric   return !M.canConvertTo<QualType>();
116a7dea167SDimitry Andric }
117a7dea167SDimitry Andric #endif
118a7dea167SDimitry Andric 
119a7dea167SDimitry Andric // Binds each rule's matcher to a unique (and deterministic) tag based on
120*5ffd83dbSDimitry Andric // `TagBase` and the id paired with the case. All of the returned matchers have
121*5ffd83dbSDimitry Andric // their traversal kind explicitly set, either based on a pre-set kind or to the
122*5ffd83dbSDimitry Andric // provided `DefaultTraversalKind`.
123a7dea167SDimitry Andric static std::vector<DynTypedMatcher> taggedMatchers(
124a7dea167SDimitry Andric     StringRef TagBase,
125*5ffd83dbSDimitry Andric     const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases,
126*5ffd83dbSDimitry Andric     ast_type_traits::TraversalKind DefaultTraversalKind) {
127a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Matchers;
128a7dea167SDimitry Andric   Matchers.reserve(Cases.size());
129a7dea167SDimitry Andric   for (const auto &Case : Cases) {
130a7dea167SDimitry Andric     std::string Tag = (TagBase + Twine(Case.first)).str();
131a7dea167SDimitry Andric     // HACK: Many matchers are not bindable, so ensure that tryBind will work.
132a7dea167SDimitry Andric     DynTypedMatcher BoundMatcher(Case.second.Matcher);
133a7dea167SDimitry Andric     BoundMatcher.setAllowBind(true);
134*5ffd83dbSDimitry Andric     auto M = *BoundMatcher.tryBind(Tag);
135*5ffd83dbSDimitry Andric     Matchers.push_back(!M.getTraversalKind()
136*5ffd83dbSDimitry Andric                            ? M.withTraversalKind(DefaultTraversalKind)
137*5ffd83dbSDimitry Andric                            : std::move(M));
138a7dea167SDimitry Andric   }
139a7dea167SDimitry Andric   return Matchers;
140a7dea167SDimitry Andric }
141a7dea167SDimitry Andric 
142a7dea167SDimitry Andric // Simply gathers the contents of the various rules into a single rule. The
143a7dea167SDimitry Andric // actual work to combine these into an ordered choice is deferred to matcher
144a7dea167SDimitry Andric // registration.
145a7dea167SDimitry Andric RewriteRule transformer::applyFirst(ArrayRef<RewriteRule> Rules) {
146a7dea167SDimitry Andric   RewriteRule R;
147a7dea167SDimitry Andric   for (auto &Rule : Rules)
148a7dea167SDimitry Andric     R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
149a7dea167SDimitry Andric   return R;
150a7dea167SDimitry Andric }
151a7dea167SDimitry Andric 
152a7dea167SDimitry Andric std::vector<DynTypedMatcher>
153a7dea167SDimitry Andric transformer::detail::buildMatchers(const RewriteRule &Rule) {
154a7dea167SDimitry Andric   // Map the cases into buckets of matchers -- one for each "root" AST kind,
155a7dea167SDimitry Andric   // which guarantees that they can be combined in a single anyOf matcher. Each
156a7dea167SDimitry Andric   // case is paired with an identifying number that is converted to a string id
157a7dea167SDimitry Andric   // in `taggedMatchers`.
158a7dea167SDimitry Andric   std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
159a7dea167SDimitry Andric       Buckets;
160a7dea167SDimitry Andric   const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
161a7dea167SDimitry Andric   for (int I = 0, N = Cases.size(); I < N; ++I) {
162a7dea167SDimitry Andric     assert(hasValidKind(Cases[I].Matcher) &&
163a7dea167SDimitry Andric            "Matcher must be non-(Qual)Type node matcher");
164a7dea167SDimitry Andric     Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
165a7dea167SDimitry Andric   }
166a7dea167SDimitry Andric 
167*5ffd83dbSDimitry Andric   // Each anyOf explicitly controls the traversal kind. The anyOf itself is set
168*5ffd83dbSDimitry Andric   // to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to the kind
169*5ffd83dbSDimitry Andric   // of the branches. Then, each branch is either left as is, if the kind is
170*5ffd83dbSDimitry Andric   // already set, or explicitly set to `TK_IgnoreUnlessSpelledInSource`. We
171*5ffd83dbSDimitry Andric   // choose this setting, because we think it is the one most friendly to
172*5ffd83dbSDimitry Andric   // beginners, who are (largely) the target audience of Transformer.
173a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Matchers;
174a7dea167SDimitry Andric   for (const auto &Bucket : Buckets) {
175a7dea167SDimitry Andric     DynTypedMatcher M = DynTypedMatcher::constructVariadic(
176a7dea167SDimitry Andric         DynTypedMatcher::VO_AnyOf, Bucket.first,
177*5ffd83dbSDimitry Andric         taggedMatchers("Tag", Bucket.second, TK_IgnoreUnlessSpelledInSource));
178a7dea167SDimitry Andric     M.setAllowBind(true);
179a7dea167SDimitry Andric     // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
180*5ffd83dbSDimitry Andric     Matchers.push_back(
181*5ffd83dbSDimitry Andric         M.tryBind(RewriteRule::RootID)->withTraversalKind(TK_AsIs));
182a7dea167SDimitry Andric   }
183a7dea167SDimitry Andric   return Matchers;
184a7dea167SDimitry Andric }
185a7dea167SDimitry Andric 
186a7dea167SDimitry Andric DynTypedMatcher transformer::detail::buildMatcher(const RewriteRule &Rule) {
187a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
188a7dea167SDimitry Andric   assert(Ms.size() == 1 && "Cases must have compatible matchers.");
189a7dea167SDimitry Andric   return Ms[0];
190a7dea167SDimitry Andric }
191a7dea167SDimitry Andric 
192a7dea167SDimitry Andric SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
193a7dea167SDimitry Andric   auto &NodesMap = Result.Nodes.getMap();
194a7dea167SDimitry Andric   auto Root = NodesMap.find(RewriteRule::RootID);
195a7dea167SDimitry Andric   assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
196a7dea167SDimitry Andric   llvm::Optional<CharSourceRange> RootRange = tooling::getRangeForEdit(
197a7dea167SDimitry Andric       CharSourceRange::getTokenRange(Root->second.getSourceRange()),
198a7dea167SDimitry Andric       *Result.Context);
199a7dea167SDimitry Andric   if (RootRange)
200a7dea167SDimitry Andric     return RootRange->getBegin();
201a7dea167SDimitry Andric   // The match doesn't have a coherent range, so fall back to the expansion
202a7dea167SDimitry Andric   // location as the "beginning" of the match.
203a7dea167SDimitry Andric   return Result.SourceManager->getExpansionLoc(
204a7dea167SDimitry Andric       Root->second.getSourceRange().getBegin());
205a7dea167SDimitry Andric }
206a7dea167SDimitry Andric 
207a7dea167SDimitry Andric // Finds the case that was "selected" -- that is, whose matcher triggered the
208a7dea167SDimitry Andric // `MatchResult`.
209a7dea167SDimitry Andric const RewriteRule::Case &
210a7dea167SDimitry Andric transformer::detail::findSelectedCase(const MatchResult &Result,
211a7dea167SDimitry Andric                                   const RewriteRule &Rule) {
212a7dea167SDimitry Andric   if (Rule.Cases.size() == 1)
213a7dea167SDimitry Andric     return Rule.Cases[0];
214a7dea167SDimitry Andric 
215a7dea167SDimitry Andric   auto &NodesMap = Result.Nodes.getMap();
216a7dea167SDimitry Andric   for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
217a7dea167SDimitry Andric     std::string Tag = ("Tag" + Twine(i)).str();
218a7dea167SDimitry Andric     if (NodesMap.find(Tag) != NodesMap.end())
219a7dea167SDimitry Andric       return Rule.Cases[i];
220a7dea167SDimitry Andric   }
221a7dea167SDimitry Andric   llvm_unreachable("No tag found for this rule.");
222a7dea167SDimitry Andric }
223a7dea167SDimitry Andric 
224a7dea167SDimitry Andric constexpr llvm::StringLiteral RewriteRule::RootID;
225480093f4SDimitry Andric 
226480093f4SDimitry Andric TextGenerator tooling::text(std::string M) {
227480093f4SDimitry Andric   return std::make_shared<SimpleTextGenerator>(std::move(M));
228480093f4SDimitry Andric }
229