xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Refactoring.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- Refactoring.cpp - Framework for clang refactoring tools ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  Implements tools to support refactorings.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/Tooling/Refactoring.h"
140b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h"
150b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
160b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
170b57cec5SDimitry Andric #include "clang/Format/Format.h"
180b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
190b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
200b57cec5SDimitry Andric #include "clang/Rewrite/Core/Rewriter.h"
210b57cec5SDimitry Andric #include "llvm/Support/Path.h"
220b57cec5SDimitry Andric #include "llvm/Support/raw_os_ostream.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace clang {
250b57cec5SDimitry Andric namespace tooling {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric RefactoringTool::RefactoringTool(
280b57cec5SDimitry Andric     const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths,
290b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps)
300b57cec5SDimitry Andric     : ClangTool(Compilations, SourcePaths, std::move(PCHContainerOps)) {}
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
330b57cec5SDimitry Andric   return FileToReplaces;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
370b57cec5SDimitry Andric   if (int Result = run(ActionFactory)) {
380b57cec5SDimitry Andric     return Result;
390b57cec5SDimitry Andric   }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   LangOptions DefaultLangOptions;
420b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
430b57cec5SDimitry Andric   TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
440b57cec5SDimitry Andric   DiagnosticsEngine Diagnostics(
450b57cec5SDimitry Andric       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
460b57cec5SDimitry Andric       &*DiagOpts, &DiagnosticPrinter, false);
470b57cec5SDimitry Andric   SourceManager Sources(Diagnostics, getFiles());
480b57cec5SDimitry Andric   Rewriter Rewrite(Sources, DefaultLangOptions);
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   if (!applyAllReplacements(Rewrite)) {
510b57cec5SDimitry Andric     llvm::errs() << "Skipped some replacements.\n";
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   return saveRewrittenFiles(Rewrite);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
580b57cec5SDimitry Andric   bool Result = true;
590b57cec5SDimitry Andric   for (const auto &Entry : groupReplacementsByFile(
600b57cec5SDimitry Andric            Rewrite.getSourceMgr().getFileManager(), FileToReplaces))
610b57cec5SDimitry Andric     Result = tooling::applyAllReplacements(Entry.second, Rewrite) && Result;
620b57cec5SDimitry Andric   return Result;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
660b57cec5SDimitry Andric   return Rewrite.overwriteChangedFiles() ? 1 : 0;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric bool formatAndApplyAllReplacements(
700b57cec5SDimitry Andric     const std::map<std::string, Replacements> &FileToReplaces,
710b57cec5SDimitry Andric     Rewriter &Rewrite, StringRef Style) {
720b57cec5SDimitry Andric   SourceManager &SM = Rewrite.getSourceMgr();
730b57cec5SDimitry Andric   FileManager &Files = SM.getFileManager();
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   bool Result = true;
760b57cec5SDimitry Andric   for (const auto &FileAndReplaces : groupReplacementsByFile(
770b57cec5SDimitry Andric            Rewrite.getSourceMgr().getFileManager(), FileToReplaces)) {
780b57cec5SDimitry Andric     const std::string &FilePath = FileAndReplaces.first;
790b57cec5SDimitry Andric     auto &CurReplaces = FileAndReplaces.second;
800b57cec5SDimitry Andric 
81*5f757f3fSDimitry Andric     FileEntryRef Entry = llvm::cantFail(Files.getFileRef(FilePath));
820b57cec5SDimitry Andric     FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
830b57cec5SDimitry Andric     StringRef Code = SM.getBufferData(ID);
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     auto CurStyle = format::getStyle(Style, FilePath, "LLVM");
860b57cec5SDimitry Andric     if (!CurStyle) {
870b57cec5SDimitry Andric       llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n";
880b57cec5SDimitry Andric       return false;
890b57cec5SDimitry Andric     }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     auto NewReplacements =
920b57cec5SDimitry Andric         format::formatReplacements(Code, CurReplaces, *CurStyle);
930b57cec5SDimitry Andric     if (!NewReplacements) {
940b57cec5SDimitry Andric       llvm::errs() << llvm::toString(NewReplacements.takeError()) << "\n";
950b57cec5SDimitry Andric       return false;
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric     Result = applyAllReplacements(*NewReplacements, Rewrite) && Result;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric   return Result;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric } // end namespace tooling
1030b57cec5SDimitry Andric } // end namespace clang
104