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/Transformer.h"
10a7dea167SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
11a7dea167SDimitry Andric #include "clang/ASTMatchers/ASTMatchersInternal.h"
12a7dea167SDimitry Andric #include "clang/Basic/SourceLocation.h"
13a7dea167SDimitry Andric #include "clang/Tooling/Refactoring/AtomicChange.h"
14a7dea167SDimitry Andric #include "llvm/Support/Error.h"
155ffd83dbSDimitry Andric #include <map>
16a7dea167SDimitry Andric #include <utility>
17a7dea167SDimitry Andric #include <vector>
18a7dea167SDimitry Andric
19*81ad6265SDimitry Andric namespace clang {
20*81ad6265SDimitry Andric namespace tooling {
21a7dea167SDimitry Andric
22*81ad6265SDimitry Andric using ::clang::ast_matchers::MatchFinder;
23a7dea167SDimitry Andric
24*81ad6265SDimitry Andric namespace detail {
25a7dea167SDimitry Andric
onMatch(const ast_matchers::MatchFinder::MatchResult & Result)26*81ad6265SDimitry Andric void TransformerImpl::onMatch(
27*81ad6265SDimitry Andric const ast_matchers::MatchFinder::MatchResult &Result) {
28a7dea167SDimitry Andric if (Result.Context->getDiagnostics().hasErrorOccurred())
29a7dea167SDimitry Andric return;
30a7dea167SDimitry Andric
31*81ad6265SDimitry Andric onMatchImpl(Result);
32a7dea167SDimitry Andric }
33a7dea167SDimitry Andric
34*81ad6265SDimitry Andric llvm::Expected<llvm::SmallVector<AtomicChange, 1>>
convertToAtomicChanges(const llvm::SmallVectorImpl<transformer::Edit> & Edits,const MatchFinder::MatchResult & Result)35*81ad6265SDimitry Andric TransformerImpl::convertToAtomicChanges(
36*81ad6265SDimitry Andric const llvm::SmallVectorImpl<transformer::Edit> &Edits,
37*81ad6265SDimitry Andric const MatchFinder::MatchResult &Result) {
385ffd83dbSDimitry Andric // Group the transformations, by file, into AtomicChanges, each anchored by
395ffd83dbSDimitry Andric // the location of the first change in that file.
405ffd83dbSDimitry Andric std::map<FileID, AtomicChange> ChangesByFileID;
41*81ad6265SDimitry Andric for (const auto &T : Edits) {
425ffd83dbSDimitry Andric auto ID = Result.SourceManager->getFileID(T.Range.getBegin());
435ffd83dbSDimitry Andric auto Iter = ChangesByFileID
445ffd83dbSDimitry Andric .emplace(ID, AtomicChange(*Result.SourceManager,
455ffd83dbSDimitry Andric T.Range.getBegin(), T.Metadata))
465ffd83dbSDimitry Andric .first;
475ffd83dbSDimitry Andric auto &AC = Iter->second;
48e8d8bef9SDimitry Andric switch (T.Kind) {
49e8d8bef9SDimitry Andric case transformer::EditKind::Range:
50e8d8bef9SDimitry Andric if (auto Err =
51e8d8bef9SDimitry Andric AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
52*81ad6265SDimitry Andric return std::move(Err);
53a7dea167SDimitry Andric }
54a7dea167SDimitry Andric break;
55e8d8bef9SDimitry Andric case transformer::EditKind::AddInclude:
56e8d8bef9SDimitry Andric AC.addHeader(T.Replacement);
57a7dea167SDimitry Andric break;
58a7dea167SDimitry Andric }
59a7dea167SDimitry Andric }
60a7dea167SDimitry Andric
61*81ad6265SDimitry Andric llvm::SmallVector<AtomicChange, 1> Changes;
62*81ad6265SDimitry Andric Changes.reserve(ChangesByFileID.size());
63e8d8bef9SDimitry Andric for (auto &IDChangePair : ChangesByFileID)
64*81ad6265SDimitry Andric Changes.push_back(std::move(IDChangePair.second));
65*81ad6265SDimitry Andric
66*81ad6265SDimitry Andric return Changes;
675ffd83dbSDimitry Andric }
68*81ad6265SDimitry Andric
69*81ad6265SDimitry Andric } // namespace detail
70*81ad6265SDimitry Andric
registerMatchers(MatchFinder * MatchFinder)71*81ad6265SDimitry Andric void Transformer::registerMatchers(MatchFinder *MatchFinder) {
72*81ad6265SDimitry Andric for (auto &Matcher : Impl->buildMatchers())
73*81ad6265SDimitry Andric MatchFinder->addDynamicMatcher(Matcher, this);
74*81ad6265SDimitry Andric }
75*81ad6265SDimitry Andric
run(const MatchFinder::MatchResult & Result)76*81ad6265SDimitry Andric void Transformer::run(const MatchFinder::MatchResult &Result) {
77*81ad6265SDimitry Andric if (Result.Context->getDiagnostics().hasErrorOccurred())
78*81ad6265SDimitry Andric return;
79*81ad6265SDimitry Andric
80*81ad6265SDimitry Andric Impl->onMatch(Result);
81*81ad6265SDimitry Andric }
82*81ad6265SDimitry Andric
83*81ad6265SDimitry Andric } // namespace tooling
84*81ad6265SDimitry Andric } // namespace clang
85