xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/Transformer/RewriteRule.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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 using ast_type_traits::ASTNodeKind;
29a7dea167SDimitry Andric 
30a7dea167SDimitry Andric using MatchResult = MatchFinder::MatchResult;
31a7dea167SDimitry Andric 
32a7dea167SDimitry Andric Expected<SmallVector<transformer::detail::Transformation, 1>>
33a7dea167SDimitry Andric transformer::detail::translateEdits(const MatchResult &Result,
34a7dea167SDimitry Andric                                 llvm::ArrayRef<ASTEdit> Edits) {
35a7dea167SDimitry Andric   SmallVector<transformer::detail::Transformation, 1> Transformations;
36a7dea167SDimitry Andric   for (const auto &Edit : Edits) {
37a7dea167SDimitry Andric     Expected<CharSourceRange> Range = Edit.TargetRange(Result);
38a7dea167SDimitry Andric     if (!Range)
39a7dea167SDimitry Andric       return Range.takeError();
40a7dea167SDimitry Andric     llvm::Optional<CharSourceRange> EditRange =
41a7dea167SDimitry Andric         tooling::getRangeForEdit(*Range, *Result.Context);
42a7dea167SDimitry Andric     // FIXME: let user specify whether to treat this case as an error or ignore
43a7dea167SDimitry Andric     // it as is currently done.
44a7dea167SDimitry Andric     if (!EditRange)
45a7dea167SDimitry Andric       return SmallVector<Transformation, 0>();
46*480093f4SDimitry Andric     auto Replacement = Edit.Replacement->eval(Result);
47a7dea167SDimitry Andric     if (!Replacement)
48a7dea167SDimitry Andric       return Replacement.takeError();
49a7dea167SDimitry Andric     transformer::detail::Transformation T;
50a7dea167SDimitry Andric     T.Range = *EditRange;
51a7dea167SDimitry Andric     T.Replacement = std::move(*Replacement);
52a7dea167SDimitry Andric     Transformations.push_back(std::move(T));
53a7dea167SDimitry Andric   }
54a7dea167SDimitry Andric   return Transformations;
55a7dea167SDimitry Andric }
56a7dea167SDimitry Andric 
57*480093f4SDimitry Andric ASTEdit transformer::changeTo(RangeSelector S, TextGenerator Replacement) {
58a7dea167SDimitry Andric   ASTEdit E;
59a7dea167SDimitry Andric   E.TargetRange = std::move(S);
60a7dea167SDimitry Andric   E.Replacement = std::move(Replacement);
61a7dea167SDimitry Andric   return E;
62a7dea167SDimitry Andric }
63a7dea167SDimitry Andric 
64*480093f4SDimitry Andric namespace {
65*480093f4SDimitry Andric /// A \c TextGenerator that always returns a fixed string.
66*480093f4SDimitry Andric class SimpleTextGenerator : public MatchComputation<std::string> {
67*480093f4SDimitry Andric   std::string S;
68*480093f4SDimitry Andric 
69*480093f4SDimitry Andric public:
70*480093f4SDimitry Andric   SimpleTextGenerator(std::string S) : S(std::move(S)) {}
71*480093f4SDimitry Andric   llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
72*480093f4SDimitry Andric                    std::string *Result) const override {
73*480093f4SDimitry Andric     Result->append(S);
74*480093f4SDimitry Andric     return llvm::Error::success();
75*480093f4SDimitry Andric   }
76*480093f4SDimitry Andric   std::string toString() const override {
77*480093f4SDimitry Andric     return (llvm::Twine("text(\"") + S + "\")").str();
78*480093f4SDimitry Andric   }
79*480093f4SDimitry Andric };
80*480093f4SDimitry Andric } // namespace
81*480093f4SDimitry Andric 
82*480093f4SDimitry Andric ASTEdit transformer::remove(RangeSelector S) {
83*480093f4SDimitry Andric   return change(std::move(S), std::make_shared<SimpleTextGenerator>(""));
84*480093f4SDimitry Andric }
85*480093f4SDimitry Andric 
86a7dea167SDimitry Andric RewriteRule transformer::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits,
87a7dea167SDimitry Andric                               TextGenerator Explanation) {
88a7dea167SDimitry Andric   return RewriteRule{{RewriteRule::Case{
89a7dea167SDimitry Andric       std::move(M), std::move(Edits), std::move(Explanation), {}}}};
90a7dea167SDimitry Andric }
91a7dea167SDimitry Andric 
92a7dea167SDimitry Andric void transformer::addInclude(RewriteRule &Rule, StringRef Header,
93a7dea167SDimitry Andric                          IncludeFormat Format) {
94a7dea167SDimitry Andric   for (auto &Case : Rule.Cases)
95a7dea167SDimitry Andric     Case.AddedIncludes.emplace_back(Header.str(), Format);
96a7dea167SDimitry Andric }
97a7dea167SDimitry Andric 
98a7dea167SDimitry Andric #ifndef NDEBUG
99a7dea167SDimitry Andric // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
100a7dea167SDimitry Andric // (all node matcher types except for `QualType` and `Type`), rather than just
101a7dea167SDimitry Andric // banning `QualType` and `Type`.
102a7dea167SDimitry Andric static bool hasValidKind(const DynTypedMatcher &M) {
103a7dea167SDimitry Andric   return !M.canConvertTo<QualType>();
104a7dea167SDimitry Andric }
105a7dea167SDimitry Andric #endif
106a7dea167SDimitry Andric 
107a7dea167SDimitry Andric // Binds each rule's matcher to a unique (and deterministic) tag based on
108a7dea167SDimitry Andric // `TagBase` and the id paired with the case.
109a7dea167SDimitry Andric static std::vector<DynTypedMatcher> taggedMatchers(
110a7dea167SDimitry Andric     StringRef TagBase,
111a7dea167SDimitry Andric     const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases) {
112a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Matchers;
113a7dea167SDimitry Andric   Matchers.reserve(Cases.size());
114a7dea167SDimitry Andric   for (const auto &Case : Cases) {
115a7dea167SDimitry Andric     std::string Tag = (TagBase + Twine(Case.first)).str();
116a7dea167SDimitry Andric     // HACK: Many matchers are not bindable, so ensure that tryBind will work.
117a7dea167SDimitry Andric     DynTypedMatcher BoundMatcher(Case.second.Matcher);
118a7dea167SDimitry Andric     BoundMatcher.setAllowBind(true);
119a7dea167SDimitry Andric     auto M = BoundMatcher.tryBind(Tag);
120a7dea167SDimitry Andric     Matchers.push_back(*std::move(M));
121a7dea167SDimitry Andric   }
122a7dea167SDimitry Andric   return Matchers;
123a7dea167SDimitry Andric }
124a7dea167SDimitry Andric 
125a7dea167SDimitry Andric // Simply gathers the contents of the various rules into a single rule. The
126a7dea167SDimitry Andric // actual work to combine these into an ordered choice is deferred to matcher
127a7dea167SDimitry Andric // registration.
128a7dea167SDimitry Andric RewriteRule transformer::applyFirst(ArrayRef<RewriteRule> Rules) {
129a7dea167SDimitry Andric   RewriteRule R;
130a7dea167SDimitry Andric   for (auto &Rule : Rules)
131a7dea167SDimitry Andric     R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
132a7dea167SDimitry Andric   return R;
133a7dea167SDimitry Andric }
134a7dea167SDimitry Andric 
135a7dea167SDimitry Andric std::vector<DynTypedMatcher>
136a7dea167SDimitry Andric transformer::detail::buildMatchers(const RewriteRule &Rule) {
137a7dea167SDimitry Andric   // Map the cases into buckets of matchers -- one for each "root" AST kind,
138a7dea167SDimitry Andric   // which guarantees that they can be combined in a single anyOf matcher. Each
139a7dea167SDimitry Andric   // case is paired with an identifying number that is converted to a string id
140a7dea167SDimitry Andric   // in `taggedMatchers`.
141a7dea167SDimitry Andric   std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
142a7dea167SDimitry Andric       Buckets;
143a7dea167SDimitry Andric   const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
144a7dea167SDimitry Andric   for (int I = 0, N = Cases.size(); I < N; ++I) {
145a7dea167SDimitry Andric     assert(hasValidKind(Cases[I].Matcher) &&
146a7dea167SDimitry Andric            "Matcher must be non-(Qual)Type node matcher");
147a7dea167SDimitry Andric     Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
148a7dea167SDimitry Andric   }
149a7dea167SDimitry Andric 
150a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Matchers;
151a7dea167SDimitry Andric   for (const auto &Bucket : Buckets) {
152a7dea167SDimitry Andric     DynTypedMatcher M = DynTypedMatcher::constructVariadic(
153a7dea167SDimitry Andric         DynTypedMatcher::VO_AnyOf, Bucket.first,
154a7dea167SDimitry Andric         taggedMatchers("Tag", Bucket.second));
155a7dea167SDimitry Andric     M.setAllowBind(true);
156a7dea167SDimitry Andric     // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
157a7dea167SDimitry Andric     Matchers.push_back(*M.tryBind(RewriteRule::RootID));
158a7dea167SDimitry Andric   }
159a7dea167SDimitry Andric   return Matchers;
160a7dea167SDimitry Andric }
161a7dea167SDimitry Andric 
162a7dea167SDimitry Andric DynTypedMatcher transformer::detail::buildMatcher(const RewriteRule &Rule) {
163a7dea167SDimitry Andric   std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
164a7dea167SDimitry Andric   assert(Ms.size() == 1 && "Cases must have compatible matchers.");
165a7dea167SDimitry Andric   return Ms[0];
166a7dea167SDimitry Andric }
167a7dea167SDimitry Andric 
168a7dea167SDimitry Andric SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
169a7dea167SDimitry Andric   auto &NodesMap = Result.Nodes.getMap();
170a7dea167SDimitry Andric   auto Root = NodesMap.find(RewriteRule::RootID);
171a7dea167SDimitry Andric   assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
172a7dea167SDimitry Andric   llvm::Optional<CharSourceRange> RootRange = tooling::getRangeForEdit(
173a7dea167SDimitry Andric       CharSourceRange::getTokenRange(Root->second.getSourceRange()),
174a7dea167SDimitry Andric       *Result.Context);
175a7dea167SDimitry Andric   if (RootRange)
176a7dea167SDimitry Andric     return RootRange->getBegin();
177a7dea167SDimitry Andric   // The match doesn't have a coherent range, so fall back to the expansion
178a7dea167SDimitry Andric   // location as the "beginning" of the match.
179a7dea167SDimitry Andric   return Result.SourceManager->getExpansionLoc(
180a7dea167SDimitry Andric       Root->second.getSourceRange().getBegin());
181a7dea167SDimitry Andric }
182a7dea167SDimitry Andric 
183a7dea167SDimitry Andric // Finds the case that was "selected" -- that is, whose matcher triggered the
184a7dea167SDimitry Andric // `MatchResult`.
185a7dea167SDimitry Andric const RewriteRule::Case &
186a7dea167SDimitry Andric transformer::detail::findSelectedCase(const MatchResult &Result,
187a7dea167SDimitry Andric                                   const RewriteRule &Rule) {
188a7dea167SDimitry Andric   if (Rule.Cases.size() == 1)
189a7dea167SDimitry Andric     return Rule.Cases[0];
190a7dea167SDimitry Andric 
191a7dea167SDimitry Andric   auto &NodesMap = Result.Nodes.getMap();
192a7dea167SDimitry Andric   for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
193a7dea167SDimitry Andric     std::string Tag = ("Tag" + Twine(i)).str();
194a7dea167SDimitry Andric     if (NodesMap.find(Tag) != NodesMap.end())
195a7dea167SDimitry Andric       return Rule.Cases[i];
196a7dea167SDimitry Andric   }
197a7dea167SDimitry Andric   llvm_unreachable("No tag found for this rule.");
198a7dea167SDimitry Andric }
199a7dea167SDimitry Andric 
200a7dea167SDimitry Andric constexpr llvm::StringLiteral RewriteRule::RootID;
201*480093f4SDimitry Andric 
202*480093f4SDimitry Andric TextGenerator tooling::text(std::string M) {
203*480093f4SDimitry Andric   return std::make_shared<SimpleTextGenerator>(std::move(M));
204*480093f4SDimitry Andric }
205