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/ASTMatchers/ASTMatchFinder.h" 11 #include "clang/ASTMatchers/ASTMatchersInternal.h" 12 #include "clang/Basic/SourceLocation.h" 13 #include "clang/Tooling/Refactoring/AtomicChange.h" 14 #include "llvm/Support/Error.h" 15 #include <map> 16 #include <utility> 17 #include <vector> 18 19 using namespace clang; 20 using namespace tooling; 21 22 using ast_matchers::MatchFinder; 23 24 void Transformer::registerMatchers(MatchFinder *MatchFinder) { 25 for (auto &Matcher : transformer::detail::buildMatchers(Rule)) 26 MatchFinder->addDynamicMatcher(Matcher, this); 27 } 28 29 void Transformer::run(const MatchFinder::MatchResult &Result) { 30 if (Result.Context->getDiagnostics().hasErrorOccurred()) 31 return; 32 33 transformer::RewriteRule::Case Case = 34 transformer::detail::findSelectedCase(Result, Rule); 35 auto Transformations = Case.Edits(Result); 36 if (!Transformations) { 37 Consumer(Transformations.takeError()); 38 return; 39 } 40 41 if (Transformations->empty()) 42 return; 43 44 // Group the transformations, by file, into AtomicChanges, each anchored by 45 // the location of the first change in that file. 46 std::map<FileID, AtomicChange> ChangesByFileID; 47 for (const auto &T : *Transformations) { 48 auto ID = Result.SourceManager->getFileID(T.Range.getBegin()); 49 auto Iter = ChangesByFileID 50 .emplace(ID, AtomicChange(*Result.SourceManager, 51 T.Range.getBegin(), T.Metadata)) 52 .first; 53 auto &AC = Iter->second; 54 if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) { 55 Consumer(std::move(Err)); 56 return; 57 } 58 } 59 60 for (auto &IDChangePair : ChangesByFileID) { 61 auto &AC = IDChangePair.second; 62 // FIXME: this will add includes to *all* changed files, which may not be 63 // the intent. We should upgrade the representation to allow associating 64 // headers with specific edits. 65 for (const auto &I : Case.AddedIncludes) { 66 auto &Header = I.first; 67 switch (I.second) { 68 case transformer::IncludeFormat::Quoted: 69 AC.addHeader(Header); 70 break; 71 case transformer::IncludeFormat::Angled: 72 AC.addHeader((llvm::Twine("<") + Header + ">").str()); 73 break; 74 } 75 } 76 77 Consumer(std::move(AC)); 78 } 79 } 80