1 //===--- Refactoring.cpp - Framework for clang refactoring tools ----------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implements tools to support refactorings. 10 // 11 //===----------------------------------------------------------------------===// 12 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 22 namespace clang { 23 namespace tooling { 24 25 RefactoringTool::RefactoringTool( 26 const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths, 27 std::shared_ptr<PCHContainerOperations> PCHContainerOps) 28 : ClangTool(Compilations, SourcePaths, std::move(PCHContainerOps)) {} 29 30 std::map<std::string, Replacements> &RefactoringTool::getReplacements() { 31 return FileToReplaces; 32 } 33 34 int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) { 35 if (int Result = run(ActionFactory)) { 36 return Result; 37 } 38 39 LangOptions DefaultLangOptions; 40 DiagnosticOptions DiagOpts; 41 TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts); 42 DiagnosticsEngine Diagnostics( 43 IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, 44 &DiagnosticPrinter, false); 45 SourceManager Sources(Diagnostics, getFiles()); 46 Rewriter Rewrite(Sources, DefaultLangOptions); 47 48 if (!applyAllReplacements(Rewrite)) { 49 llvm::errs() << "Skipped some replacements.\n"; 50 } 51 52 return saveRewrittenFiles(Rewrite); 53 } 54 55 bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) { 56 bool Result = true; 57 for (const auto &Entry : groupReplacementsByFile( 58 Rewrite.getSourceMgr().getFileManager(), FileToReplaces)) 59 Result = tooling::applyAllReplacements(Entry.second, Rewrite) && Result; 60 return Result; 61 } 62 63 int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) { 64 return Rewrite.overwriteChangedFiles() ? 1 : 0; 65 } 66 67 bool formatAndApplyAllReplacements( 68 const std::map<std::string, Replacements> &FileToReplaces, 69 Rewriter &Rewrite, StringRef Style) { 70 SourceManager &SM = Rewrite.getSourceMgr(); 71 FileManager &Files = SM.getFileManager(); 72 73 bool Result = true; 74 for (const auto &FileAndReplaces : groupReplacementsByFile( 75 Rewrite.getSourceMgr().getFileManager(), FileToReplaces)) { 76 const std::string &FilePath = FileAndReplaces.first; 77 auto &CurReplaces = FileAndReplaces.second; 78 79 FileEntryRef Entry = llvm::cantFail(Files.getFileRef(FilePath)); 80 FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User); 81 StringRef Code = SM.getBufferData(ID); 82 83 auto CurStyle = format::getStyle(Style, FilePath, "LLVM"); 84 if (!CurStyle) { 85 llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n"; 86 return false; 87 } 88 89 auto NewReplacements = 90 format::formatReplacements(Code, CurReplaces, *CurStyle); 91 if (!NewReplacements) { 92 llvm::errs() << llvm::toString(NewReplacements.takeError()) << "\n"; 93 return false; 94 } 95 Result = applyAllReplacements(*NewReplacements, Rewrite) && Result; 96 } 97 return Result; 98 } 99 100 } // end namespace tooling 101 } // end namespace clang 102