| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 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: */
 |