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/Support/FileSystem.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/raw_ostream.h"
32 using namespace clang;
42 using namespace llvm::sys::fs;
43 using namespace llvm::sys::path;
49 if (filename(I->path())[0] ==
'.') {
55 if (extension(I->path()) !=
".yaml")
58 TUFiles.push_back(I->path());
60 ErrorOr<std::unique_ptr<MemoryBuffer>>
Out =
61 MemoryBuffer::getFile(I->path());
62 if (std::error_code BufferError =
Out.getError()) {
63 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
69 tooling::TranslationUnitReplacements TU;
86 using namespace llvm::sys::fs;
87 using namespace llvm::sys::path;
93 if (filename(I->path())[0] ==
'.') {
99 if (extension(I->path()) !=
".yaml")
102 TUFiles.push_back(I->path());
104 ErrorOr<std::unique_ptr<MemoryBuffer>>
Out =
105 MemoryBuffer::getFile(I->path());
106 if (std::error_code BufferError =
Out.getError()) {
107 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
113 tooling::TranslationUnitDiagnostics TU;
139 static llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
141 const clang::SourceManager &SM) {
142 std::set<StringRef> Warned;
143 llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
149 llvm::DenseMap<
const FileEntry *,
150 std::map<tooling::Replacement,
151 const tooling::TranslationUnitDiagnostics *>>
154 auto AddToGroup = [&](
const tooling::Replacement &R,
155 const tooling::TranslationUnitDiagnostics *SourceTU) {
158 if (
auto Entry = SM.getFileManager().getFile(R.getFilePath())) {
160 auto &Replaces = DiagReplacements[*
Entry];
161 auto It = Replaces.find(R);
162 if (It == Replaces.end())
163 Replaces.emplace(R, SourceTU);
164 else if (It->second != SourceTU)
168 GroupedReplacements[*
Entry].push_back(R);
169 }
else if (Warned.insert(R.getFilePath()).second) {
170 errs() <<
"Described file '" << R.getFilePath()
171 <<
"' doesn't exist. Ignoring...\n";
175 for (
const auto &TU : TUs)
176 for (
const tooling::Replacement &R : TU.Replacements)
177 AddToGroup(R,
nullptr);
179 for (
const auto &TU : TUDs)
180 for (
const auto &D : TU.Diagnostics)
181 if (
const auto *ChoosenFix = tooling::selectFirstFix(D)) {
182 for (
const auto &
Fix : *ChoosenFix)
183 for (
const tooling::Replacement &R :
Fix.second)
189 for (
auto &FileAndReplacements : GroupedReplacements) {
190 llvm::sort(FileAndReplacements.second.begin(),
191 FileAndReplacements.second.end());
194 return GroupedReplacements;
199 clang::SourceManager &SM) {
201 bool ConflictDetected =
false;
205 for (
const auto &FileAndReplacements : GroupedReplacements) {
206 const FileEntry *
Entry = FileAndReplacements.first;
207 const SourceLocation BeginLoc =
208 SM.getLocForStartOfFile(SM.getOrCreateFileID(
Entry, SrcMgr::C_User));
209 tooling::AtomicChange FileChange(
Entry->getName(),
Entry->getName());
210 for (
const auto &R : FileAndReplacements.second) {
212 FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
213 R.getLength(), R.getReplacementText());
228 ConflictDetected =
true;
231 FileChanges.try_emplace(
Entry,
232 std::vector<tooling::AtomicChange>{FileChange});
235 return !ConflictDetected;
238 llvm::Expected<std::string>
240 const tooling::ApplyChangesSpec &Spec,
241 DiagnosticsEngine &Diagnostics) {
242 FileManager Files((FileSystemOptions()));
243 SourceManager SM(Diagnostics, Files);
245 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
246 SM.getFileManager().getBufferForFile(File);
248 return errorCodeToError(Buffer.getError());
249 return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(),
Changes,
254 clang::DiagnosticsEngine &Diagnostics) {
256 for (
const auto &
Filename : Files) {
257 std::error_code Error = llvm::sys::fs::remove(
Filename);
261 errs() <<
"Error deleting file: " <<
Filename <<
"\n";
262 errs() << Error.message() <<
"\n";
263 errs() <<
"Please delete the file manually\n";