Hiralo created this revision.
Hiralo added reviewers: alexfh, njames93, hokein, DmitryPolukhin.
Hiralo added a project: clang-tools-extra.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Hiralo requested review of this revision.

commit 5c98467825b128aabd04a770ac26905d856a3757
Author: Hiral Oza <hiral....@netapp.com>
Date:   Wed Oct 21 23:30:22 2020 -0700

  clang-tidy: adding "--clang-tidy-config=<file-path>" to specify custom config 
file.
  
  Let clang-tidy to read config from specified file.
  Example:
   $ clang-tidy --clang-tidy-config=/some/path/myTidyConfig --list-checks --
     ...this will read config from '/some/path/myTidyConfig'.
  
  May speed-up tidy runtime since now it will just look-up <file-path>
  instead of searching ".clang-tidy" in parent-dir(s).
  
  Directly specifying config path helps setting build dependencies.

Thank you in advance for your kind review.
-Hiral


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89936

Files:
  clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
  clang-tools-extra/clang-tidy/ClangTidyOptions.h
  clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp

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
@@ -73,6 +73,13 @@
 )"),
                                    cl::init(""), cl::cat(ClangTidyCategory));
 
+static cl::opt<std::string> ClangTidyConfig("clang-tidy-config", cl::desc(R"(
+Specify full path of .clang-tidy config file.
+For example, --clang-tidy-config=/some/path/myTidyConfig
+)"),
+                                            cl::init(""),
+                                            cl::cat(ClangTidyCategory));
+
 static cl::opt<std::string> WarningsAsErrors("warnings-as-errors", cl::desc(R"(
 Upgrades warnings to errors. Same format as
 '-checks'.
@@ -279,6 +286,7 @@
 
   ClangTidyOptions DefaultOptions;
   DefaultOptions.Checks = DefaultChecks;
+  DefaultOptions.ClangTidyConfig = "";
   DefaultOptions.WarningsAsErrors = "";
   DefaultOptions.HeaderFilterRegex = HeaderFilter;
   DefaultOptions.SystemHeaders = SystemHeaders;
@@ -291,6 +299,8 @@
   ClangTidyOptions OverrideOptions;
   if (Checks.getNumOccurrences() > 0)
     OverrideOptions.Checks = Checks;
+  if (ClangTidyConfig.getNumOccurrences() > 0)
+    OverrideOptions.ClangTidyConfig = ClangTidyConfig;
   if (WarningsAsErrors.getNumOccurrences() > 0)
     OverrideOptions.WarningsAsErrors = WarningsAsErrors;
   if (HeaderFilter.getNumOccurrences() > 0)
Index: clang-tools-extra/clang-tidy/ClangTidyOptions.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -64,6 +64,9 @@
   /// Checks filter.
   llvm::Optional<std::string> Checks;
 
+  /// Clang-tidy-config
+  llvm::Optional<std::string> ClangTidyConfig;
+
   /// WarningsAsErrors filter.
   llvm::Optional<std::string> WarningsAsErrors;
 
@@ -227,6 +230,8 @@
   /// Try to read configuration files from \p Directory using registered
   /// \c ConfigHandlers.
   llvm::Optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory);
+  llvm::Optional<OptionsSource> tryReadConfigFile(llvm::StringRef Path,
+                                                  bool IsFile);
 
   llvm::StringMap<OptionsSource> CachedOptions;
   ClangTidyOptions OverrideOptions;
Index: clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -109,6 +109,7 @@
 ClangTidyOptions ClangTidyOptions::getDefaults() {
   ClangTidyOptions Options;
   Options.Checks = "";
+  Options.ClangTidyConfig = "";
   Options.WarningsAsErrors = "";
   Options.HeaderFilterRegex = "";
   Options.SystemHeaders = false;
@@ -306,7 +307,41 @@
                           << "...\n");
   assert(FS && "FS must be set.");
 
-  llvm::SmallString<128> AbsoluteFilePath(FileName);
+  llvm::SmallString<1024> AbsoluteFilePath(FileName);
+  if (!OverrideOptions.ClangTidyConfig.getValue().empty()) {
+    AbsoluteFilePath.assign(OverrideOptions.ClangTidyConfig.getValue());
+    if (FS->makeAbsolute(AbsoluteFilePath)) {
+      std::string Msg;
+      llvm::raw_string_ostream ErrStream(Msg);
+      ErrStream << " reading configuration from <" << AbsoluteFilePath
+                << "> can't make absolute path.\n";
+      llvm::report_fatal_error(ErrStream.str());
+    }
+    bool IsFile = false;
+    bool IsLink = false;
+    llvm::sys::fs::is_regular_file(Twine(AbsoluteFilePath), IsFile);
+    llvm::sys::fs::is_symlink_file(Twine(AbsoluteFilePath), IsLink);
+    if (!(IsFile || IsLink)) {
+      std::string Msg;
+      llvm::raw_string_ostream ErrStream(Msg);
+      ErrStream << " reading configuration from <" << AbsoluteFilePath
+                << "> file doesn't exist or not regular/symlink file.\n";
+      llvm::report_fatal_error(ErrStream.str());
+    }
+
+    std::vector<OptionsSource> RawOptions =
+        DefaultOptionsProvider::getRawOptions(AbsoluteFilePath.str());
+    OptionsSource CommandLineOptions(OverrideOptions,
+                                     OptionsSourceTypeCheckCommandLineOption);
+
+    llvm::Optional<OptionsSource> Result;
+    Result = tryReadConfigFile(AbsoluteFilePath, true);
+    if (Result) {
+      RawOptions.push_back(*Result);
+    }
+    RawOptions.push_back(CommandLineOptions);
+    return RawOptions;
+  }
 
   if (FS->makeAbsolute(AbsoluteFilePath))
     return {};
@@ -368,6 +403,47 @@
   return llvm::None;
 }
 
+llvm::Optional<OptionsSource>
+FileOptionsProvider::tryReadConfigFile(StringRef Path, bool IsFile) {
+  // llvm::outs() << "tryReadConfigFile IsFile<" <<
+  // OverrideOptions.ClangTidyConfig << ">\n";
+  assert(!Path.empty());
+
+  if (!IsFile) {
+    tryReadConfigFile(Path);
+  }
+
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+      llvm::MemoryBuffer::getFile(Path);
+  if (std::error_code EC = Text.getError()) {
+    std::string Msg;
+    llvm::raw_string_ostream ErrStream(Msg);
+    ErrStream << " Can't read <" << Path << ">: " << EC.message() << "\n";
+    llvm::report_fatal_error(ErrStream.str());
+  }
+
+  // Skip empty files, e.g. files opened for writing via shell output
+  // redirection.
+  if ((*Text)->getBuffer().empty()) {
+    std::string Msg;
+    llvm::raw_string_ostream ErrStream(Msg);
+    ErrStream << " empty configuration file <" << Path << ">.\n";
+    llvm::report_fatal_error(ErrStream.str());
+  }
+  llvm::ErrorOr<ClangTidyOptions> ParsedOptions =
+      parseConfiguration((*Text)->getBuffer());
+  if (!ParsedOptions) {
+    if (ParsedOptions.getError()) {
+      std::string Msg;
+      llvm::raw_string_ostream ErrStream(Msg);
+      ErrStream << " parsing <" << Path
+                << ">: " << ParsedOptions.getError().message() << "\n";
+      llvm::report_fatal_error(ErrStream.str());
+    }
+  }
+  return OptionsSource(*ParsedOptions, Path);
+}
+
 /// Parses -line-filter option and stores it to the \c Options.
 std::error_code parseLineFilter(StringRef LineFilter,
                                 clang::tidy::ClangTidyGlobalOptions &Options) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to