hokein updated this revision to Diff 193510.
hokein added a comment.
Emit the check fix description via diagnostic::note.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D59932/new/
https://reviews.llvm.org/D59932
Files:
clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
clang-tools-extra/clang-tidy/ClangTidy.cpp
clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
clang-tools-extra/test/clang-tidy/export-diagnostics.cpp
clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
clang/include/clang/Tooling/Core/Diagnostic.h
clang/include/clang/Tooling/DiagnosticsYaml.h
clang/lib/Tooling/Core/Diagnostic.cpp
clang/unittests/Tooling/DiagnosticsYamlTest.cpp
Index: clang/unittests/Tooling/DiagnosticsYamlTest.cpp
===================================================================
--- clang/unittests/Tooling/DiagnosticsYamlTest.cpp
+++ clang/unittests/Tooling/DiagnosticsYamlTest.cpp
@@ -20,11 +20,13 @@
using clang::tooling::Diagnostic;
static DiagnosticMessage makeMessage(const std::string &Message, int FileOffset,
- const std::string &FilePath) {
+ const std::string &FilePath,
+ const StringMap<Replacements> &Fix) {
DiagnosticMessage DiagMessage;
DiagMessage.Message = Message;
DiagMessage.FileOffset = FileOffset;
DiagMessage.FilePath = FilePath;
+ DiagMessage.Fix = Fix;
return DiagMessage;
}
@@ -32,10 +34,52 @@
const std::string &Message, int FileOffset,
const std::string &FilePath,
const StringMap<Replacements> &Fix) {
- return Diagnostic(DiagnosticName, makeMessage(Message, FileOffset, FilePath),
- Fix, {}, Diagnostic::Warning, "path/to/build/directory");
+ return Diagnostic(DiagnosticName,
+ makeMessage(Message, FileOffset, FilePath, Fix), {},
+ Diagnostic::Warning, "path/to/build/directory");
}
+static const char *YAMLContent =
+ "---\n"
+ "MainSourceFile: 'path/to/source.cpp'\n"
+ "Diagnostics: \n"
+ " - DiagnosticName: 'diagnostic#1\'\n"
+ " DiagnosticMessage: \n"
+ " Message: 'message #1'\n"
+ " FilePath: 'path/to/source.cpp'\n"
+ " FileOffset: 55\n"
+ " Replacements: \n"
+ " - FilePath: 'path/to/source.cpp'\n"
+ " Offset: 100\n"
+ " Length: 12\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - DiagnosticName: 'diagnostic#2'\n"
+ " DiagnosticMessage: \n"
+ " Message: 'message #2'\n"
+ " FilePath: 'path/to/header.h'\n"
+ " FileOffset: 60\n"
+ " Replacements: \n"
+ " - FilePath: 'path/to/header.h'\n"
+ " Offset: 62\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ " - DiagnosticName: 'diagnostic#3'\n"
+ " DiagnosticMessage: \n"
+ " Message: 'message #3'\n"
+ " FilePath: 'path/to/source2.cpp'\n"
+ " FileOffset: 72\n"
+ " Replacements: []\n"
+ " Notes: \n"
+ " - Message: Note1\n"
+ " FilePath: 'path/to/note1.cpp'\n"
+ " FileOffset: 88\n"
+ " Replacements: []\n"
+ " - Message: Note2\n"
+ " FilePath: 'path/to/note2.cpp'\n"
+ " FileOffset: 99\n"
+ " Replacements: []\n"
+ "...\n";
+
TEST(DiagnosticsYamlTest, serializesDiagnostics) {
TranslationUnitDiagnostics TUD;
TUD.MainSourceFile = "path/to/source.cpp";
@@ -55,9 +99,9 @@
TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#3", "message #3", 72,
"path/to/source2.cpp", {}));
TUD.Diagnostics.back().Notes.push_back(
- makeMessage("Note1", 88, "path/to/note1.cpp"));
+ makeMessage("Note1", 88, "path/to/note1.cpp", {}));
TUD.Diagnostics.back().Notes.push_back(
- makeMessage("Note2", 99, "path/to/note2.cpp"));
+ makeMessage("Note2", 99, "path/to/note2.cpp", {}));
std::string YamlContent;
raw_string_ostream YamlContentStream(YamlContent);
@@ -65,80 +109,12 @@
yaml::Output YAML(YamlContentStream);
YAML << TUD;
- EXPECT_EQ("---\n"
- "MainSourceFile: 'path/to/source.cpp'\n"
- "Diagnostics: \n"
- " - DiagnosticName: 'diagnostic#1\'\n"
- " Message: 'message #1'\n"
- " FileOffset: 55\n"
- " FilePath: 'path/to/source.cpp'\n"
- " Replacements: \n"
- " - FilePath: 'path/to/source.cpp'\n"
- " Offset: 100\n"
- " Length: 12\n"
- " ReplacementText: 'replacement #1'\n"
- " - DiagnosticName: 'diagnostic#2'\n"
- " Message: 'message #2'\n"
- " FileOffset: 60\n"
- " FilePath: 'path/to/header.h'\n"
- " Replacements: \n"
- " - FilePath: 'path/to/header.h'\n"
- " Offset: 62\n"
- " Length: 2\n"
- " ReplacementText: 'replacement #2'\n"
- " - DiagnosticName: 'diagnostic#3'\n"
- " Message: 'message #3'\n"
- " FileOffset: 72\n"
- " FilePath: 'path/to/source2.cpp'\n"
- " Notes: \n"
- " - Message: Note1\n"
- " FilePath: 'path/to/note1.cpp'\n"
- " FileOffset: 88\n"
- " - Message: Note2\n"
- " FilePath: 'path/to/note2.cpp'\n"
- " FileOffset: 99\n"
- " Replacements: []\n"
- "...\n",
- YamlContentStream.str());
+ EXPECT_EQ(YAMLContent, YamlContentStream.str());
}
TEST(DiagnosticsYamlTest, deserializesDiagnostics) {
- std::string YamlContent = "---\n"
- "MainSourceFile: path/to/source.cpp\n"
- "Diagnostics: \n"
- " - DiagnosticName: 'diagnostic#1'\n"
- " Message: 'message #1'\n"
- " FileOffset: 55\n"
- " FilePath: path/to/source.cpp\n"
- " Replacements: \n"
- " - FilePath: path/to/source.cpp\n"
- " Offset: 100\n"
- " Length: 12\n"
- " ReplacementText: 'replacement #1'\n"
- " - DiagnosticName: 'diagnostic#2'\n"
- " Message: 'message #2'\n"
- " FileOffset: 60\n"
- " FilePath: path/to/header.h\n"
- " Replacements: \n"
- " - FilePath: path/to/header.h\n"
- " Offset: 62\n"
- " Length: 2\n"
- " ReplacementText: 'replacement #2'\n"
- " - DiagnosticName: 'diagnostic#3'\n"
- " Message: 'message #3'\n"
- " FileOffset: 98\n"
- " FilePath: path/to/source.cpp\n"
- " Notes:\n"
- " - Message: Note1\n"
- " FilePath: 'path/to/note1.cpp'\n"
- " FileOffset: 66\n"
- " - Message: Note2\n"
- " FilePath: 'path/to/note2.cpp'\n"
- " FileOffset: 77\n"
- " Replacements: []\n"
- "...\n";
TranslationUnitDiagnostics TUDActual;
- yaml::Input YAML(YamlContent);
+ yaml::Input YAML(YAMLContent);
YAML >> TUDActual;
ASSERT_FALSE(YAML.error());
@@ -160,7 +136,7 @@
EXPECT_EQ("message #1", D1.Message.Message);
EXPECT_EQ(55u, D1.Message.FileOffset);
EXPECT_EQ("path/to/source.cpp", D1.Message.FilePath);
- std::vector<Replacement> Fixes1 = getFixes(D1.Fix);
+ std::vector<Replacement> Fixes1 = getFixes(D1.Message.Fix);
ASSERT_EQ(1u, Fixes1.size());
EXPECT_EQ("path/to/source.cpp", Fixes1[0].getFilePath());
EXPECT_EQ(100u, Fixes1[0].getOffset());
@@ -172,7 +148,7 @@
EXPECT_EQ("message #2", D2.Message.Message);
EXPECT_EQ(60u, D2.Message.FileOffset);
EXPECT_EQ("path/to/header.h", D2.Message.FilePath);
- std::vector<Replacement> Fixes2 = getFixes(D2.Fix);
+ std::vector<Replacement> Fixes2 = getFixes(D2.Message.Fix);
ASSERT_EQ(1u, Fixes2.size());
EXPECT_EQ("path/to/header.h", Fixes2[0].getFilePath());
EXPECT_EQ(62u, Fixes2[0].getOffset());
@@ -182,15 +158,15 @@
Diagnostic D3 = TUDActual.Diagnostics[2];
EXPECT_EQ("diagnostic#3", D3.DiagnosticName);
EXPECT_EQ("message #3", D3.Message.Message);
- EXPECT_EQ(98u, D3.Message.FileOffset);
- EXPECT_EQ("path/to/source.cpp", D3.Message.FilePath);
+ EXPECT_EQ(72u, D3.Message.FileOffset);
+ EXPECT_EQ("path/to/source2.cpp", D3.Message.FilePath);
EXPECT_EQ(2u, D3.Notes.size());
EXPECT_EQ("Note1", D3.Notes[0].Message);
- EXPECT_EQ(66u, D3.Notes[0].FileOffset);
+ EXPECT_EQ(88u, D3.Notes[0].FileOffset);
EXPECT_EQ("path/to/note1.cpp", D3.Notes[0].FilePath);
EXPECT_EQ("Note2", D3.Notes[1].Message);
- EXPECT_EQ(77u, D3.Notes[1].FileOffset);
+ EXPECT_EQ(99u, D3.Notes[1].FileOffset);
EXPECT_EQ("path/to/note2.cpp", D3.Notes[1].FilePath);
- std::vector<Replacement> Fixes3 = getFixes(D3.Fix);
+ std::vector<Replacement> Fixes3 = getFixes(D3.Message.Fix);
EXPECT_TRUE(Fixes3.empty());
}
Index: clang/lib/Tooling/Core/Diagnostic.cpp
===================================================================
--- clang/lib/Tooling/Core/Diagnostic.cpp
+++ clang/lib/Tooling/Core/Diagnostic.cpp
@@ -40,10 +40,9 @@
Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
const DiagnosticMessage &Message,
- const llvm::StringMap<Replacements> &Fix,
const SmallVector<DiagnosticMessage, 1> &Notes,
Level DiagLevel, llvm::StringRef BuildDirectory)
- : DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes),
+ : DiagnosticName(DiagnosticName), Message(Message), Notes(Notes),
DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {}
} // end namespace tooling
Index: clang/include/clang/Tooling/DiagnosticsYaml.h
===================================================================
--- clang/include/clang/Tooling/DiagnosticsYaml.h
+++ clang/include/clang/Tooling/DiagnosticsYaml.h
@@ -31,6 +31,21 @@
Io.mapRequired("Message", M.Message);
Io.mapOptional("FilePath", M.FilePath);
Io.mapOptional("FileOffset", M.FileOffset);
+ std::vector<clang::tooling::Replacement> Fixes;
+ for (auto &Replacements : M.Fix) {
+ for (auto &Replacement : Replacements.second) {
+ Fixes.push_back(Replacement);
+ }
+ }
+ Io.mapRequired("Replacements", Fixes);
+ for (auto &Fix : Fixes) {
+ llvm::Error Err = M.Fix[Fix.getFilePath()].add(Fix);
+ if (Err) {
+ // FIXME: Implement better conflict handling.
+ llvm::errs() << "Fix conflicts with existing fix: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
}
};
@@ -43,12 +58,11 @@
: DiagLevel(clang::tooling::Diagnostic::Level::Warning) {}
NormalizedDiagnostic(const IO &, const clang::tooling::Diagnostic &D)
- : DiagnosticName(D.DiagnosticName), Message(D.Message), Fix(D.Fix),
- Notes(D.Notes), DiagLevel(D.DiagLevel),
- BuildDirectory(D.BuildDirectory) {}
+ : DiagnosticName(D.DiagnosticName), Message(D.Message), Notes(D.Notes),
+ DiagLevel(D.DiagLevel), BuildDirectory(D.BuildDirectory) {}
clang::tooling::Diagnostic denormalize(const IO &) {
- return clang::tooling::Diagnostic(DiagnosticName, Message, Fix, Notes,
+ return clang::tooling::Diagnostic(DiagnosticName, Message, Notes,
DiagLevel, BuildDirectory);
}
@@ -64,28 +78,10 @@
MappingNormalization<NormalizedDiagnostic, clang::tooling::Diagnostic> Keys(
Io, D);
Io.mapRequired("DiagnosticName", Keys->DiagnosticName);
- Io.mapRequired("Message", Keys->Message.Message);
- Io.mapRequired("FileOffset", Keys->Message.FileOffset);
- Io.mapRequired("FilePath", Keys->Message.FilePath);
+ Io.mapRequired("DiagnosticMessage", Keys->Message);
Io.mapOptional("Notes", Keys->Notes);
// FIXME: Export properly all the different fields.
-
- std::vector<clang::tooling::Replacement> Fixes;
- for (auto &Replacements : Keys->Fix) {
- for (auto &Replacement : Replacements.second) {
- Fixes.push_back(Replacement);
- }
- }
- Io.mapRequired("Replacements", Fixes);
- for (auto &Fix : Fixes) {
- llvm::Error Err = Keys->Fix[Fix.getFilePath()].add(Fix);
- if (Err) {
- // FIXME: Implement better conflict handling.
- llvm::errs() << "Fix conflicts with existing fix: "
- << llvm::toString(std::move(Err)) << "\n";
- }
- }
}
};
Index: clang/include/clang/Tooling/Core/Diagnostic.h
===================================================================
--- clang/include/clang/Tooling/Core/Diagnostic.h
+++ clang/include/clang/Tooling/Core/Diagnostic.h
@@ -42,6 +42,9 @@
std::string Message;
std::string FilePath;
unsigned FileOffset;
+
+ /// Fixes for this diagnostic.
+ llvm::StringMap<Replacements> Fix;
};
/// Represents the diagnostic with the level of severity and possible
@@ -58,7 +61,6 @@
StringRef BuildDirectory);
Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message,
- const llvm::StringMap<Replacements> &Fix,
const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
llvm::StringRef BuildDirectory);
@@ -68,9 +70,6 @@
/// Message associated to the diagnostic.
DiagnosticMessage Message;
- /// Fixes to apply, grouped by file path.
- llvm::StringMap<Replacements> Fix;
-
/// Potential notes about the diagnostic.
SmallVector<DiagnosticMessage, 1> Notes;
Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===================================================================
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -14,6 +14,7 @@
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Core/Replacement.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/Optional.h"
@@ -131,7 +132,7 @@
tooling::Replacements Fixes;
std::vector<ClangTidyError> Diags = DiagConsumer.take();
for (const ClangTidyError &Error : Diags) {
- for (const auto &FileAndFixes : Error.Fix) {
+ for (const auto &FileAndFixes : Error.Message.Fix) {
for (const auto &Fix : FileAndFixes.second) {
auto Err = Fixes.add(Fix);
// FIXME: better error handling. Keep the behavior for now.
Index: clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
+++ clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
@@ -26,7 +26,6 @@
TUs.push_back({MainSourceFile,
{{DiagnosticName,
Message,
- Replacements,
{},
Diagnostic::Warning,
BuildDirectory}}});
Index: clang-tools-extra/test/clang-tidy/export-diagnostics.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/export-diagnostics.cpp
+++ clang-tools-extra/test/clang-tidy/export-diagnostics.cpp
@@ -13,16 +13,19 @@
// CHECK-YAML-NEXT: MainSourceFile: '{{.*}}-input.cpp'
// CHECK-YAML-NEXT: Diagnostics:
// CHECK-YAML-NEXT: - DiagnosticName: clang-diagnostic-missing-prototypes
-// CHECK-YAML-NEXT: Message: 'no previous prototype for function ''ff'''
-// CHECK-YAML-NEXT: FileOffset: 30
-// CHECK-YAML-NEXT: FilePath: '{{.*}}-input.cpp'
+// CHECK-YAML-NEXT: DiagnosticMessage:
+// CHECK-YAML-NEXT: Message: 'no previous prototype for function
+// ''ff'''
+// CHECK-YAML-NEXT: FilePath: '{{.*}}-input.cpp'
+// CHECK-YAML-NEXT: FileOffset: 30
+// CHECK-YAML-NEXT: Replacements: []
// CHECK-YAML-NEXT: Notes:
// CHECK-YAML-NEXT: - Message: 'expanded from macro ''X'''
// CHECK-YAML-NEXT: FilePath: '{{.*}}-input.cpp'
// CHECK-YAML-NEXT: FileOffset: 18
+// CHECK-YAML-NEXT: Replacements: []
// CHECK-YAML-NEXT: - Message: expanded from here
// CHECK-YAML-NEXT: FilePath: ''
// CHECK-YAML-NEXT: FileOffset: 0
-// CHECK-YAML-NEXT: Replacements: []
+// CHECK-YAML-NEXT: Replacements: []
// CHECK-YAML-NEXT: ...
-
Index: clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -154,7 +154,10 @@
for (const auto &Context : Contexts) {
if (!Context.IsUsed) {
diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused")
- << Context.FoundUsingDecl
+ << Context.FoundUsingDecl;
+ // Emit a fix and a fix description of the check;
+ diag(Context.FoundUsingDecl->getLocation(),
+ /*FixDescription=*/"remove the using", DiagnosticIDs::Note)
<< FixItHint::CreateRemoval(Context.UsingDeclRange);
}
}
Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -18,8 +18,10 @@
#include "ClangTidyDiagnosticConsumer.h"
#include "ClangTidyOptions.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Tooling/Core/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include <tuple>
@@ -68,6 +70,9 @@
SmallVectorImpl<CharSourceRange> &Ranges,
ArrayRef<FixItHint> Hints) override {
assert(Loc.isValid());
+ tooling::DiagnosticMessage *DiagWithFix =
+ Level == DiagnosticsEngine::Note ? &Error.Notes.back() : &Error.Message;
+
for (const auto &FixIt : Hints) {
CharSourceRange Range = FixIt.RemoveRange;
assert(Range.getBegin().isValid() && Range.getEnd().isValid() &&
@@ -77,7 +82,8 @@
tooling::Replacement Replacement(Loc.getManager(), Range,
FixIt.CodeToInsert);
- llvm::Error Err = Error.Fix[Replacement.getFilePath()].add(Replacement);
+ llvm::Error Err =
+ DiagWithFix->Fix[Replacement.getFilePath()].add(Replacement);
// FIXME: better error handling (at least, don't let other replacements be
// applied).
if (Err) {
@@ -581,9 +587,24 @@
// Compute error sizes.
std::vector<int> Sizes;
- for (const auto &Error : Errors) {
+ std::vector<
+ std::pair<ClangTidyError *, llvm::StringMap<tooling::Replacements> *>>
+ ErrorFixes;
+ for (auto &Error : Errors) {
+ if (!Error.Message.Fix.empty())
+ ErrorFixes.emplace_back(&Error, &Error.Message.Fix);
+ else {
+ auto Iter =
+ llvm::find_if(Error.Notes, [](const tooling::DiagnosticMessage &D) {
+ return !D.Fix.empty();
+ });
+ if (Iter != Error.Notes.end())
+ ErrorFixes.emplace_back(&Error, &Iter->Fix);
+ }
+ }
+ for (const auto &ErrorAndFix : ErrorFixes) {
int Size = 0;
- for (const auto &FileAndReplaces : Error.Fix) {
+ for (const auto &FileAndReplaces : *ErrorAndFix.second) {
for (const auto &Replace : FileAndReplaces.second)
Size += Replace.getLength();
}
@@ -592,8 +613,8 @@
// Build events from error intervals.
std::map<std::string, std::vector<Event>> FileEvents;
- for (unsigned I = 0; I < Errors.size(); ++I) {
- for (const auto &FileAndReplace : Errors[I].Fix) {
+ for (unsigned I = 0; I < ErrorFixes.size(); ++I) {
+ for (const auto &FileAndReplace : *ErrorFixes[I].second) {
for (const auto &Replace : FileAndReplace.second) {
unsigned Begin = Replace.getOffset();
unsigned End = Begin + Replace.getLength();
@@ -608,7 +629,7 @@
}
}
- std::vector<bool> Apply(Errors.size(), true);
+ std::vector<bool> Apply(ErrorFixes.size(), true);
for (auto &FileAndEvents : FileEvents) {
std::vector<Event> &Events = FileAndEvents.second;
// Sweep.
@@ -627,10 +648,10 @@
assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match");
}
- for (unsigned I = 0; I < Errors.size(); ++I) {
+ for (unsigned I = 0; I < ErrorFixes.size(); ++I) {
if (!Apply[I]) {
- Errors[I].Fix.clear();
- Errors[I].Notes.emplace_back(
+ ErrorFixes[I].second->clear();
+ ErrorFixes[I].first->Notes.emplace_back(
"this fix will not be applied because it overlaps with another fix");
}
}
Index: clang-tools-extra/clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -35,6 +35,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Tooling/Core/Diagnostic.h"
#if CLANG_ENABLE_STATIC_ANALYZER
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
@@ -125,15 +126,30 @@
}
auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
<< Message.Message << Name;
- for (const auto &FileAndReplacements : Error.Fix) {
- for (const auto &Repl : FileAndReplacements.second) {
- SourceLocation FixLoc;
- ++TotalFixes;
- bool CanBeApplied = false;
- if (Repl.isApplicable()) {
- SmallString<128> FixAbsoluteFilePath = Repl.getFilePath();
- Files.makeAbsolutePath(FixAbsoluteFilePath);
- if (ApplyFixes) {
+
+ // If we have alternative fixes (attached via diagnostic::Notes), we just
+ // choose the first one to apply.
+ const llvm::StringMap<Replacements> *ErrorFix = nullptr;
+ if (!Error.Message.Fix.empty())
+ ErrorFix = &Error.Message.Fix;
+ else {
+ auto Iter =
+ llvm::find_if(Error.Notes, [](const tooling::DiagnosticMessage &D) {
+ return !D.Fix.empty();
+ });
+ if (Iter != Error.Notes.end())
+ ErrorFix = &Iter->Fix;
+ }
+
+ if (ApplyFixes && ErrorFix) {
+ for (const auto &FileAndReplacements : *ErrorFix) {
+ for (const auto &Repl : FileAndReplacements.second) {
+ ++TotalFixes;
+ bool CanBeApplied = false;
+ if (Repl.isApplicable()) {
+ SourceLocation FixLoc;
+ SmallString<128> FixAbsoluteFilePath = Repl.getFilePath();
+ Files.makeAbsolutePath(FixAbsoluteFilePath);
tooling::Replacement R(FixAbsoluteFilePath, Repl.getOffset(),
Repl.getLength(),
Repl.getReplacementText());
@@ -158,28 +174,17 @@
llvm::errs()
<< "Can't resolve conflict, skipping the replacement.\n";
}
-
} else {
CanBeApplied = true;
++AppliedFixes;
}
+ FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset());
+ FixLocations.push_back(std::make_pair(FixLoc, CanBeApplied));
}
- FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset());
- SourceLocation FixEndLoc =
- FixLoc.getLocWithOffset(Repl.getLength());
- // Retrieve the source range for applicable fixes. Macro definitions
- // on the command line have locations in a virtual buffer and don't
- // have valid file paths and are therefore not applicable.
- CharSourceRange Range =
- CharSourceRange::getCharRange(SourceRange(FixLoc, FixEndLoc));
- Diag << FixItHint::CreateReplacement(Range,
- Repl.getReplacementText());
}
-
- if (ApplyFixes)
- FixLocations.push_back(std::make_pair(FixLoc, CanBeApplied));
}
}
+ reportFix(Diag, Error.Message.Fix);
}
for (auto Fix : FixLocations) {
Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
@@ -250,10 +255,34 @@
return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
}
+ void reportFix(const DiagnosticBuilder &Diag,
+ const llvm::StringMap<Replacements> &Fix) {
+ for (const auto &FileAndReplacements : Fix) {
+ for (const auto &Repl : FileAndReplacements.second) {
+ if (Repl.isApplicable()) {
+ SmallString<128> FixAbsoluteFilePath = Repl.getFilePath();
+ Files.makeAbsolutePath(FixAbsoluteFilePath);
+ SourceLocation FixLoc =
+ getLocation(FixAbsoluteFilePath, Repl.getOffset());
+ SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Repl.getLength());
+ // Retrieve the source range for applicable fixes. Macro definitions
+ // on the command line have locations in a virtual buffer and don't
+ // have valid file paths and are therefore not applicable.
+ CharSourceRange Range =
+ CharSourceRange::getCharRange(SourceRange(FixLoc, FixEndLoc));
+ Diag << FixItHint::CreateReplacement(Range,
+ Repl.getReplacementText());
+ }
+ }
+ }
+ }
+
void reportNote(const tooling::DiagnosticMessage &Message) {
SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
- Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
+ auto Diag =
+ Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
<< Message.Message;
+ reportFix(Diag, Message.Fix);
}
FileManager Files;
Index: clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
===================================================================
--- clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
+++ clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
@@ -167,11 +167,12 @@
for (const tooling::Replacement &R : TU.Replacements)
AddToGroup(R, false);
- for (const auto &TU : TUDs)
- for (const auto &D : TU.Diagnostics)
- for (const auto &Fix : D.Fix)
- for (const tooling::Replacement &R : Fix.second)
- AddToGroup(R, true);
+ // FIXME: fix it.
+ // for (const auto &TU : TUDs)
+ // for (const auto &D : TU.Diagnostics)
+ // for (const auto &Fix : D.Fix)
+ // for (const tooling::Replacement &R : Fix.second)
+ // AddToGroup(R, true);
// Sort replacements per file to keep consistent behavior when
// clang-apply-replacements run on differents machine.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits