[clang-tools-extra] r210260 - Allow per-file clang-tidy options.

Alexander Kornienko alexfh at google.com
Thu Jun 5 06:31:46 PDT 2014


Author: alexfh
Date: Thu Jun  5 08:31:45 2014
New Revision: 210260

URL: http://llvm.org/viewvc/llvm-project?rev=210260&view=rev
Log:
Allow per-file clang-tidy options.

Summary:
This patch makes it possible for clang-tidy clients to provide
different options for different translation units. The option, which doesn't
make sense to be file-dependent, was moved to a separate ClangTidyGlobalOptions
struct. Added parsing of ClangTidyOptions.

Reviewers: klimek

Reviewed By: klimek

Subscribers: cfe-commits

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

Modified:
    clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidy.h
    clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h
    clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h
    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
    clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp
    clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp Thu Jun  5 08:31:45 2014
@@ -169,51 +169,63 @@ private:
   unsigned AppliedFixes;
 };
 
+class ClangTidyASTConsumer : public MultiplexConsumer {
+public:
+  ClangTidyASTConsumer(const SmallVectorImpl<ASTConsumer *> &Consumers,
+                       std::unique_ptr<ast_matchers::MatchFinder> Finder,
+                       std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
+      : MultiplexConsumer(Consumers), Finder(std::move(Finder)),
+        Checks(std::move(Checks)) {}
+
+private:
+  std::unique_ptr<ast_matchers::MatchFinder> Finder;
+  std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+};
+
 } // namespace
 
 ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
-    ClangTidyContext &Context, const ClangTidyOptions &Options)
-    : Context(Context), CheckFactories(new ClangTidyCheckFactories),
-      Options(Options) {
+    ClangTidyContext &Context)
+    : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
   for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
                                          E = ClangTidyModuleRegistry::end();
        I != E; ++I) {
     std::unique_ptr<ClangTidyModule> Module(I->instantiate());
     Module->addCheckFactories(*CheckFactories);
   }
-
-  CheckFactories->createChecks(Context.getChecksFilter(), Checks);
-
-  for (ClangTidyCheck *Check : Checks) {
-    Check->setContext(&Context);
-    Check->registerMatchers(&Finder);
-  }
 }
 
-ClangTidyASTConsumerFactory::~ClangTidyASTConsumerFactory() {
-  for (ClangTidyCheck *Check : Checks)
-    delete Check;
-}
 
 clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
     clang::CompilerInstance &Compiler, StringRef File) {
   // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
   // modify Compiler.
   Context.setSourceManager(&Compiler.getSourceManager());
-  for (ClangTidyCheck *Check : Checks)
+  Context.setCurrentFile(File);
+
+  std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+  ChecksFilter &Filter = Context.getChecksFilter();
+  CheckFactories->createChecks(Filter, Checks);
+
+  std::unique_ptr<ast_matchers::MatchFinder> Finder(
+      new ast_matchers::MatchFinder);
+  for (auto &Check : Checks) {
+    Check->setContext(&Context);
+    Check->registerMatchers(&*Finder);
     Check->registerPPCallbacks(Compiler);
+  }
 
   SmallVector<ASTConsumer *, 2> Consumers;
-  if (!CheckFactories->empty())
-    Consumers.push_back(Finder.newASTConsumer());
+  if (!Checks.empty())
+    Consumers.push_back(Finder->newASTConsumer());
 
   AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
   // FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
   // to true.
   AnalyzerOptions->Config["cfg-temporary-dtors"] =
-      Options.AnalyzeTemporaryDtors ? "true" : "false";
+      Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
 
-  AnalyzerOptions->CheckersControlList = getCheckersControlList();
+  AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
   if (!AnalyzerOptions->CheckersControlList.empty()) {
     AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
     AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
@@ -226,17 +238,19 @@ clang::ASTConsumer *ClangTidyASTConsumer
         new AnalyzerDiagnosticConsumer(Context));
     Consumers.push_back(AnalysisConsumer);
   }
-  return new MultiplexConsumer(Consumers);
+  return new ClangTidyASTConsumer(Consumers, std::move(Finder),
+                                  std::move(Checks));
 }
 
-std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
+std::vector<std::string>
+ClangTidyASTConsumerFactory::getCheckNames(ChecksFilter &Filter) {
   std::vector<std::string> CheckNames;
   for (const auto &CheckFactory : *CheckFactories) {
-    if (Context.getChecksFilter().isCheckEnabled(CheckFactory.first))
+    if (Filter.isCheckEnabled(CheckFactory.first))
       CheckNames.push_back(CheckFactory.first);
   }
 
-  for (const auto &AnalyzerCheck : getCheckersControlList())
+  for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
     CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
 
   std::sort(CheckNames.begin(), CheckNames.end());
@@ -244,15 +258,15 @@ std::vector<std::string> ClangTidyASTCon
 }
 
 ClangTidyASTConsumerFactory::CheckersList
-ClangTidyASTConsumerFactory::getCheckersControlList() {
+ClangTidyASTConsumerFactory::getCheckersControlList(ChecksFilter &Filter) {
   CheckersList List;
 
   bool AnalyzerChecksEnabled = false;
   for (StringRef CheckName : StaticAnalyzerChecks) {
     std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
-    AnalyzerChecksEnabled |=
-        Context.getChecksFilter().isCheckEnabled(Checker) &&
-        !CheckName.startswith("debug");
+    AnalyzerChecksEnabled =
+        AnalyzerChecksEnabled ||
+        (!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker));
   }
 
   if (AnalyzerChecksEnabled) {
@@ -267,8 +281,7 @@ ClangTidyASTConsumerFactory::getCheckers
       std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
 
       if (CheckName.startswith("core") ||
-          (!CheckName.startswith("debug") &&
-           Context.getChecksFilter().isCheckEnabled(Checker)))
+          (!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker)))
         List.push_back(std::make_pair(CheckName, true));
     }
   }
@@ -291,17 +304,18 @@ void ClangTidyCheck::setName(StringRef N
 }
 
 std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
-  clang::tidy::ClangTidyContext Context(Options);
-  ClangTidyASTConsumerFactory Factory(Context, Options);
-  return Factory.getCheckNames();
+  clang::tidy::ClangTidyContext Context(
+      new DefaultOptionsProvider(ClangTidyGlobalOptions(), Options));
+  ClangTidyASTConsumerFactory Factory(Context);
+  return Factory.getCheckNames(Context.getChecksFilter());
 }
 
-ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
+ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
                             const tooling::CompilationDatabase &Compilations,
                             ArrayRef<std::string> InputFiles,
                             std::vector<ClangTidyError> *Errors) {
   ClangTool Tool(Compilations, InputFiles);
-  clang::tidy::ClangTidyContext Context(Options);
+  clang::tidy::ClangTidyContext Context(OptionsProvider);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
 
   Tool.setDiagnosticConsumer(&DiagConsumer);
@@ -328,7 +342,7 @@ ClangTidyStats runClangTidy(const ClangT
     ClangTidyASTConsumerFactory *ConsumerFactory;
   };
 
-  Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context, Options)));
+  Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
   *Errors = Context.getErrors();
   return Context.getStats();
 }

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidy.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidy.h?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidy.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidy.h Thu Jun  5 08:31:45 2014
@@ -16,6 +16,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Tooling/Refactoring.h"
+#include <memory>
 #include <vector>
 
 namespace clang {
@@ -95,26 +96,21 @@ class ClangTidyCheckFactories;
 
 class ClangTidyASTConsumerFactory {
 public:
-  ClangTidyASTConsumerFactory(ClangTidyContext &Context,
-                              const ClangTidyOptions &Options);
-  ~ClangTidyASTConsumerFactory();
+  ClangTidyASTConsumerFactory(ClangTidyContext &Context);
 
   /// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
   clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
                                         StringRef File);
 
   /// \brief Get the list of enabled checks.
-  std::vector<std::string> getCheckNames();
+  std::vector<std::string> getCheckNames(ChecksFilter &Filter);
 
 private:
   typedef std::vector<std::pair<std::string, bool> > CheckersList;
-  CheckersList getCheckersControlList();
+  CheckersList getCheckersControlList(ChecksFilter &Filter);
 
-  SmallVector<ClangTidyCheck *, 8> Checks;
   ClangTidyContext &Context;
-  ast_matchers::MatchFinder Finder;
   std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
-  ClangTidyOptions Options;
 };
 
 /// \brief Fills the list of check names that are enabled when the provided
@@ -122,10 +118,13 @@ private:
 std::vector<std::string> getCheckNames(const ClangTidyOptions &Options);
 
 /// \brief Run a set of clang-tidy checks on a set of files.
-ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
-                            const tooling::CompilationDatabase &Compilations,
-                            ArrayRef<std::string> InputFiles,
-                            std::vector<ClangTidyError> *Errors);
+///
+/// Takes ownership of the \c OptionsProvider.
+ClangTidyStats
+runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
+             const tooling::CompilationDatabase &Compilations,
+             ArrayRef<std::string> InputFiles,
+             std::vector<ClangTidyError> *Errors);
 
 // FIXME: This interface will need to be significantly extended to be useful.
 // FIXME: Implement confidence levels for displaying/fixing errors.

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp Thu Jun  5 08:31:45 2014
@@ -154,8 +154,12 @@ bool ChecksFilter::isCheckEnabled(String
   return Enabled;
 }
 
-ClangTidyContext::ClangTidyContext(const ClangTidyOptions &Options)
-    : DiagEngine(nullptr), Options(Options), Filter(Options.Checks) {}
+ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
+    : DiagEngine(nullptr), OptionsProvider(OptionsProvider) {
+  // Before the first translation unit we can get errors related to command-line
+  // parsing, use empty string for the file name in this case.
+  setCurrentFile("");
+}
 
 DiagnosticBuilder ClangTidyContext::diag(
     StringRef CheckName, SourceLocation Loc, StringRef Description,
@@ -190,6 +194,24 @@ void ClangTidyContext::setSourceManager(
   DiagEngine->setSourceManager(SourceMgr);
 }
 
+void ClangTidyContext::setCurrentFile(StringRef File) {
+  CurrentFile = File;
+  CheckFilter.reset(new ChecksFilter(getOptions().Checks));
+}
+
+const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
+  return OptionsProvider->getGlobalOptions();
+}
+
+const ClangTidyOptions &ClangTidyContext::getOptions() const {
+  return OptionsProvider->getOptions(CurrentFile);
+}
+
+ChecksFilter &ClangTidyContext::getChecksFilter() {
+  assert(CheckFilter != nullptr);
+  return *CheckFilter;
+}
+
 /// \brief Store a \c ClangTidyError.
 void ClangTidyContext::storeError(const ClangTidyError &Error) {
   Errors.push_back(Error);
@@ -204,8 +226,8 @@ StringRef ClangTidyContext::getCheckName
 }
 
 ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
-    : Context(Ctx), HeaderFilter(Ctx.getOptions().HeaderFilterRegex),
-      LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false) {
+    : Context(Ctx), LastErrorRelatesToUserCode(false),
+      LastErrorPassesLineFilter(false) {
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   Diags.reset(new DiagnosticsEngine(
       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
@@ -274,11 +296,18 @@ void ClangTidyDiagnosticConsumer::Handle
   checkFilters(Info.getLocation());
 }
 
+void ClangTidyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
+                                                  const Preprocessor *PP) {
+  // Before the first translation unit we don't need HeaderFilter, as we
+  // shouldn't get valid source locations in diagnostics.
+  HeaderFilter.reset(new llvm::Regex(Context.getOptions().HeaderFilterRegex));
+}
+
 bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
                                                    unsigned LineNumber) const {
-  if (Context.getOptions().LineFilter.empty())
+  if (Context.getGlobalOptions().LineFilter.empty())
     return true;
-  for (const FileFilter& Filter : Context.getOptions().LineFilter) {
+  for (const FileFilter& Filter : Context.getGlobalOptions().LineFilter) {
     if (FileName.endswith(Filter.Name)) {
       if (Filter.LineRanges.empty())
         return true;
@@ -319,10 +348,15 @@ void ClangTidyDiagnosticConsumer::checkF
   }
 
   StringRef FileName(File->getName());
+  assert(LastErrorRelatesToUserCode || Sources.isInMainFile(Location) ||
+         HeaderFilter != nullptr);
+  LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
+                               Sources.isInMainFile(Location) ||
+                               HeaderFilter->match(FileName);
+
   unsigned LineNumber = Sources.getExpansionLineNumber(Location);
-  LastErrorRelatesToUserCode |=
-      Sources.isInMainFile(Location) || HeaderFilter.match(FileName);
-  LastErrorPassesLineFilter |= passesLineFilter(FileName, LineNumber);
+  LastErrorPassesLineFilter =
+      LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
 }
 
 namespace {

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h Thu Jun  5 08:31:45 2014
@@ -67,12 +67,13 @@ struct ClangTidyError {
 /// \brief Filters checks by name.
 class ChecksFilter {
 public:
-  // GlobList is a comma-separated list of globs (only '*' metacharacter is
-  // supported) with optional '-' prefix to denote exclusion.
+  /// \brief \p GlobList is a comma-separated list of globs (only '*'
+  /// metacharacter is supported) with optional '-' prefix to denote exclusion.
   ChecksFilter(StringRef GlobList);
-  // Returns true if the check with the specified Name should be enabled.
-  // The result is the last matching glob's Positive flag. If Name is not
-  // matched by any globs, the check is not enabled.
+
+  /// \brief Returns \c true if the check with the specified \p Name should be
+  /// enabled. The result is the last matching glob's Positive flag. If \p Name
+  /// is not matched by any globs, the check is not enabled.
   bool isCheckEnabled(StringRef Name) { return isCheckEnabled(Name, false); }
 
 private:
@@ -83,6 +84,8 @@ private:
   std::unique_ptr<ChecksFilter> NextFilter;
 };
 
+/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
+/// run.
 struct ClangTidyStats {
   ClangTidyStats()
       : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
@@ -111,7 +114,10 @@ struct ClangTidyStats {
 /// \endcode
 class ClangTidyContext {
 public:
-  ClangTidyContext(const ClangTidyOptions &Options);
+  /// \brief Initializes \c ClangTidyContext instance.
+  ///
+  /// Takes ownership of the \c OptionsProvider.
+  ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider);
 
   /// \brief Report any errors detected using this method.
   ///
@@ -122,37 +128,55 @@ public:
                          StringRef Message,
                          DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
 
-  /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
-  /// correctly.
-  ///
-  /// This is called from the \c ClangTidyCheck base class.
-  void setDiagnosticsEngine(DiagnosticsEngine *Engine);
-
   /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
   ///
   /// This is called from the \c ClangTidyCheck base class.
   void setSourceManager(SourceManager *SourceMgr);
 
+  /// \brief Should be called when starting to process new translation unit.
+  void setCurrentFile(StringRef File);
+
   /// \brief Returns the name of the clang-tidy check which produced this
   /// diagnostic ID.
   StringRef getCheckName(unsigned DiagnosticID) const;
 
-  ChecksFilter &getChecksFilter() { return Filter; }
-  const ClangTidyOptions &getOptions() const { return Options; }
+  /// \brief Returns check filter for the \c CurrentFile.
+  ChecksFilter &getChecksFilter();
+
+  /// \brief Returns global options.
+  const ClangTidyGlobalOptions &getGlobalOptions() const;
+
+  /// \brief Returns options for \c CurrentFile.
+  const ClangTidyOptions &getOptions() const;
+
+  /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
+  /// counters.
   const ClangTidyStats &getStats() const { return Stats; }
+
+  /// \brief Returns all collected errors.
   const std::vector<ClangTidyError> &getErrors() const { return Errors; }
+
+  /// \brief Clears collected errors.
   void clearErrors() { Errors.clear(); }
 
 private:
-  friend class ClangTidyDiagnosticConsumer; // Calls storeError().
+  // Calls setDiagnosticsEngine() and storeError().
+  friend class ClangTidyDiagnosticConsumer;
 
-  /// \brief Store a \c ClangTidyError.
+  /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
+  /// correctly.
+  void setDiagnosticsEngine(DiagnosticsEngine *Engine);
+
+  /// \brief Store an \p Error.
   void storeError(const ClangTidyError &Error);
 
   std::vector<ClangTidyError> Errors;
   DiagnosticsEngine *DiagEngine;
-  ClangTidyOptions Options;
-  ChecksFilter Filter;
+  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
+
+  std::string CurrentFile;
+  std::unique_ptr<ChecksFilter> CheckFilter;
+
   ClangTidyStats Stats;
 
   llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
@@ -173,18 +197,25 @@ public:
   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
                         const Diagnostic &Info) override;
 
-  // Flushes the internal diagnostics buffer to the ClangTidyContext.
+  /// \brief Sets \c HeaderFilter to the value configured for this file.
+  void BeginSourceFile(const LangOptions &LangOpts,
+                       const Preprocessor *PP) override;
+
+  /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
   void finish() override;
 
 private:
   void finalizeLastError();
+
+  /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
+  /// according to the diagnostic \p Location.
   void checkFilters(SourceLocation Location);
   bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
 
   ClangTidyContext &Context;
-  llvm::Regex HeaderFilter;
   std::unique_ptr<DiagnosticsEngine> Diags;
   SmallVector<ClangTidyError, 8> Errors;
+  std::unique_ptr<llvm::Regex> HeaderFilter;
   bool LastErrorRelatesToUserCode;
   bool LastErrorPassesLineFilter;
 };

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp Thu Jun  5 08:31:45 2014
@@ -27,12 +27,13 @@ void ClangTidyCheckFactories::addCheckFa
 }
 
 void ClangTidyCheckFactories::createChecks(
-    ChecksFilter &Filter, SmallVectorImpl<ClangTidyCheck *> &Checks) {
+    ChecksFilter &Filter,
+    std::vector<std::unique_ptr<ClangTidyCheck>> &Checks) {
   for (const auto &Factory : Factories) {
     if (Filter.isCheckEnabled(Factory.first)) {
       ClangTidyCheck *Check = Factory.second->createCheck();
       Check->setName(Factory.first);
-      Checks.push_back(Check);
+      Checks.emplace_back(Check);
     }
   }
 }

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h Thu Jun  5 08:31:45 2014
@@ -87,7 +87,7 @@ public:
   ///
   /// The caller takes ownership of the return \c ClangTidyChecks.
   void createChecks(ChecksFilter &Filter,
-                    SmallVectorImpl<ClangTidyCheck *> &Checks);
+                    std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
 
   typedef std::map<std::string, CheckFactoryBase *> FactoryMap;
   FactoryMap::const_iterator begin() const { return Factories.begin(); }

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=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp Thu Jun  5 08:31:45 2014
@@ -10,6 +10,7 @@
 #include "ClangTidyOptions.h"
 #include "llvm/Support/YAMLTraits.h"
 
+using clang::tidy::ClangTidyOptions;
 using clang::tidy::FileFilter;
 
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
@@ -46,6 +47,14 @@ template <> struct MappingTraits<FileFil
   }
 };
 
+template <> struct MappingTraits<ClangTidyOptions> {
+  static void mapping(IO &IO, ClangTidyOptions &Options) {
+    IO.mapOptional("Checks", Options.Checks);
+    IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
+    IO.mapOptional("AnalyzeTemporaryDtors", Options.AnalyzeTemporaryDtors);
+  }
+};
+
 } // namespace yaml
 } // namespace llvm
 
@@ -54,11 +63,18 @@ namespace tidy {
 
 /// \brief Parses -line-filter option and stores it to the \c Options.
 llvm::error_code parseLineFilter(const std::string &LineFilter,
-                                 clang::tidy::ClangTidyOptions &Options) {
+                                 clang::tidy::ClangTidyGlobalOptions &Options) {
   llvm::yaml::Input Input(LineFilter);
   Input >> Options.LineFilter;
   return Input.error();
 }
 
+llvm::error_code parseConfiguration(const std::string &Config,
+                                    clang::tidy::ClangTidyOptions &Options) {
+  llvm::yaml::Input Input(Config);
+  Input >> Options;
+  return Input.error();
+}
+
 } // namespace tidy
 } // namespace clang

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=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h Thu Jun  5 08:31:45 2014
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
 
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/system_error.h"
 #include <string>
 #include <utility>
@@ -18,32 +19,82 @@
 namespace clang {
 namespace tidy {
 
+/// \brief Contains a list of line ranges in a single file.
 struct FileFilter {
+  /// \brief File name.
   std::string Name;
-  // LineRange is a pair<start, end> (inclusive).
+
+  /// \brief LineRange is a pair<start, end> (inclusive).
   typedef std::pair<unsigned, unsigned> LineRange;
+
+  /// \brief A list of line ranges in this file, for which we show warnings.
   std::vector<LineRange> LineRanges;
 };
 
-/// \brief Contains options for clang-tidy.
+/// \brief Global options. These options are neither stored nor read from
+/// configuration files.
+struct ClangTidyGlobalOptions {
+  /// \brief Output warnings from certain line ranges of certain files only. If
+  /// this list is emtpy, it won't be applied.
+  std::vector<FileFilter> LineFilter;
+};
+
+/// \brief Contains options for clang-tidy. These options may be read from
+/// configuration files, and may be different for different translation units.
 struct ClangTidyOptions {
+  /// \brief Allow all checks and no headers by default.
   ClangTidyOptions() : Checks("*"), AnalyzeTemporaryDtors(false) {}
+
+  /// \brief Checks filter.
   std::string Checks;
 
-  // Output warnings from headers matching this filter. Warnings from main files
-  // will always be displayed.
+  /// \brief Output warnings from headers matching this filter. Warnings from
+  /// main files will always be displayed.
   std::string HeaderFilterRegex;
 
-  // Output warnings from certain line ranges of certain files only. If this
-  // list is emtpy, it won't be applied.
-  std::vector<FileFilter> LineFilter;
-
+  /// \brief Turns on temporary destructor-based analysis.
   bool AnalyzeTemporaryDtors;
 };
 
-/// \brief Parses LineFilter from JSON and stores it to the \c Options.
+/// \brief Abstract interface for retrieving various ClangTidy options.
+class ClangTidyOptionsProvider {
+public:
+  virtual ~ClangTidyOptionsProvider() {}
+
+  /// \brief Returns global options, which are independent of the file.
+  virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
+
+  /// \brief Returns options applying to a specific translation unit with the
+  /// specified \p FileName.
+  virtual const ClangTidyOptions &getOptions(llvm::StringRef FileName) = 0;
+};
+
+/// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
+/// returns the same options for all files.
+class DefaultOptionsProvider : public ClangTidyOptionsProvider {
+public:
+  DefaultOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+                         const ClangTidyOptions &Options)
+      : GlobalOptions(GlobalOptions), DefaultOptions(Options) {}
+  const ClangTidyGlobalOptions &getGlobalOptions() override {
+    return GlobalOptions;
+  }
+  const ClangTidyOptions &getOptions(llvm::StringRef) override {
+    return DefaultOptions;
+  }
+
+private:
+  ClangTidyGlobalOptions GlobalOptions;
+  ClangTidyOptions DefaultOptions;
+};
+
+/// \brief Parses LineFilter from JSON and stores it to the \p Options.
 llvm::error_code parseLineFilter(const std::string &LineFilter,
-                                 clang::tidy::ClangTidyOptions &Options);
+                                 clang::tidy::ClangTidyGlobalOptions &Options);
+
+/// \brief Parses configuration from JSON and stores it to the \p Options.
+llvm::error_code parseConfiguration(const std::string &Config,
+                                    clang::tidy::ClangTidyOptions &Options);
 
 } // end namespace tidy
 } // end namespace clang

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=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp Thu Jun  5 08:31:45 2014
@@ -108,17 +108,19 @@ static void printStats(const clang::tidy
 int main(int argc, const char **argv) {
   CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory);
 
-  clang::tidy::ClangTidyOptions Options;
-  Options.Checks = DefaultChecks + Checks;
-  Options.HeaderFilterRegex = HeaderFilter;
-  Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+  clang::tidy::ClangTidyGlobalOptions GlobalOptions;
   if (llvm::error_code Err =
-          clang::tidy::parseLineFilter(LineFilter, Options)) {
+          clang::tidy::parseLineFilter(LineFilter, GlobalOptions)) {
     llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
     llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
     return 1;
   }
 
+  clang::tidy::ClangTidyOptions Options;
+  Options.Checks = DefaultChecks + Checks;
+  Options.HeaderFilterRegex = HeaderFilter;
+  Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+
   std::vector<std::string> EnabledChecks = clang::tidy::getCheckNames(Options);
 
   // FIXME: Allow using --list-checks without positional arguments.
@@ -136,10 +138,13 @@ int main(int argc, const char **argv) {
     return 1;
   }
 
+  // TODO: Implement configuration file reading and a "real" options provider.
+  auto OptionsProvider =
+      new clang::tidy::DefaultOptionsProvider(GlobalOptions, Options);
   std::vector<clang::tidy::ClangTidyError> Errors;
-  clang::tidy::ClangTidyStats Stats =
-      clang::tidy::runClangTidy(Options, OptionsParser.getCompilations(),
-                                OptionsParser.getSourcePathList(), &Errors);
+  clang::tidy::ClangTidyStats Stats = clang::tidy::runClangTidy(
+      OptionsProvider, OptionsParser.getCompilations(),
+      OptionsParser.getSourcePathList(), &Errors);
   clang::tidy::handleErrors(Errors, Fix);
 
   printStats(Stats);

Modified: clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp Thu Jun  5 08:31:45 2014
@@ -6,7 +6,7 @@ namespace tidy {
 namespace test {
 
 TEST(ParseLineFilter, EmptyFilter) {
-  ClangTidyOptions Options;
+  ClangTidyGlobalOptions Options;
   EXPECT_FALSE(parseLineFilter("", Options));
   EXPECT_TRUE(Options.LineFilter.empty());
   EXPECT_FALSE(parseLineFilter("[]", Options));
@@ -14,7 +14,7 @@ TEST(ParseLineFilter, EmptyFilter) {
 }
 
 TEST(ParseLineFilter, InvalidFilter) {
-  ClangTidyOptions Options;
+  ClangTidyGlobalOptions Options;
   // TODO: Figure out why parsing succeeds here.
   EXPECT_FALSE(parseLineFilter("asdf", Options));
   EXPECT_TRUE(Options.LineFilter.empty());
@@ -30,7 +30,7 @@ TEST(ParseLineFilter, InvalidFilter) {
 }
 
 TEST(ParseLineFilter, ValidFilter) {
-  ClangTidyOptions Options;
+  ClangTidyGlobalOptions Options;
   llvm::error_code Error = parseLineFilter(
       "[{\"name\":\"file1.cpp\",\"lines\":[[3,15],[20,30],[42,42]]},"
       "{\"name\":\"file2.h\"},"
@@ -54,6 +54,18 @@ TEST(ParseLineFilter, ValidFilter) {
   EXPECT_EQ(1000u, Options.LineFilter[2].LineRanges[0].second);
 }
 
+TEST(ParseConfiguration, ValidConfiguration) {
+  ClangTidyOptions Options;
+  llvm::error_code Error = parseConfiguration("Checks: \"-*,misc-*\"\n"
+                                              "HeaderFilterRegex: \".*\"\n"
+                                              "AnalyzeTemporaryDtors: true\n",
+                                              Options);
+  EXPECT_FALSE(Error);
+  EXPECT_EQ("-*,misc-*", Options.Checks);
+  EXPECT_EQ(".*", Options.HeaderFilterRegex);
+  EXPECT_TRUE(Options.AnalyzeTemporaryDtors);
+}
+
 } // namespace test
 } // namespace tidy
 } // namespace clang

Modified: clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h?rev=210260&r1=210259&r2=210260&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h (original)
+++ clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyTest.h Thu Jun  5 08:31:45 2014
@@ -43,8 +43,8 @@ template <typename T>
 std::string runCheckOnCode(StringRef Code,
                            std::vector<ClangTidyError> *Errors = nullptr) {
   T Check;
-  ClangTidyOptions Options;
-  ClangTidyContext Context(Options);
+  ClangTidyContext Context(
+      new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions()));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
   Check.setContext(&Context);
   std::vector<std::string> ArgCXX11(1, "-std=c++11");





More information about the cfe-commits mailing list