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/Transformer.h"
10 #include "clang/AST/Expr.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Rewrite/Core/Rewriter.h"
16 #include "clang/Tooling/Refactoring/AtomicChange.h"
17 #include "clang/Tooling/Transformer/SourceCode.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Errc.h"
21 #include "llvm/Support/Error.h"
22 #include <map>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 using namespace clang;
28 using namespace tooling;
29 
30 using ast_matchers::MatchFinder;
31 using ast_matchers::internal::DynTypedMatcher;
32 using ast_type_traits::ASTNodeKind;
33 using ast_type_traits::DynTypedNode;
34 using llvm::Error;
35 using llvm::StringError;
36 
37 using MatchResult = MatchFinder::MatchResult;
38 
39 Expected<SmallVector<tooling::detail::Transformation, 1>>
40 tooling::detail::translateEdits(const MatchResult &Result,
41                                 llvm::ArrayRef<ASTEdit> Edits) {
42   SmallVector<tooling::detail::Transformation, 1> Transformations;
43   for (const auto &Edit : Edits) {
44     Expected<CharSourceRange> Range = Edit.TargetRange(Result);
45     if (!Range)
46       return Range.takeError();
47     llvm::Optional<CharSourceRange> EditRange =
48         getRangeForEdit(*Range, *Result.Context);
49     // FIXME: let user specify whether to treat this case as an error or ignore
50     // it as is currently done.
51     if (!EditRange)
52       return SmallVector<Transformation, 0>();
53     auto Replacement = Edit.Replacement(Result);
54     if (!Replacement)
55       return Replacement.takeError();
56     tooling::detail::Transformation T;
57     T.Range = *EditRange;
58     T.Replacement = std::move(*Replacement);
59     Transformations.push_back(std::move(T));
60   }
61   return Transformations;
62 }
63 
64 ASTEdit tooling::change(RangeSelector S, TextGenerator Replacement) {
65   ASTEdit E;
66   E.TargetRange = std::move(S);
67   E.Replacement = std::move(Replacement);
68   return E;
69 }
70 
71 RewriteRule tooling::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits,
72                               TextGenerator Explanation) {
73   return RewriteRule{{RewriteRule::Case{
74       std::move(M), std::move(Edits), std::move(Explanation), {}}}};
75 }
76 
77 void tooling::addInclude(RewriteRule &Rule, StringRef Header,
78                          IncludeFormat Format) {
79   for (auto &Case : Rule.Cases)
80     Case.AddedIncludes.emplace_back(Header.str(), Format);
81 }
82 
83 #ifndef NDEBUG
84 // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
85 // (all node matcher types except for `QualType` and `Type`), rather than just
86 // banning `QualType` and `Type`.
87 static bool hasValidKind(const DynTypedMatcher &M) {
88   return !M.canConvertTo<QualType>();
89 }
90 #endif
91 
92 // Binds each rule's matcher to a unique (and deterministic) tag based on
93 // `TagBase` and the id paired with the case.
94 static std::vector<DynTypedMatcher> taggedMatchers(
95     StringRef TagBase,
96     const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases) {
97   std::vector<DynTypedMatcher> Matchers;
98   Matchers.reserve(Cases.size());
99   for (const auto &Case : Cases) {
100     std::string Tag = (TagBase + Twine(Case.first)).str();
101     // HACK: Many matchers are not bindable, so ensure that tryBind will work.
102     DynTypedMatcher BoundMatcher(Case.second.Matcher);
103     BoundMatcher.setAllowBind(true);
104     auto M = BoundMatcher.tryBind(Tag);
105     Matchers.push_back(*std::move(M));
106   }
107   return Matchers;
108 }
109 
110 // Simply gathers the contents of the various rules into a single rule. The
111 // actual work to combine these into an ordered choice is deferred to matcher
112 // registration.
113 RewriteRule tooling::applyFirst(ArrayRef<RewriteRule> Rules) {
114   RewriteRule R;
115   for (auto &Rule : Rules)
116     R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
117   return R;
118 }
119 
120 std::vector<DynTypedMatcher>
121 tooling::detail::buildMatchers(const RewriteRule &Rule) {
122   // Map the cases into buckets of matchers -- one for each "root" AST kind,
123   // which guarantees that they can be combined in a single anyOf matcher. Each
124   // case is paired with an identifying number that is converted to a string id
125   // in `taggedMatchers`.
126   std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
127       Buckets;
128   const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
129   for (int I = 0, N = Cases.size(); I < N; ++I) {
130     assert(hasValidKind(Cases[I].Matcher) &&
131            "Matcher must be non-(Qual)Type node matcher");
132     Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
133   }
134 
135   std::vector<DynTypedMatcher> Matchers;
136   for (const auto &Bucket : Buckets) {
137     DynTypedMatcher M = DynTypedMatcher::constructVariadic(
138         DynTypedMatcher::VO_AnyOf, Bucket.first,
139         taggedMatchers("Tag", Bucket.second));
140     M.setAllowBind(true);
141     // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
142     Matchers.push_back(*M.tryBind(RewriteRule::RootID));
143   }
144   return Matchers;
145 }
146 
147 DynTypedMatcher tooling::detail::buildMatcher(const RewriteRule &Rule) {
148   std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
149   assert(Ms.size() == 1 && "Cases must have compatible matchers.");
150   return Ms[0];
151 }
152 
153 SourceLocation tooling::detail::getRuleMatchLoc(const MatchResult &Result) {
154   auto &NodesMap = Result.Nodes.getMap();
155   auto Root = NodesMap.find(RewriteRule::RootID);
156   assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
157   llvm::Optional<CharSourceRange> RootRange = getRangeForEdit(
158       CharSourceRange::getTokenRange(Root->second.getSourceRange()),
159       *Result.Context);
160   if (RootRange)
161     return RootRange->getBegin();
162   // The match doesn't have a coherent range, so fall back to the expansion
163   // location as the "beginning" of the match.
164   return Result.SourceManager->getExpansionLoc(
165       Root->second.getSourceRange().getBegin());
166 }
167 
168 // Finds the case that was "selected" -- that is, whose matcher triggered the
169 // `MatchResult`.
170 const RewriteRule::Case &
171 tooling::detail::findSelectedCase(const MatchResult &Result,
172                                   const RewriteRule &Rule) {
173   if (Rule.Cases.size() == 1)
174     return Rule.Cases[0];
175 
176   auto &NodesMap = Result.Nodes.getMap();
177   for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
178     std::string Tag = ("Tag" + Twine(i)).str();
179     if (NodesMap.find(Tag) != NodesMap.end())
180       return Rule.Cases[i];
181   }
182   llvm_unreachable("No tag found for this rule.");
183 }
184 
185 constexpr llvm::StringLiteral RewriteRule::RootID;
186 
187 void Transformer::registerMatchers(MatchFinder *MatchFinder) {
188   for (auto &Matcher : tooling::detail::buildMatchers(Rule))
189     MatchFinder->addDynamicMatcher(Matcher, this);
190 }
191 
192 void Transformer::run(const MatchResult &Result) {
193   if (Result.Context->getDiagnostics().hasErrorOccurred())
194     return;
195 
196   RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, Rule);
197   auto Transformations = tooling::detail::translateEdits(Result, Case.Edits);
198   if (!Transformations) {
199     Consumer(Transformations.takeError());
200     return;
201   }
202 
203   if (Transformations->empty()) {
204     // No rewrite applied (but no error encountered either).
205     detail::getRuleMatchLoc(Result).print(
206         llvm::errs() << "note: skipping match at loc ", *Result.SourceManager);
207     llvm::errs() << "\n";
208     return;
209   }
210 
211   // Record the results in the AtomicChange, anchored at the location of the
212   // first change.
213   AtomicChange AC(*Result.SourceManager,
214                   (*Transformations)[0].Range.getBegin());
215   for (const auto &T : *Transformations) {
216     if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
217       Consumer(std::move(Err));
218       return;
219     }
220   }
221 
222   for (const auto &I : Case.AddedIncludes) {
223     auto &Header = I.first;
224     switch (I.second) {
225     case IncludeFormat::Quoted:
226       AC.addHeader(Header);
227       break;
228     case IncludeFormat::Angled:
229       AC.addHeader((llvm::Twine("<") + Header + ">").str());
230       break;
231     }
232   }
233 
234   Consumer(std::move(AC));
235 }
236