18 #include "clang/Basic/LangOptions.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "clang/Format/Format.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Rewrite/Core/Rewriter.h"
23 #include "clang/Tooling/ReplacementsYaml.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/raw_ostream.h"
31 using namespace clang;
43 clang::DiagnosticsEngine &Diagnostics) {
44 using namespace llvm::sys::fs;
45 using namespace llvm::sys::path;
47 std::error_code ErrorCode;
49 for (recursive_directory_iterator I(Directory, ErrorCode), E;
50 I != E && !ErrorCode; I.increment(ErrorCode)) {
51 if (filename(I->path())[0] ==
'.') {
57 if (extension(I->path()) !=
".yaml")
60 TURFiles.push_back(I->path());
62 ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
63 MemoryBuffer::getFile(I->path());
64 if (std::error_code BufferError = Out.getError()) {
65 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
71 tooling::TranslationUnitReplacements TU;
92 const FileEntry *
File,
93 const llvm::ArrayRef<clang::tooling::Replacement> ConflictingReplacements,
95 FileID FID = SM.translateFile(File);
97 FID = SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
100 errs() <<
"The following changes conflict:\n";
101 for (
const tooling::Replacement &R : ConflictingReplacements) {
102 if (R.getLength() == 0) {
103 errs() <<
" Insert at " << SM.getLineNumber(FID, R.getOffset()) <<
":"
104 << SM.getColumnNumber(FID, R.getOffset()) <<
" "
105 << R.getReplacementText() <<
"\n";
107 if (R.getReplacementText().empty())
108 errs() <<
" Remove ";
110 errs() <<
" Replace ";
112 errs() << SM.getLineNumber(FID, R.getOffset()) <<
":"
113 << SM.getColumnNumber(FID, R.getOffset()) <<
"-"
114 << SM.getLineNumber(FID, R.getOffset() + R.getLength() - 1) <<
":"
115 << SM.getColumnNumber(FID, R.getOffset() + R.getLength() - 1);
117 if (R.getReplacementText().empty())
120 errs() <<
" with \"" << R.getReplacementText() <<
"\"\n";
139 bool conflictsFound =
false;
141 for (
auto &FileAndReplacements : Replacements) {
142 const FileEntry *
Entry = FileAndReplacements.first;
143 auto &Replacements = FileAndReplacements.second;
144 assert(Entry !=
nullptr &&
"No file entry!");
146 std::vector<tooling::Range> Conflicts;
147 tooling::deduplicate(FileAndReplacements.second, Conflicts);
149 if (Conflicts.empty())
152 conflictsFound =
true;
154 errs() <<
"There are conflicting changes to " << Entry->getName() <<
":\n";
157 auto ConflictingReplacements = llvm::makeArrayRef(
158 &Replacements[Conflict.getOffset()], Conflict.getLength());
163 return conflictsFound;
168 clang::SourceManager &
SM) {
171 std::set<StringRef> Warned;
172 for (
const auto &TU : TUs) {
173 for (
const tooling::Replacement &R : TU.Replacements) {
176 const FileEntry *
Entry = SM.getFileManager().getFile(R.getFilePath());
177 if (!Entry && Warned.insert(R.getFilePath()).second) {
178 errs() <<
"Described file '" << R.getFilePath()
179 <<
"' doesn't exist. Ignoring...\n";
182 GroupedReplacements[Entry].push_back(R);
191 clang::Rewriter &Rewrites) {
199 for (
const auto &FileAndReplacements : GroupedReplacements) {
200 if (!tooling::applyAllReplacements(FileAndReplacements.second, Rewrites))
208 const std::vector<clang::tooling::Replacement> &Replaces) {
213 for (
const tooling::Replacement &R : Replaces) {
214 unsigned Offset = R.getOffset() + Shift;
215 unsigned Length = R.getReplacementText().size();
216 Shift += Length - R.getLength();
220 return ChangedRanges;
225 for (Rewriter::const_buffer_iterator BufferI = Rewrites.buffer_begin(),
226 BufferE = Rewrites.buffer_end();
227 BufferI != BufferE; ++BufferI) {
228 const char *FileName =
229 Rewrites.getSourceMgr().getFileEntryForID(BufferI->first)->getName();
232 llvm::raw_fd_ostream FileStream(FileName, EC, llvm::sys::fs::F_Text);
234 errs() <<
"Warning: Could not write to " << EC.message() <<
"\n";
237 BufferI->second.write(FileStream);
244 clang::DiagnosticsEngine &Diagnostics) {
246 for (
const auto &
Filename : Files) {
247 std::error_code Error = llvm::sys::fs::remove(
Filename);
251 errs() <<
"Error deleting file: " <<
Filename <<
"\n";
252 errs() << Error.message() <<
"\n";
253 errs() <<
"Please delete the file manually\n";
static bool deduplicateAndDetectConflicts(FileToReplacementsMap &Replacements, SourceManager &SM)
Deduplicates and tests for conflicts among the replacements for each file in Replacements.
static void reportConflict(const FileEntry *File, const llvm::ArrayRef< clang::tooling::Replacement > ConflictingReplacements, SourceManager &SM)
Dumps information for a sequence of conflicting Replacements.
llvm::DenseMap< const clang::FileEntry *, std::vector< clang::tooling::Replacement > > FileToReplacementsMap
Map mapping file name to Replacements targeting that file.
bool deleteReplacementFiles(const TUReplacementFiles &Files, clang::DiagnosticsEngine &Diagnostics)
Delete the replacement files.
std::vector< clang::tooling::TranslationUnitReplacements > TUReplacements
Collection of TranslationUnitReplacements.
static void eatDiagnostics(const SMDiagnostic &, void *)
std::error_code collectReplacementsFromDirectory(const llvm::StringRef Directory, TUReplacements &TUs, TUReplacementFiles &TURFiles, clang::DiagnosticsEngine &Diagnostics)
Recursively descends through a directory structure rooted at Directory and attempts to deserialize *...
bool writeFiles(const clang::Rewriter &Rewrites)
Write the contents of FileContents to disk.
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
std::string Filename
Filename as a string.
std::vector< clang::tooling::Range > RangeVector
Collection of source ranges.
RangeVector calculateChangedRanges(const std::vector< clang::tooling::Replacement > &Replacements)
Given a collection of Replacements for a single file, produces a list of source ranges that enclose t...
CharSourceRange Range
SourceRange for the file name.
This file provides the interface for deduplicating, detecting conflicts in, and applying collections ...
std::vector< std::string > TUReplacementFiles
Collection of TranslationUnitReplacement files.
bool mergeAndDeduplicate(const TUReplacements &TUs, FileToReplacementsMap &GroupedReplacements, clang::SourceManager &SM)
Deduplicate, check for conflicts, and apply all Replacements stored in TUs.
static bool applyReplacements(const std::vector< tooling::Replacement > &Replacements, std::string &Result, DiagnosticsEngine &Diagnostics)
Apply Replacements and return the new file contents.