[clang-tools-extra] r267683 - [ClangTidy] Add an 'explain-checks' option to diagnose where each checks comes from.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 27 02:15:01 PDT 2016


Author: hokein
Date: Wed Apr 27 04:15:01 2016
New Revision: 267683

URL: http://llvm.org/viewvc/llvm-project?rev=267683&view=rev
Log:
[ClangTidy] Add an 'explain-checks' option to diagnose where each checks comes from.

Reviewers: alexfh

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D18694

Added:
    clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/
    clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/.clang-tidy
    clang-tools-extra/trunk/test/clang-tidy/explain-checks.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h
    clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp?rev=267683&r1=267682&r2=267683&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp Wed Apr 27 04:15:01 2016
@@ -23,6 +23,7 @@
 
 using clang::tidy::ClangTidyOptions;
 using clang::tidy::FileFilter;
+using OptionsSource = clang::tidy::ClangTidyOptionsProvider::OptionsSource;
 
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange)
@@ -151,6 +152,48 @@ ClangTidyOptions::mergeWith(const ClangT
   return Result;
 }
 
+const char ClangTidyOptionsProvider::OptionsSourceTypeDefaultBinary[] =
+    "clang-tidy binary";
+const char ClangTidyOptionsProvider::OptionsSourceTypeCheckCommandLineOption[] =
+    "command-line option '-checks'";
+const char
+    ClangTidyOptionsProvider::OptionsSourceTypeConfigCommandLineOption[] =
+        "command-line option '-config'";
+
+ClangTidyOptions
+ClangTidyOptionsProvider::getOptions(llvm::StringRef FileName) {
+  ClangTidyOptions Result;
+  for (const auto &Source : getRawOptions(FileName))
+    Result = Result.mergeWith(Source.first);
+  return Result;
+}
+
+std::vector<OptionsSource>
+DefaultOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+  std::vector<OptionsSource> Result;
+  Result.emplace_back(DefaultOptions, OptionsSourceTypeDefaultBinary);
+  return Result;
+}
+
+ConfigOptionsProvider::ConfigOptionsProvider(
+    const ClangTidyGlobalOptions &GlobalOptions,
+    const ClangTidyOptions &DefaultOptions,
+    const ClangTidyOptions &ConfigOptions,
+    const ClangTidyOptions &OverrideOptions)
+    : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
+      ConfigOptions(ConfigOptions), OverrideOptions(OverrideOptions) {}
+
+std::vector<OptionsSource>
+ConfigOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+  std::vector<OptionsSource> RawOptions =
+      DefaultOptionsProvider::getRawOptions(FileName);
+  RawOptions.emplace_back(ConfigOptions,
+                          OptionsSourceTypeConfigCommandLineOption);
+  RawOptions.emplace_back(OverrideOptions,
+                          OptionsSourceTypeCheckCommandLineOption);
+  return RawOptions;
+}
+
 FileOptionsProvider::FileOptionsProvider(
     const ClangTidyGlobalOptions &GlobalOptions,
     const ClangTidyOptions &DefaultOptions,
@@ -158,7 +201,6 @@ FileOptionsProvider::FileOptionsProvider
     : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
       OverrideOptions(OverrideOptions) {
   ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
-  CachedOptions[""] = DefaultOptions.mergeWith(OverrideOptions);
 }
 
 FileOptionsProvider::FileOptionsProvider(
@@ -168,13 +210,13 @@ FileOptionsProvider::FileOptionsProvider
     const FileOptionsProvider::ConfigFileHandlers &ConfigHandlers)
     : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
       OverrideOptions(OverrideOptions), ConfigHandlers(ConfigHandlers) {
-  CachedOptions[""] = DefaultOptions.mergeWith(OverrideOptions);
 }
 
 // FIXME: This method has some common logic with clang::format::getStyle().
 // Consider pulling out common bits to a findParentFileWithName function or
 // similar.
-ClangTidyOptions FileOptionsProvider::getOptions(StringRef FileName) {
+std::vector<OptionsSource>
+FileOptionsProvider::getRawOptions(StringRef FileName) {
   DEBUG(llvm::dbgs() << "Getting options for file " << FileName << "...\n");
   SmallString<256> FilePath(FileName);
 
@@ -186,19 +228,23 @@ ClangTidyOptions FileOptionsProvider::ge
     FileName = FilePath;
   }
 
+  std::vector<OptionsSource> RawOptions =
+      DefaultOptionsProvider::getRawOptions(FileName);
+  OptionsSource CommandLineOptions(OverrideOptions,
+                                   OptionsSourceTypeCheckCommandLineOption);
   // Look for a suitable configuration file in all parent directories of the
   // file. Start with the immediate parent directory and move up.
   StringRef Path = llvm::sys::path::parent_path(FileName);
-  for (StringRef CurrentPath = Path;;
+  for (StringRef CurrentPath = Path; !CurrentPath.empty();
        CurrentPath = llvm::sys::path::parent_path(CurrentPath)) {
-    llvm::Optional<ClangTidyOptions> Result;
+    llvm::Optional<OptionsSource> Result;
 
     auto Iter = CachedOptions.find(CurrentPath);
     if (Iter != CachedOptions.end())
       Result = Iter->second;
 
     if (!Result)
-      Result = TryReadConfigFile(CurrentPath);
+      Result = tryReadConfigFile(CurrentPath);
 
     if (Result) {
       // Store cached value for all intermediate directories.
@@ -208,13 +254,18 @@ ClangTidyOptions FileOptionsProvider::ge
         CachedOptions[Path] = *Result;
         Path = llvm::sys::path::parent_path(Path);
       }
-      return CachedOptions[Path] = *Result;
+      CachedOptions[Path] = *Result;
+
+      RawOptions.push_back(*Result);
+      break;
     }
   }
+  RawOptions.push_back(CommandLineOptions);
+  return RawOptions;
 }
 
-llvm::Optional<ClangTidyOptions>
-FileOptionsProvider::TryReadConfigFile(StringRef Directory) {
+llvm::Optional<OptionsSource>
+FileOptionsProvider::tryReadConfigFile(StringRef Directory) {
   assert(!Directory.empty());
 
   if (!llvm::sys::fs::is_directory(Directory)) {
@@ -255,10 +306,7 @@ FileOptionsProvider::TryReadConfigFile(S
                      << ParsedOptions.getError().message() << "\n";
       continue;
     }
-
-    return DefaultOptionsProvider::getOptions(Directory)
-        .mergeWith(*ParsedOptions)
-        .mergeWith(OverrideOptions);
+    return OptionsSource(*ParsedOptions, ConfigFile.c_str());
   }
   return llvm::None;
 }

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h?rev=267683&r1=267682&r2=267683&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h Wed Apr 27 04:15:01 2016
@@ -99,14 +99,33 @@ struct ClangTidyOptions {
 /// \brief Abstract interface for retrieving various ClangTidy options.
 class ClangTidyOptionsProvider {
 public:
+  static const char OptionsSourceTypeDefaultBinary[];
+  static const char OptionsSourceTypeCheckCommandLineOption[];
+  static const char OptionsSourceTypeConfigCommandLineOption[];
+
   virtual ~ClangTidyOptionsProvider() {}
 
   /// \brief Returns global options, which are independent of the file.
   virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
 
+  /// \brief ClangTidyOptions and its source.
+  //
+  /// clang-tidy has 3 types of the sources in order of increasing priority:
+  ///    * clang-tidy binary.
+  ///    * '-config' commandline option or a specific configuration file. If the
+  ///       commandline option is specified, clang-tidy will ignore the
+  ///       configuration file.
+  ///    * '-checks' commandline option.
+  typedef std::pair<ClangTidyOptions, std::string> OptionsSource;
+
+  /// \brief Returns an ordered vector of OptionsSources, in order of increasing
+  /// priority.
+  virtual std::vector<OptionsSource>
+  getRawOptions(llvm::StringRef FileName) = 0;
+
   /// \brief Returns options applying to a specific translation unit with the
   /// specified \p FileName.
-  virtual ClangTidyOptions getOptions(llvm::StringRef FileName) = 0;
+  ClangTidyOptions getOptions(llvm::StringRef FileName);
 };
 
 /// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
@@ -119,15 +138,28 @@ public:
   const ClangTidyGlobalOptions &getGlobalOptions() override {
     return GlobalOptions;
   }
-  ClangTidyOptions getOptions(llvm::StringRef /*FileName*/) override {
-    return DefaultOptions;
-  }
+  std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
 
 private:
   ClangTidyGlobalOptions GlobalOptions;
   ClangTidyOptions DefaultOptions;
 };
 
+/// \brief Implementation of ClangTidyOptions interface, which is used for
+/// '-config' command-line option.
+class ConfigOptionsProvider : public DefaultOptionsProvider {
+public:
+  ConfigOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+                        const ClangTidyOptions &DefaultOptions,
+                        const ClangTidyOptions &ConfigOptions,
+                        const ClangTidyOptions &OverrideOptions);
+  std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
+
+private:
+  ClangTidyOptions ConfigOptions;
+  ClangTidyOptions OverrideOptions;
+};
+
 /// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
 /// tries to find a configuration file in the closest parent directory of each
 /// source file.
@@ -198,14 +230,14 @@ public:
                       const ClangTidyOptions &OverrideOptions,
                       const ConfigFileHandlers &ConfigHandlers);
 
-  ClangTidyOptions getOptions(llvm::StringRef FileName) override;
+  std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
 
 protected:
   /// \brief Try to read configuration files from \p Directory using registered
   /// \c ConfigHandlers.
-  llvm::Optional<ClangTidyOptions> TryReadConfigFile(llvm::StringRef Directory);
+  llvm::Optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory);
 
-  llvm::StringMap<ClangTidyOptions> CachedOptions;
+  llvm::StringMap<OptionsSource> CachedOptions;
   ClangTidyOptions OverrideOptions;
   ConfigFileHandlers ConfigHandlers;
 };

Modified: clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp?rev=267683&r1=267682&r2=267683&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp Wed Apr 27 04:15:01 2016
@@ -128,6 +128,12 @@ List all enabled checks and exit. Use wi
 )"),
                                 cl::init(false), cl::cat(ClangTidyCategory));
 
+static cl::opt<bool> ExplainConfig("explain-config", cl::desc(R"(
+for each enabled check explains, where it is enabled, i.e. in clang-tidy binary,
+command line or a specific configuration file.
+)"),
+                                   cl::init(false), cl::cat(ClangTidyCategory));
+
 static cl::opt<std::string> Config("config", cl::desc(R"(
 Specifies a configuration in YAML/JSON format:
   -config="{Checks: '*',
@@ -280,11 +286,10 @@ static std::unique_ptr<ClangTidyOptionsP
   if (!Config.empty()) {
     if (llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
             parseConfiguration(Config)) {
-      return llvm::make_unique<DefaultOptionsProvider>(
-          GlobalOptions, ClangTidyOptions::getDefaults()
-                             .mergeWith(DefaultOptions)
-                             .mergeWith(*ParsedConfig)
-                             .mergeWith(OverrideOptions));
+      return llvm::make_unique<ConfigOptionsProvider>(
+          GlobalOptions,
+          ClangTidyOptions::getDefaults().mergeWith(DefaultOptions),
+          *ParsedConfig, OverrideOptions);
     } else {
       llvm::errs() << "Error: invalid configuration specified.\n"
                    << ParsedConfig.getError().message() << "\n";
@@ -311,6 +316,22 @@ static int clangTidyMain(int argc, const
   ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName);
   std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions);
 
+  if (ExplainConfig) {
+    //FIXME: Show other ClangTidyOptions' fields, like ExtraArg.
+    std::vector<clang::tidy::ClangTidyOptionsProvider::OptionsSource>
+        RawOptions = OptionsProvider->getRawOptions(FileName);
+    for (const std::string &Check : EnabledChecks) {
+      for (auto It = RawOptions.rbegin(); It != RawOptions.rend(); ++It) {
+        if (It->first.Checks && GlobList(*It->first.Checks).contains(Check)) {
+          llvm::outs() << "'" << Check << "' is enabled in the " << It->second
+                       << ".\n";
+          break;
+        }
+      }
+    }
+    return 0;
+  }
+
   if (ListChecks) {
     llvm::outs() << "Enabled checks:";
     for (auto CheckName : EnabledChecks)

Added: clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/.clang-tidy
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/.clang-tidy?rev=267683&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/.clang-tidy (added)
+++ clang-tools-extra/trunk/test/clang-tidy/Inputs/explain-config/.clang-tidy Wed Apr 27 04:15:01 2016
@@ -0,0 +1 @@
+Checks: '-*,modernize-use-nullptr'

Added: clang-tools-extra/trunk/test/clang-tidy/explain-checks.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/explain-checks.cpp?rev=267683&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/explain-checks.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/explain-checks.cpp Wed Apr 27 04:15:01 2016
@@ -0,0 +1,14 @@
+// RUN: clang-tidy -checks=-*,modernize-use-nullptr -explain-config | FileCheck --check-prefix=CHECK-MESSAGE1 %s
+// RUN: clang-tidy -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE2 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE3 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,-modernize-use-nullptr'}" %S/Inputs/explain-config/a.cc -explain-config | FileCheck --check-prefix=CHECK-MESSAGE4 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-*'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE5 %s
+// RUN: clang-tidy -config="{Checks: 'modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE6 %s
+// RUN: clang-tidy -explain-config %S/Inputs/explain-config/a.cc | grep "'modernize-use-nullptr' is enabled in the %S/Inputs/explain-config/.clang-tidy."
+
+// CHECK-MESSAGE1: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE2: 'modernize-use-nullptr' is enabled in the command-line option '-config'.
+// CHECK-MESSAGE3: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE4: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE5: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE6: 'clang-analyzer-unix.API' is enabled in the clang-tidy binary.




More information about the cfe-commits mailing list