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
RefactoringTool(const CompilationDatabase & Compilations,ArrayRef<std::string> SourcePaths,std::shared_ptr<PCHContainerOperations> PCHContainerOps)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
getReplacements()320b57cec5SDimitry Andric std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
330b57cec5SDimitry Andric return FileToReplaces;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric
runAndSave(FrontendActionFactory * ActionFactory)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
applyAllReplacements(Rewriter & Rewrite)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
saveRewrittenFiles(Rewriter & Rewrite)650b57cec5SDimitry Andric int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
660b57cec5SDimitry Andric return Rewrite.overwriteChangedFiles() ? 1 : 0;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
formatAndApplyAllReplacements(const std::map<std::string,Replacements> & FileToReplaces,Rewriter & Rewrite,StringRef Style)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