# Cppcheck report - LibreOffice: compilerplugins/clang/store/postfixincrementfix.cxx

      1
      2
      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

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

    #include "postfixincrementfix.hxx"

    /*
    This is a rewriter.

    Change all postfix ++ operators of non-trivial types to prefix if possible.
    */

    namespace loplugin
    {

    PostfixIncrementFix::PostfixIncrementFix( const InstantiationData& data )
        : RewritePlugin( data )
        {
        }

    void PostfixIncrementFix::run()
        {
        TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
        }

    bool PostfixIncrementFix::VisitCXXOperatorCallExpr( const CXXOperatorCallExpr* op )<--- The function 'VisitCXXOperatorCallExpr' is never used.
        {
        if( ignoreLocation( op ))
            return true;
        // postfix ++ has two arguments (the operand and the hidden extra int)
        if( op->getOperator() == OO_PlusPlus && op->getNumArgs() == 2 )
            fixPostfixOperator( op );
        // For primitive types it would be UnaryOperatorExpr, but probably no good reason to change those.
        return true;
        }

    void PostfixIncrementFix::fixPostfixOperator( const CXXOperatorCallExpr* op )
        {
        if( !canChangePostfixToPrefix( op, op ))
            return;
        if( !shouldDoChange( op->getArg( 0 )))
            return;
        // Adding spaces around the moved ++ should not be necessary
        // (there might a problem with e.g. a+b++ -> a+++b (i.e. a++ +b),
        // but we don't change such expressions).
        if( insertText( op->getLocStart(), "++" )) // insert is intentionally first, in case it fails
            removeText( op->getCallee()->getSourceRange());
        }

    bool PostfixIncrementFix::canChangePostfixToPrefix( const Stmt* stmt , const CXXOperatorCallExpr* op )
        {
        const Stmt* parent = parentStmt( stmt );
        if( parent == NULL )
            return true;
        // check if foo++ can be safely replaced by ++foo
        switch( parent->getStmtClass())
            {
            case Stmt::CompoundStmtClass:
                return true;
            // these mean somebody is going to use it
            case Stmt::ImplicitCastExprClass:
            case Stmt::MaterializeTemporaryExprClass:
            case Stmt::BinaryOperatorClass:
            case Stmt::UnaryOperatorClass:
            case Stmt::CallExprClass:
            case Stmt::CXXOperatorCallExprClass:
                return false;
            case Stmt::CXXBindTemporaryExprClass:
                // tricky, it may just mean the temporary will be cleaned up
                // (by ExprWithCleanups), ignore and go up
                return canChangePostfixToPrefix( parent, op );
            case Stmt::ExprWithCleanupsClass:
                // cleanup of a temporary, should be harmless (if the use
                // of the postfix ++ operator here relies on the fact that
                // the dtor for the object will be called, that's pretty insane
                // code). Ignore and go up.
                return canChangePostfixToPrefix( parent, op );
            case Stmt::ParenExprClass: // parentheses, go up
                return canChangePostfixToPrefix( parent, op );
            case Stmt::IfStmtClass:
                // cannot be changed in condition, can be changed in statements
                return cast< IfStmt >( parent )->getCond() != stmt;
            case Stmt::WhileStmtClass:
                return cast< WhileStmt >( parent )->getCond() != stmt;
            case Stmt::DoStmtClass:
                return cast< DoStmt >( parent )->getCond() != stmt;
            case Stmt::ForStmtClass:
                return cast< ForStmt >( parent )->getCond() != stmt;
            default:
                report( DiagnosticsEngine::Fatal, "cannot analyze operator++ (plugin needs fixing)",
                    op->getLocStart()) << parent->getSourceRange();
                parent->dump();
                return false;
            }
        }

    bool PostfixIncrementFix::shouldDoChange( const Expr* operand )
        {
        // TODO Changing 'a->b++' to '++a->b' is technically the same, but the latter probably looks confusing,
        // so either avoid that, or add parentheses. Avoid for now.
        const Expr* expr = const_cast< Expr* >( operand )->IgnoreImplicit(); // does not have const version
        switch( expr->getStmtClass())
            {
            case Stmt::ParenExprClass:
                return true; // there are already parentheses, ok to move the ++
            case Stmt::MemberExprClass:
                return false; // ++a->b , avoid
            case Stmt::DeclRefExprClass:
                return true;
            default:
                {
                report( DiagnosticsEngine::Fatal, "cannot analyze operator++ (plugin needs fixing)",
                    expr->getLocStart()) << operand->getSourceRange();
                expr->dump();
                operand->dump();
                return false;
                }
            }
        }

    static Plugin::Registration< PostfixIncrementFix > X( "postfixincrementfix" );

    } // namespace

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */