1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
15 Replaces all calls to the deprecated O(U)String::valueOf() .
25 : public loplugin::FilteringRewritePlugin
< ConvertValueOf
>
28 explicit ConvertValueOf( CompilerInstance
& compiler
, Rewriter
& rewriter
);
29 virtual void run() override
;
30 bool VisitCallExpr( const CallExpr
* call
);
32 void removeCast( const Expr
* arg
);
35 ConvertValueOf::ConvertValueOf( CompilerInstance
& compiler
, Rewriter
& rewriter
)
36 : FilteringRewritePlugin( compiler
, rewriter
)
40 void ConvertValueOf::run()
42 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
45 bool ConvertValueOf::VisitCallExpr( const CallExpr
* call
)
47 if( ignoreLocation( call
))
49 // Using getDirectCallee() here means that we find only calls
50 // that call the function directly (i.e. not using a pointer, for example).
51 // Use getCallee() to include also those :
52 // if( const FunctionDecl* func = dyn_cast_or_null< FunctionDecl >( call->getCalleeDecl()))
53 if( const FunctionDecl
* func
= call
->getDirectCallee())
55 // Optimize, getQualifiedNameAsString() is reportedly expensive,
56 // so first check fast details like number of arguments or the (unqualified)
57 // name before checking the fully qualified name.
58 // See FunctionDecl for all the API about the function.
59 if( func
->getIdentifier() != NULL
60 && ( func
->getName() == "valueOf" ))
62 string qualifiedName
= func
->getQualifiedNameAsString();
63 if( qualifiedName
== "rtl::OString::valueOf" )
65 // Further checks about arguments. Check mainly ParmVarDecl, VarDecl,
66 // ValueDecl and QualType for Clang API details.
67 string arg0
= func
->getParamDecl( 0 )->getType().getAsString();
68 if( arg0
== "sal_Bool" )
69 replaceText( call
->getCallee()->getSourceRange(), "OString::boolean" );
70 else if( arg0
== "sal_Char" )
71 replaceText( call
->getCallee()->getSourceRange(), "OString" );
74 replaceText( call
->getCallee()->getSourceRange(), "OString::number" );
75 removeCast( call
->getArg( 0 ));
78 if( qualifiedName
== "rtl::OUString::valueOf" )
80 // Further checks about arguments. Check mainly ParmVarDecl, VarDecl,
81 // ValueDecl and QualType for Clang API details.
82 string arg0
= func
->getParamDecl( 0 )->getType().getAsString();
83 if( arg0
== "sal_Bool" )
84 replaceText( call
->getCallee()->getSourceRange(), "OUString::boolean" );
85 else if( arg0
== "sal_Unicode" )
86 replaceText( call
->getCallee()->getSourceRange(), "OUString" );
89 replaceText( call
->getCallee()->getSourceRange(), "OUString::number" );
90 removeCast( call
->getArg( 0 ));
98 void ConvertValueOf::removeCast( const Expr
* arg
)
100 arg
= arg
->IgnoreImpCasts();
101 if( const ExplicitCastExpr
* cast
= dyn_cast
< ExplicitCastExpr
>( arg
))
103 // Explicit casts don't seem to actually always change the type (integer promotion
104 // takes place first?), so remove also preceding implicit casts:
108 // |-CallExpr 0x1a84f20 <line:6:5, col:16> 'void'
109 // | |-ImplicitCastExpr 0x1a84f08 <col:5> 'void (*)(int)' <FunctionToPointerDecay>
110 // | | `-DeclRefExpr 0x1a84eb8 <col:5> 'void (int)' lvalue Function 0x1a58900 'f' 'void (int)'
111 // | `-CXXFunctionalCastExpr 0x1a84e90 <col:8, col:15> 'int' functional cast to int <NoOp>
112 // | `-ImplicitCastExpr 0x1a84e78 <col:13> 'int' <IntegralCast>
113 // | `-ImplicitCastExpr 0x1a84e60 <col:13> 'char' <LValueToRValue>
114 // | `-DeclRefExpr 0x1a58b88 <col:13> 'char' lvalue Var 0x1a58ab0 'a' 'char'
115 const Expr
* castFrom
= cast
->getSubExpr()->IgnoreImpCasts();
116 if( cast
->getType()->isIntegerType() && castFrom
->getType()->isIntegerType())
118 string fromType
= castFrom
->getType().getAsString();
119 if( fromType
!= "sal_Bool" && fromType
!= "bool" && fromType
!= "sal_Char" && fromType
!= "sal_Unicode" )
121 if( const CXXFunctionalCastExpr
* funcCast
= dyn_cast
< CXXFunctionalCastExpr
>( cast
))
123 removeText( CharSourceRange::getCharRange( funcCast
->getLocStart(),
124 compiler
.getSourceManager().getExpansionLoc( funcCast
->getSubExpr()->getLocStart())));
125 removeText( CharSourceRange::getCharRange( locationAfterToken(
126 compiler
.getSourceManager().getExpansionLoc( funcCast
->getSubExpr()->getLocEnd())),
127 locationAfterToken( funcCast
->getLocEnd())));
129 else if( const CXXNamedCastExpr
* namedCast
= dyn_cast
< CXXNamedCastExpr
>( cast
))
131 removeText( CharSourceRange::getCharRange( namedCast
->getLocStart(),
132 compiler
.getSourceManager().getExpansionLoc( namedCast
->getSubExpr()->getLocStart())));
133 removeText( CharSourceRange::getCharRange( locationAfterToken(
134 compiler
.getSourceManager().getExpansionLoc( namedCast
->getSubExpr()->getLocEnd())),
135 locationAfterToken( namedCast
->getLocEnd())));
137 else if( const CStyleCastExpr
* cCast
= dyn_cast
< CStyleCastExpr
>( cast
))
138 removeText( SourceRange( cCast
->getLocStart(), cCast
->getRParenLoc()));
146 static Plugin::Registration
< ConvertValueOf
> X( "convertvalueof" );
150 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */