From 857a39265452c23d4769e6d729ae4c30e44b2973 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Sat, 9 Feb 2013 18:47:55 +0100 Subject: make it possible to limit what files will be modified by a compiler plugin Change-Id: I4e3e8f5ca5e5b5b59b1bd067281f90940dd893b1 --- compilerplugins/clang/pluginhandler.cxx | 101 ++++++++++++++++++++++++-------- compilerplugins/clang/pluginhandler.hxx | 3 + 2 files changed, 81 insertions(+), 23 deletions(-) (limited to 'compilerplugins/clang') diff --git a/compilerplugins/clang/pluginhandler.cxx b/compilerplugins/clang/pluginhandler.cxx index 468587e58c6f..0d27ff67d0bb 100644 --- a/compilerplugins/clang/pluginhandler.cxx +++ b/compilerplugins/clang/pluginhandler.cxx @@ -13,6 +13,7 @@ #include #include #include +#include #include /* @@ -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; diff --git a/compilerplugins/clang/pluginhandler.hxx b/compilerplugins/clang/pluginhandler.hxx index 23ca21767fd5..0a3251eeeb4f 100644 --- a/compilerplugins/clang/pluginhandler.hxx +++ b/compilerplugins/clang/pluginhandler.hxx @@ -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; }; /** -- cgit