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