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 RecursiveASTVisitor
< SvStreamOutputOperators
>
37 , public RewritePlugin
40 explicit SvStreamOutputOperators( InstantiationData
const & data
);
41 virtual void run() override
;
42 bool VisitCallExpr( const CallExpr
* call
);
44 SourceLocation
after(const SourceLocation
& loc
);
47 SvStreamOutputOperators::SvStreamOutputOperators( InstantiationData
const & data
)
48 : RewritePlugin( data
)
52 void SvStreamOutputOperators::run()
54 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
57 bool SvStreamOutputOperators::VisitCallExpr( const CallExpr
* callExpr
)
59 if( ignoreLocation( callExpr
))
61 if( callExpr
->getNumArgs() < 2 )
63 const FunctionDecl
* func
= dyn_cast_or_null
< FunctionDecl
>( callExpr
->getCalleeDecl() );
66 if( func
->getNumParams() != 1 )
68 string qualifiedName
= func
->getQualifiedNameAsString();
70 if( qualifiedName
== "SvStream::operator<<" )
71 bOutputOperator
= true;
72 else if( qualifiedName
== "SvStream::operator>>" )
73 bOutputOperator
= false;
77 string arg0
= func
->getParamDecl( 0 )->getType().getAsString();
81 if( arg0
== "sal_uInt16" )
82 newIOMethod
= "WriteUInt16";
83 else if( arg0
== "sal_uInt32" )
84 newIOMethod
= "WriteUInt32";
85 else if( arg0
== "sal_uInt64" )
86 newIOMethod
= "WriteUInt64";
87 else if( arg0
== "sal_Int16" )
88 newIOMethod
= "WriteInt16";
89 else if( arg0
== "sal_Int32" )
90 newIOMethod
= "WriteInt32";
91 else if( arg0
== "sal_Int64" )
92 newIOMethod
= "WriteInt64";
93 else if( arg0
== "sal_uInt8" )
94 newIOMethod
= "WriteUInt8";
95 else if( arg0
== "sal_Unicode" )
96 newIOMethod
= "WriteUnicode";
97 else if( arg0
== "rtl::OString" )
98 newIOMethod
= "WriteOString";
99 else if( arg0
== "bool" )
100 newIOMethod
= "WriteBool";
101 else if( arg0
== "signed char" )
102 newIOMethod
= "WriteSChar";
103 else if( arg0
== "char" )
104 newIOMethod
= "WriteChar";
105 else if( arg0
== "unsigned char" )
106 newIOMethod
= "WriteUChar";
107 else if( arg0
== "float" )
108 newIOMethod
= "WriteFloat";
109 else if( arg0
== "double" )
110 newIOMethod
= "WriteDouble";
111 else if( arg0
== "const double &" )
112 newIOMethod
= "WriteDouble";
113 else if( arg0
== "const char *" )
114 newIOMethod
= "WriteCharPtr";
115 else if( arg0
== "char *" )
116 newIOMethod
= "WriteCharPtr";
117 else if( arg0
== "const unsigned char *" )
118 newIOMethod
= "WriteUCharPtr";
119 else if( arg0
== "unsigned char *" )
120 newIOMethod
= "WriteUCharPtr";
121 else if( arg0
== "class SvStream &" )
122 newIOMethod
= "WriteStream";
125 report( DiagnosticsEngine::Warning
,
126 "found call to operator<< that I cannot convert with type: " + arg0
,
127 callExpr
->getLocStart());
133 if( arg0
== "sal_uInt16 &" )
134 newIOMethod
= "ReadUInt16";
135 else if( arg0
== "sal_uInt32 &" )
136 newIOMethod
= "ReadUInt32";
137 else if( arg0
== "sal_uInt64 &" )
138 newIOMethod
= "ReadUInt64";
139 else if( arg0
== "sal_Int16 &" )
140 newIOMethod
= "ReadInt16";
141 else if( arg0
== "sal_Int32 &" )
142 newIOMethod
= "ReadInt32";
143 else if( arg0
== "sal_Int64 &" )
144 newIOMethod
= "ReadInt64";
145 else if( arg0
== "sal_uInt8 &" )
146 newIOMethod
= "ReadUInt8";
147 else if( arg0
== "signed char &" )
148 newIOMethod
= "ReadSChar";
149 else if( arg0
== "char &" )
150 newIOMethod
= "ReadChar";
151 else if( arg0
== "unsigned char &" )
152 newIOMethod
= "ReadUChar";
153 else if( arg0
== "float &" )
154 newIOMethod
= "ReadFloat";
155 else if( arg0
== "double &" )
156 newIOMethod
= "ReadDouble";
157 else if( arg0
== "class SvStream &" )
158 newIOMethod
= "ReadStream";
161 report( DiagnosticsEngine::Warning
,
162 "found call to operator>> that I cannot convert with type: " + arg0
,
163 callExpr
->getLocStart());
168 // CallExpr overrides the children() method from Stmt, but not the const variant of it, so we need to cast const away.
169 StmtRange range
= const_cast<CallExpr
*>(callExpr
)->children();
170 const Stmt
* child1
= *range
; // ImplicitCastExpr
172 const Stmt
* child2
= *range
; // ImplicitCastExpr
174 if( dyn_cast_or_null
< UnaryOperator
>( child2
) != NULL
)
176 // remove the "*" before the stream variable
177 if( !replaceText( callExpr
->getLocStart(), 1, "" ) )
179 if( !replaceText( child1
->getLocStart().getLocWithOffset(-1), 4, "->" ) )
184 if( !replaceText( child1
->getLocStart().getLocWithOffset(-1), 4, "." ) )
188 if( !insertTextBefore( callExpr
->getArg( 1 )->getLocStart(), newIOMethod
+ "( " ) )
190 if( !insertTextAfter( after( callExpr
->getLocEnd() ), " )" ) )
193 //TODO for some reason this is currently removing too much text
194 // if there was a cast e.g. "r << (sal_Int32) 1", then remove the cast
195 // const CStyleCastExpr* cast = dyn_cast_or_null< CStyleCastExpr >( callExpr->getArg(1) );
198 // replaceText( SourceRange( cast->getLParenLoc(), cast->getRParenLoc() ), "" );
201 // if there was already parentheses around the expression, remove them
202 const ParenExpr
* paren
= dyn_cast_or_null
< ParenExpr
>( callExpr
->getArg(1) );
205 if( !replaceText( paren
->getLocStart(), 1, "" ) )
207 if( !replaceText( paren
->getLocEnd(), 1, "" ) )
211 // report( DiagnosticsEngine::Note, "found", callExpr->getLocStart());
215 SourceLocation
SvStreamOutputOperators::after( const SourceLocation
& loc
)
217 return Lexer::getLocForEndOfToken( loc
, 0, compiler
.getASTContext().getSourceManager(), compiler
.getASTContext().getLangOpts() );
220 static Plugin::Registration
< SvStreamOutputOperators
> X( "svstreamoutputoperators" );
224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */