1
0
Fork 0
libreoffice/compilerplugins/clang/store/rtlconstasciimacro.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

144 lines
5 KiB
C++

/* -*- 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: */