diff options
Diffstat (limited to '')
-rw-r--r-- | compilerplugins/clang/store/rtlconstasciimacro.cxx | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/rtlconstasciimacro.cxx b/compilerplugins/clang/store/rtlconstasciimacro.cxx new file mode 100644 index 000000000..c930fbfd1 --- /dev/null +++ b/compilerplugins/clang/store/rtlconstasciimacro.cxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +/* +This is a rewriter. + +Remove uses of the macro RTL_CONSTASCII_USTRINGPARAM. One run is for one +specific use (see below), modify source to remove other uses. +*/ + +#include "plugin.hxx" + +#include <clang/Lex/Preprocessor.h> + +namespace loplugin +{ + +class RtlConstAsciiMacro + : public loplugin::FilteringRewritePlugin< RtlConstAsciiMacro > + , public PPCallbacks + { + public: + explicit RtlConstAsciiMacro( const InstantiationData& data ); + virtual void run() override; + bool VisitCXXConstructExpr( CXXConstructExpr* expr ); + bool VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr ); + bool VisitStringLiteral( const StringLiteral* literal ); + virtual void MacroExpands( const Token& macro, const MacroDirective* directive, + SourceRange range, const MacroArgs* args ) override; + enum { isPPCallback = true }; + private: + map< SourceLocation, SourceLocation > expansions; // start location -> end location + bool searchingForString; + bool suitableString; + }; + +RtlConstAsciiMacro::RtlConstAsciiMacro( const InstantiationData& data ) + : FilteringRewritePlugin( data ) + , searchingForString( false ) + { + compiler.getPreprocessor().addPPCallbacks( this ); + } + +void RtlConstAsciiMacro::run() + { + TraverseDecl( compiler.getASTContext().getTranslationUnitDecl()); + } + +void RtlConstAsciiMacro::MacroExpands( const Token& macro, const MacroDirective*, + SourceRange range, const MacroArgs* ) + { + if( macro.getIdentifierInfo()->getName() != "RTL_CONSTASCII_USTRINGPARAM" ) + return; + expansions[ range.getBegin() ] = range.getEnd(); + } + +/* Remove use with the following ctor: + OUString( const char * value, sal_Int32 length, + rtl_TextEncoding encoding, + sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS ) + This means searching for CXXConstructExpr. + For removal when used with functions it should check e.g. for CallExpr. +*/ +bool RtlConstAsciiMacro::VisitCXXConstructExpr( CXXConstructExpr* expr ) + { + if( ignoreLocation( expr )) + return true; + if( expr->getNumArgs() != 4 ) + return true; + // The last argument should be the default one when the macro is used. + if( dyn_cast< CXXDefaultArgExpr >( expr->getArg( 3 )) == NULL ) + return true; + if( expr->getConstructor()->getQualifiedNameAsString() != "rtl::OUString::OUString" ) + return true; + const SourceManager& src = compiler.getSourceManager(); + SourceLocation start = src.getExpansionLoc( expr->getArg( 0 )->getLocStart()); + // Macro fills in the first 3 arguments, so they must all come from the same expansion. + if( start != src.getExpansionLoc( expr->getArg( 2 )->getLocEnd())) + return true; + if( expansions.find( start ) == expansions.end()) + return true; + SourceLocation end = expansions[ start ]; + // Remove the location, since sometimes the same code may be processed more than once + // (e.g. non-trivial default arguments). + expansions.erase( start ); + // Check if the string argument to the macro is suitable. + searchingForString = true; + suitableString = false; + TraverseStmt( expr->getArg( 0 )); + searchingForString = false; + if( !suitableString ) + return true; + // Search for '(' (don't just remove a given length to handle possible whitespace). + const char* text = compiler.getSourceManager().getCharacterData( start ); + const char* pos = text; + while( *pos != '(' ) + ++pos; + ++pos; + if( text[ -1 ] == ' ' && *pos == ' ' ) + ++pos; // do not leave two spaces + removeText( start, pos - text, RemoveLineIfEmpty ); + const char* textend = compiler.getSourceManager().getCharacterData( end ); + if( textend[ -1 ] == ' ' && textend[ 1 ] == ' ' ) + removeText( end, 2, RemoveLineIfEmpty ); // Remove ') '. + else + removeText( end, 1, RemoveLineIfEmpty ); // Remove ')'. + return true; + } + +bool RtlConstAsciiMacro::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr ) + { + return VisitCXXConstructExpr( expr ); + } + +bool RtlConstAsciiMacro::VisitStringLiteral( const StringLiteral* literal ) + { + if( !searchingForString ) + return true; + if( suitableString ) // two string literals? + { + report( DiagnosticsEngine::Warning, "cannot analyze RTL_CONSTASCII_USTRINGPARAM (plugin needs fixing)" ) + << literal->getSourceRange(); + return true; + } + if( !literal->isAscii()) // ignore + return true; + if( !literal->containsNonAsciiOrNull()) + suitableString = true; + return true; + } + +static Plugin::Registration< RtlConstAsciiMacro > X( "rtlconstasciimacro" ); + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |