update credits
[LibreOffice.git] / compilerplugins / clang / rtlconstasciimacro.cxx
blobd3843149b2eaa8db809fea8eda11b6a5d8c88c0c
1 /*
2 * This file is part of the LibreOffice project.
4 * Based on LLVM/Clang.
6 * This file is distributed under the University of Illinois Open Source
7 * License. See LICENSE.TXT for details.
9 */
12 This is a rewriter.
14 Remove uses of the macro RTL_CONSTASCII_USTRINGPARAM. One run is for one
15 specific use (see below), modify source to remove other uses.
18 #include "plugin.hxx"
20 #include <clang/Lex/Preprocessor.h>
22 namespace loplugin
25 class RtlConstAsciiMacro
26 : public RecursiveASTVisitor< RtlConstAsciiMacro >
27 , public PPCallbacks
28 , public RewritePlugin
30 public:
31 explicit RtlConstAsciiMacro( CompilerInstance& compiler, Rewriter& rewriter );
32 virtual void run() override;
33 bool VisitCXXConstructExpr( CXXConstructExpr* expr );
34 bool VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr );
35 bool VisitStringLiteral( const StringLiteral* literal );
36 #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
37 virtual void MacroExpands( const Token& macro, const MacroInfo* info, SourceRange range ) override;
38 #else
39 virtual void MacroExpands( const Token& macro, const MacroDirective* directive,
40 SourceRange range, const MacroArgs* args ) override;
41 #endif
42 private:
43 map< SourceLocation, SourceLocation > expansions; // start location -> end location
44 bool searchingForString;
45 bool suitableString;
48 RtlConstAsciiMacro::RtlConstAsciiMacro( CompilerInstance& compiler, Rewriter& rewriter )
49 : RewritePlugin( compiler, rewriter )
50 , searchingForString( false )
52 compiler.getPreprocessor().addPPCallbacks( this );
55 void RtlConstAsciiMacro::run()
57 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
61 #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
62 void RtlConstAsciiMacro::MacroExpands( const Token& macro, const MacroInfo*, SourceRange range )
63 #else
64 void RtlConstAsciiMacro::MacroExpands( const Token& macro, const MacroDirective*,
65 SourceRange range, const MacroArgs* )
66 #endif
68 if( macro.getIdentifierInfo()->getName() != "RTL_CONSTASCII_USTRINGPARAM" )
69 return;
70 expansions[ range.getBegin() ] = range.getEnd();
73 /* Remove use with the following ctor:
74 OUString( const sal_Char * value, sal_Int32 length,
75 rtl_TextEncoding encoding,
76 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS )
77 This means searching for CXXConstructExpr.
78 For removal when used with functions it should check e.g. for CallExpr.
80 bool RtlConstAsciiMacro::VisitCXXConstructExpr( CXXConstructExpr* expr )
82 if( ignoreLocation( expr ))
83 return true;
84 if( expr->getNumArgs() != 4 )
85 return true;
86 // The last argument should be the default one when the macro is used.
87 if( dyn_cast< CXXDefaultArgExpr >( expr->getArg( 3 )) == NULL )
88 return true;
89 if( expr->getConstructor()->getQualifiedNameAsString() != "rtl::OUString::OUString" )
90 return true;
91 const SourceManager& src = compiler.getSourceManager();
92 SourceLocation start = src.getExpansionLoc( expr->getArg( 0 )->getLocStart());
93 // Macro fills in the first 3 arguments, so they must all come from the same expansion.
94 if( start != src.getExpansionLoc( expr->getArg( 2 )->getLocEnd()))
95 return true;
96 if( expansions.find( start ) == expansions.end())
97 return true;
98 SourceLocation end = expansions[ start ];
99 // Remove the location, since sometimes the same code may be processed more than once
100 // (e.g. non-trivial default arguments).
101 expansions.erase( start );
102 // Check if the string argument to the macro is suitable.
103 searchingForString = true;
104 suitableString = false;
105 TraverseStmt( expr->getArg( 0 ));
106 searchingForString = false;
107 if( !suitableString )
108 return true;
109 // Seach for '(' (don't just remove a given length to handle possible whitespace).
110 const char* text = compiler.getSourceManager().getCharacterData( start );
111 const char* pos = text;
112 while( *pos != '(' )
113 ++pos;
114 ++pos;
115 if( text[ -1 ] == ' ' && *pos == ' ' )
116 ++pos; // do not leave two spaces
117 removeText( start, pos - text, RemoveLineIfEmpty );
118 const char* textend = compiler.getSourceManager().getCharacterData( end );
119 if( textend[ -1 ] == ' ' && textend[ 1 ] == ' ' )
120 removeText( end, 2, RemoveLineIfEmpty ); // Remove ') '.
121 else
122 removeText( end, 1, RemoveLineIfEmpty ); // Remove ')'.
123 return true;
126 bool RtlConstAsciiMacro::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr )
128 return VisitCXXConstructExpr( expr );
131 bool RtlConstAsciiMacro::VisitStringLiteral( const StringLiteral* literal )
133 if( !searchingForString )
134 return true;
135 if( suitableString ) // two string literals?
137 report( DiagnosticsEngine::Warning, "cannot analyze RTL_CONSTASCII_USTRINGPARAM (plugin needs fixing)" )
138 << literal->getSourceRange();
139 return true;
141 if( !literal->isAscii()) // ignore
142 return true;
143 if( !literal->containsNonAsciiOrNull())
144 suitableString = true;
145 return true;
148 static Plugin::Registration< RtlConstAsciiMacro > X( "rtlconstasciimacro" );
150 } // namespace