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 <utility>
16 #include <vector>
17 
18 using namespace clang;
19 using namespace tooling;
20 
21 using ast_matchers::MatchFinder;
22 
23 void Transformer::registerMatchers(MatchFinder *MatchFinder) {
24   for (auto &Matcher : tooling::detail::buildMatchers(Rule))
25     MatchFinder->addDynamicMatcher(Matcher, this);
26 }
27 
28 void Transformer::run(const MatchFinder::MatchResult &Result) {
29   if (Result.Context->getDiagnostics().hasErrorOccurred())
30     return;
31 
32   RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, Rule);
33   auto Transformations = tooling::detail::translateEdits(Result, Case.Edits);
34   if (!Transformations) {
35     Consumer(Transformations.takeError());
36     return;
37   }
38 
39   if (Transformations->empty()) {
40     // No rewrite applied (but no error encountered either).
41     tooling::detail::getRuleMatchLoc(Result).print(
42         llvm::errs() << "note: skipping match at loc ", *Result.SourceManager);
43     llvm::errs() << "\n";
44     return;
45   }
46 
47   // Record the results in the AtomicChange, anchored at the location of the
48   // first change.
49   AtomicChange AC(*Result.SourceManager,
50                   (*Transformations)[0].Range.getBegin());
51   for (const auto &T : *Transformations) {
52     if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
53       Consumer(std::move(Err));
54       return;
55     }
56   }
57 
58   for (const auto &I : Case.AddedIncludes) {
59     auto &Header = I.first;
60     switch (I.second) {
61     case IncludeFormat::Quoted:
62       AC.addHeader(Header);
63       break;
64     case IncludeFormat::Angled:
65       AC.addHeader((llvm::Twine("<") + Header + ">").str());
66       break;
67     }
68   }
69 
70   Consumer(std::move(AC));
71 }
72