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