diff options
author | Luboš Luňák <l.lunak@suse.cz> | 2012-12-20 23:08:52 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@suse.cz> | 2013-01-04 15:27:26 +0100 |
commit | c26e655264f03bb8bc484130ab2f539a9f831f16 (patch) | |
tree | c25225c8deab3cdfd3d3aa11b491beb7817fa33c | |
parent | 217e3f2ea1e8983328364607f244daceeafca167 (diff) |
support for removing a statement as a whole
Change-Id: Icb7b017a0c76a6169f0f629bb40bf97449c75837
-rw-r--r-- | compilerplugins/clang/plugin.cxx | 39 | ||||
-rw-r--r-- | compilerplugins/clang/plugin.hxx | 28 |
2 files changed, 57 insertions, 10 deletions
diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx index 6535e1a96471..22bac0cdfe8c 100644 --- a/compilerplugins/clang/plugin.cxx +++ b/compilerplugins/clang/plugin.cxx @@ -105,22 +105,47 @@ bool RewritePlugin::insertTextBefore( SourceLocation Loc, StringRef Str ) bool RewritePlugin::removeText( SourceLocation Start, unsigned Length, RewriteOptions opts ) { - if( rewriter.RemoveText( Start, Length, opts )) - return reportEditFailure( Start ); - return true; + return removeText( SourceRange( Start, Start.getLocWithOffset( Length )), opts ); } -bool RewritePlugin::removeText( CharSourceRange range, RewriteOptions opts ) +bool RewritePlugin::removeText( SourceRange range, RewriteOptions opts ) { + if( opts.RemoveWholeStatement ) + { + if( !adjustForWholeStatement( &range )) + return reportEditFailure( range.getBegin()); + } if( rewriter.RemoveText( range, opts )) return reportEditFailure( range.getBegin()); return true; } -bool RewritePlugin::removeText( SourceRange range, RewriteOptions opts ) +bool RewritePlugin::adjustForWholeStatement( SourceRange* range ) { - if( rewriter.RemoveText( range, opts )) - return reportEditFailure( range.getBegin()); + SourceManager& SM = rewriter.getSourceMgr(); + SourceLocation fileStartLoc = SM.getLocForStartOfFile( SM.getFileID( range->getBegin())); + if( fileStartLoc.isInvalid()) + return false; + bool invalid = false; + const char* fileBuf = SM.getCharacterData( fileStartLoc, &invalid ); + if( invalid ) + return false; + const char* startBuf = SM.getCharacterData( range->getBegin(), &invalid ); + if( invalid ) + return false; + const char* endBuf = SM.getCharacterData( range->getEnd(), &invalid ); + if( invalid ) + return false; + const char* startSpacePos = startBuf; + // do not skip \n here, RemoveLineIfEmpty can take care of that + --startSpacePos; + while( startSpacePos >= fileBuf && ( *startSpacePos == ' ' || *startSpacePos == '\t' )) + --startSpacePos; + const char* semiPos = strchr( endBuf, ';' ); + if( semiPos == NULL ) + return false; + *range = SourceRange( range->getBegin().getLocWithOffset( startSpacePos - startBuf + 1 ), + range->getEnd().getLocWithOffset( semiPos - endBuf + 1 )); return true; } diff --git a/compilerplugins/clang/plugin.hxx b/compilerplugins/clang/plugin.hxx index 2a587addcb54..b9409b2cfc1c 100644 --- a/compilerplugins/clang/plugin.hxx +++ b/compilerplugins/clang/plugin.hxx @@ -44,18 +44,39 @@ class RewritePlugin public: explicit RewritePlugin( ASTContext& context, Rewriter& rewriter ); protected: - typedef Rewriter::RewriteOptions RewriteOptions; + // This enum allows passing just 'RemoveLineIfEmpty' to functions below. + enum RemoveLineIfEmpty_t { RemoveLineIfEmpty }; + // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement + // and the trailing semicolor (is not part of the AST element range itself). + // The trailing semicolon must be present. + enum RemoveWholeStatement_t { RemoveWholeStatement }; + enum RemoveLineIfEmptyAndWholeStatement_t { RemoveLineIfEmptyAndWholeStatement }; + // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement' + friend RemoveLineIfEmptyAndWholeStatement_t operator|( RemoveLineIfEmpty_t, RemoveWholeStatement_t ) + { return RemoveLineIfEmptyAndWholeStatement; } + struct RewriteOptions + : public Rewriter::RewriteOptions + { + RewriteOptions() : RemoveWholeStatement( false ) {} // default + RewriteOptions( RemoveLineIfEmpty_t ) : RemoveWholeStatement( false ) { RemoveLineIfEmpty = true; } + RewriteOptions( RemoveWholeStatement_t ) : RemoveWholeStatement( true ) {} + RewriteOptions( RemoveLineIfEmptyAndWholeStatement_t ) : RemoveWholeStatement( true ) { RemoveLineIfEmpty = true; } + bool RemoveWholeStatement; + }; // These following insert/remove/replaceText functions map to functions - // in clang::Rewriter, with two differences: + // in clang::Rewriter, with these differences: // - they (more intuitively) return false on failure rather than true // - they report a warning when the change cannot be done + // - There is RemoveWholeStatement to also remove the trailing semicolon when removing (must be there) + // and al preceding whitespace. bool insertText( SourceLocation Loc, StringRef Str, bool InsertAfter = true, bool indentNewLines = false ); bool insertTextAfter( SourceLocation Loc, StringRef Str ); bool insertTextAfterToken( SourceLocation Loc, StringRef Str ); bool insertTextBefore( SourceLocation Loc, StringRef Str ); bool removeText( SourceLocation Start, unsigned Length, RewriteOptions opts = RewriteOptions()); - bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions()); + // CharSourceRange not supported, unless really needed, as it makes RemoveSemicolon more complicated + //bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions()); bool removeText( SourceRange range, RewriteOptions opts = RewriteOptions()); bool replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr ); bool replaceText( SourceRange range, StringRef NewStr ); @@ -63,6 +84,7 @@ class RewritePlugin Rewriter& rewriter; private: bool reportEditFailure( SourceLocation loc ); + bool adjustForWholeStatement( SourceRange* range ); }; inline |