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/StringSet.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"
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 TUFiles.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;
88 using namespace llvm::sys::fs;
89 using namespace llvm::sys::path;
91 std::error_code ErrorCode;
93 for (recursive_directory_iterator I(
Directory, ErrorCode),
E;
94 I !=
E && !ErrorCode; I.increment(ErrorCode)) {
95 if (filename(I->path())[0] ==
'.') {
101 if (extension(I->path()) !=
".yaml")
104 TUFiles.push_back(I->path());
106 ErrorOr<std::unique_ptr<MemoryBuffer>>
Out =
107 MemoryBuffer::getFile(I->path());
108 if (std::error_code BufferError =
Out.getError()) {
109 errs() <<
"Error reading " << I->path() <<
": " << BufferError.message()
115 tooling::TranslationUnitDiagnostics TU;
141static llvm::DenseMap<FileEntryRef, std::vector<tooling::Replacement>>
143 const clang::SourceManager &SM) {
144 llvm::StringSet<> Warned;
145 llvm::DenseMap<FileEntryRef, std::vector<tooling::Replacement>>
151 llvm::DenseMap<
const FileEntry *,
152 std::map<tooling::Replacement,
153 const tooling::TranslationUnitDiagnostics *>>
156 auto AddToGroup = [&](
const tooling::Replacement &R,
157 const tooling::TranslationUnitDiagnostics *SourceTU,
158 const std::optional<std::string> BuildDir) {
162 SmallString<128>
Path = R.getFilePath();
164 llvm::sys::fs::make_absolute(*BuildDir,
Path);
166 SM.getFileManager().makeAbsolutePath(
Path);
168 if (
auto Entry = SM.getFileManager().getOptionalFileRef(
Path)) {
170 auto &Replaces = DiagReplacements[*
Entry];
171 auto It = Replaces.find(R);
172 if (It == Replaces.end())
173 Replaces.emplace(R, SourceTU);
174 else if (It->second != SourceTU)
178 GroupedReplacements[*
Entry].push_back(R);
179 }
else if (Warned.insert(
Path).second) {
180 errs() <<
"Described file '" << R.getFilePath()
181 <<
"' doesn't exist. Ignoring...\n";
185 for (
const auto &TU : TUs)
186 for (
const tooling::Replacement &R : TU.Replacements)
187 AddToGroup(R,
nullptr, {});
189 for (
const auto &TU : TUDs)
190 for (
const auto &D : TU.Diagnostics)
191 if (
const auto *ChoosenFix = tooling::selectFirstFix(D)) {
192 for (
const auto &
Fix : *ChoosenFix)
193 for (
const tooling::Replacement &R :
Fix.second)
194 AddToGroup(R, &TU, D.BuildDirectory);
199 for (
auto &FileAndReplacements : GroupedReplacements) {
200 llvm::sort(FileAndReplacements.second);
203 return GroupedReplacements;
210 bool ConflictDetected =
false;
214 for (
const auto &FileAndReplacements : GroupedReplacements) {
215 FileEntryRef
Entry = FileAndReplacements.first;
216 const SourceLocation BeginLoc =
217 SM.getLocForStartOfFile(SM.getOrCreateFileID(
Entry, SrcMgr::C_User));
218 tooling::AtomicChange FileChange(
Entry.getName(),
Entry.getName());
219 for (
const auto &R : FileAndReplacements.second) {
221 FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
222 R.getLength(), R.getReplacementText());
236 errs() << llvm::toString(std::move(Err)) <<
"\n";
238 tooling::Replacements &Replacements = FileChange.getReplacements();
240 Replacements.getShiftedCodePosition(R.getOffset());
241 unsigned NewLength = Replacements.getShiftedCodePosition(
242 R.getOffset() + R.getLength()) -
244 if (NewLength == R.getLength()) {
245 tooling::Replacement RR = tooling::Replacement(
246 R.getFilePath(), NewOffset, NewLength, R.getReplacementText());
247 Replacements = Replacements.merge(tooling::Replacements(RR));
250 <<
"Can't resolve conflict, skipping the replacement.\n";
251 ConflictDetected =
true;
254 ConflictDetected =
true;
257 FileChanges.try_emplace(
Entry,
258 std::vector<tooling::AtomicChange>{FileChange});
261 return !ConflictDetected;
264llvm::Expected<std::string>
266 const tooling::ApplyChangesSpec &Spec,
268 FileManager Files((FileSystemOptions()));
271 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
272 SM.getFileManager().getBufferForFile(File);
274 return errorCodeToError(Buffer.getError());
275 return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(),
Changes,
282 for (
const auto &
Filename : Files) {
287 errs() <<
"Error deleting file: " <<
Filename <<
"\n";
288 errs() <<
Error.message() <<
"\n";
289 errs() <<
"Please delete the file manually\n";
static void eatDiagnostics(const SMDiagnostic &, void *)
This file provides the interface for deduplicating, detecting conflicts in, and applying collections ...
static cl::opt< bool > IgnoreInsertConflict("ignore-insert-conflict", cl::desc("Ignore insert conflict and keep running to fix."), cl::init(false), cl::cat(ReplacementCategory))
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
static constexpr llvm::SourceMgr::DiagKind Error
CompiledFragmentImpl & Out
std::string Filename
Filename as a string.
std::vector< HeaderHandle > Path
llvm::StringRef Directory
WantDiagnostics Diagnostics
llvm::DenseMap< clang::FileEntryRef, std::vector< tooling::AtomicChange > > FileToChangesMap
Map mapping file name to a set of AtomicChange targeting that file.
bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs, FileToChangesMap &FileChanges, clang::SourceManager &SM, bool IgnoreInsertConflict=false)
Deduplicate, check for conflicts, and extract all Replacements stored in TUs.
static llvm::DenseMap< FileEntryRef, std::vector< tooling::Replacement > > groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs, const clang::SourceManager &SM)
Extract replacements from collected TranslationUnitReplacements and TranslationUnitDiagnostics and gr...
bool deleteReplacementFiles(const TUReplacementFiles &Files, clang::DiagnosticsEngine &Diagnostics)
Delete the replacement files.
std::vector< clang::tooling::TranslationUnitReplacements > TUReplacements
Collection of TranslationUnitReplacements.
std::vector< std::string > TUReplacementFiles
Collection of TranslationUnitReplacement files.
std::error_code collectReplacementsFromDirectory(const llvm::StringRef Directory, TUReplacements &TUs, TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics)
Recursively descends through a directory structure rooted at Directory and attempts to deserialize *....
llvm::Expected< std::string > applyChanges(StringRef File, const std::vector< tooling::AtomicChange > &Changes, const tooling::ApplyChangesSpec &Spec, DiagnosticsEngine &Diagnostics)
Apply AtomicChange on File and rewrite it.
std::vector< clang::tooling::TranslationUnitDiagnostics > TUDiagnostics
Collection of TranslationUniDiagnostics.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.