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/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;
47 for (recursive_directory_iterator I(Directory, ErrorCode), E;
48 I != E && !
ErrorCode; I.increment(ErrorCode)) {
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;
91 for (recursive_directory_iterator I(Directory, ErrorCode), E;
92 I != E && !
ErrorCode; I.increment(ErrorCode)) {
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()
112 yaml::Input YIn(Out.get()->getBuffer(),
nullptr, &
eatDiagnostics);
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>>
148 llvm::DenseMap<const FileEntry *, std::set<tooling::Replacement>>
151 auto AddToGroup = [&](
const tooling::Replacement &R,
bool FromDiag) {
154 if (
const FileEntry *
Entry = SM.getFileManager().getFile(R.getFilePath())) {
156 auto &Replaces = DiagReplacements[
Entry];
157 if (!Replaces.insert(R).second)
160 GroupedReplacements[
Entry].push_back(R);
161 }
else if (Warned.insert(R.getFilePath()).second) {
162 errs() <<
"Described file '" << R.getFilePath()
163 <<
"' doesn't exist. Ignoring...\n";
167 for (
const auto &TU : TUs)
168 for (
const tooling::Replacement &R : TU.Replacements)
169 AddToGroup(R,
false);
171 for (
const auto &TU : TUDs)
172 for (
const auto &
D : TU.Diagnostics)
173 for (
const auto &
Fix :
D.Fix)
174 for (
const tooling::Replacement &R :
Fix.second)
179 for (
auto &FileAndReplacements : GroupedReplacements) {
180 llvm::sort(FileAndReplacements.second.begin(),
181 FileAndReplacements.second.end());
184 return GroupedReplacements;
189 clang::SourceManager &SM) {
191 bool ConflictDetected =
false;
195 for (
const auto &FileAndReplacements : GroupedReplacements) {
196 const FileEntry *
Entry = FileAndReplacements.first;
197 const SourceLocation BeginLoc =
198 SM.getLocForStartOfFile(SM.getOrCreateFileID(Entry, SrcMgr::C_User));
199 tooling::AtomicChange FileChange(Entry->getName(), Entry->getName());
200 for (
const auto &R : FileAndReplacements.second) {
202 FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
203 R.getLength(), R.getReplacementText());
218 ConflictDetected =
true;
221 FileChanges.try_emplace(Entry,
222 std::vector<tooling::AtomicChange>{FileChange});
225 return !ConflictDetected;
228 llvm::Expected<std::string>
229 applyChanges(StringRef File,
const std::vector<tooling::AtomicChange> &Changes,
230 const tooling::ApplyChangesSpec &Spec,
231 DiagnosticsEngine &Diagnostics) {
232 FileManager Files((FileSystemOptions()));
233 SourceManager SM(Diagnostics, Files);
235 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
236 SM.getFileManager().getBufferForFile(File);
238 return errorCodeToError(Buffer.getError());
239 return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(), Changes,
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";
Some operations such as code completion produce a set of candidates.
bool deleteReplacementFiles(const TUReplacementFiles &Files, clang::DiagnosticsEngine &Diagnostics)
Delete the replacement files.
std::vector< clang::tooling::TranslationUnitReplacements > TUReplacements
Collection of TranslationUnitReplacements.
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
static void eatDiagnostics(const SMDiagnostic &, void *)
static llvm::DenseMap< const FileEntry *, std::vector< tooling::Replacement > > groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs, const clang::SourceManager &SM)
Extract replacements from collected TranslationUnitReplacements and TranslationUnitDiagnostics and gr...
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
std::string Filename
Filename as a string.
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::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 *...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs, FileToChangesMap &FileChanges, clang::SourceManager &SM)
Deduplicate, check for conflicts, and extract all Replacements stored in TUs.
This file provides the interface for deduplicating, detecting conflicts in, and applying collections ...
std::vector< clang::tooling::TranslationUnitDiagnostics > TUDiagnostics
Collection of TranslationUniDiagnostics.
std::vector< std::string > TUReplacementFiles
Collection of TranslationUnitReplacement files.
static cl::opt< bool > Fix("fix", cl::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))
llvm::DenseMap< const clang::FileEntry *, std::vector< tooling::AtomicChange > > FileToChangesMap
Map mapping file name to a set of AtomicChange targeting that file.