1 //===--- Refactoring.cpp - Framework for clang refactoring tools ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // Implements tools to support refactorings.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Tooling/Refactoring.h"
14 #include "clang/Basic/DiagnosticOptions.h"
15 #include "clang/Basic/FileManager.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Format/Format.h"
18 #include "clang/Frontend/TextDiagnosticPrinter.h"
19 #include "clang/Lex/Lexer.h"
20 #include "clang/Rewrite/Core/Rewriter.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/raw_os_ostream.h"
27 RefactoringTool::RefactoringTool(
28 const CompilationDatabase
&Compilations
, ArrayRef
<std::string
> SourcePaths
,
29 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
)
30 : ClangTool(Compilations
, SourcePaths
, std::move(PCHContainerOps
)) {}
32 std::map
<std::string
, Replacements
> &RefactoringTool::getReplacements() {
33 return FileToReplaces
;
36 int RefactoringTool::runAndSave(FrontendActionFactory
*ActionFactory
) {
37 if (int Result
= run(ActionFactory
)) {
41 LangOptions DefaultLangOptions
;
42 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
43 TextDiagnosticPrinter
DiagnosticPrinter(llvm::errs(), &*DiagOpts
);
44 DiagnosticsEngine
Diagnostics(
45 IntrusiveRefCntPtr
<DiagnosticIDs
>(new DiagnosticIDs()),
46 &*DiagOpts
, &DiagnosticPrinter
, false);
47 SourceManager
Sources(Diagnostics
, getFiles());
48 Rewriter
Rewrite(Sources
, DefaultLangOptions
);
50 if (!applyAllReplacements(Rewrite
)) {
51 llvm::errs() << "Skipped some replacements.\n";
54 return saveRewrittenFiles(Rewrite
);
57 bool RefactoringTool::applyAllReplacements(Rewriter
&Rewrite
) {
59 for (const auto &Entry
: groupReplacementsByFile(
60 Rewrite
.getSourceMgr().getFileManager(), FileToReplaces
))
61 Result
= tooling::applyAllReplacements(Entry
.second
, Rewrite
) && Result
;
65 int RefactoringTool::saveRewrittenFiles(Rewriter
&Rewrite
) {
66 return Rewrite
.overwriteChangedFiles() ? 1 : 0;
69 bool formatAndApplyAllReplacements(
70 const std::map
<std::string
, Replacements
> &FileToReplaces
,
71 Rewriter
&Rewrite
, StringRef Style
) {
72 SourceManager
&SM
= Rewrite
.getSourceMgr();
73 FileManager
&Files
= SM
.getFileManager();
76 for (const auto &FileAndReplaces
: groupReplacementsByFile(
77 Rewrite
.getSourceMgr().getFileManager(), FileToReplaces
)) {
78 const std::string
&FilePath
= FileAndReplaces
.first
;
79 auto &CurReplaces
= FileAndReplaces
.second
;
81 const FileEntry
*Entry
= nullptr;
82 if (auto File
= Files
.getFile(FilePath
))
85 FileID ID
= SM
.getOrCreateFileID(Entry
, SrcMgr::C_User
);
86 StringRef Code
= SM
.getBufferData(ID
);
88 auto CurStyle
= format::getStyle(Style
, FilePath
, "LLVM");
90 llvm::errs() << llvm::toString(CurStyle
.takeError()) << "\n";
94 auto NewReplacements
=
95 format::formatReplacements(Code
, CurReplaces
, *CurStyle
);
96 if (!NewReplacements
) {
97 llvm::errs() << llvm::toString(NewReplacements
.takeError()) << "\n";
100 Result
= applyAllReplacements(*NewReplacements
, Rewrite
) && Result
;
105 } // end namespace tooling
106 } // end namespace clang