17 #include "clang/Basic/LangOptions.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Format/Format.h"
20 #include "clang/Lex/Lexer.h"
21 #include "clang/Rewrite/Core/Rewriter.h"
22 #include "clang/Tooling/Core/Diagnostic.h"
23 #include "clang/Tooling/DiagnosticsYaml.h"
24 #include "clang/Tooling/ReplacementsYaml.h"
25 #include "llvm/ADT/ArrayRef.h"
26 #include "llvm/ADT/Optional.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/raw_ostream.h"
33 using namespace clang;
43 using namespace llvm::sys::fs;
44 using namespace llvm::sys::path;
50 if (filename(I->path())[0] ==
'.') {
56 if (extension(I->path()) !=
".yaml")
59 TUFiles.push_back(I->path());
61 ErrorOr<std::unique_ptr<MemoryBuffer>>
Out =
62 MemoryBuffer::getFile(I->path());
63 if (std::error_code BufferError =
Out.getError()) {
64 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
70 tooling::TranslationUnitReplacements TU;
87 using namespace llvm::sys::fs;
88 using namespace llvm::sys::path;
94 if (filename(I->path())[0] ==
'.') {
100 if (extension(I->path()) !=
".yaml")
103 TUFiles.push_back(I->path());
105 ErrorOr<std::unique_ptr<MemoryBuffer>>
Out =
106 MemoryBuffer::getFile(I->path());
107 if (std::error_code BufferError =
Out.getError()) {
108 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
114 tooling::TranslationUnitDiagnostics TU;
140 static llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
142 const clang::SourceManager &SM) {
143 std::set<StringRef> Warned;
144 llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
150 llvm::DenseMap<
const FileEntry *,
151 std::map<tooling::Replacement,
152 const tooling::TranslationUnitDiagnostics *>>
155 auto AddToGroup = [&](
const tooling::Replacement &R,
156 const tooling::TranslationUnitDiagnostics *SourceTU,
157 const llvm::Optional<std::string> BuildDir) {
160 auto PrevWorkingDir = SM.getFileManager().getFileSystemOpts().WorkingDir;
162 SM.getFileManager().getFileSystemOpts().WorkingDir = std::move(*BuildDir);
163 if (
auto Entry = SM.getFileManager().getFile(R.getFilePath())) {
165 auto &Replaces = DiagReplacements[*
Entry];
166 auto It = Replaces.find(R);
167 if (It == Replaces.end())
168 Replaces.emplace(R, SourceTU);
169 else if (It->second != SourceTU)
173 GroupedReplacements[*
Entry].push_back(R);
174 }
else if (Warned.insert(R.getFilePath()).second) {
175 errs() <<
"Described file '" << R.getFilePath()
176 <<
"' doesn't exist. Ignoring...\n";
178 SM.getFileManager().getFileSystemOpts().WorkingDir = PrevWorkingDir;
181 for (
const auto &TU : TUs)
182 for (
const tooling::Replacement &R : TU.Replacements)
183 AddToGroup(R,
nullptr, {});
185 for (
const auto &TU : TUDs)
186 for (
const auto &
D : TU.Diagnostics)
187 if (
const auto *ChoosenFix = tooling::selectFirstFix(
D)) {
188 for (
const auto &
Fix : *ChoosenFix)
189 for (
const tooling::Replacement &R :
Fix.second)
190 AddToGroup(R, &TU,
D.BuildDirectory);
195 for (
auto &FileAndReplacements : GroupedReplacements) {
196 llvm::sort(FileAndReplacements.second.begin(),
197 FileAndReplacements.second.end());
200 return GroupedReplacements;
205 clang::SourceManager &SM) {
207 bool ConflictDetected =
false;
211 for (
const auto &FileAndReplacements : GroupedReplacements) {
212 const FileEntry *
Entry = FileAndReplacements.first;
213 const SourceLocation BeginLoc =
214 SM.getLocForStartOfFile(SM.getOrCreateFileID(
Entry, SrcMgr::C_User));
215 tooling::AtomicChange FileChange(
Entry->getName(),
Entry->getName());
216 for (
const auto &R : FileAndReplacements.second) {
218 FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
219 R.getLength(), R.getReplacementText());
234 ConflictDetected =
true;
237 FileChanges.try_emplace(
Entry,
238 std::vector<tooling::AtomicChange>{FileChange});
241 return !ConflictDetected;
244 llvm::Expected<std::string>
246 const tooling::ApplyChangesSpec &Spec,
248 FileManager
Files((FileSystemOptions()));
251 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
252 SM.getFileManager().getBufferForFile(File);
254 return errorCodeToError(Buffer.getError());
255 return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(),
Changes,
263 std::error_code Error = llvm::sys::fs::remove(
Filename);
267 errs() <<
"Error deleting file: " <<
Filename <<
"\n";
268 errs() << Error.message() <<
"\n";
269 errs() <<
"Please delete the file manually\n";