bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / store / valueof.cxx
blob63dfa2f0c2bc2ddb754733a5c1aa2900318bbe57
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * Based on LLVM/Clang.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
13 This is a rewriter.
15 Replaces all calls to the deprecated O(U)String::valueOf() .
19 #include "plugin.hxx"
21 namespace loplugin
24 class ConvertValueOf
25 : public RecursiveASTVisitor< ConvertValueOf >
26 , public RewritePlugin
28 public:
29 explicit ConvertValueOf( CompilerInstance& compiler, Rewriter& rewriter );
30 virtual void run() override;
31 bool VisitCallExpr( const CallExpr* call );
32 private:
33 void removeCast( const Expr* arg );
36 ConvertValueOf::ConvertValueOf( CompilerInstance& compiler, Rewriter& rewriter )
37 : RewritePlugin( compiler, rewriter )
41 void ConvertValueOf::run()
43 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
46 bool ConvertValueOf::VisitCallExpr( const CallExpr* call )
48 if( ignoreLocation( call ))
49 return true;
50 // Using getDirectCallee() here means that we find only calls
51 // that call the function directly (i.e. not using a pointer, for example).
52 // Use getCallee() to include also those :
53 // if( const FunctionDecl* func = dyn_cast_or_null< FunctionDecl >( call->getCalleeDecl()))
54 if( const FunctionDecl* func = call->getDirectCallee())
56 // Optimize, getQualifiedNameAsString() is reportedly expensive,
57 // so first check fast details like number of arguments or the (unqualified)
58 // name before checking the fully qualified name.
59 // See FunctionDecl for all the API about the function.
60 if( func->getIdentifier() != NULL
61 && ( func->getName() == "valueOf" ))
63 string qualifiedName = func->getQualifiedNameAsString();
64 if( qualifiedName == "rtl::OString::valueOf" )
66 // Further checks about arguments. Check mainly ParmVarDecl, VarDecl,
67 // ValueDecl and QualType for Clang API details.
68 string arg0 = func->getParamDecl( 0 )->getType().getAsString();
69 if( arg0 == "sal_Bool" )
70 replaceText( call->getCallee()->getSourceRange(), "OString::boolean" );
71 else if( arg0 == "sal_Char" )
72 replaceText( call->getCallee()->getSourceRange(), "OString" );
73 else
75 replaceText( call->getCallee()->getSourceRange(), "OString::number" );
76 removeCast( call->getArg( 0 ));
79 if( qualifiedName == "rtl::OUString::valueOf" )
81 // Further checks about arguments. Check mainly ParmVarDecl, VarDecl,
82 // ValueDecl and QualType for Clang API details.
83 string arg0 = func->getParamDecl( 0 )->getType().getAsString();
84 if( arg0 == "sal_Bool" )
85 replaceText( call->getCallee()->getSourceRange(), "OUString::boolean" );
86 else if( arg0 == "sal_Unicode" )
87 replaceText( call->getCallee()->getSourceRange(), "OUString" );
88 else
90 replaceText( call->getCallee()->getSourceRange(), "OUString::number" );
91 removeCast( call->getArg( 0 ));
96 return true;
99 void ConvertValueOf::removeCast( const Expr* arg )
101 arg = arg->IgnoreImpCasts();
102 if( const ExplicitCastExpr* cast = dyn_cast< ExplicitCastExpr >( arg ))
104 // Explicit casts don't seem to actually always change the type (integer promotion
105 // takes place first?), so remove also preceding implicit casts:
106 // void f( int );
107 // char a;
108 // f( int( a ));
109 // |-CallExpr 0x1a84f20 <line:6:5, col:16> 'void'
110 // | |-ImplicitCastExpr 0x1a84f08 <col:5> 'void (*)(int)' <FunctionToPointerDecay>
111 // | | `-DeclRefExpr 0x1a84eb8 <col:5> 'void (int)' lvalue Function 0x1a58900 'f' 'void (int)'
112 // | `-CXXFunctionalCastExpr 0x1a84e90 <col:8, col:15> 'int' functional cast to int <NoOp>
113 // | `-ImplicitCastExpr 0x1a84e78 <col:13> 'int' <IntegralCast>
114 // | `-ImplicitCastExpr 0x1a84e60 <col:13> 'char' <LValueToRValue>
115 // | `-DeclRefExpr 0x1a58b88 <col:13> 'char' lvalue Var 0x1a58ab0 'a' 'char'
116 const Expr* castFrom = cast->getSubExpr()->IgnoreImpCasts();
117 if( cast->getType()->isIntegerType() && castFrom->getType()->isIntegerType())
119 string fromType = castFrom->getType().getAsString();
120 if( fromType != "sal_Bool" && fromType != "bool" && fromType != "sal_Char" && fromType != "sal_Unicode" )
122 if( const CXXFunctionalCastExpr* funcCast = dyn_cast< CXXFunctionalCastExpr >( cast ))
124 removeText( CharSourceRange::getCharRange( funcCast->getLocStart(),
125 compiler.getSourceManager().getExpansionLoc( funcCast->getSubExpr()->getLocStart())));
126 removeText( CharSourceRange::getCharRange( locationAfterToken(
127 compiler.getSourceManager().getExpansionLoc( funcCast->getSubExpr()->getLocEnd())),
128 locationAfterToken( funcCast->getLocEnd())));
130 else if( const CXXNamedCastExpr* namedCast = dyn_cast< CXXNamedCastExpr >( cast ))
132 removeText( CharSourceRange::getCharRange( namedCast->getLocStart(),
133 compiler.getSourceManager().getExpansionLoc( namedCast->getSubExpr()->getLocStart())));
134 removeText( CharSourceRange::getCharRange( locationAfterToken(
135 compiler.getSourceManager().getExpansionLoc( namedCast->getSubExpr()->getLocEnd())),
136 locationAfterToken( namedCast->getLocEnd())));
138 else if( const CStyleCastExpr* cCast = dyn_cast< CStyleCastExpr >( cast ))
139 removeText( SourceRange( cCast->getLocStart(), cCast->getRParenLoc()));
140 else
141 abort();
147 static Plugin::Registration< ConvertValueOf > X( "convertvalueof" );
149 } // namespace
151 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */