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 Remove uses of the macro RTL_CONSTASCII_USTRINGPARAM. One run is for one
16 specific use (see below), modify source to remove other uses.
21 #include <clang/Lex/Preprocessor.h>
26 class RtlConstAsciiMacro
27 : public RecursiveASTVisitor
< RtlConstAsciiMacro
>
29 , public RewritePlugin
32 explicit RtlConstAsciiMacro( const InstantiationData
& data
);
33 virtual void run() override
;
34 bool VisitCXXConstructExpr( CXXConstructExpr
* expr
);
35 bool VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr
* expr
);
36 bool VisitStringLiteral( const StringLiteral
* literal
);
37 #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
38 virtual void MacroExpands( const Token
& macro
, const MacroInfo
* info
, SourceRange range
) override
;
40 virtual void MacroExpands( const Token
& macro
, const MacroDirective
* directive
,
41 SourceRange range
, const MacroArgs
* args
) override
;
43 enum { isPPCallback
= true };
45 map
< SourceLocation
, SourceLocation
> expansions
; // start location -> end location
46 bool searchingForString
;
50 RtlConstAsciiMacro::RtlConstAsciiMacro( const InstantiationData
& data
)
51 : RewritePlugin( data
)
52 , searchingForString( false )
54 compiler
.getPreprocessor().addPPCallbacks( this );
57 void RtlConstAsciiMacro::run()
59 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
62 #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
63 void RtlConstAsciiMacro::MacroExpands( const Token
& macro
, const MacroInfo
*, SourceRange range
)
65 void RtlConstAsciiMacro::MacroExpands( const Token
& macro
, const MacroDirective
*,
66 SourceRange range
, const MacroArgs
* )
69 if( macro
.getIdentifierInfo()->getName() != "RTL_CONSTASCII_USTRINGPARAM" )
71 expansions
[ range
.getBegin() ] = range
.getEnd();
74 /* Remove use with the following ctor:
75 OUString( const sal_Char * value, sal_Int32 length,
76 rtl_TextEncoding encoding,
77 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS )
78 This means searching for CXXConstructExpr.
79 For removal when used with functions it should check e.g. for CallExpr.
81 bool RtlConstAsciiMacro::VisitCXXConstructExpr( CXXConstructExpr
* expr
)
83 if( ignoreLocation( expr
))
85 if( expr
->getNumArgs() != 4 )
87 // The last argument should be the default one when the macro is used.
88 if( dyn_cast
< CXXDefaultArgExpr
>( expr
->getArg( 3 )) == NULL
)
90 if( expr
->getConstructor()->getQualifiedNameAsString() != "rtl::OUString::OUString" )
92 const SourceManager
& src
= compiler
.getSourceManager();
93 SourceLocation start
= src
.getExpansionLoc( expr
->getArg( 0 )->getLocStart());
94 // Macro fills in the first 3 arguments, so they must all come from the same expansion.
95 if( start
!= src
.getExpansionLoc( expr
->getArg( 2 )->getLocEnd()))
97 if( expansions
.find( start
) == expansions
.end())
99 SourceLocation end
= expansions
[ start
];
100 // Remove the location, since sometimes the same code may be processed more than once
101 // (e.g. non-trivial default arguments).
102 expansions
.erase( start
);
103 // Check if the string argument to the macro is suitable.
104 searchingForString
= true;
105 suitableString
= false;
106 TraverseStmt( expr
->getArg( 0 ));
107 searchingForString
= false;
108 if( !suitableString
)
110 // Search for '(' (don't just remove a given length to handle possible whitespace).
111 const char* text
= compiler
.getSourceManager().getCharacterData( start
);
112 const char* pos
= text
;
116 if( text
[ -1 ] == ' ' && *pos
== ' ' )
117 ++pos
; // do not leave two spaces
118 removeText( start
, pos
- text
, RemoveLineIfEmpty
);
119 const char* textend
= compiler
.getSourceManager().getCharacterData( end
);
120 if( textend
[ -1 ] == ' ' && textend
[ 1 ] == ' ' )
121 removeText( end
, 2, RemoveLineIfEmpty
); // Remove ') '.
123 removeText( end
, 1, RemoveLineIfEmpty
); // Remove ')'.
127 bool RtlConstAsciiMacro::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr
* expr
)
129 return VisitCXXConstructExpr( expr
);
132 bool RtlConstAsciiMacro::VisitStringLiteral( const StringLiteral
* literal
)
134 if( !searchingForString
)
136 if( suitableString
) // two string literals?
138 report( DiagnosticsEngine::Warning
, "cannot analyze RTL_CONSTASCII_USTRINGPARAM (plugin needs fixing)" )
139 << literal
->getSourceRange();
142 if( !literal
->isAscii()) // ignore
144 if( !literal
->containsNonAsciiOrNull())
145 suitableString
= true;
149 static Plugin::Registration
< RtlConstAsciiMacro
> X( "rtlconstasciimacro" );
153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */