PiotrZSL created this revision.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
PiotrZSL requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Currently due to missing DiagnosticsEngine when invalid
enum config value is passed to check, and --dump-config
is used, clang-tidy would crash. This change fixes this
and extends --verify-config command to actually verify
those invalid enum values instead of ignoring them and
printing that 'No config errors detected.'.

Fixes:

- https://github.com/llvm/llvm-project/issues/50876


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D146842

Files:
  clang-tools-extra/clang-tidy/ClangTidy.cpp
  clang-tools-extra/clang-tidy/ClangTidy.h
  clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
  clang-tools-extra/test/clang-tidy/infrastructure/invalid-enum-config-value.cpp

Index: clang-tools-extra/test/clang-tidy/infrastructure/invalid-enum-config-value.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/infrastructure/invalid-enum-config-value.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-tidy --checks="-*,modernize-make-shared" \
+// RUN:   --config="CheckOptions: [{ \
+// RUN:      key: modernize-make-shared.IncludeStyle, value: '0' }]" \
+// RUN:   --dump-config -- | FileCheck %s -check-prefix=CHECK-DUMP
+// RUN: not clang-tidy --checks="-*,modernize-make-shared" \
+// RUN:   --config="CheckOptions: [{ \
+// RUN:      key: modernize-make-shared.IncludeStyle, value: '0' }]" \
+// RUN:   --verify-config -- 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY
+
+// CHECK-DUMP: modernize-make-shared.IncludeStyle: llvm
+// CHECK-VERIFY: command-line option '-config': warning: invalid configuration value '0' for option 'modernize-make-shared.IncludeStyle' [clang-tidy-config]
Index: clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
===================================================================
--- clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -511,6 +511,63 @@
   return AnyInvalid;
 }
 
+static raw_ostream &getDiagnosticForLevel(tooling::Diagnostic::Level DiagLevel,
+                                          llvm::StringRef Prefix = "") {
+  switch (DiagLevel) {
+  case tooling::Diagnostic::Error:
+    return llvm::WithColor::error(llvm::errs(), Prefix);
+  case tooling::Diagnostic::Warning:
+    return llvm::WithColor::warning(llvm::errs(), Prefix);
+  case tooling::Diagnostic::Remark:
+    return llvm::WithColor::remark(llvm::errs(), Prefix);
+  }
+}
+
+static llvm::StringSet<> findSourcesForDiagnostic(
+    const std::vector<ClangTidyOptionsProvider::OptionsSource> &RawOptions,
+    llvm::StringRef Diagnostic) {
+  llvm::StringSet<> Result;
+  if (!Diagnostic.consume_front("invalid configuration value '") ||
+      !Diagnostic.contains("' for option '")) {
+    Result.insert("");
+    return Result;
+  }
+
+  auto [Value, Rest] = Diagnostic.split("' for option '");
+  auto [Option, _] = Rest.split('\'');
+
+  for (const auto &[Opts, Source] : RawOptions) {
+    for (const auto &[ItOption, ItValue] : Opts.CheckOptions) {
+      if (ItOption == Option && ItValue.Value == Value) {
+        Result.insert(Source);
+        break;
+      }
+    }
+  }
+
+  if (Result.empty())
+    Result.insert("");
+
+  return Result;
+}
+
+static bool verifyDiagnosticErrors(
+    const std::vector<ClangTidyError> &Errors,
+    const std::vector<ClangTidyOptionsProvider::OptionsSource> &RawOptions) {
+  for (const ClangTidyError &Error : Errors) {
+    for (const auto &Source :
+         findSourcesForDiagnostic(RawOptions, Error.Message.Message)) {
+      getDiagnosticForLevel(Error.DiagLevel, Source.getKey())
+          << Error.Message.Message << " [" << Error.DiagnosticName << "]\n";
+      for (const DiagnosticMessage &Note : Error.Notes)
+        llvm::WithColor::note(llvm::errs(), Source.getKey())
+            << Note.Message << '\n';
+    }
+  }
+
+  return !Errors.empty();
+}
+
 int clangTidyMain(int argc, const char **argv) {
   llvm::InitLLVM X(argc, argv);
 
@@ -607,9 +664,10 @@
   if (VerifyConfig) {
     std::vector<ClangTidyOptionsProvider::OptionsSource> RawOptions =
         OptionsProvider->getRawOptions(FileName);
-    NamesAndOptions Valid =
-        getAllChecksAndOptions(AllowEnablingAnalyzerAlphaCheckers);
+    NamesAndOptions Valid = getAllChecksAndOptions(
+        EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers);
     bool AnyInvalid = false;
+    AnyInvalid |= verifyDiagnosticErrors(Valid.Errors, RawOptions);
     for (const auto &[Opts, Source] : RawOptions) {
       if (Opts.Checks)
         AnyInvalid |= verifyChecks(Valid.Names, *Opts.Checks, Source);
Index: clang-tools-extra/clang-tidy/ClangTidy.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.h
+++ clang-tools-extra/clang-tidy/ClangTidy.h
@@ -61,10 +61,12 @@
 struct NamesAndOptions {
   llvm::StringSet<> Names;
   llvm::StringSet<> Options;
+  std::vector<ClangTidyError> Errors;
 };
 
 NamesAndOptions
-getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers = true);
+getAllChecksAndOptions(const ClangTidyOptions &Options,
+                       bool AllowEnablingAnalyzerAlphaCheckers = true);
 
 /// Returns the effective check-specific options.
 ///
Index: clang-tools-extra/clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -498,6 +498,10 @@
       std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
+  ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, false, false);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
+                       &DiagConsumer, /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(&DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -623,13 +627,18 @@
 }
 
 NamesAndOptions
-getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) {
+getAllChecksAndOptions(const ClangTidyOptions &Options,
+                       bool AllowEnablingAnalyzerAlphaCheckers) {
   NamesAndOptions Result;
-  ClangTidyOptions Opts;
-  Opts.Checks = "*";
+  ClangTidyOptions Opt(Options);
+  Opt.Checks = "*";
   clang::tidy::ClangTidyContext Context(
-      std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
+      std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opt),
       AllowEnablingAnalyzerAlphaCheckers);
+  ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, false, false);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
+                       &DiagConsumer, /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(&DE);
   ClangTidyCheckFactories Factories;
   for (const ClangTidyModuleRegistry::entry &Module :
        ClangTidyModuleRegistry::entries()) {
@@ -655,6 +664,7 @@
     Factory.getValue()(Factory.getKey(), &Context);
   }
 
+  Result.Errors = DiagConsumer.take();
   return Result;
 }
 } // namespace clang::tidy
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to