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;
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 if (
const auto *ChoosenFix = tooling::selectFirstFix(
D)) {
174 for (
const auto &
Fix : *ChoosenFix)
175 for (
const tooling::Replacement &R :
Fix.second)
181 for (
auto &FileAndReplacements : GroupedReplacements) {
182 llvm::sort(FileAndReplacements.second.begin(),
183 FileAndReplacements.second.end());
186 return GroupedReplacements;
191 clang::SourceManager &SM) {
193 bool ConflictDetected =
false;
197 for (
const auto &FileAndReplacements : GroupedReplacements) {
198 const FileEntry *
Entry = FileAndReplacements.first;
199 const SourceLocation BeginLoc =
200 SM.getLocForStartOfFile(SM.getOrCreateFileID(Entry, SrcMgr::C_User));
201 tooling::AtomicChange FileChange(Entry->getName(), Entry->getName());
202 for (
const auto &R : FileAndReplacements.second) {
204 FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
205 R.getLength(), R.getReplacementText());
220 ConflictDetected =
true;
223 FileChanges.try_emplace(Entry,
224 std::vector<tooling::AtomicChange>{FileChange});
227 return !ConflictDetected;
230 llvm::Expected<std::string>
232 const tooling::ApplyChangesSpec &Spec,
233 DiagnosticsEngine &Diagnostics) {
234 FileManager
Files((FileSystemOptions()));
235 SourceManager SM(Diagnostics, Files);
237 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
238 SM.getFileManager().getBufferForFile(File);
240 return errorCodeToError(Buffer.getError());
241 return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(),
Changes,
246 clang::DiagnosticsEngine &Diagnostics) {
248 for (
const auto &
Filename : Files) {
249 std::error_code Error = llvm::sys::fs::remove(
Filename);
253 errs() <<
"Error deleting file: " <<
Filename <<
"\n";
254 errs() << Error.message() <<
"\n";
255 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 std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle, llvm::StringRef Repl)
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...
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.
llvm::StringRef Directory
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.
llvm::StringMap< std::string > Files