avoid having to manuall modify sources when adding a new clang plugin

Now each one registers in its .cxx file.

Change-Id: I811c0d4400c2bdccc1c287269378d7e8ad8743ce
This commit is contained in:
Luboš Luňák
2013-02-02 17:45:18 +01:00
parent b8f932b6a5
commit a7c3adb773
16 changed files with 161 additions and 52 deletions

View File

@@ -139,4 +139,6 @@ void BodyNotInBlock::checkBody( const Stmt* body, SourceLocation stmtLocation, c
}
}
static Plugin::Registration< BodyNotInBlock > X( "bodynotinblock" );
} // namespace

View File

@@ -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;

View File

@@ -49,4 +49,6 @@ bool LclStaticFix::VisitFunctionDecl( FunctionDecl* declaration )
return true;
}
static Plugin::Registration< LclStaticFix > X( "lclstaticfix" );
} // namespace

View File

@@ -22,7 +22,7 @@ class LclStaticFix
{
public:
explicit LclStaticFix( ASTContext& context, Rewriter& rewriter );
void run();
virtual void run();
bool VisitFunctionDecl( FunctionDecl* declaration );
};

View File

@@ -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 )

View File

@@ -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

View File

@@ -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())
for( int i = 0;
i < pluginCount;
++i )
{
bodyNotInBlock.run();
salLogAreas.run();
unusedVariableCheck.run();
}
else
{
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();

View File

@@ -16,13 +16,6 @@
#include <clang/AST/ASTConsumer.h>
#include <clang/Frontend/FrontendAction.h>
#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

View File

@@ -162,4 +162,6 @@ bool PostfixIncrementFix::shouldDoChange( const Expr* operand )
}
}
static Plugin::Registration< PostfixIncrementFix > X( "postfixincrementfix" );
} // namespace

View File

@@ -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;

View File

@@ -73,4 +73,6 @@ bool RemoveForwardStringDecl::tryRemoveStringForwardDecl( const Decl* decl )
return false;
}
static Plugin::Registration< RemoveForwardStringDecl > X( "removeforwardstringdecl" );
} // namespace

View File

@@ -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 );

View File

@@ -131,4 +131,6 @@ void SalLogAreas::readLogAreas()
report( DiagnosticsEngine::Warning, "error reading log areas [loplugin]" );
}
static Plugin::Registration< SalLogAreas > X( "sallogareas" );
} // namespace

View File

@@ -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:

View File

@@ -100,4 +100,6 @@ bool UnusedVariableCheck::VisitVarDecl( VarDecl* var )
return true;
}
static Plugin::Registration< UnusedVariableCheck > X( "unusedvariablecheck" );
} // namespace

View File

@@ -22,7 +22,7 @@ class UnusedVariableCheck
{
public:
explicit UnusedVariableCheck( ASTContext& context );
void run();
virtual void run();
bool VisitVarDecl( VarDecl* var );
};