[llvm-branch-commits] [clang-tools-extra] ddffcdf - [clang-tidy] Add a diagnostic callback to parseConfiguration
Nathan James via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Dec 16 16:29:51 PST 2020
Author: Nathan James
Date: 2020-12-17T00:24:58Z
New Revision: ddffcdf0a6603747a6734dcf23dfe81476b5523c
URL: https://github.com/llvm/llvm-project/commit/ddffcdf0a6603747a6734dcf23dfe81476b5523c
DIFF: https://github.com/llvm/llvm-project/commit/ddffcdf0a6603747a6734dcf23dfe81476b5523c.diff
LOG: [clang-tidy] Add a diagnostic callback to parseConfiguration
Currently errors detected when parsing the YAML for .clang-tidy files are always printed to errs.
For clang-tidy binary workflows this usually isn't an issue, but using clang-tidy as a library for integrations may want to handle displaying those errors in their own specific way.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D92920
Added:
Modified:
clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
clang-tools-extra/clang-tidy/ClangTidyOptions.h
clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index f17ef716d60f..197552acf927 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
@@ -390,6 +391,22 @@ parseConfiguration(llvm::MemoryBufferRef Config) {
return Options;
}
+static void diagHandlerImpl(const llvm::SMDiagnostic &Diag, void *Ctx) {
+ (*reinterpret_cast<DiagCallback *>(Ctx))(Diag);
+};
+
+llvm::ErrorOr<ClangTidyOptions>
+parseConfigurationWithDiags(llvm::MemoryBufferRef Config,
+ DiagCallback Handler) {
+ llvm::yaml::Input Input(Config, nullptr, Handler ? diagHandlerImpl : nullptr,
+ &Handler);
+ ClangTidyOptions Options;
+ Input >> Options;
+ if (Input.error())
+ return Input.error();
+ return Options;
+}
+
std::string configurationAsText(const ClangTidyOptions &Options) {
std::string Text;
llvm::raw_string_ostream Stream(Text);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index e7cd89951ff9..d8a4a14f5b52 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <functional>
#include <string>
@@ -311,6 +312,11 @@ std::error_code parseLineFilter(llvm::StringRef LineFilter,
llvm::ErrorOr<ClangTidyOptions>
parseConfiguration(llvm::MemoryBufferRef Config);
+using DiagCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>;
+
+llvm::ErrorOr<ClangTidyOptions>
+parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler);
+
/// Serializes configuration to a YAML-encoded string.
std::string configurationAsText(const ClangTidyOptions &Options);
diff --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
index 5b0cbac3a61e..be35b71d15cf 100644
--- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
FrontendOpenMP
Support
+ TestingSupport
)
get_filename_component(CLANG_LINT_SOURCE_DIR
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index db9624684dfe..6447f34661e9 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -2,6 +2,9 @@
#include "ClangTidyCheck.h"
#include "ClangTidyDiagnosticConsumer.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
@@ -123,6 +126,100 @@ TEST(ParseConfiguration, MergeConfigurations) {
EXPECT_TRUE(*Options.UseColor);
}
+namespace {
+class DiagCollecter {
+public:
+ struct Diag {
+ private:
+ static size_t posToOffset(const llvm::SMLoc Loc,
+ const llvm::SourceMgr *Src) {
+ return Loc.getPointer() -
+ Src->getMemoryBuffer(Src->FindBufferContainingLoc(Loc))
+ ->getBufferStart();
+ }
+
+ public:
+ Diag(const llvm::SMDiagnostic &D)
+ : Message(D.getMessage()), Kind(D.getKind()),
+ Pos(posToOffset(D.getLoc(), D.getSourceMgr())) {
+ if (!D.getRanges().empty()) {
+ // Ranges are stored as column numbers on the line that has the error.
+ unsigned Offset = Pos - D.getColumnNo();
+ Range.emplace();
+ Range->Begin = Offset + D.getRanges().front().first,
+ Range->End = Offset + D.getRanges().front().second;
+ }
+ }
+ std::string Message;
+ llvm::SourceMgr::DiagKind Kind;
+ size_t Pos;
+ Optional<llvm::Annotations::Range> Range;
+
+ friend void PrintTo(const Diag &D, std::ostream *OS) {
+ *OS << (D.Kind == llvm::SourceMgr::DK_Error ? "error: " : "warning: ")
+ << D.Message << "@" << llvm::to_string(D.Pos);
+ if (D.Range)
+ *OS << ":[" << D.Range->Begin << ", " << D.Range->End << ")";
+ }
+ };
+
+ DiagCollecter() = default;
+ DiagCollecter(const DiagCollecter &) = delete;
+
+ std::function<void(const llvm::SMDiagnostic &)>
+ getCallback(bool Clear = true) & {
+ if (Clear)
+ Diags.clear();
+ return [&](const llvm::SMDiagnostic &Diag) { Diags.emplace_back(Diag); };
+ }
+
+ std::function<void(const llvm::SMDiagnostic &)>
+ getCallback(bool Clear = true) && = delete;
+
+ llvm::ArrayRef<Diag> getDiags() const { return Diags; }
+
+private:
+ std::vector<Diag> Diags;
+};
+
+MATCHER_P(DiagMessage, M, "") { return arg.Message == M; }
+MATCHER_P(DiagKind, K, "") { return arg.Kind == K; }
+MATCHER_P(DiagPos, P, "") { return arg.Pos == P; }
+MATCHER_P(DiagRange, P, "") { return arg.Range && *arg.Range == P; }
+} // namespace
+
+using ::testing::AllOf;
+using ::testing::ElementsAre;
+
+TEST(ParseConfiguration, CollectDiags) {
+ DiagCollecter Collector;
+ auto ParseWithDiags = [&](llvm::StringRef Buffer) {
+ return parseConfigurationWithDiags(llvm::MemoryBufferRef(Buffer, "Options"),
+ Collector.getCallback());
+ };
+ llvm::Annotations Options(R"(
+ [[Check]]: llvm-include-order
+ )");
+ llvm::ErrorOr<ClangTidyOptions> ParsedOpt = ParseWithDiags(Options.code());
+ EXPECT_TRUE(!ParsedOpt);
+ EXPECT_THAT(Collector.getDiags(),
+ testing::ElementsAre(AllOf(DiagMessage("unknown key 'Check'"),
+ DiagKind(llvm::SourceMgr::DK_Error),
+ DiagPos(Options.range().Begin),
+ DiagRange(Options.range()))));
+
+ Options = llvm::Annotations(R"(
+ UseColor: [[NotABool]]
+ )");
+ ParsedOpt = ParseWithDiags(Options.code());
+ EXPECT_TRUE(!ParsedOpt);
+ EXPECT_THAT(Collector.getDiags(),
+ testing::ElementsAre(AllOf(DiagMessage("invalid boolean"),
+ DiagKind(llvm::SourceMgr::DK_Error),
+ DiagPos(Options.range().Begin),
+ DiagRange(Options.range()))));
+}
+
namespace {
class TestCheck : public ClangTidyCheck {
public:
More information about the llvm-branch-commits
mailing list