brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.8 KiB · 76de8bd Raw
169 lines · cpp
1//===-- ClangApplyReplacementsMain.cpp - Main file for the tool -----------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file provides the main function for the11/// clang-apply-replacements tool.12///13//===----------------------------------------------------------------------===//14 15#include "clang-apply-replacements/Tooling/ApplyReplacements.h"16#include "clang/Basic/Diagnostic.h"17#include "clang/Basic/DiagnosticOptions.h"18#include "clang/Basic/SourceManager.h"19#include "clang/Basic/Version.h"20#include "clang/Format/Format.h"21#include "clang/Rewrite/Core/Rewriter.h"22#include "llvm/ADT/STLExtras.h"23#include "llvm/ADT/StringSet.h"24#include "llvm/Support/CommandLine.h"25 26using namespace llvm;27using namespace clang;28using namespace clang::replace;29 30static cl::opt<std::string> Directory(cl::Positional, cl::Required,31                                      cl::desc("<Search Root Directory>"));32 33static cl::OptionCategory ReplacementCategory("Replacement Options");34static cl::OptionCategory FormattingCategory("Formatting Options");35 36const cl::OptionCategory *VisibleCategories[] = {&ReplacementCategory,37                                                 &FormattingCategory};38 39static cl::opt<bool> RemoveTUReplacementFiles(40    "remove-change-desc-files",41    cl::desc("Remove the change description files regardless of successful\n"42             "merging/replacing."),43    cl::init(false), cl::cat(ReplacementCategory));44 45static cl::opt<bool> IgnoreInsertConflict(46    "ignore-insert-conflict",47    cl::desc("Ignore insert conflict and keep running to fix."),48    cl::init(false), cl::cat(ReplacementCategory));49 50static cl::opt<bool> DoFormat(51    "format",52    cl::desc("Enable formatting of code changed by applying replacements.\n"53             "Use -style to choose formatting style.\n"),54    cl::cat(FormattingCategory));55 56// FIXME: Consider making the default behaviour for finding a style57// configuration file to start the search anew for every file being changed to58// handle situations where the style is different for different parts of a59// project.60 61static cl::opt<std::string> FormatStyleConfig(62    "style-config",63    cl::desc("Path to a directory containing a .clang-format file\n"64             "describing a formatting style to use for formatting\n"65             "code when -style=file.\n"),66    cl::init(""), cl::cat(FormattingCategory));67 68static cl::opt<std::string>69    FormatStyleOpt("style", cl::desc(format::StyleOptionHelpDescription),70                   cl::init("LLVM"), cl::cat(FormattingCategory));71 72namespace {73// Helper object to remove the TUReplacement and TUDiagnostic (triggered by74// "remove-change-desc-files" command line option) when exiting current scope.75class ScopedFileRemover {76public:77  ScopedFileRemover(const TUReplacementFiles &Files,78                    clang::DiagnosticsEngine &Diagnostics)79      : TURFiles(Files), Diag(Diagnostics) {}80 81  ~ScopedFileRemover() { deleteReplacementFiles(TURFiles, Diag); }82 83private:84  const TUReplacementFiles &TURFiles;85  clang::DiagnosticsEngine &Diag;86};87} // namespace88 89static void printVersion(raw_ostream &OS) {90  OS << "clang-apply-replacements version " CLANG_VERSION_STRING << "\n";91}92 93int main(int argc, char **argv) {94  cl::HideUnrelatedOptions(ArrayRef(VisibleCategories));95 96  cl::SetVersionPrinter(printVersion);97  cl::ParseCommandLineOptions(argc, argv);98 99  DiagnosticOptions DiagOpts;100  DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts);101 102  // Determine a formatting style from options.103  auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,104                                             format::DefaultFallbackStyle);105  if (!FormatStyleOrError) {106    llvm::errs() << llvm::toString(FormatStyleOrError.takeError()) << "\n";107    return 1;108  }109  format::FormatStyle FormatStyle = std::move(*FormatStyleOrError);110 111  TUReplacements TURs;112  TUReplacementFiles TUFiles;113 114  std::error_code ErrorCode =115      collectReplacementsFromDirectory(Directory, TURs, TUFiles, Diagnostics);116 117  TUDiagnostics TUDs;118  TUFiles.clear();119  ErrorCode =120      collectReplacementsFromDirectory(Directory, TUDs, TUFiles, Diagnostics);121 122  if (ErrorCode) {123    errs() << "Trouble iterating over directory '" << Directory124           << "': " << ErrorCode.message() << "\n";125    return 1;126  }127 128  // Remove the TUReplacementFiles (triggered by "remove-change-desc-files"129  // command line option) when exiting main().130  std::unique_ptr<ScopedFileRemover> Remover;131  if (RemoveTUReplacementFiles)132    Remover.reset(new ScopedFileRemover(TUFiles, Diagnostics));133 134  FileManager Files((FileSystemOptions()));135  SourceManager SM(Diagnostics, Files);136 137  FileToChangesMap Changes;138  if (!mergeAndDeduplicate(TURs, TUDs, Changes, SM, IgnoreInsertConflict))139    return 1;140 141  tooling::ApplyChangesSpec Spec;142  Spec.Cleanup = true;143  Spec.Format = DoFormat ? tooling::ApplyChangesSpec::kAll144                         : tooling::ApplyChangesSpec::kNone;145  Spec.Style = DoFormat ? FormatStyle : format::getNoStyle();146 147  for (const auto &FileChange : Changes) {148    FileEntryRef Entry = FileChange.first;149    StringRef FileName = Entry.getName();150    llvm::Expected<std::string> NewFileData =151        applyChanges(FileName, FileChange.second, Spec, Diagnostics);152    if (!NewFileData) {153      errs() << llvm::toString(NewFileData.takeError()) << "\n";154      continue;155    }156 157    // Write new file to disk158    std::error_code EC;159    llvm::raw_fd_ostream FileStream(FileName, EC, llvm::sys::fs::OF_None);160    if (EC) {161      llvm::errs() << "Could not open " << FileName << " for writing\n";162      continue;163    }164    FileStream << *NewFileData;165  }166 167  return 0;168}169