bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / pointertobool.cxx
blobd1637cf5525ca3ae9fbc83d4b0e3bfbfd64696d7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * Based on LLVM/Clang.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "plugin.hxx"
14 #include <clang/AST/ASTContext.h>
15 #include <clang/Basic/SourceManager.h>
16 #include <clang/Lex/Lexer.h>
18 namespace loplugin
22 This is a compile check.
24 Check for pointer-to-bool conversions (that are sadly implicit) which are unwanted
25 and potentially mistakes.
27 So far the only places that are checked are passing arguments to functions, as those
28 could easily choose a different overload.
30 The original idea was that to follow the explicit bool feature from C++11, where
31 the only conversions that would be considered safe are in conditions (which
32 in turn means also in ||, && and ! operators) and places where it's considered
33 unlikely for it to be a problem (or rather, less of a problem
34 than explicitly avoiding the warning in the code). The code for this is currently
35 commented out (there are a couple of places such as 'bool foo = returns_pointer();'
36 that would need modification), possibly enable those later.
39 class PointerToBool
40 : public RecursiveASTVisitor< PointerToBool >
41 , public Plugin
43 public:
44 explicit PointerToBool( const InstantiationData& data );
45 void run();
46 bool VisitImplicitCastExpr( const ImplicitCastExpr* expr );
47 private:
48 bool ignoreConversion( const Stmt* stmt );
51 PointerToBool::PointerToBool( const InstantiationData& data )
52 : Plugin( data )
56 void PointerToBool::run()
58 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
61 bool PointerToBool::VisitImplicitCastExpr( const ImplicitCastExpr* expr )
63 if( ignoreLocation( expr ))
64 return true;
65 // Warning about CK_MemberPointerToBoolean would mean warning about
66 // cases there the 'safe bool' idiom is used, so give that such
67 // a conversion is otherwise unlikely anyway, it's probably better
68 // not to warn here at all (at least as long as the 'explicit bool'
69 // from C++11 is not in use).
70 if( expr->getCastKind() == CK_PointerToBoolean )
72 if( ignoreConversion( expr ))
73 return true;
74 report( DiagnosticsEngine::Warning,
75 "pointer %0 implicitly converted to bool", expr->getLocStart())
76 << expr->getSubExpr()->getType() << expr->getSourceRange();
77 SourceLocation endOfExpression = locationAfterToken( expr->getLocEnd());
78 report( DiagnosticsEngine::Note,
79 "explicitly compare to null pointer to silence this warning", endOfExpression )
80 << FixItHint::CreateInsertion( endOfExpression, " != NULL" );
82 return true;
85 bool PointerToBool::ignoreConversion( const Stmt* stmt )
87 #if 1 // less strict version
88 const Stmt* parent = parentStmt( stmt );
89 if( parent == NULL )
90 return true;
91 switch( parent->getStmtClass())
93 case Stmt::ConditionalOperatorClass:
94 if( stmt == cast< ConditionalOperator >( parent )->getCond())
95 return true;
96 break;
97 case Stmt::BinaryOperatorClass:
99 const BinaryOperator* binary = cast< BinaryOperator >( parent );
100 if(( binary->getOpcode() == BO_LAnd || binary->getOpcode() == BO_LOr )
101 && ( stmt == binary->getLHS() || stmt == binary->getRHS()))
103 return true;
105 break;
107 case Stmt::UnaryOperatorClass:
109 const UnaryOperator* unary = cast< UnaryOperator >( parent );
110 if( unary->getOpcode() == UO_LNot && stmt == unary->getSubExpr())
111 return true;
112 break;
114 default:
115 if( const ExplicitCastExpr* castexpr = dyn_cast< ExplicitCastExpr >( parent ))
116 if( castexpr->getTypeAsWritten()->isBooleanType() && stmt == castexpr->getSubExpr())
117 return true;
118 if( dyn_cast< CallExpr >( parent ))
119 return false; // The only place where it's not ignored.
120 break;
122 return ignoreConversion( parent );
123 #else // more strict version
124 // Warn only if the expression is not used in a conditional context.
125 const Stmt* parent = parentStmt( stmt );
126 if( parent == NULL ) // Should not happen inside a function, but can happen inside
127 return false; // ctor initializer list.
128 switch( parent->getStmtClass())
130 case Stmt::IfStmtClass:
131 return ( stmt == cast< IfStmt >( parent )->getCond());
132 case Stmt::WhileStmtClass:
133 return ( stmt == cast< WhileStmt >( parent )->getCond());
134 case Stmt::DoStmtClass:
135 return ( stmt == cast< DoStmt >( parent )->getCond());
136 case Stmt::ForStmtClass:
137 return ( stmt == cast< ForStmt >( parent )->getCond());
138 case Stmt::ConditionalOperatorClass:
139 return ( stmt == cast< ConditionalOperator >( parent )->getCond());
140 case Stmt::BinaryOperatorClass:
142 const BinaryOperator* binary = cast< BinaryOperator >( parent );
143 return (( binary->getOpcode() == BO_LAnd || binary->getOpcode() == BO_LOr )
144 && ( stmt == binary->getLHS() || stmt == binary->getRHS()));
146 case Stmt::UnaryOperatorClass:
148 const UnaryOperator* unary = cast< UnaryOperator >( parent );
149 return ( unary->getOpcode() == UO_LNot && stmt == unary->getSubExpr());
151 case Stmt::ExprWithCleanupsClass: // Often happens inside if() condition.
152 return isInConditionalContext( parent );
153 default:
154 if( const ExplicitCastExpr* castexpr = dyn_cast< ExplicitCastExpr >( parent ))
155 if( castexpr->getTypeAsWritten()->isBooleanType() && stmt == castexpr->getSubExpr())
156 return true;
157 break;
159 return false;
160 #endif
163 static Plugin::Registration< PointerToBool > X( "pointertobool" );
165 } // namespace
167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */