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 It changes the SvStream operator<< calls into calls to more explicitly named
16 methods, which reduces the casting needed, and makes it less likely that we
17 will accidentally write data to a file using the wrong data-type-size.
19 TODO we don't currently cope with macro expansion e.g. if the constant on the RHS is a #define
21 TODO we don't currently cope with code like "(*this) << 1;"
23 TODO we don't currently cope with code like "aStream << x << endl;" the "endl" parts ends up dangling.
25 TODO we don't currently cope with custom overloads of operator<< in some of the use-sites.
29 #include <clang/Lex/Lexer.h>
35 class SvStreamOutputOperators
36 : public loplugin::FilteringRewritePlugin
< SvStreamOutputOperators
>
39 explicit SvStreamOutputOperators( InstantiationData
const & data
);
40 virtual void run() override
;
41 bool VisitCallExpr( const CallExpr
* call
);
43 SourceLocation
after(const SourceLocation
& loc
);
46 SvStreamOutputOperators::SvStreamOutputOperators( InstantiationData
const & data
)
47 : FilteringRewritePlugin( data
)
51 void SvStreamOutputOperators::run()
53 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
56 bool SvStreamOutputOperators::VisitCallExpr( const CallExpr
* callExpr
)
58 if( ignoreLocation( callExpr
))
60 if( callExpr
->getNumArgs() < 2 )
62 const FunctionDecl
* func
= dyn_cast_or_null
< FunctionDecl
>( callExpr
->getCalleeDecl() );
65 if( func
->getNumParams() != 1 )
67 string qualifiedName
= func
->getQualifiedNameAsString();
69 if( qualifiedName
== "SvStream::operator<<" )
70 bOutputOperator
= true;
71 else if( qualifiedName
== "SvStream::operator>>" )
72 bOutputOperator
= false;
76 string arg0
= func
->getParamDecl( 0 )->getType().getAsString();
80 if( arg0
== "sal_uInt16" )
81 newIOMethod
= "WriteUInt16";
82 else if( arg0
== "sal_uInt32" )
83 newIOMethod
= "WriteUInt32";
84 else if( arg0
== "sal_uInt64" )
85 newIOMethod
= "WriteUInt64";
86 else if( arg0
== "sal_Int16" )
87 newIOMethod
= "WriteInt16";
88 else if( arg0
== "sal_Int32" )
89 newIOMethod
= "WriteInt32";
90 else if( arg0
== "sal_Int64" )
91 newIOMethod
= "WriteInt64";
92 else if( arg0
== "sal_uInt8" )
93 newIOMethod
= "WriteUInt8";
94 else if( arg0
== "sal_Unicode" )
95 newIOMethod
= "WriteUnicode";
96 else if( arg0
== "rtl::OString" )
97 newIOMethod
= "WriteOString";
98 else if( arg0
== "bool" )
99 newIOMethod
= "WriteBool";
100 else if( arg0
== "signed char" )
101 newIOMethod
= "WriteSChar";
102 else if( arg0
== "char" )
103 newIOMethod
= "WriteChar";
104 else if( arg0
== "unsigned char" )
105 newIOMethod
= "WriteUChar";
106 else if( arg0
== "float" )
107 newIOMethod
= "WriteFloat";
108 else if( arg0
== "double" )
109 newIOMethod
= "WriteDouble";
110 else if( arg0
== "const double &" )
111 newIOMethod
= "WriteDouble";
112 else if( arg0
== "const char *" )
113 newIOMethod
= "WriteCharPtr";
114 else if( arg0
== "char *" )
115 newIOMethod
= "WriteCharPtr";
116 else if( arg0
== "const unsigned char *" )
117 newIOMethod
= "WriteUCharPtr";
118 else if( arg0
== "unsigned char *" )
119 newIOMethod
= "WriteUCharPtr";
120 else if( arg0
== "class SvStream &" )
121 newIOMethod
= "WriteStream";
124 report( DiagnosticsEngine::Warning
,
125 "found call to operator<< that I cannot convert with type: " + arg0
,
126 callExpr
->getLocStart());
132 if( arg0
== "sal_uInt16 &" )
133 newIOMethod
= "ReadUInt16";
134 else if( arg0
== "sal_uInt32 &" )
135 newIOMethod
= "ReadUInt32";
136 else if( arg0
== "sal_uInt64 &" )
137 newIOMethod
= "ReadUInt64";
138 else if( arg0
== "sal_Int16 &" )
139 newIOMethod
= "ReadInt16";
140 else if( arg0
== "sal_Int32 &" )
141 newIOMethod
= "ReadInt32";
142 else if( arg0
== "sal_Int64 &" )
143 newIOMethod
= "ReadInt64";
144 else if( arg0
== "sal_uInt8 &" )
145 newIOMethod
= "ReadUInt8";
146 else if( arg0
== "signed char &" )
147 newIOMethod
= "ReadSChar";
148 else if( arg0
== "char &" )
149 newIOMethod
= "ReadChar";
150 else if( arg0
== "unsigned char &" )
151 newIOMethod
= "ReadUChar";
152 else if( arg0
== "float &" )
153 newIOMethod
= "ReadFloat";
154 else if( arg0
== "double &" )
155 newIOMethod
= "ReadDouble";
156 else if( arg0
== "class SvStream &" )
157 newIOMethod
= "ReadStream";
160 report( DiagnosticsEngine::Warning
,
161 "found call to operator>> that I cannot convert with type: " + arg0
,
162 callExpr
->getLocStart());
167 // CallExpr overrides the children() method from Stmt, but not the const variant of it, so we need to cast const away.
168 StmtRange range
= const_cast<CallExpr
*>(callExpr
)->children();
169 const Stmt
* child1
= *range
; // ImplicitCastExpr
171 const Stmt
* child2
= *range
; // ImplicitCastExpr
173 if( dyn_cast_or_null
< UnaryOperator
>( child2
) != NULL
)
175 // remove the "*" before the stream variable
176 if( !replaceText( callExpr
->getLocStart(), 1, "" ) )
178 if( !replaceText( child1
->getLocStart().getLocWithOffset(-1), 4, "->" ) )
183 if( !replaceText( child1
->getLocStart().getLocWithOffset(-1), 4, "." ) )
187 if( !insertTextBefore( callExpr
->getArg( 1 )->getLocStart(), newIOMethod
+ "( " ) )
189 if( !insertTextAfter( after( callExpr
->getLocEnd() ), " )" ) )
192 //TODO for some reason this is currently removing too much text
193 // if there was a cast e.g. "r << (sal_Int32) 1", then remove the cast
194 // const CStyleCastExpr* cast = dyn_cast_or_null< CStyleCastExpr >( callExpr->getArg(1) );
197 // replaceText( SourceRange( cast->getLParenLoc(), cast->getRParenLoc() ), "" );
200 // if there was already parentheses around the expression, remove them
201 const ParenExpr
* paren
= dyn_cast_or_null
< ParenExpr
>( callExpr
->getArg(1) );
204 if( !replaceText( paren
->getLocStart(), 1, "" ) )
206 if( !replaceText( paren
->getLocEnd(), 1, "" ) )
210 // report( DiagnosticsEngine::Note, "found", callExpr->getLocStart());
214 SourceLocation
SvStreamOutputOperators::after( const SourceLocation
& loc
)
216 return Lexer::getLocForEndOfToken( loc
, 0, compiler
.getASTContext().getSourceManager(), compiler
.getASTContext().getLangOpts() );
219 static Plugin::Registration
< SvStreamOutputOperators
> X( "svstreamoutputoperators" );
223 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */