Kaydet (Commit) 857a3926 authored tarafından Luboš Luňák's avatar Luboš Luňák

make it possible to limit what files will be modified by a compiler plugin

Change-Id: I4e3e8f5ca5e5b5b59b1bd067281f90940dd893b1
üst 8f1a01ad
......@@ -35,8 +35,15 @@ All warnings and errors are marked '[loplugin]' in the message.
Rewriters analyse and possibly modify given source files.
Usage: make COMPILER_PLUGIN_TOOL=<rewriter_name>
It is possible to also pass FORCE_COMPILE_ALL=1 to make to trigger rebuild of all source files,
even those that are up to date.
Additional optional make arguments:
- it is possible to also pass FORCE_COMPILE_ALL=1 to make to trigger rebuild of all source files,
even those that are up to date.
- UPDATE_FILES=<scope> - limits which modified files will be actually written back with the changes
- mainfile - only the main .cxx file will be modifed (default)
- all - all source files involved will be modified (possibly even header files from other LO modules),
3rd party header files are however never modified
- <module> - only files in the given LO module (toplevel directory) will be modified (including headers)
Modifications will be written directly to the source files.
......
......@@ -13,6 +13,7 @@
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
/*
......@@ -38,29 +39,24 @@ static bool pluginObjectsCreated = false;
PluginHandler::PluginHandler( ASTContext& context, const vector< string >& args )
: context( context )
, rewriter( context.getSourceManager(), context.getLangOpts())
, scope( "mainfile" )
{
bool wasCreated = false;
for( int i = 0;
i < pluginCount;
++i )
bool wasPlugin = false;
for( vector< string >::const_iterator it = args.begin();
it != args.end();
++it )
{
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 )
if( it->size() >= 2 && (*it)[ 0 ] == '-' && (*it)[ 1 ] == '-' )
handleOption( it->substr( 2 ));
else
{
plugins[ i ].object = plugins[ i ].create( context, rewriter );
wasCreated = true;
createPlugin( *it );
wasPlugin = true;
}
}
if( !wasPlugin )
createPlugin( "" ); // = all non-rewriters
pluginObjectsCreated = true;
if( !args.empty() && !wasCreated )
report( DiagnosticsEngine::Fatal, "unknown plugin tool %0" ) << args.front();
}
PluginHandler::~PluginHandler()
......@@ -72,6 +68,45 @@ PluginHandler::~PluginHandler()
delete plugins[ i ].object;
}
void PluginHandler::handleOption( const string& option )
{
if( option.substr( 0, 6 ) == "scope=" )
{
scope = option.substr( 6 );
if( scope == "mainfile" || scope == "all" )
; // ok
else
{
struct stat st;
if( stat(( SRCDIR "/" + scope ).c_str(), &st ) != 0 || !S_ISDIR( st.st_mode ))
report( DiagnosticsEngine::Fatal, "unknown scope %0 (no such module directory)" ) << scope;
}
}
else
report( DiagnosticsEngine::Fatal, "unknown option %0" ) << option;
}
void PluginHandler::createPlugin( const string& name )
{
for( int i = 0;
i < pluginCount;
++i )
{
if( name.empty()) // no plugin given -> create non-writer plugins
{
if( !plugins[ i ].isRewriter )
plugins[ i ].object = plugins[ i ].create( context, rewriter );
}
else if( plugins[ i ].optionName == name )
{
plugins[ i ].object = plugins[ i ].create( context, rewriter );
return;
}
}
if( !name.empty())
report( DiagnosticsEngine::Fatal, "unknown plugin tool %0" ) << name;
}
void PluginHandler::registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter )
{
assert( !pluginObjectsCreated );
......@@ -109,6 +144,8 @@ void PluginHandler::HandleTranslationUnit( ASTContext& context )
The order here is important, as OUTDIR and WORKDIR are often in SRCDIR/BUILDDIR,
and BUILDDIR is sometimes in SRCDIR. */
string modifyFile;
const char* pathWarning = NULL;
bool skip = false;
if( strncmp( e->getName(), OUTDIR "/", strlen( OUTDIR "/" )) == 0 )
{
/* Try to find a matching file for a file in solver/ (include files
......@@ -125,22 +162,40 @@ void PluginHandler::HandleTranslationUnit( ASTContext& context )
}
}
if( modifyFile.empty())
report( DiagnosticsEngine::Warning, "modified source in solver/ : %0" ) << e->getName();
pathWarning = "modified source in solver/ : %0";
}
else if( strncmp( e->getName(), WORKDIR "/", strlen( WORKDIR "/" )) == 0 )
report( DiagnosticsEngine::Warning, "modified source in workdir/ : %0" ) << e->getName();
pathWarning = "modified source in workdir/ : %0";
else if( strcmp( SRCDIR, BUILDDIR ) != 0 && strncmp( e->getName(), BUILDDIR "/", strlen( BUILDDIR "/" )) == 0 )
report( DiagnosticsEngine::Warning, "modified source in build dir : %0" ) << e->getName();
pathWarning = "modified source in build dir : %0";
else if( strncmp( e->getName(), SRCDIR "/", strlen( SRCDIR "/" )) == 0 )
; // ok
else
{
report( DiagnosticsEngine::Warning, "modified source in unknown location, not modifying : %0" )
<< e->getName();
continue; // --->
pathWarning = "modified source in unknown location, not modifying : %0";
skip = true;
}
if( modifyFile.empty())
modifyFile = e->getName();
// Check whether the modified file is in the wanted scope (done after path checking above), so
// that files mapped from OUTDIR to SRCDIR are included.
if( scope == "mainfile" )
{
if( it->first != context.getSourceManager().getMainFileID())
continue;
}
else if( scope == "all" )
; // ok
else // scope is module
{
if( strncmp( modifyFile.c_str(), ( SRCDIR "/" + scope + "/" ).c_str(), ( SRCDIR "/" + scope + "/" ).size()) != 0 )
continue;
}
// Warn only now, so that files not in scope do not cause warnings.
if( pathWarning != NULL )
report( DiagnosticsEngine::Warning, pathWarning ) << e->getName();
if( skip )
continue;
char* filename = new char[ modifyFile.length() + 100 ];
sprintf( filename, "%s.new.%d", modifyFile.c_str(), getpid());
string error;
......
......@@ -31,9 +31,12 @@ class PluginHandler
virtual void HandleTranslationUnit( ASTContext& context );
static void registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter );
private:
void handleOption( const string& option );
void createPlugin( const string& name );
DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation());
ASTContext& context;
Rewriter rewriter;
string scope;
};
/**
......
......@@ -167,6 +167,9 @@ ifeq ($(COMPILER_PLUGIN_TOOL),)
gb_COMPILER_PLUGINS := -Xclang -load -Xclang $(BUILDDIR)/compilerplugins/obj/plugin.so -Xclang -add-plugin -Xclang loplugin
else
gb_COMPILER_PLUGINS := -Xclang -load -Xclang $(BUILDDIR)/compilerplugins/obj/plugin.so -Xclang -plugin -Xclang loplugin -Xclang -plugin-arg-loplugin -Xclang $(COMPILER_PLUGIN_TOOL)
ifneq ($(UPDATE_FILES),)
gb_COMPILER_PLUGINS += -Xclang -plugin-arg-loplugin -Xclang --scope=$(UPDATE_FILES)
endif
endif
# extra EF variable to make the command line shorter (just like is done with $(SRCDIR) etc.)
gb_COMPILER_PLUGINS_SETUP := EF=$(SRCDIR)/sal/inc/sal/log-areas.dox && ICECC_EXTRAFILES=$$EF CCACHE_EXTRAFILES=$$EF
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment