1*e5dd7070Spatrick //===--- Refactoring.cpp - Framework for clang refactoring tools ----------===//
2*e5dd7070Spatrick //
3*e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e5dd7070Spatrick //
7*e5dd7070Spatrick //===----------------------------------------------------------------------===//
8*e5dd7070Spatrick //
9*e5dd7070Spatrick // Implements tools to support refactorings.
10*e5dd7070Spatrick //
11*e5dd7070Spatrick //===----------------------------------------------------------------------===//
12*e5dd7070Spatrick
13*e5dd7070Spatrick #include "clang/Tooling/Refactoring.h"
14*e5dd7070Spatrick #include "clang/Basic/DiagnosticOptions.h"
15*e5dd7070Spatrick #include "clang/Basic/FileManager.h"
16*e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
17*e5dd7070Spatrick #include "clang/Format/Format.h"
18*e5dd7070Spatrick #include "clang/Frontend/TextDiagnosticPrinter.h"
19*e5dd7070Spatrick #include "clang/Lex/Lexer.h"
20*e5dd7070Spatrick #include "clang/Rewrite/Core/Rewriter.h"
21*e5dd7070Spatrick #include "llvm/Support/Path.h"
22*e5dd7070Spatrick #include "llvm/Support/raw_os_ostream.h"
23*e5dd7070Spatrick
24*e5dd7070Spatrick namespace clang {
25*e5dd7070Spatrick namespace tooling {
26*e5dd7070Spatrick
RefactoringTool(const CompilationDatabase & Compilations,ArrayRef<std::string> SourcePaths,std::shared_ptr<PCHContainerOperations> PCHContainerOps)27*e5dd7070Spatrick RefactoringTool::RefactoringTool(
28*e5dd7070Spatrick const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths,
29*e5dd7070Spatrick std::shared_ptr<PCHContainerOperations> PCHContainerOps)
30*e5dd7070Spatrick : ClangTool(Compilations, SourcePaths, std::move(PCHContainerOps)) {}
31*e5dd7070Spatrick
getReplacements()32*e5dd7070Spatrick std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
33*e5dd7070Spatrick return FileToReplaces;
34*e5dd7070Spatrick }
35*e5dd7070Spatrick
runAndSave(FrontendActionFactory * ActionFactory)36*e5dd7070Spatrick int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
37*e5dd7070Spatrick if (int Result = run(ActionFactory)) {
38*e5dd7070Spatrick return Result;
39*e5dd7070Spatrick }
40*e5dd7070Spatrick
41*e5dd7070Spatrick LangOptions DefaultLangOptions;
42*e5dd7070Spatrick IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
43*e5dd7070Spatrick TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
44*e5dd7070Spatrick DiagnosticsEngine Diagnostics(
45*e5dd7070Spatrick IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
46*e5dd7070Spatrick &*DiagOpts, &DiagnosticPrinter, false);
47*e5dd7070Spatrick SourceManager Sources(Diagnostics, getFiles());
48*e5dd7070Spatrick Rewriter Rewrite(Sources, DefaultLangOptions);
49*e5dd7070Spatrick
50*e5dd7070Spatrick if (!applyAllReplacements(Rewrite)) {
51*e5dd7070Spatrick llvm::errs() << "Skipped some replacements.\n";
52*e5dd7070Spatrick }
53*e5dd7070Spatrick
54*e5dd7070Spatrick return saveRewrittenFiles(Rewrite);
55*e5dd7070Spatrick }
56*e5dd7070Spatrick
applyAllReplacements(Rewriter & Rewrite)57*e5dd7070Spatrick bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
58*e5dd7070Spatrick bool Result = true;
59*e5dd7070Spatrick for (const auto &Entry : groupReplacementsByFile(
60*e5dd7070Spatrick Rewrite.getSourceMgr().getFileManager(), FileToReplaces))
61*e5dd7070Spatrick Result = tooling::applyAllReplacements(Entry.second, Rewrite) && Result;
62*e5dd7070Spatrick return Result;
63*e5dd7070Spatrick }
64*e5dd7070Spatrick
saveRewrittenFiles(Rewriter & Rewrite)65*e5dd7070Spatrick int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
66*e5dd7070Spatrick return Rewrite.overwriteChangedFiles() ? 1 : 0;
67*e5dd7070Spatrick }
68*e5dd7070Spatrick
formatAndApplyAllReplacements(const std::map<std::string,Replacements> & FileToReplaces,Rewriter & Rewrite,StringRef Style)69*e5dd7070Spatrick bool formatAndApplyAllReplacements(
70*e5dd7070Spatrick const std::map<std::string, Replacements> &FileToReplaces,
71*e5dd7070Spatrick Rewriter &Rewrite, StringRef Style) {
72*e5dd7070Spatrick SourceManager &SM = Rewrite.getSourceMgr();
73*e5dd7070Spatrick FileManager &Files = SM.getFileManager();
74*e5dd7070Spatrick
75*e5dd7070Spatrick bool Result = true;
76*e5dd7070Spatrick for (const auto &FileAndReplaces : groupReplacementsByFile(
77*e5dd7070Spatrick Rewrite.getSourceMgr().getFileManager(), FileToReplaces)) {
78*e5dd7070Spatrick const std::string &FilePath = FileAndReplaces.first;
79*e5dd7070Spatrick auto &CurReplaces = FileAndReplaces.second;
80*e5dd7070Spatrick
81*e5dd7070Spatrick const FileEntry *Entry = nullptr;
82*e5dd7070Spatrick if (auto File = Files.getFile(FilePath))
83*e5dd7070Spatrick Entry = *File;
84*e5dd7070Spatrick
85*e5dd7070Spatrick FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
86*e5dd7070Spatrick StringRef Code = SM.getBufferData(ID);
87*e5dd7070Spatrick
88*e5dd7070Spatrick auto CurStyle = format::getStyle(Style, FilePath, "LLVM");
89*e5dd7070Spatrick if (!CurStyle) {
90*e5dd7070Spatrick llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n";
91*e5dd7070Spatrick return false;
92*e5dd7070Spatrick }
93*e5dd7070Spatrick
94*e5dd7070Spatrick auto NewReplacements =
95*e5dd7070Spatrick format::formatReplacements(Code, CurReplaces, *CurStyle);
96*e5dd7070Spatrick if (!NewReplacements) {
97*e5dd7070Spatrick llvm::errs() << llvm::toString(NewReplacements.takeError()) << "\n";
98*e5dd7070Spatrick return false;
99*e5dd7070Spatrick }
100*e5dd7070Spatrick Result = applyAllReplacements(*NewReplacements, Rewrite) && Result;
101*e5dd7070Spatrick }
102*e5dd7070Spatrick return Result;
103*e5dd7070Spatrick }
104*e5dd7070Spatrick
105*e5dd7070Spatrick } // end namespace tooling
106*e5dd7070Spatrick } // end namespace clang
107