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 : transformer::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   transformer::RewriteRule::Case Case =
33       transformer::detail::findSelectedCase(Result, Rule);
34   auto Transformations = transformer::detail::translateEdits(Result, Case.Edits);
35   if (!Transformations) {
36     Consumer(Transformations.takeError());
37     return;
38   }
39 
40   if (Transformations->empty()) {
41     // No rewrite applied (but no error encountered either).
42     transformer::detail::getRuleMatchLoc(Result).print(
43         llvm::errs() << "note: skipping match at loc ", *Result.SourceManager);
44     llvm::errs() << "\n";
45     return;
46   }
47 
48   // Record the results in the AtomicChange, anchored at the location of the
49   // first change.
50   AtomicChange AC(*Result.SourceManager,
51                   (*Transformations)[0].Range.getBegin());
52   for (const auto &T : *Transformations) {
53     if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
54       Consumer(std::move(Err));
55       return;
56     }
57   }
58 
59   for (const auto &I : Case.AddedIncludes) {
60     auto &Header = I.first;
61     switch (I.second) {
62     case transformer::IncludeFormat::Quoted:
63       AC.addHeader(Header);
64       break;
65     case transformer::IncludeFormat::Angled:
66       AC.addHeader((llvm::Twine("<") + Header + ">").str());
67       break;
68     }
69   }
70 
71   Consumer(std::move(AC));
72 }
73