bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / store / rtlconstasciimacro.cxx
blob66e202ce266fdb78ab42bf56f780699e245836f6
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 Remove uses of the macro RTL_CONSTASCII_USTRINGPARAM. One run is for one
16 specific use (see below), modify source to remove other uses.
19 #include "plugin.hxx"
21 #include <clang/Lex/Preprocessor.h>
23 namespace loplugin
26 class RtlConstAsciiMacro
27 : public loplugin::FilteringRewritePlugin< RtlConstAsciiMacro >
28 , public PPCallbacks
30 public:
31 explicit RtlConstAsciiMacro( const InstantiationData& data );
32 virtual void run() override;
33 bool VisitCXXConstructExpr( CXXConstructExpr* expr );
34 bool VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr );
35 bool VisitStringLiteral( const StringLiteral* literal );
36 virtual void MacroExpands( const Token& macro, const MacroDirective* directive,
37 SourceRange range, const MacroArgs* args ) override;
38 enum { isPPCallback = true };
39 private:
40 map< SourceLocation, SourceLocation > expansions; // start location -> end location
41 bool searchingForString;
42 bool suitableString;
45 RtlConstAsciiMacro::RtlConstAsciiMacro( const InstantiationData& data )
46 : FilteringRewritePlugin( data )
47 , searchingForString( false )
49 compiler.getPreprocessor().addPPCallbacks( this );
52 void RtlConstAsciiMacro::run()
54 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
57 void RtlConstAsciiMacro::MacroExpands( const Token& macro, const MacroDirective*,
58 SourceRange range, const MacroArgs* )
60 if( macro.getIdentifierInfo()->getName() != "RTL_CONSTASCII_USTRINGPARAM" )
61 return;
62 expansions[ range.getBegin() ] = range.getEnd();
65 /* Remove use with the following ctor:
66 OUString( const sal_Char * value, sal_Int32 length,
67 rtl_TextEncoding encoding,
68 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS )
69 This means searching for CXXConstructExpr.
70 For removal when used with functions it should check e.g. for CallExpr.
72 bool RtlConstAsciiMacro::VisitCXXConstructExpr( CXXConstructExpr* expr )
74 if( ignoreLocation( expr ))
75 return true;
76 if( expr->getNumArgs() != 4 )
77 return true;
78 // The last argument should be the default one when the macro is used.
79 if( dyn_cast< CXXDefaultArgExpr >( expr->getArg( 3 )) == NULL )
80 return true;
81 if( expr->getConstructor()->getQualifiedNameAsString() != "rtl::OUString::OUString" )
82 return true;
83 const SourceManager& src = compiler.getSourceManager();
84 SourceLocation start = src.getExpansionLoc( expr->getArg( 0 )->getLocStart());
85 // Macro fills in the first 3 arguments, so they must all come from the same expansion.
86 if( start != src.getExpansionLoc( expr->getArg( 2 )->getLocEnd()))
87 return true;
88 if( expansions.find( start ) == expansions.end())
89 return true;
90 SourceLocation end = expansions[ start ];
91 // Remove the location, since sometimes the same code may be processed more than once
92 // (e.g. non-trivial default arguments).
93 expansions.erase( start );
94 // Check if the string argument to the macro is suitable.
95 searchingForString = true;
96 suitableString = false;
97 TraverseStmt( expr->getArg( 0 ));
98 searchingForString = false;
99 if( !suitableString )
100 return true;
101 // Search for '(' (don't just remove a given length to handle possible whitespace).
102 const char* text = compiler.getSourceManager().getCharacterData( start );
103 const char* pos = text;
104 while( *pos != '(' )
105 ++pos;
106 ++pos;
107 if( text[ -1 ] == ' ' && *pos == ' ' )
108 ++pos; // do not leave two spaces
109 removeText( start, pos - text, RemoveLineIfEmpty );
110 const char* textend = compiler.getSourceManager().getCharacterData( end );
111 if( textend[ -1 ] == ' ' && textend[ 1 ] == ' ' )
112 removeText( end, 2, RemoveLineIfEmpty ); // Remove ') '.
113 else
114 removeText( end, 1, RemoveLineIfEmpty ); // Remove ')'.
115 return true;
118 bool RtlConstAsciiMacro::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr )
120 return VisitCXXConstructExpr( expr );
123 bool RtlConstAsciiMacro::VisitStringLiteral( const StringLiteral* literal )
125 if( !searchingForString )
126 return true;
127 if( suitableString ) // two string literals?
129 report( DiagnosticsEngine::Warning, "cannot analyze RTL_CONSTASCII_USTRINGPARAM (plugin needs fixing)" )
130 << literal->getSourceRange();
131 return true;
133 if( !literal->isAscii()) // ignore
134 return true;
135 if( !literal->containsNonAsciiOrNull())
136 suitableString = true;
137 return true;
140 static Plugin::Registration< RtlConstAsciiMacro > X( "rtlconstasciimacro" );
142 } // namespace
144 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */