diff options
Diffstat (limited to '')
-rw-r--r-- | compilerplugins/clang/store/valueof.cxx | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/valueof.cxx b/compilerplugins/clang/store/valueof.cxx new file mode 100644 index 000000000..2b769a3e8 --- /dev/null +++ b/compilerplugins/clang/store/valueof.cxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +/* +This is a rewriter. + +Replaces all calls to the deprecated O(U)String::valueOf() . + +*/ + +#include "plugin.hxx" + +namespace loplugin +{ + +class ConvertValueOf + : public loplugin::FilteringRewritePlugin< ConvertValueOf > + { + public: + explicit ConvertValueOf( CompilerInstance& compiler, Rewriter& rewriter ); + virtual void run() override; + bool VisitCallExpr( const CallExpr* call ); + private: + void removeCast( const Expr* arg ); + }; + +ConvertValueOf::ConvertValueOf( CompilerInstance& compiler, Rewriter& rewriter ) + : FilteringRewritePlugin( compiler, rewriter ) + { + } + +void ConvertValueOf::run() + { + TraverseDecl( compiler.getASTContext().getTranslationUnitDecl()); + } + +bool ConvertValueOf::VisitCallExpr( const CallExpr* call ) + { + if( ignoreLocation( call )) + return true; + // Using getDirectCallee() here means that we find only calls + // that call the function directly (i.e. not using a pointer, for example). + // Use getCallee() to include also those : + // if( const FunctionDecl* func = dyn_cast_or_null< FunctionDecl >( call->getCalleeDecl())) + if( const FunctionDecl* func = call->getDirectCallee()) + { + // Optimize, getQualifiedNameAsString() is reportedly expensive, + // so first check fast details like number of arguments or the (unqualified) + // name before checking the fully qualified name. + // See FunctionDecl for all the API about the function. + if( func->getIdentifier() != NULL + && ( func->getName() == "valueOf" )) + { + string qualifiedName = func->getQualifiedNameAsString(); + if( qualifiedName == "rtl::OString::valueOf" ) + { + // Further checks about arguments. Check mainly ParmVarDecl, VarDecl, + // ValueDecl and QualType for Clang API details. + string arg0 = func->getParamDecl( 0 )->getType().getAsString(); + if( arg0 == "sal_Bool" ) + replaceText( call->getCallee()->getSourceRange(), "OString::boolean" ); + else if( arg0 == "sal_Char" ) + replaceText( call->getCallee()->getSourceRange(), "OString" ); + else + { + replaceText( call->getCallee()->getSourceRange(), "OString::number" ); + removeCast( call->getArg( 0 )); + } + } + if( qualifiedName == "rtl::OUString::valueOf" ) + { + // Further checks about arguments. Check mainly ParmVarDecl, VarDecl, + // ValueDecl and QualType for Clang API details. + string arg0 = func->getParamDecl( 0 )->getType().getAsString(); + if( arg0 == "sal_Bool" ) + replaceText( call->getCallee()->getSourceRange(), "OUString::boolean" ); + else if( arg0 == "sal_Unicode" ) + replaceText( call->getCallee()->getSourceRange(), "OUString" ); + else + { + replaceText( call->getCallee()->getSourceRange(), "OUString::number" ); + removeCast( call->getArg( 0 )); + } + } + } + } + return true; + } + +void ConvertValueOf::removeCast( const Expr* arg ) + { + arg = arg->IgnoreImpCasts(); + if( const ExplicitCastExpr* cast = dyn_cast< ExplicitCastExpr >( arg )) + { +// Explicit casts don't seem to actually always change the type (integer promotion +// takes place first?), so remove also preceding implicit casts: +// void f( int ); +// char a; +// f( int( a )); +// |-CallExpr 0x1a84f20 <line:6:5, col:16> 'void' +// | |-ImplicitCastExpr 0x1a84f08 <col:5> 'void (*)(int)' <FunctionToPointerDecay> +// | | `-DeclRefExpr 0x1a84eb8 <col:5> 'void (int)' lvalue Function 0x1a58900 'f' 'void (int)' +// | `-CXXFunctionalCastExpr 0x1a84e90 <col:8, col:15> 'int' functional cast to int <NoOp> +// | `-ImplicitCastExpr 0x1a84e78 <col:13> 'int' <IntegralCast> +// | `-ImplicitCastExpr 0x1a84e60 <col:13> 'char' <LValueToRValue> +// | `-DeclRefExpr 0x1a58b88 <col:13> 'char' lvalue Var 0x1a58ab0 'a' 'char' + const Expr* castFrom = cast->getSubExpr()->IgnoreImpCasts(); + if( cast->getType()->isIntegerType() && castFrom->getType()->isIntegerType()) + { + string fromType = castFrom->getType().getAsString(); + if( fromType != "sal_Bool" && fromType != "bool" && fromType != "sal_Char" && fromType != "sal_Unicode" ) + { + if( const CXXFunctionalCastExpr* funcCast = dyn_cast< CXXFunctionalCastExpr >( cast )) + { + removeText( CharSourceRange::getCharRange( funcCast->getLocStart(), + compiler.getSourceManager().getExpansionLoc( funcCast->getSubExpr()->getLocStart()))); + removeText( CharSourceRange::getCharRange( locationAfterToken( + compiler.getSourceManager().getExpansionLoc( funcCast->getSubExpr()->getLocEnd())), + locationAfterToken( funcCast->getLocEnd()))); + } + else if( const CXXNamedCastExpr* namedCast = dyn_cast< CXXNamedCastExpr >( cast )) + { + removeText( CharSourceRange::getCharRange( namedCast->getLocStart(), + compiler.getSourceManager().getExpansionLoc( namedCast->getSubExpr()->getLocStart()))); + removeText( CharSourceRange::getCharRange( locationAfterToken( + compiler.getSourceManager().getExpansionLoc( namedCast->getSubExpr()->getLocEnd())), + locationAfterToken( namedCast->getLocEnd()))); + } + else if( const CStyleCastExpr* cCast = dyn_cast< CStyleCastExpr >( cast )) + removeText( SourceRange( cCast->getLocStart(), cCast->getRParenLoc())); + else + abort(); + } + } + } + } + +static Plugin::Registration< ConvertValueOf > X( "convertvalueof" ); + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |