Remove loplugin:pointertobool
For one, intended warnings about pointers as function call arguments being
implicitly converted to bool are also covered (along with more) by
loplugin:implicitboolconversion. For another, this code generates false
positives inside lambdas (where the check for CallExpr eventually always hits in
the PointerToBool::ignoreConversion recursion), see
762e90ffa0
"vcl: loplugin:pointertobool."
Change-Id: I55eaa668c1b4a2c66a5a015b2414bf161f796f2a
This commit is contained in:
@@ -1,167 +0,0 @@
|
|||||||
/* -*- 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 "plugin.hxx"
|
|
||||||
|
|
||||||
#include <clang/AST/ASTContext.h>
|
|
||||||
#include <clang/Basic/SourceManager.h>
|
|
||||||
#include <clang/Lex/Lexer.h>
|
|
||||||
|
|
||||||
namespace loplugin
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is a compile check.
|
|
||||||
|
|
||||||
Check for pointer-to-bool conversions (that are sadly implicit) which are unwanted
|
|
||||||
and potentially mistakes.
|
|
||||||
|
|
||||||
So far the only places that are checked are passing arguments to functions, as those
|
|
||||||
could easily choose a different overload.
|
|
||||||
|
|
||||||
The original idea was that to follow the explicit bool feature from C++11, where
|
|
||||||
the only conversions that would be considered safe are in conditions (which
|
|
||||||
in turn means also in ||, && and ! operators) and places where it's considered
|
|
||||||
unlikely for it to be a problem (or rather, less of a problem
|
|
||||||
than explicitly avoiding the warning in the code). The code for this is currently
|
|
||||||
commented out (there are a couple of places such as 'bool foo = returns_pointer();'
|
|
||||||
that would need modification), possibly enable those later.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class PointerToBool
|
|
||||||
: public RecursiveASTVisitor< PointerToBool >
|
|
||||||
, public Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit PointerToBool( const InstantiationData& data );
|
|
||||||
void run();
|
|
||||||
bool VisitImplicitCastExpr( const ImplicitCastExpr* expr );
|
|
||||||
private:
|
|
||||||
bool ignoreConversion( const Stmt* stmt );
|
|
||||||
};
|
|
||||||
|
|
||||||
PointerToBool::PointerToBool( const InstantiationData& data )
|
|
||||||
: Plugin( data )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PointerToBool::run()
|
|
||||||
{
|
|
||||||
TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PointerToBool::VisitImplicitCastExpr( const ImplicitCastExpr* expr )
|
|
||||||
{
|
|
||||||
if( ignoreLocation( expr ))
|
|
||||||
return true;
|
|
||||||
// Warning about CK_MemberPointerToBoolean would mean warning about
|
|
||||||
// cases there the 'safe bool' idiom is used, so give that such
|
|
||||||
// a conversion is otherwise unlikely anyway, it's probably better
|
|
||||||
// not to warn here at all (at least as long as the 'explicit bool'
|
|
||||||
// from C++11 is not in use).
|
|
||||||
if( expr->getCastKind() == CK_PointerToBoolean )
|
|
||||||
{
|
|
||||||
if( ignoreConversion( expr ))
|
|
||||||
return true;
|
|
||||||
report( DiagnosticsEngine::Warning,
|
|
||||||
"pointer %0 implicitly converted to bool", expr->getLocStart())
|
|
||||||
<< expr->getSubExpr()->getType() << expr->getSourceRange();
|
|
||||||
SourceLocation endOfExpression = locationAfterToken( expr->getLocEnd());
|
|
||||||
report( DiagnosticsEngine::Note,
|
|
||||||
"explicitly compare to null pointer to silence this warning", endOfExpression )
|
|
||||||
<< FixItHint::CreateInsertion( endOfExpression, " != NULL" );
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PointerToBool::ignoreConversion( const Stmt* stmt )
|
|
||||||
{
|
|
||||||
#if 1 // less strict version
|
|
||||||
const Stmt* parent = parentStmt( stmt );
|
|
||||||
if( parent == NULL )
|
|
||||||
return true;
|
|
||||||
switch( parent->getStmtClass())
|
|
||||||
{
|
|
||||||
case Stmt::ConditionalOperatorClass:
|
|
||||||
if( stmt == cast< ConditionalOperator >( parent )->getCond())
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case Stmt::BinaryOperatorClass:
|
|
||||||
{
|
|
||||||
const BinaryOperator* binary = cast< BinaryOperator >( parent );
|
|
||||||
if(( binary->getOpcode() == BO_LAnd || binary->getOpcode() == BO_LOr )
|
|
||||||
&& ( stmt == binary->getLHS() || stmt == binary->getRHS()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Stmt::UnaryOperatorClass:
|
|
||||||
{
|
|
||||||
const UnaryOperator* unary = cast< UnaryOperator >( parent );
|
|
||||||
if( unary->getOpcode() == UO_LNot && stmt == unary->getSubExpr())
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if( const ExplicitCastExpr* castexpr = dyn_cast< ExplicitCastExpr >( parent ))
|
|
||||||
if( castexpr->getTypeAsWritten()->isBooleanType() && stmt == castexpr->getSubExpr())
|
|
||||||
return true;
|
|
||||||
if( dyn_cast< CallExpr >( parent ))
|
|
||||||
return false; // The only place where it's not ignored.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ignoreConversion( parent );
|
|
||||||
#else // more strict version
|
|
||||||
// Warn only if the expression is not used in a conditional context.
|
|
||||||
const Stmt* parent = parentStmt( stmt );
|
|
||||||
if( parent == NULL ) // Should not happen inside a function, but can happen inside
|
|
||||||
return false; // ctor initializer list.
|
|
||||||
switch( parent->getStmtClass())
|
|
||||||
{
|
|
||||||
case Stmt::IfStmtClass:
|
|
||||||
return ( stmt == cast< IfStmt >( parent )->getCond());
|
|
||||||
case Stmt::WhileStmtClass:
|
|
||||||
return ( stmt == cast< WhileStmt >( parent )->getCond());
|
|
||||||
case Stmt::DoStmtClass:
|
|
||||||
return ( stmt == cast< DoStmt >( parent )->getCond());
|
|
||||||
case Stmt::ForStmtClass:
|
|
||||||
return ( stmt == cast< ForStmt >( parent )->getCond());
|
|
||||||
case Stmt::ConditionalOperatorClass:
|
|
||||||
return ( stmt == cast< ConditionalOperator >( parent )->getCond());
|
|
||||||
case Stmt::BinaryOperatorClass:
|
|
||||||
{
|
|
||||||
const BinaryOperator* binary = cast< BinaryOperator >( parent );
|
|
||||||
return (( binary->getOpcode() == BO_LAnd || binary->getOpcode() == BO_LOr )
|
|
||||||
&& ( stmt == binary->getLHS() || stmt == binary->getRHS()));
|
|
||||||
}
|
|
||||||
case Stmt::UnaryOperatorClass:
|
|
||||||
{
|
|
||||||
const UnaryOperator* unary = cast< UnaryOperator >( parent );
|
|
||||||
return ( unary->getOpcode() == UO_LNot && stmt == unary->getSubExpr());
|
|
||||||
}
|
|
||||||
case Stmt::ExprWithCleanupsClass: // Often happens inside if() condition.
|
|
||||||
return isInConditionalContext( parent );
|
|
||||||
default:
|
|
||||||
if( const ExplicitCastExpr* castexpr = dyn_cast< ExplicitCastExpr >( parent ))
|
|
||||||
if( castexpr->getTypeAsWritten()->isBooleanType() && stmt == castexpr->getSubExpr())
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static Plugin::Registration< PointerToBool > X( "pointertobool" );
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
Reference in New Issue
Block a user