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