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
  
     | 
    
      /* -*- 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 "tutorial2.hxx"
/*
This is a compile check.
Warns about if statements with a comparison followed by literal return false:
if( a == 1 )
    return false;
*/
namespace loplugin
{
Tutorial2::Tutorial2( const InstantiationData& data )
    : FilteringPlugin( data )
    {
    }
void Tutorial2::run()
    {
    // The Clang AST helper class will call VisitIfStmt for every if statement.
    TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
    }
// This function is called for every if statement.
bool Tutorial2::VisitIfStmt( const IfStmt* ifstmt )
    {
    if( ignoreLocation( ifstmt ))
        return true;
    // Check if the condition of the if statement is a binary operator.
    if( const BinaryOperator* oper = dyn_cast< BinaryOperator >( ifstmt->getCond()))
        {
        // And if it's operator==.
        if( oper->getOpcode() == BO_EQ )
            {
            // Now check if the sub-statement is 'return false'.
            const Stmt* warn = NULL; // The return statement (for the warning message).
            // Check if the sub-statement is directly 'return false;'.
            if( isReturnFalse( ifstmt->getThen()))
                warn = ifstmt->getThen();
            // Check if the sub-statement is '{ return false; }'
            else if( const CompoundStmt* compound = dyn_cast< CompoundStmt >( ifstmt->getThen()))
                {
                if( compound->size() == 1 ) // one statement
                    if( isReturnFalse( *compound->body_begin())) // check the one sub-statement
                        warn = *compound->body_begin();
                }
            if( warn != NULL ) // there is a return statement to warn about.
                {
                report( DiagnosticsEngine::Warning,
                    "returning false after if with equality comparison",
                    cast< ReturnStmt >( warn )->getRetValue()->getLocStart()) // the 'false' in the return
                    << warn->getSourceRange();
                // Also add a note showing the if statement.
                report( DiagnosticsEngine::Note,
                    "the if statement is here",
                    ifstmt->getLocStart());
                }
            }
        }
    return true;
    }
bool Tutorial2::isReturnFalse( const Stmt* stmt )
    {
    // Is it return statement?
    if( const ReturnStmt* returnstmt = dyn_cast< ReturnStmt >( stmt ))
        {
        // dyn_cast_or_null<> can also be passed NULL, unlike dyn_cast<>
        if( const CXXBoolLiteralExpr* boolliteral = dyn_cast_or_null< CXXBoolLiteralExpr >( returnstmt->getRetValue()))
            {
            if( boolliteral->getValue() == false )
                return true;
            }
        }
    return false;
    }
// Register the plugin action with the LO plugin handling.
static Plugin::Registration< Tutorial2 > tutorial2( "tutorial2" );
} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 
     |