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 FileEntryRef Entry
= llvm::cantFail(Files
.getFileRef(FilePath
));
82 FileID ID
= SM
.getOrCreateFileID(Entry
, SrcMgr::C_User
);
83 StringRef Code
= SM
.getBufferData(ID
);
85 auto CurStyle
= format::getStyle(Style
, FilePath
, "LLVM");
87 llvm::errs() << llvm::toString(CurStyle
.takeError()) << "\n";
91 auto NewReplacements
=
92 format::formatReplacements(Code
, CurReplaces
, *CurStyle
);
93 if (!NewReplacements
) {
94 llvm::errs() << llvm::toString(NewReplacements
.takeError()) << "\n";
97 Result
= applyAllReplacements(*NewReplacements
, Rewrite
) && Result
;
102 } // end namespace tooling
103 } // end namespace clang