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