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