Hi klimek,

Made ClangTidyAction more slim and moved its declaration to header to
allow easy creation of Clang-tidy ASTConsumer. Don't derive from
clang::ento::AnalysisAction, use clang::ento::CreateAnalysisConsumer instead
(I'll propose making this function a part of a public API in a separate patch).

Use MultiplexConsumer instead of a custom class.

Don't re-filter checkers list for each TU.

http://llvm-reviews.chandlerc.com/D2481

Files:
  clang-tidy/ClangTidy.cpp
  clang-tidy/ClangTidy.h
  clang-tidy/ClangTidyDiagnosticConsumer.h
Index: clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tidy/ClangTidy.cpp
+++ clang-tidy/ClangTidy.cpp
@@ -26,58 +26,60 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Frontend/ASTConsumers.h"
 #include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Rewrite/Frontend/FixItRewriter.h"
 #include "clang/Rewrite/Frontend/FrontendActions.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
 #include "clang/Tooling/Tooling.h"
 #include "clang/Tooling/Refactoring.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Signals.h"
 #include <algorithm>
 #include <vector>
+// FIXME: Move AnalysisConsumer to include/clang/StaticAnalyzer/Frontend.
+#include "../../../lib/StaticAnalyzer/Frontend/AnalysisConsumer.h"
 
 using namespace clang::ast_matchers;
 using namespace clang::driver;
 using namespace clang::tooling;
 using namespace llvm;
 
 namespace clang {
 namespace tidy {
-namespace {
 
-/// \brief A combined ASTConsumer that forwards calls to two different
-/// consumers.
-///
-/// FIXME: This currently forwards just enough methods for the static analyzer
-/// and the \c MatchFinder's consumer to work; expand this to all methods of
-/// ASTConsumer and put it into a common location.
-class CombiningASTConsumer : public ASTConsumer {
-public:
-  CombiningASTConsumer(ASTConsumer *Consumer1, ASTConsumer *Consumer2)
-      : Consumer1(Consumer1), Consumer2(Consumer2) {}
+ClangTidyAction::ClangTidyAction(ClangTidyAction::CheckersList AnalyzerCheckers,
+                                 SmallVectorImpl<ClangTidyCheck *> &Checks,
+                                 ClangTidyContext &Context, MatchFinder &Finder)
+    : AnalyzerCheckers(AnalyzerCheckers), Checks(Checks), Context(Context),
+      Finder(Finder) {}
+
+clang::ASTConsumer *
+ClangTidyAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
+                                   StringRef File) {
+  Context.setSourceManager(&Compiler.getSourceManager());
+  for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(),
+                                                   E = Checks.end();
+       I != E; ++I)
+    (*I)->registerPPCallbacks(Compiler);
+
+  AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts();
+  Options->CheckersControlList = AnalyzerCheckers;
+  Options->AnalysisStoreOpt = RegionStoreModel;
+  Options->AnalysisDiagOpt = PD_TEXT;
+  Options->AnalyzeNestedBlocks = true;
+  Options->eagerlyAssumeBinOpBifurcation = true;
+  ASTConsumer *Consumers[] = {
+    Finder.newASTConsumer(),
+    ento::CreateAnalysisConsumer(Compiler.getPreprocessor(),
+                                 Compiler.getFrontendOpts().OutputFile, Options,
+                                 Compiler.getFrontendOpts().Plugins)
+  };
+  return new MultiplexConsumer(Consumers);
+}
 
-  virtual void Initialize(ASTContext &Context) LLVM_OVERRIDE {
-    Consumer1->Initialize(Context);
-    Consumer2->Initialize(Context);
-  }
-  virtual bool HandleTopLevelDecl(DeclGroupRef D) LLVM_OVERRIDE {
-    return Consumer1->HandleTopLevelDecl(D) && Consumer2->HandleTopLevelDecl(D);
-  }
-  virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) LLVM_OVERRIDE {
-    Consumer1->HandleTopLevelDeclInObjCContainer(D);
-    Consumer2->HandleTopLevelDeclInObjCContainer(D);
-  }
-  virtual void HandleTranslationUnit(ASTContext &Context) LLVM_OVERRIDE {
-    Consumer1->HandleTranslationUnit(Context);
-    Consumer2->HandleTranslationUnit(Context);
-  }
+namespace {
 
-private:
-  llvm::OwningPtr<ASTConsumer> Consumer1;
-  llvm::OwningPtr<ASTConsumer> Consumer2;
-};
+static const char *AnalyzerCheckerNamePrefix = "clang-analyzer-";
 
 static StringRef StaticAnalyzerCheckers[] = {
 #define GET_CHECKERS
@@ -88,82 +90,6 @@
 #undef GET_CHECKERS
 };
 
-static const char *AnalyzerCheckerNamePrefix = "clang-analyzer-";
-
-/// \brief Action that runs clang-tidy and static analyzer checks.
-///
-/// FIXME: Note that this inherits from \c AnalysisAction as this is the only
-/// way we can currently get to AnalysisAction::CreateASTConsumer. Ideally
-/// we'd want to build a more generic way to use \c FrontendAction based
-/// checkers in clang-tidy, but that needs some preparation work first.
-class ClangTidyAction : public ento::AnalysisAction {
-public:
-  ClangTidyAction(ChecksFilter &Filter,
-                  SmallVectorImpl<ClangTidyCheck *> &Checks,
-                  ClangTidyContext &Context, MatchFinder &Finder)
-      : Filter(Filter), Checks(Checks), Context(Context), Finder(Finder) {}
-
-  typedef std::vector<std::pair<std::string, bool> > CheckersList;
-  void fillCheckersControlList(CheckersList &List) {
-    ArrayRef<StringRef> Checkers(StaticAnalyzerCheckers);
-
-    bool AnalyzerChecksEnabled = false;
-    for (unsigned i = 0; i < Checkers.size(); ++i) {
-      std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str());
-      AnalyzerChecksEnabled |=
-          Filter.IsCheckEnabled(Checker) && !Checkers[i].startswith("debug");
-    }
-
-    if (!AnalyzerChecksEnabled)
-      return;
-
-    // Run our regex against all possible static analyzer checkers.
-    // Note that debug checkers print values / run programs to visualize the CFG
-    // and are thus not applicable to clang-tidy in general.
-    // Always add all core checkers if any other static analyzer checks are
-    // enabled. This is currently necessary, as other path sensitive checks rely
-    // on the core checkers.
-    for (unsigned i = 0; i < Checkers.size(); ++i) {
-      std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str());
-
-      if (Checkers[i].startswith("core") ||
-          (!Checkers[i].startswith("debug") && Filter.IsCheckEnabled(Checker)))
-        List.push_back(std::make_pair(Checkers[i], true));
-    }
-  }
-
-private:
-  clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
-                                        StringRef File) LLVM_OVERRIDE {
-    AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts();
-    fillCheckersControlList(Options->CheckersControlList);
-    Options->AnalysisStoreOpt = RegionStoreModel;
-    Options->AnalysisDiagOpt = PD_TEXT;
-    Options->AnalyzeNestedBlocks = true;
-    Options->eagerlyAssumeBinOpBifurcation = true;
-    return new CombiningASTConsumer(
-        Finder.newASTConsumer(),
-        ento::AnalysisAction::CreateASTConsumer(Compiler, File));
-  }
-
-  virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
-                                     llvm::StringRef Filename) LLVM_OVERRIDE {
-    if (!ento::AnalysisAction::BeginSourceFileAction(Compiler, Filename))
-      return false;
-    Context.setSourceManager(&Compiler.getSourceManager());
-    for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(),
-                                                     E = Checks.end();
-         I != E; ++I)
-      (*I)->registerPPCallbacks(Compiler);
-    return true;
-  }
-
-  ChecksFilter &Filter;
-  SmallVectorImpl<ClangTidyCheck *> &Checks;
-  ClangTidyContext &Context;
-  MatchFinder &Finder;
-};
-
 class ClangTidyActionFactory : public FrontendActionFactory {
 public:
   ClangTidyActionFactory(StringRef EnableChecksRegex,
@@ -189,7 +115,8 @@
   }
 
   virtual FrontendAction *create() {
-    return new ClangTidyAction(Filter, Checks, Context, Finder);
+    return new ClangTidyAction(getCheckersControlList(), Checks, Context,
+                               Finder);
   }
 
   std::vector<std::string> getCheckNames() {
@@ -202,9 +129,7 @@
         CheckNames.push_back(I->first);
     }
 
-    ClangTidyAction Action(Filter, Checks, Context, Finder);
-    ClangTidyAction::CheckersList AnalyzerChecks;
-    Action.fillCheckersControlList(AnalyzerChecks);
+    ClangTidyAction::CheckersList AnalyzerChecks = getCheckersControlList();
     for (ClangTidyAction::CheckersList::const_iterator
              I = AnalyzerChecks.begin(),
              E = AnalyzerChecks.end();
@@ -216,6 +141,38 @@
   }
 
 private:
+  ClangTidyAction::CheckersList getCheckersControlList() {
+    ClangTidyAction::CheckersList List;
+    ArrayRef<StringRef> Checkers(StaticAnalyzerCheckers);
+
+    bool AnalyzerChecksEnabled = false;
+    for (unsigned i = 0; i < Checkers.size(); ++i) {
+      std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str());
+      AnalyzerChecksEnabled |=
+          Filter.IsCheckEnabled(Checker) && !Checkers[i].startswith("debug");
+    }
+
+    if (AnalyzerChecksEnabled) {
+      // Run our regex against all possible static analyzer checkers.
+      // Note that debug checkers print values / run programs to visualize the
+      // CFG
+      // and are thus not applicable to clang-tidy in general.
+      // Always add all core checkers if any other static analyzer checks are
+      // enabled. This is currently necessary, as other path sensitive checks
+      // rely
+      // on the core checkers.
+      for (unsigned i = 0; i < Checkers.size(); ++i) {
+        std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str());
+
+        if (Checkers[i].startswith("core") ||
+            (!Checkers[i].startswith("debug") &&
+             Filter.IsCheckEnabled(Checker)))
+          List.push_back(std::make_pair(Checkers[i], true));
+      }
+    }
+    return List;
+  }
+
   ChecksFilter Filter;
   SmallVector<ClangTidyCheck *, 8> Checks;
   ClangTidyContext &Context;
Index: clang-tidy/ClangTidy.h
===================================================================
--- clang-tidy/ClangTidy.h
+++ clang-tidy/ClangTidy.h
@@ -13,6 +13,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/Refactoring.h"
 #include "ClangTidyDiagnosticConsumer.h"
 
@@ -101,6 +102,29 @@
 std::vector<std::string> getCheckNames(StringRef EnableChecksRegex,
                                        StringRef DisableChecksRegex);
 
+/// \brief Action that runs clang-tidy and static analyzer checks.
+///
+/// FIXME: Ideally we'd want to build a more generic way to use
+/// \c FrontendAction based checkers in clang-tidy, but that needs some
+/// preparation work first.
+class ClangTidyAction : public ASTFrontendAction {
+public:
+  typedef std::vector<std::pair<std::string, bool> > CheckersList;
+
+  ClangTidyAction(CheckersList AnalyzerCheckers,
+                  SmallVectorImpl<ClangTidyCheck *> &Checks,
+                  ClangTidyContext &Context, ast_matchers::MatchFinder &Finder);
+
+  clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
+                                        StringRef File) LLVM_OVERRIDE;
+
+private:
+  CheckersList AnalyzerCheckers;
+  SmallVectorImpl<ClangTidyCheck *> &Checks;
+  ClangTidyContext &Context;
+  ast_matchers::MatchFinder &Finder;
+};
+
 /// \brief Returns an action factory that runs the specified clang-tidy checks.
 tooling::FrontendActionFactory *
 createClangTidyActionFactory(StringRef EnableChecksRegex,
Index: clang-tidy/ClangTidyDiagnosticConsumer.h
===================================================================
--- clang-tidy/ClangTidyDiagnosticConsumer.h
+++ clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -65,7 +65,8 @@
 /// \endcode
 class ClangTidyContext {
 public:
-  ClangTidyContext(SmallVectorImpl<ClangTidyError> *Errors) : Errors(Errors) {}
+  ClangTidyContext(SmallVectorImpl<ClangTidyError> *Errors)
+      : Errors(Errors), DiagEngine(0) {}
 
   /// \brief Report any errors detected using this method.
   ///
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to