From deb6447d0029bdb122397fafb5fa2a4e76f2e555 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 28 Feb 2011 17:36:09 +0000 Subject: [PATCH] [analyzer] Introduce "event" mechanism in CheckerManager. A checker can register as receiver/listener of "events" (basically it registers a callback with a function getting called with an argument of the event type) and other checkers can register as "dispatchers" and can pass an event object to all the listeners. This allows cooperation amongst checkers but with very loose coupling. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126658 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../StaticAnalyzer/Core/CheckerManager.h | 57 ++++++++++++++++- include/clang/StaticAnalyzer/Core/CheckerV2.h | 63 +++++++++++++++---- lib/StaticAnalyzer/Core/CheckerManager.cpp | 10 +++ .../Frontend/CheckerRegistration.cpp | 2 + 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 3c23cbd29f..d57b55f5f7 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -97,6 +97,8 @@ public: CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } ~CheckerManager(); + void finishedCheckerRegistration(); + const LangOptions &getLangOptions() const { return LangOpts; } typedef void *CheckerRef; @@ -112,7 +114,7 @@ public: /// \returns a pointer to the checker object. template CHECKER *registerChecker() { - CheckerTag tag = getCheckerTag(); + CheckerTag tag = getTag(); CheckerRef &ref = CheckerTags[tag]; if (ref) return static_cast(ref); // already registered. @@ -349,6 +351,46 @@ public: void _registerForEvalCall(EvalCallFunc checkfn); +//===----------------------------------------------------------------------===// +// Internal registration functions for events. +//===----------------------------------------------------------------------===// + + typedef void *EventTag; + + class CheckEventFunc { + typedef void (*Func)(void *, const void *); + Func Fn; + public: + void *Checker; + CheckEventFunc(void *checker, Func fn) + : Fn(fn), Checker(checker) { } + void operator()(const void *event) const { + return Fn(Checker, event); + } + }; + + template + void _registerListenerForEvent(CheckEventFunc checkfn) { + EventInfo &info = Events[getTag()]; + info.Checkers.push_back(checkfn); + } + + template + void _registerDispatcherForEvent() { + EventInfo &info = Events[getTag()]; + info.HasDispatcher = true; + } + + template + void _dispatchEvent(const EVENT &event) const { + EventsTy::const_iterator I = Events.find(getTag()); + if (I == Events.end()) + return; + const EventInfo &info = I->second; + for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) + info.Checkers[i](&event); + } + //===----------------------------------------------------------------------===// // Implementation details. //===----------------------------------------------------------------------===// @@ -357,8 +399,8 @@ private: template static void destruct(void *obj) { delete static_cast(obj); } - template - static CheckerTag getCheckerTag() { static int tag; return &tag; } + template + static void *getTag() { static int tag; return &tag; } llvm::DenseMap CheckerTags; @@ -439,6 +481,15 @@ private: std::vector EvalAssumeCheckers; std::vector EvalCallCheckers; + + struct EventInfo { + llvm::SmallVector Checkers; + bool HasDispatcher; + EventInfo() : HasDispatcher(false) { } + }; + + typedef llvm::DenseMap EventsTy; + EventsTy Events; }; } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h index 931cee9931..a4c7c7d806 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerV2.h +++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -259,6 +259,20 @@ public: } }; +template +class Event { + template + static void _checkEvent(void *checker, const void *event) { + ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); + } +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerListenerForEvent( + CheckerManager::CheckEventFunc(checker, _checkEvent)); + } +}; + } // end check namespace namespace eval { @@ -300,22 +314,47 @@ template -class CheckerV2 { +class CheckerV2; + +template <> +class CheckerV2 { +public: + static void _register(void *checker, CheckerManager &mgr) { } +}; + +template +class CheckerV2 + : public CHECK1, + public CheckerV2 { public: template static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); - CHECK2::_register(checker, mgr); - CHECK3::_register(checker, mgr); - CHECK4::_register(checker, mgr); - CHECK5::_register(checker, mgr); - CHECK6::_register(checker, mgr); - CHECK7::_register(checker, mgr); - CHECK8::_register(checker, mgr); - CHECK9::_register(checker, mgr); - CHECK10::_register(checker, mgr); - CHECK11::_register(checker, mgr); - CHECK12::_register(checker, mgr); + CheckerV2::_register(checker, mgr); + } +}; + +template +class EventDispatcher { + CheckerManager *Mgr; +public: + EventDispatcher() : Mgr(0) { } + + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerDispatcherForEvent(); + static_cast *>(checker)->Mgr = &mgr; + } + + void dispatchEvent(const EVENT &event) const { + Mgr->_dispatchEvent(event); } }; diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index 4776f5702d..74f47e4f77 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -20,6 +20,16 @@ using namespace clang; using namespace ento; +void CheckerManager::finishedCheckerRegistration() { +#ifndef NDEBUG + // Make sure that for every event that has listeners, there is at least + // one dispatcher registered for it. + for (llvm::DenseMap::iterator + I = Events.begin(), E = Events.end(); I != E; ++I) + assert(I->second.HasDispatcher && "No dispatcher registered for an event"); +#endif +} + //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing.. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 677e20cd9c..0484cbed3b 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -43,6 +43,8 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts, // FIXME: Load CheckerProviders from plugins. + checkerMgr->finishedCheckerRegistration(); + for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { if (checkerOpts[i].isUnclaimed()) diags.Report(diag::warn_unkwown_analyzer_checker) -- 2.40.0