2013-08-30 22:33:56 +08:00
|
|
|
//===-- ApplyReplacements.cpp - Apply and deduplicate replacements --------===//
|
2013-08-22 21:07:14 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-08-22 21:07:14 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
Remove \brief commands from doxygen comments.
Summary:
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
[This is analogous to LLVM r331272 and CFE r331834]
Subscribers: srhines, nemanjai, javed.absar, kbarton, MaskRay, jkorous, arphaman, jfb, kadircet, jsji, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66578
llvm-svn: 369643
2019-08-22 19:32:57 +08:00
|
|
|
/// This file provides the implementation for deduplicating, detecting
|
2013-08-30 22:33:56 +08:00
|
|
|
/// conflicts in, and applying collections of Replacements.
|
|
|
|
///
|
|
|
|
/// FIXME: Use Diagnostics for output instead of llvm::errs().
|
2013-08-22 21:07:14 +08:00
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-09-04 01:58:19 +08:00
|
|
|
#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
|
2013-08-22 21:07:14 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
2013-09-30 21:59:21 +08:00
|
|
|
#include "clang/Format/Format.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
2013-08-22 21:40:32 +08:00
|
|
|
#include "clang/Rewrite/Core/Rewriter.h"
|
[clang-tidy] Add fix descriptions to clang-tidy checks.
Summary:
Motivation/Context: in the code review system integrating with clang-tidy,
clang-tidy doesn't provide a human-readable description of the fix. Usually
developers have to preview a code diff (before vs after apply the fix) to
understand what the fix does before applying a fix.
This patch proposes that each clang-tidy check provides a short and
actional fix description that can be shown in the UI, so that users can know
what the fix does without previewing diff.
This patch extends clang-tidy framework to support fix descriptions (will add implementations for
existing checks in the future). Fix descriptions and fixes are emitted via diagnostic::Note (rather than
attaching the main warning diagnostic).
Before this patch:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning") << FixtItHint::CreateReplacement(...);
}
```
After:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning"); // Emit a check warning
diag(loc, "fix description", DiagnosticIDs::Note) << FixtItHint::CreateReplacement(...); // Emit a diagnostic note and a fix
}
```
Reviewers: sammccall, alexfh
Reviewed By: alexfh
Subscribers: MyDeveloperDay, Eugene.Zelenko, aaron.ballman, JonasToth, xazax.hun, jdoerfert, cfe-commits
Tags: #clang-tools-extra, #clang
Differential Revision: https://reviews.llvm.org/D59932
llvm-svn: 358576
2019-04-17 20:53:59 +08:00
|
|
|
#include "clang/Tooling/Core/Diagnostic.h"
|
2017-01-03 22:36:13 +08:00
|
|
|
#include "clang/Tooling/DiagnosticsYaml.h"
|
2013-08-29 01:19:10 +08:00
|
|
|
#include "clang/Tooling/ReplacementsYaml.h"
|
2013-08-22 21:07:14 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
static void eatDiagnostics(const SMDiagnostic &, void *) {}
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace replace {
|
|
|
|
|
2016-11-08 15:50:19 +08:00
|
|
|
std::error_code collectReplacementsFromDirectory(
|
|
|
|
const llvm::StringRef Directory, TUReplacements &TUs,
|
2017-01-03 22:36:13 +08:00
|
|
|
TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics) {
|
2013-08-22 21:07:14 +08:00
|
|
|
using namespace llvm::sys::fs;
|
|
|
|
using namespace llvm::sys::path;
|
|
|
|
|
2014-06-13 06:08:48 +08:00
|
|
|
std::error_code ErrorCode;
|
2013-08-22 21:07:14 +08:00
|
|
|
|
|
|
|
for (recursive_directory_iterator I(Directory, ErrorCode), E;
|
|
|
|
I != E && !ErrorCode; I.increment(ErrorCode)) {
|
|
|
|
if (filename(I->path())[0] == '.') {
|
|
|
|
// Indicate not to descend into directories beginning with '.'
|
|
|
|
I.no_push();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extension(I->path()) != ".yaml")
|
|
|
|
continue;
|
|
|
|
|
2017-01-03 22:36:13 +08:00
|
|
|
TUFiles.push_back(I->path());
|
2013-08-27 03:58:59 +08:00
|
|
|
|
2014-07-07 01:43:19 +08:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
|
|
|
|
MemoryBuffer::getFile(I->path());
|
|
|
|
if (std::error_code BufferError = Out.getError()) {
|
2013-08-22 21:07:14 +08:00
|
|
|
errs() << "Error reading " << I->path() << ": " << BufferError.message()
|
|
|
|
<< "\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-07 01:43:19 +08:00
|
|
|
yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
|
2013-08-22 21:07:14 +08:00
|
|
|
tooling::TranslationUnitReplacements TU;
|
|
|
|
YIn >> TU;
|
|
|
|
if (YIn.error()) {
|
|
|
|
// File doesn't appear to be a header change description. Ignore it.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only keep files that properly parse.
|
|
|
|
TUs.push_back(TU);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
std::error_code collectReplacementsFromDirectory(
|
|
|
|
const llvm::StringRef Directory, TUDiagnostics &TUs,
|
|
|
|
TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics) {
|
2017-01-03 22:36:13 +08:00
|
|
|
using namespace llvm::sys::fs;
|
|
|
|
using namespace llvm::sys::path;
|
|
|
|
|
|
|
|
std::error_code ErrorCode;
|
|
|
|
|
|
|
|
for (recursive_directory_iterator I(Directory, ErrorCode), E;
|
|
|
|
I != E && !ErrorCode; I.increment(ErrorCode)) {
|
|
|
|
if (filename(I->path())[0] == '.') {
|
|
|
|
// Indicate not to descend into directories beginning with '.'
|
|
|
|
I.no_push();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extension(I->path()) != ".yaml")
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TUFiles.push_back(I->path());
|
|
|
|
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
|
|
|
|
MemoryBuffer::getFile(I->path());
|
|
|
|
if (std::error_code BufferError = Out.getError()) {
|
|
|
|
errs() << "Error reading " << I->path() << ": " << BufferError.message()
|
|
|
|
<< "\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
|
|
|
|
tooling::TranslationUnitDiagnostics TU;
|
|
|
|
YIn >> TU;
|
|
|
|
if (YIn.error()) {
|
|
|
|
// File doesn't appear to be a header change description. Ignore it.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only keep files that properly parse.
|
|
|
|
TUs.push_back(TU);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
|
Remove \brief commands from doxygen comments.
Summary:
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
[This is analogous to LLVM r331272 and CFE r331834]
Subscribers: srhines, nemanjai, javed.absar, kbarton, MaskRay, jkorous, arphaman, jfb, kadircet, jsji, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66578
llvm-svn: 369643
2019-08-22 19:32:57 +08:00
|
|
|
/// Extract replacements from collected TranslationUnitReplacements and
|
2018-09-25 16:24:07 +08:00
|
|
|
/// TranslationUnitDiagnostics and group them per file. Identical replacements
|
|
|
|
/// from diagnostics are deduplicated.
|
2013-08-22 21:07:14 +08:00
|
|
|
///
|
2018-04-11 22:39:17 +08:00
|
|
|
/// \param[in] TUs Collection of all found and deserialized
|
|
|
|
/// TranslationUnitReplacements.
|
|
|
|
/// \param[in] TUDs Collection of all found and deserialized
|
|
|
|
/// TranslationUnitDiagnostics.
|
|
|
|
/// \param[in] SM Used to deduplicate paths.
|
2013-08-22 21:07:14 +08:00
|
|
|
///
|
2018-04-11 22:39:17 +08:00
|
|
|
/// \returns A map mapping FileEntry to a set of Replacement targeting that
|
|
|
|
/// file.
|
|
|
|
static llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
|
|
|
|
groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
|
|
|
|
const clang::SourceManager &SM) {
|
2014-09-09 21:53:51 +08:00
|
|
|
std::set<StringRef> Warned;
|
2018-04-11 22:39:17 +08:00
|
|
|
llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
|
|
|
|
GroupedReplacements;
|
|
|
|
|
2020-03-23 21:42:17 +08:00
|
|
|
// Deduplicate identical replacements in diagnostics unless they are from the
|
|
|
|
// same TU.
|
2018-09-25 16:24:07 +08:00
|
|
|
// FIXME: Find an efficient way to deduplicate on diagnostics level.
|
2020-03-23 21:42:17 +08:00
|
|
|
llvm::DenseMap<const FileEntry *,
|
|
|
|
std::map<tooling::Replacement,
|
|
|
|
const tooling::TranslationUnitDiagnostics *>>
|
2018-09-25 16:24:07 +08:00
|
|
|
DiagReplacements;
|
|
|
|
|
2020-03-23 21:42:17 +08:00
|
|
|
auto AddToGroup = [&](const tooling::Replacement &R,
|
|
|
|
const tooling::TranslationUnitDiagnostics *SourceTU) {
|
2018-04-11 22:39:17 +08:00
|
|
|
// Use the file manager to deduplicate paths. FileEntries are
|
|
|
|
// automatically canonicalized.
|
2019-08-02 05:32:01 +08:00
|
|
|
if (auto Entry = SM.getFileManager().getFile(R.getFilePath())) {
|
2020-03-23 21:42:17 +08:00
|
|
|
if (SourceTU) {
|
2019-08-02 05:32:01 +08:00
|
|
|
auto &Replaces = DiagReplacements[*Entry];
|
2020-03-23 21:42:17 +08:00
|
|
|
auto It = Replaces.find(R);
|
|
|
|
if (It == Replaces.end())
|
|
|
|
Replaces.emplace(R, SourceTU);
|
|
|
|
else if (It->second != SourceTU)
|
|
|
|
// This replacement is a duplicate of one suggested by another TU.
|
2018-09-25 16:24:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-08-02 05:32:01 +08:00
|
|
|
GroupedReplacements[*Entry].push_back(R);
|
2018-04-11 22:39:17 +08:00
|
|
|
} else if (Warned.insert(R.getFilePath()).second) {
|
|
|
|
errs() << "Described file '" << R.getFilePath()
|
|
|
|
<< "' doesn't exist. Ignoring...\n";
|
2014-09-09 21:53:51 +08:00
|
|
|
}
|
2018-04-11 22:39:17 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto &TU : TUs)
|
|
|
|
for (const tooling::Replacement &R : TU.Replacements)
|
2020-03-23 21:42:17 +08:00
|
|
|
AddToGroup(R, nullptr);
|
2018-04-11 22:39:17 +08:00
|
|
|
|
|
|
|
for (const auto &TU : TUDs)
|
|
|
|
for (const auto &D : TU.Diagnostics)
|
[clang-tidy] Add fix descriptions to clang-tidy checks.
Summary:
Motivation/Context: in the code review system integrating with clang-tidy,
clang-tidy doesn't provide a human-readable description of the fix. Usually
developers have to preview a code diff (before vs after apply the fix) to
understand what the fix does before applying a fix.
This patch proposes that each clang-tidy check provides a short and
actional fix description that can be shown in the UI, so that users can know
what the fix does without previewing diff.
This patch extends clang-tidy framework to support fix descriptions (will add implementations for
existing checks in the future). Fix descriptions and fixes are emitted via diagnostic::Note (rather than
attaching the main warning diagnostic).
Before this patch:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning") << FixtItHint::CreateReplacement(...);
}
```
After:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning"); // Emit a check warning
diag(loc, "fix description", DiagnosticIDs::Note) << FixtItHint::CreateReplacement(...); // Emit a diagnostic note and a fix
}
```
Reviewers: sammccall, alexfh
Reviewed By: alexfh
Subscribers: MyDeveloperDay, Eugene.Zelenko, aaron.ballman, JonasToth, xazax.hun, jdoerfert, cfe-commits
Tags: #clang-tools-extra, #clang
Differential Revision: https://reviews.llvm.org/D59932
llvm-svn: 358576
2019-04-17 20:53:59 +08:00
|
|
|
if (const auto *ChoosenFix = tooling::selectFirstFix(D)) {
|
|
|
|
for (const auto &Fix : *ChoosenFix)
|
|
|
|
for (const tooling::Replacement &R : Fix.second)
|
2020-03-23 21:42:17 +08:00
|
|
|
AddToGroup(R, &TU);
|
[clang-tidy] Add fix descriptions to clang-tidy checks.
Summary:
Motivation/Context: in the code review system integrating with clang-tidy,
clang-tidy doesn't provide a human-readable description of the fix. Usually
developers have to preview a code diff (before vs after apply the fix) to
understand what the fix does before applying a fix.
This patch proposes that each clang-tidy check provides a short and
actional fix description that can be shown in the UI, so that users can know
what the fix does without previewing diff.
This patch extends clang-tidy framework to support fix descriptions (will add implementations for
existing checks in the future). Fix descriptions and fixes are emitted via diagnostic::Note (rather than
attaching the main warning diagnostic).
Before this patch:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning") << FixtItHint::CreateReplacement(...);
}
```
After:
```
void MyCheck::check(...) {
...
diag(loc, "my check warning"); // Emit a check warning
diag(loc, "fix description", DiagnosticIDs::Note) << FixtItHint::CreateReplacement(...); // Emit a diagnostic note and a fix
}
```
Reviewers: sammccall, alexfh
Reviewed By: alexfh
Subscribers: MyDeveloperDay, Eugene.Zelenko, aaron.ballman, JonasToth, xazax.hun, jdoerfert, cfe-commits
Tags: #clang-tools-extra, #clang
Differential Revision: https://reviews.llvm.org/D59932
llvm-svn: 358576
2019-04-17 20:53:59 +08:00
|
|
|
}
|
2018-04-11 22:39:17 +08:00
|
|
|
|
|
|
|
// Sort replacements per file to keep consistent behavior when
|
|
|
|
// clang-apply-replacements run on differents machine.
|
|
|
|
for (auto &FileAndReplacements : GroupedReplacements) {
|
|
|
|
llvm::sort(FileAndReplacements.second.begin(),
|
|
|
|
FileAndReplacements.second.end());
|
2014-09-09 21:53:51 +08:00
|
|
|
}
|
2013-08-22 21:07:14 +08:00
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
return GroupedReplacements;
|
2013-08-22 21:07:14 +08:00
|
|
|
}
|
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs,
|
|
|
|
FileToChangesMap &FileChanges,
|
2017-01-03 22:36:13 +08:00
|
|
|
clang::SourceManager &SM) {
|
2018-04-11 22:39:17 +08:00
|
|
|
auto GroupedReplacements = groupReplacements(TUs, TUDs, SM);
|
|
|
|
bool ConflictDetected = false;
|
2017-01-03 22:36:13 +08:00
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
// To report conflicting replacements on corresponding file, all replacements
|
|
|
|
// are stored into 1 big AtomicChange.
|
|
|
|
for (const auto &FileAndReplacements : GroupedReplacements) {
|
|
|
|
const FileEntry *Entry = FileAndReplacements.first;
|
|
|
|
const SourceLocation BeginLoc =
|
|
|
|
SM.getLocForStartOfFile(SM.getOrCreateFileID(Entry, SrcMgr::C_User));
|
|
|
|
tooling::AtomicChange FileChange(Entry->getName(), Entry->getName());
|
|
|
|
for (const auto &R : FileAndReplacements.second) {
|
|
|
|
llvm::Error Err =
|
|
|
|
FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
|
|
|
|
R.getLength(), R.getReplacementText());
|
|
|
|
if (Err) {
|
|
|
|
// FIXME: This will report conflicts by pair using a file+offset format
|
|
|
|
// which is not so much human readable.
|
|
|
|
// A first improvement could be to translate offset to line+col. For
|
2020-01-04 23:28:41 +08:00
|
|
|
// this and without loosing error message some modifications around
|
2018-04-11 22:39:17 +08:00
|
|
|
// `tooling::ReplacementError` are need (access to
|
|
|
|
// `getReplacementErrString`).
|
|
|
|
// A better strategy could be to add a pretty printer methods for
|
|
|
|
// conflict reporting. Methods that could be parameterized to report a
|
|
|
|
// conflict in different format, file+offset, file+line+col, or even
|
|
|
|
// more human readable using VCS conflict markers.
|
|
|
|
// For now, printing directly the error reported by `AtomicChange` is
|
|
|
|
// the easiest solution.
|
|
|
|
errs() << llvm::toString(std::move(Err)) << "\n";
|
|
|
|
ConflictDetected = true;
|
2017-01-03 22:36:13 +08:00
|
|
|
}
|
|
|
|
}
|
2018-04-11 22:39:17 +08:00
|
|
|
FileChanges.try_emplace(Entry,
|
|
|
|
std::vector<tooling::AtomicChange>{FileChange});
|
2017-01-03 22:36:13 +08:00
|
|
|
}
|
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
return !ConflictDetected;
|
2013-09-30 21:59:21 +08:00
|
|
|
}
|
|
|
|
|
2018-04-11 22:39:17 +08:00
|
|
|
llvm::Expected<std::string>
|
|
|
|
applyChanges(StringRef File, const std::vector<tooling::AtomicChange> &Changes,
|
|
|
|
const tooling::ApplyChangesSpec &Spec,
|
|
|
|
DiagnosticsEngine &Diagnostics) {
|
|
|
|
FileManager Files((FileSystemOptions()));
|
|
|
|
SourceManager SM(Diagnostics, Files);
|
|
|
|
|
|
|
|
llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
|
|
|
|
SM.getFileManager().getBufferForFile(File);
|
|
|
|
if (!Buffer)
|
|
|
|
return errorCodeToError(Buffer.getError());
|
|
|
|
return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(), Changes,
|
|
|
|
Spec);
|
2013-08-22 21:40:32 +08:00
|
|
|
}
|
|
|
|
|
2013-08-27 03:58:59 +08:00
|
|
|
bool deleteReplacementFiles(const TUReplacementFiles &Files,
|
|
|
|
clang::DiagnosticsEngine &Diagnostics) {
|
|
|
|
bool Success = true;
|
2014-09-09 22:09:48 +08:00
|
|
|
for (const auto &Filename : Files) {
|
|
|
|
std::error_code Error = llvm::sys::fs::remove(Filename);
|
2013-08-27 03:58:59 +08:00
|
|
|
if (Error) {
|
|
|
|
Success = false;
|
|
|
|
// FIXME: Use Diagnostics for outputting errors.
|
2014-09-09 22:09:48 +08:00
|
|
|
errs() << "Error deleting file: " << Filename << "\n";
|
2013-08-27 03:58:59 +08:00
|
|
|
errs() << Error.message() << "\n";
|
|
|
|
errs() << "Please delete the file manually\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
2013-08-22 21:07:14 +08:00
|
|
|
} // end namespace replace
|
|
|
|
} // end namespace clang
|