From a7c3adb773e5b69601716bda181cc481090a4d59 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Sat, 2 Feb 2013 17:45:18 +0100 Subject: avoid having to manuall modify sources when adding a new clang plugin Now each one registers in its .cxx file. Change-Id: I811c0d4400c2bdccc1c287269378d7e8ad8743ce --- compilerplugins/clang/bodynotinblock.cxx | 2 + compilerplugins/clang/bodynotinblock.hxx | 2 +- compilerplugins/clang/lclstaticfix.cxx | 2 + compilerplugins/clang/lclstaticfix.hxx | 2 +- compilerplugins/clang/plugin.cxx | 6 ++ compilerplugins/clang/plugin.hxx | 71 ++++++++++++++++++ compilerplugins/clang/pluginhandler.cxx | 87 +++++++++++++++++------ compilerplugins/clang/pluginhandler.hxx | 25 +------ compilerplugins/clang/postfixincrementfix.cxx | 2 + compilerplugins/clang/postfixincrementfix.hxx | 2 +- compilerplugins/clang/removeforwardstringdecl.cxx | 2 + compilerplugins/clang/removeforwardstringdecl.hxx | 2 +- compilerplugins/clang/sallogareas.cxx | 2 + compilerplugins/clang/sallogareas.hxx | 2 +- compilerplugins/clang/unusedvariablecheck.cxx | 2 + compilerplugins/clang/unusedvariablecheck.hxx | 2 +- 16 files changed, 161 insertions(+), 52 deletions(-) (limited to 'compilerplugins/clang') diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx index a2e79680d8e2..74cab892166b 100644 --- a/compilerplugins/clang/bodynotinblock.cxx +++ b/compilerplugins/clang/bodynotinblock.cxx @@ -139,4 +139,6 @@ void BodyNotInBlock::checkBody( const Stmt* body, SourceLocation stmtLocation, c } } +static Plugin::Registration< BodyNotInBlock > X( "bodynotinblock" ); + } // namespace diff --git a/compilerplugins/clang/bodynotinblock.hxx b/compilerplugins/clang/bodynotinblock.hxx index 3cfc9bafc8d5..e8d35dd58480 100644 --- a/compilerplugins/clang/bodynotinblock.hxx +++ b/compilerplugins/clang/bodynotinblock.hxx @@ -22,7 +22,7 @@ class BodyNotInBlock { public: explicit BodyNotInBlock( ASTContext& context ); - void run(); + virtual void run(); bool VisitFunctionDecl( FunctionDecl* declaration ); private: typedef vector< const Stmt* > StmtParents; diff --git a/compilerplugins/clang/lclstaticfix.cxx b/compilerplugins/clang/lclstaticfix.cxx index a5c765b229b7..e966139dbaa1 100644 --- a/compilerplugins/clang/lclstaticfix.cxx +++ b/compilerplugins/clang/lclstaticfix.cxx @@ -49,4 +49,6 @@ bool LclStaticFix::VisitFunctionDecl( FunctionDecl* declaration ) return true; } +static Plugin::Registration< LclStaticFix > X( "lclstaticfix" ); + } // namespace diff --git a/compilerplugins/clang/lclstaticfix.hxx b/compilerplugins/clang/lclstaticfix.hxx index fdf9d34107e7..64e5b2919461 100644 --- a/compilerplugins/clang/lclstaticfix.hxx +++ b/compilerplugins/clang/lclstaticfix.hxx @@ -22,7 +22,7 @@ class LclStaticFix { public: explicit LclStaticFix( ASTContext& context, Rewriter& rewriter ); - void run(); + virtual void run(); bool VisitFunctionDecl( FunctionDecl* declaration ); }; diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx index 05172b7a9a91..9ab9f2d13f7f 100644 --- a/compilerplugins/clang/plugin.cxx +++ b/compilerplugins/clang/plugin.cxx @@ -55,6 +55,12 @@ bool Plugin::ignoreLocation( SourceLocation loc ) return true; } +void Plugin::registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter ) + { + PluginHandler::registerPlugin( create, optionName, isRewriter ); + } + +///// RewritePlugin::RewritePlugin( ASTContext& context, Rewriter& rewriter ) : Plugin( context ) diff --git a/compilerplugins/clang/plugin.hxx b/compilerplugins/clang/plugin.hxx index af1394d57b6f..014329e12eb1 100644 --- a/compilerplugins/clang/plugin.hxx +++ b/compilerplugins/clang/plugin.hxx @@ -28,18 +28,36 @@ using namespace std; namespace loplugin { +/** + Base class for plugins. + + If you want to create a non-rewriter action, inherit from this class. Remember to also + use Plugin::Registration. +*/ class Plugin { public: explicit Plugin( ASTContext& context ); + virtual ~Plugin(); + virtual void run() = 0; + template< typename T > class Registration; protected: DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation()); bool ignoreLocation( SourceLocation loc ); bool ignoreLocation( const Decl* decl ); bool ignoreLocation( const Stmt* stmt ); ASTContext& context; + private: + static void registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter ); + template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter ); + enum { isRewriter = false }; }; +/** + Base class for rewriter plugins. + + Remember to also use Plugin::Registration. +*/ class RewritePlugin : public Plugin { @@ -85,10 +103,44 @@ class RewritePlugin bool replaceText( SourceRange range, SourceRange replacementRange ); Rewriter& rewriter; private: + template< typename T > friend class Plugin::Registration; + template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter ); + enum { isRewriter = true }; bool reportEditFailure( SourceLocation loc ); bool adjustForWholeStatement( SourceRange* range ); }; +/** + Plugin registration helper. + + If you create a new helper class, create also an instance of this class to automatically register it. + The passed argument is name of the plugin, used for explicitly invoking rewriter plugins + (it is ignored for non-rewriter plugins). + + @code + static Plugin::Registration< NameOfClass > X( "nameofclass" ); + @endcode +*/ +template< typename T > +class Plugin::Registration + { + public: + Registration( const char* optionName ); + }; + +class RegistrationCreate + { + public: + template< typename T, bool > static T* create( ASTContext& context, Rewriter& rewriter ); + }; + +///// + +inline +Plugin::~Plugin() + { + } + inline bool Plugin::ignoreLocation( const Decl* decl ) { @@ -101,6 +153,25 @@ bool Plugin::ignoreLocation( const Stmt* stmt ) return ignoreLocation( stmt->getLocStart()); } +template< typename T > +Plugin* Plugin::createHelper( ASTContext& context, Rewriter& ) + { + return new T( context ); + } + +template< typename T > +Plugin* RewritePlugin::createHelper( ASTContext& context, Rewriter& rewriter ) + { + return new T( context, rewriter ); + } + +template< typename T > +inline +Plugin::Registration< T >::Registration( const char* optionName ) + { + registerPlugin( &T::template createHelper< T >, optionName, T::isRewriter ); + } + } // namespace #endif // COMPILEPLUGIN_H diff --git a/compilerplugins/clang/pluginhandler.cxx b/compilerplugins/clang/pluginhandler.cxx index fd2c62e58caf..35d881ec52f2 100644 --- a/compilerplugins/clang/pluginhandler.cxx +++ b/compilerplugins/clang/pluginhandler.cxx @@ -19,39 +19,80 @@ namespace loplugin { +struct PluginData + { + Plugin* (*create)( ASTContext&, Rewriter& ); + Plugin* object; + const char* optionName; + bool isRewriter; + }; + +const int MAX_PLUGINS = 100; +static PluginData plugins[ MAX_PLUGINS ]; +static int pluginCount = 0; +static bool pluginObjectsCreated = false; + PluginHandler::PluginHandler( ASTContext& context, const vector< string >& args ) : rewriter( context.getSourceManager(), context.getLangOpts()) - , args( args ) - , bodyNotInBlock( context ) - , lclStaticFix( context, rewriter ) - , postfixIncrementFix( context, rewriter ) - , removeForwardStringDecl( context, rewriter ) - , salLogAreas( context ) - , unusedVariableCheck( context ) { + bool wasCreated = false; + for( int i = 0; + i < pluginCount; + ++i ) + { + bool create = false; + if( args.empty()) // no args -> create non-writer plugins + create = !plugins[ i ].isRewriter; + else // create only the given plugin(s) + { + if( find( args.begin(), args.end(), plugins[ i ].optionName ) != args.end()) + create = true; + } + if( create ) + { + plugins[ i ].object = plugins[ i ].create( context, rewriter ); + wasCreated = true; + } + } + pluginObjectsCreated = true; + if( !args.empty() && !wasCreated ) + { + DiagnosticsEngine& diag = context.getDiagnostics(); + diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Fatal, + "unknown plugin tool %0 [loplugin]" )) << args.front(); + } + } + +PluginHandler::~PluginHandler() + { + for( int i = 0; + i < pluginCount; + ++i ) + if( plugins[ i ].object != NULL ) + delete plugins[ i ].object; + } + +void PluginHandler::registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter ) + { + assert( !pluginObjectsCreated ); + assert( pluginCount < MAX_PLUGINS ); + plugins[ pluginCount ].create = create; + plugins[ pluginCount ].object = NULL; + plugins[ pluginCount ].optionName = optionName; + plugins[ pluginCount ].isRewriter = isRewriter; + ++pluginCount; } void PluginHandler::HandleTranslationUnit( ASTContext& context ) { if( context.getDiagnostics().hasErrorOccurred()) return; - if( isArg( "lclstaticfix" )) - lclStaticFix.run(); - else if( isArg( "postfixincrementfix" )) - postfixIncrementFix.run(); - else if( isArg( "removeforwardstringdecl" )) - removeForwardStringDecl.run(); - else if( args.empty()) - { - bodyNotInBlock.run(); - salLogAreas.run(); - unusedVariableCheck.run(); - } - else + for( int i = 0; + i < pluginCount; + ++i ) { - DiagnosticsEngine& diag = context.getDiagnostics(); - diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Fatal, - "unknown plugin tool %0 [loplugin]" )) << args.front(); + if( plugins[ i ].object != NULL ) + plugins[ i ].object->run(); } for( Rewriter::buffer_iterator it = rewriter.buffer_begin(); it != rewriter.buffer_end(); diff --git a/compilerplugins/clang/pluginhandler.hxx b/compilerplugins/clang/pluginhandler.hxx index d9ac63341122..2211275208ae 100644 --- a/compilerplugins/clang/pluginhandler.hxx +++ b/compilerplugins/clang/pluginhandler.hxx @@ -16,13 +16,6 @@ #include #include -#include "bodynotinblock.hxx" -#include "lclstaticfix.hxx" -#include "postfixincrementfix.hxx" -#include "removeforwardstringdecl.hxx" -#include "sallogareas.hxx" -#include "unusedvariablecheck.hxx" - namespace loplugin { @@ -34,17 +27,11 @@ class PluginHandler { public: PluginHandler( ASTContext& context, const vector< string >& args ); + virtual ~PluginHandler(); virtual void HandleTranslationUnit( ASTContext& context ); + static void registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter ); private: - bool isArg( const char* arg ) const; Rewriter rewriter; - vector< string > args; - BodyNotInBlock bodyNotInBlock; - LclStaticFix lclStaticFix; - PostfixIncrementFix postfixIncrementFix; - RemoveForwardStringDecl removeForwardStringDecl; - SalLogAreas salLogAreas; - UnusedVariableCheck unusedVariableCheck; }; /** @@ -60,14 +47,6 @@ class LibreOfficeAction vector< string > _args; }; -///// - -inline -bool PluginHandler::isArg( const char* arg ) const - { - return find( args.begin(), args.end(), arg ) != args.end(); - } - } // namespace #endif // COMPILEPLUGIN_H diff --git a/compilerplugins/clang/postfixincrementfix.cxx b/compilerplugins/clang/postfixincrementfix.cxx index bfaf77cefa6c..2f474761830f 100644 --- a/compilerplugins/clang/postfixincrementfix.cxx +++ b/compilerplugins/clang/postfixincrementfix.cxx @@ -162,4 +162,6 @@ bool PostfixIncrementFix::shouldDoChange( const Expr* operand ) } } +static Plugin::Registration< PostfixIncrementFix > X( "postfixincrementfix" ); + } // namespace diff --git a/compilerplugins/clang/postfixincrementfix.hxx b/compilerplugins/clang/postfixincrementfix.hxx index 6f6b414690b0..beae8a76e520 100644 --- a/compilerplugins/clang/postfixincrementfix.hxx +++ b/compilerplugins/clang/postfixincrementfix.hxx @@ -22,7 +22,7 @@ class PostfixIncrementFix { public: explicit PostfixIncrementFix( ASTContext& context, Rewriter& rewriter ); - void run(); + virtual void run(); bool VisitFunctionDecl( FunctionDecl* declaration ); private: typedef std::vector< const Stmt* > StmtParents; diff --git a/compilerplugins/clang/removeforwardstringdecl.cxx b/compilerplugins/clang/removeforwardstringdecl.cxx index 45891d5d7fb3..711d9604dc9f 100644 --- a/compilerplugins/clang/removeforwardstringdecl.cxx +++ b/compilerplugins/clang/removeforwardstringdecl.cxx @@ -73,4 +73,6 @@ bool RemoveForwardStringDecl::tryRemoveStringForwardDecl( const Decl* decl ) return false; } +static Plugin::Registration< RemoveForwardStringDecl > X( "removeforwardstringdecl" ); + } // namespace diff --git a/compilerplugins/clang/removeforwardstringdecl.hxx b/compilerplugins/clang/removeforwardstringdecl.hxx index 7f40e371817d..2b66a522fc4d 100644 --- a/compilerplugins/clang/removeforwardstringdecl.hxx +++ b/compilerplugins/clang/removeforwardstringdecl.hxx @@ -22,7 +22,7 @@ class RemoveForwardStringDecl { public: explicit RemoveForwardStringDecl( ASTContext& context, Rewriter& rewriter ); - void run(); + virtual void run(); bool VisitNamespaceDecl( NamespaceDecl* declaration ); private: bool tryRemoveStringForwardDecl( const Decl* decl ); diff --git a/compilerplugins/clang/sallogareas.cxx b/compilerplugins/clang/sallogareas.cxx index 7e6c187d7e9a..1a3a651a7959 100644 --- a/compilerplugins/clang/sallogareas.cxx +++ b/compilerplugins/clang/sallogareas.cxx @@ -131,4 +131,6 @@ void SalLogAreas::readLogAreas() report( DiagnosticsEngine::Warning, "error reading log areas [loplugin]" ); } +static Plugin::Registration< SalLogAreas > X( "sallogareas" ); + } // namespace diff --git a/compilerplugins/clang/sallogareas.hxx b/compilerplugins/clang/sallogareas.hxx index e83e890697e4..d572591c62ee 100644 --- a/compilerplugins/clang/sallogareas.hxx +++ b/compilerplugins/clang/sallogareas.hxx @@ -24,7 +24,7 @@ class SalLogAreas { public: explicit SalLogAreas( ASTContext& context ); - void run(); + virtual void run(); bool VisitFunctionDecl( FunctionDecl* function ); bool VisitCallExpr( CallExpr* call ); private: diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx index 759b9fa946ec..93ad85163607 100644 --- a/compilerplugins/clang/unusedvariablecheck.cxx +++ b/compilerplugins/clang/unusedvariablecheck.cxx @@ -100,4 +100,6 @@ bool UnusedVariableCheck::VisitVarDecl( VarDecl* var ) return true; } +static Plugin::Registration< UnusedVariableCheck > X( "unusedvariablecheck" ); + } // namespace diff --git a/compilerplugins/clang/unusedvariablecheck.hxx b/compilerplugins/clang/unusedvariablecheck.hxx index 7bf1cdd15ddd..6ccdee3e193e 100644 --- a/compilerplugins/clang/unusedvariablecheck.hxx +++ b/compilerplugins/clang/unusedvariablecheck.hxx @@ -22,7 +22,7 @@ class UnusedVariableCheck { public: explicit UnusedVariableCheck( ASTContext& context ); - void run(); + virtual void run(); bool VisitVarDecl( VarDecl* var ); }; -- cgit