1 //== IdenticalExprChecker.cpp - Identical expression checker----------------==//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This defines IdenticalExprChecker, a check that warns about
11 /// unintended use of identical expressions.
13 /// It checks for use of identical expressions with comparison operators and
14 /// inside conditional expressions.
16 //===----------------------------------------------------------------------===//
18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19 #include "clang/AST/RecursiveASTVisitor.h"
20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21 #include "clang/StaticAnalyzer/Core/Checker.h"
22 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25 using namespace clang
;
28 static bool isIdenticalStmt(const ASTContext
&Ctx
, const Stmt
*Stmt1
,
29 const Stmt
*Stmt2
, bool IgnoreSideEffects
= false);
30 //===----------------------------------------------------------------------===//
31 // FindIdenticalExprVisitor - Identify nodes using identical expressions.
32 //===----------------------------------------------------------------------===//
35 class FindIdenticalExprVisitor
36 : public RecursiveASTVisitor
<FindIdenticalExprVisitor
> {
38 const CheckerBase
*Checker
;
39 AnalysisDeclContext
*AC
;
41 explicit FindIdenticalExprVisitor(BugReporter
&B
,
42 const CheckerBase
*Checker
,
43 AnalysisDeclContext
*A
)
44 : BR(B
), Checker(Checker
), AC(A
) {}
45 // FindIdenticalExprVisitor only visits nodes
46 // that are binary operators, if statements or
47 // conditional operators.
48 bool VisitBinaryOperator(const BinaryOperator
*B
);
49 bool VisitIfStmt(const IfStmt
*I
);
50 bool VisitConditionalOperator(const ConditionalOperator
*C
);
53 void reportIdenticalExpr(const BinaryOperator
*B
, bool CheckBitwise
,
54 ArrayRef
<SourceRange
> Sr
);
55 void checkBitwiseOrLogicalOp(const BinaryOperator
*B
, bool CheckBitwise
);
56 void checkComparisonOp(const BinaryOperator
*B
);
58 } // end anonymous namespace
60 void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator
*B
,
62 ArrayRef
<SourceRange
> Sr
) {
65 Message
= "identical expressions on both sides of bitwise operator";
67 Message
= "identical expressions on both sides of logical operator";
69 PathDiagnosticLocation ELoc
=
70 PathDiagnosticLocation::createOperatorLoc(B
, BR
.getSourceManager());
71 BR
.EmitBasicReport(AC
->getDecl(), Checker
,
72 "Use of identical expressions",
73 categories::LogicError
,
77 void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator
*B
,
81 const Expr
*LHS
= B
->getLHS();
82 const Expr
*RHS
= B
->getRHS();
84 // Split operators as long as we still have operators to split on. We will
85 // get called for every binary operator in an expression so there is no need
86 // to check every one against each other here, just the right most one with
88 while (const BinaryOperator
*B2
= dyn_cast
<BinaryOperator
>(LHS
)) {
89 if (B
->getOpcode() != B2
->getOpcode())
91 if (isIdenticalStmt(AC
->getASTContext(), RHS
, B2
->getRHS())) {
92 Sr
[0] = RHS
->getSourceRange();
93 Sr
[1] = B2
->getRHS()->getSourceRange();
94 reportIdenticalExpr(B
, CheckBitwise
, Sr
);
99 if (isIdenticalStmt(AC
->getASTContext(), RHS
, LHS
)) {
100 Sr
[0] = RHS
->getSourceRange();
101 Sr
[1] = LHS
->getSourceRange();
102 reportIdenticalExpr(B
, CheckBitwise
, Sr
);
106 bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt
*I
) {
107 const Stmt
*Stmt1
= I
->getThen();
108 const Stmt
*Stmt2
= I
->getElse();
110 // Check for identical inner condition:
115 if (const CompoundStmt
*CS
= dyn_cast
<CompoundStmt
>(Stmt1
)) {
116 if (!CS
->body_empty()) {
117 const IfStmt
*InnerIf
= dyn_cast
<IfStmt
>(*CS
->body_begin());
118 if (InnerIf
&& isIdenticalStmt(AC
->getASTContext(), I
->getCond(), InnerIf
->getCond(), /*IgnoreSideEffects=*/ false)) {
119 PathDiagnosticLocation
ELoc(InnerIf
->getCond(), BR
.getSourceManager(), AC
);
120 BR
.EmitBasicReport(AC
->getDecl(), Checker
, "Identical conditions",
121 categories::LogicError
,
122 "conditions of the inner and outer statements are identical",
128 // Check for identical conditions:
135 if (Stmt1
&& Stmt2
) {
136 const Expr
*Cond1
= I
->getCond();
137 const Stmt
*Else
= Stmt2
;
138 while (const IfStmt
*I2
= dyn_cast_or_null
<IfStmt
>(Else
)) {
139 const Expr
*Cond2
= I2
->getCond();
140 if (isIdenticalStmt(AC
->getASTContext(), Cond1
, Cond2
, false)) {
141 SourceRange Sr
= Cond1
->getSourceRange();
142 PathDiagnosticLocation
ELoc(Cond2
, BR
.getSourceManager(), AC
);
143 BR
.EmitBasicReport(AC
->getDecl(), Checker
, "Identical conditions",
144 categories::LogicError
,
145 "expression is identical to previous condition",
148 Else
= I2
->getElse();
152 if (!Stmt1
|| !Stmt2
)
155 // Special handling for code like:
161 if (const CompoundStmt
*CompStmt
= dyn_cast
<CompoundStmt
>(Stmt1
)) {
162 if (CompStmt
->size() == 1)
163 Stmt1
= CompStmt
->body_back();
165 if (const CompoundStmt
*CompStmt
= dyn_cast
<CompoundStmt
>(Stmt2
)) {
166 if (CompStmt
->size() == 1)
167 Stmt2
= CompStmt
->body_back();
170 if (isIdenticalStmt(AC
->getASTContext(), Stmt1
, Stmt2
, true)) {
171 PathDiagnosticLocation ELoc
=
172 PathDiagnosticLocation::createBegin(I
, BR
.getSourceManager(), AC
);
173 BR
.EmitBasicReport(AC
->getDecl(), Checker
,
174 "Identical branches",
175 categories::LogicError
,
176 "true and false branches are identical", ELoc
);
181 bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator
*B
) {
182 BinaryOperator::Opcode Op
= B
->getOpcode();
184 if (BinaryOperator::isBitwiseOp(Op
))
185 checkBitwiseOrLogicalOp(B
, true);
187 if (BinaryOperator::isLogicalOp(Op
))
188 checkBitwiseOrLogicalOp(B
, false);
190 if (BinaryOperator::isComparisonOp(Op
))
191 checkComparisonOp(B
);
193 // We want to visit ALL nodes (subexpressions of binary comparison
194 // expressions too) that contains comparison operators.
195 // True is always returned to traverse ALL nodes.
199 void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator
*B
) {
200 BinaryOperator::Opcode Op
= B
->getOpcode();
203 // Special case for floating-point representation.
205 // If expressions on both sides of comparison operator are of type float,
206 // then for some comparison operators no warning shall be
207 // reported even if the expressions are identical from a symbolic point of
208 // view. Comparison between expressions, declared variables and literals
209 // are treated differently.
211 // != and == between float literals that have the same value should NOT warn.
212 // < > between float literals that have the same value SHOULD warn.
214 // != and == between the same float declaration should NOT warn.
215 // < > between the same float declaration SHOULD warn.
217 // != and == between eq. expressions that evaluates into float
219 // < > between eq. expressions that evaluates into float
222 const Expr
*LHS
= B
->getLHS()->IgnoreParenImpCasts();
223 const Expr
*RHS
= B
->getRHS()->IgnoreParenImpCasts();
225 const DeclRefExpr
*DeclRef1
= dyn_cast
<DeclRefExpr
>(LHS
);
226 const DeclRefExpr
*DeclRef2
= dyn_cast
<DeclRefExpr
>(RHS
);
227 const FloatingLiteral
*FloatLit1
= dyn_cast
<FloatingLiteral
>(LHS
);
228 const FloatingLiteral
*FloatLit2
= dyn_cast
<FloatingLiteral
>(RHS
);
229 if ((DeclRef1
) && (DeclRef2
)) {
230 if ((DeclRef1
->getType()->hasFloatingRepresentation()) &&
231 (DeclRef2
->getType()->hasFloatingRepresentation())) {
232 if (DeclRef1
->getDecl() == DeclRef2
->getDecl()) {
233 if ((Op
== BO_EQ
) || (Op
== BO_NE
)) {
238 } else if ((FloatLit1
) && (FloatLit2
)) {
239 if (FloatLit1
->getValue().bitwiseIsEqual(FloatLit2
->getValue())) {
240 if ((Op
== BO_EQ
) || (Op
== BO_NE
)) {
244 } else if (LHS
->getType()->hasFloatingRepresentation()) {
245 // If any side of comparison operator still has floating-point
246 // representation, then it's an expression. Don't warn.
247 // Here only LHS is checked since RHS will be implicit casted to float.
250 // No special case with floating-point representation, report as usual.
253 if (isIdenticalStmt(AC
->getASTContext(), B
->getLHS(), B
->getRHS())) {
254 PathDiagnosticLocation ELoc
=
255 PathDiagnosticLocation::createOperatorLoc(B
, BR
.getSourceManager());
258 Message
= "comparison of identical expressions always evaluates to "
260 else if (((Op
== BO_EQ
) || (Op
== BO_LE
) || (Op
== BO_GE
)))
261 Message
= "comparison of identical expressions always evaluates to true";
263 Message
= "comparison of identical expressions always evaluates to false";
264 BR
.EmitBasicReport(AC
->getDecl(), Checker
,
265 "Compare of identical expressions",
266 categories::LogicError
, Message
, ELoc
);
270 bool FindIdenticalExprVisitor::VisitConditionalOperator(
271 const ConditionalOperator
*C
) {
273 // Check if expressions in conditional expression are identical
274 // from a symbolic point of view.
276 if (isIdenticalStmt(AC
->getASTContext(), C
->getTrueExpr(),
277 C
->getFalseExpr(), true)) {
278 PathDiagnosticLocation ELoc
=
279 PathDiagnosticLocation::createConditionalColonLoc(
280 C
, BR
.getSourceManager());
283 Sr
[0] = C
->getTrueExpr()->getSourceRange();
284 Sr
[1] = C
->getFalseExpr()->getSourceRange();
286 AC
->getDecl(), Checker
,
287 "Identical expressions in conditional expression",
288 categories::LogicError
,
289 "identical expressions on both sides of ':' in conditional expression",
292 // We want to visit ALL nodes (expressions in conditional
293 // expressions too) that contains conditional operators,
294 // thus always return true to traverse ALL nodes.
298 /// Determines whether two statement trees are identical regarding
299 /// operators and symbols.
301 /// Exceptions: expressions containing macros or functions with possible side
302 /// effects are never considered identical.
303 /// Limitations: (t + u) and (u + t) are not considered identical.
304 /// t*(u + t) and t*u + t*t are not considered identical.
306 static bool isIdenticalStmt(const ASTContext
&Ctx
, const Stmt
*Stmt1
,
307 const Stmt
*Stmt2
, bool IgnoreSideEffects
) {
309 if (!Stmt1
|| !Stmt2
) {
310 return !Stmt1
&& !Stmt2
;
313 // If Stmt1 & Stmt2 are of different class then they are not
314 // identical statements.
315 if (Stmt1
->getStmtClass() != Stmt2
->getStmtClass())
318 const Expr
*Expr1
= dyn_cast
<Expr
>(Stmt1
);
319 const Expr
*Expr2
= dyn_cast
<Expr
>(Stmt2
);
321 if (Expr1
&& Expr2
) {
322 // If Stmt1 has side effects then don't warn even if expressions
324 if (!IgnoreSideEffects
&& Expr1
->HasSideEffects(Ctx
))
326 // If either expression comes from a macro then don't warn even if
327 // the expressions are identical.
328 if ((Expr1
->getExprLoc().isMacroID()) || (Expr2
->getExprLoc().isMacroID()))
331 // If all children of two expressions are identical, return true.
332 Expr::const_child_iterator I1
= Expr1
->child_begin();
333 Expr::const_child_iterator I2
= Expr2
->child_begin();
334 while (I1
!= Expr1
->child_end() && I2
!= Expr2
->child_end()) {
335 if (!*I1
|| !*I2
|| !isIdenticalStmt(Ctx
, *I1
, *I2
, IgnoreSideEffects
))
340 // If there are different number of children in the statements, return
342 if (I1
!= Expr1
->child_end())
344 if (I2
!= Expr2
->child_end())
348 switch (Stmt1
->getStmtClass()) {
351 case Stmt::CallExprClass
:
352 case Stmt::ArraySubscriptExprClass
:
353 case Stmt::OMPArraySectionExprClass
:
354 case Stmt::OMPArrayShapingExprClass
:
355 case Stmt::OMPIteratorExprClass
:
356 case Stmt::ImplicitCastExprClass
:
357 case Stmt::ParenExprClass
:
358 case Stmt::BreakStmtClass
:
359 case Stmt::ContinueStmtClass
:
360 case Stmt::NullStmtClass
:
362 case Stmt::CStyleCastExprClass
: {
363 const CStyleCastExpr
* CastExpr1
= cast
<CStyleCastExpr
>(Stmt1
);
364 const CStyleCastExpr
* CastExpr2
= cast
<CStyleCastExpr
>(Stmt2
);
366 return CastExpr1
->getTypeAsWritten() == CastExpr2
->getTypeAsWritten();
368 case Stmt::ReturnStmtClass
: {
369 const ReturnStmt
*ReturnStmt1
= cast
<ReturnStmt
>(Stmt1
);
370 const ReturnStmt
*ReturnStmt2
= cast
<ReturnStmt
>(Stmt2
);
372 return isIdenticalStmt(Ctx
, ReturnStmt1
->getRetValue(),
373 ReturnStmt2
->getRetValue(), IgnoreSideEffects
);
375 case Stmt::ForStmtClass
: {
376 const ForStmt
*ForStmt1
= cast
<ForStmt
>(Stmt1
);
377 const ForStmt
*ForStmt2
= cast
<ForStmt
>(Stmt2
);
379 if (!isIdenticalStmt(Ctx
, ForStmt1
->getInit(), ForStmt2
->getInit(),
382 if (!isIdenticalStmt(Ctx
, ForStmt1
->getCond(), ForStmt2
->getCond(),
385 if (!isIdenticalStmt(Ctx
, ForStmt1
->getInc(), ForStmt2
->getInc(),
388 if (!isIdenticalStmt(Ctx
, ForStmt1
->getBody(), ForStmt2
->getBody(),
393 case Stmt::DoStmtClass
: {
394 const DoStmt
*DStmt1
= cast
<DoStmt
>(Stmt1
);
395 const DoStmt
*DStmt2
= cast
<DoStmt
>(Stmt2
);
397 if (!isIdenticalStmt(Ctx
, DStmt1
->getCond(), DStmt2
->getCond(),
400 if (!isIdenticalStmt(Ctx
, DStmt1
->getBody(), DStmt2
->getBody(),
405 case Stmt::WhileStmtClass
: {
406 const WhileStmt
*WStmt1
= cast
<WhileStmt
>(Stmt1
);
407 const WhileStmt
*WStmt2
= cast
<WhileStmt
>(Stmt2
);
409 if (!isIdenticalStmt(Ctx
, WStmt1
->getCond(), WStmt2
->getCond(),
412 if (!isIdenticalStmt(Ctx
, WStmt1
->getBody(), WStmt2
->getBody(),
417 case Stmt::IfStmtClass
: {
418 const IfStmt
*IStmt1
= cast
<IfStmt
>(Stmt1
);
419 const IfStmt
*IStmt2
= cast
<IfStmt
>(Stmt2
);
421 if (!isIdenticalStmt(Ctx
, IStmt1
->getCond(), IStmt2
->getCond(),
424 if (!isIdenticalStmt(Ctx
, IStmt1
->getThen(), IStmt2
->getThen(),
427 if (!isIdenticalStmt(Ctx
, IStmt1
->getElse(), IStmt2
->getElse(),
432 case Stmt::CompoundStmtClass
: {
433 const CompoundStmt
*CompStmt1
= cast
<CompoundStmt
>(Stmt1
);
434 const CompoundStmt
*CompStmt2
= cast
<CompoundStmt
>(Stmt2
);
436 if (CompStmt1
->size() != CompStmt2
->size())
439 CompoundStmt::const_body_iterator I1
= CompStmt1
->body_begin();
440 CompoundStmt::const_body_iterator I2
= CompStmt2
->body_begin();
441 while (I1
!= CompStmt1
->body_end() && I2
!= CompStmt2
->body_end()) {
442 if (!isIdenticalStmt(Ctx
, *I1
, *I2
, IgnoreSideEffects
))
450 case Stmt::CompoundAssignOperatorClass
:
451 case Stmt::BinaryOperatorClass
: {
452 const BinaryOperator
*BinOp1
= cast
<BinaryOperator
>(Stmt1
);
453 const BinaryOperator
*BinOp2
= cast
<BinaryOperator
>(Stmt2
);
454 return BinOp1
->getOpcode() == BinOp2
->getOpcode();
456 case Stmt::CharacterLiteralClass
: {
457 const CharacterLiteral
*CharLit1
= cast
<CharacterLiteral
>(Stmt1
);
458 const CharacterLiteral
*CharLit2
= cast
<CharacterLiteral
>(Stmt2
);
459 return CharLit1
->getValue() == CharLit2
->getValue();
461 case Stmt::DeclRefExprClass
: {
462 const DeclRefExpr
*DeclRef1
= cast
<DeclRefExpr
>(Stmt1
);
463 const DeclRefExpr
*DeclRef2
= cast
<DeclRefExpr
>(Stmt2
);
464 return DeclRef1
->getDecl() == DeclRef2
->getDecl();
466 case Stmt::IntegerLiteralClass
: {
467 const IntegerLiteral
*IntLit1
= cast
<IntegerLiteral
>(Stmt1
);
468 const IntegerLiteral
*IntLit2
= cast
<IntegerLiteral
>(Stmt2
);
470 llvm::APInt I1
= IntLit1
->getValue();
471 llvm::APInt I2
= IntLit2
->getValue();
472 if (I1
.getBitWidth() != I2
.getBitWidth())
476 case Stmt::FloatingLiteralClass
: {
477 const FloatingLiteral
*FloatLit1
= cast
<FloatingLiteral
>(Stmt1
);
478 const FloatingLiteral
*FloatLit2
= cast
<FloatingLiteral
>(Stmt2
);
479 return FloatLit1
->getValue().bitwiseIsEqual(FloatLit2
->getValue());
481 case Stmt::StringLiteralClass
: {
482 const StringLiteral
*StringLit1
= cast
<StringLiteral
>(Stmt1
);
483 const StringLiteral
*StringLit2
= cast
<StringLiteral
>(Stmt2
);
484 return StringLit1
->getBytes() == StringLit2
->getBytes();
486 case Stmt::MemberExprClass
: {
487 const MemberExpr
*MemberStmt1
= cast
<MemberExpr
>(Stmt1
);
488 const MemberExpr
*MemberStmt2
= cast
<MemberExpr
>(Stmt2
);
489 return MemberStmt1
->getMemberDecl() == MemberStmt2
->getMemberDecl();
491 case Stmt::UnaryOperatorClass
: {
492 const UnaryOperator
*UnaryOp1
= cast
<UnaryOperator
>(Stmt1
);
493 const UnaryOperator
*UnaryOp2
= cast
<UnaryOperator
>(Stmt2
);
494 return UnaryOp1
->getOpcode() == UnaryOp2
->getOpcode();
499 //===----------------------------------------------------------------------===//
500 // FindIdenticalExprChecker
501 //===----------------------------------------------------------------------===//
504 class FindIdenticalExprChecker
: public Checker
<check::ASTCodeBody
> {
506 void checkASTCodeBody(const Decl
*D
, AnalysisManager
&Mgr
,
507 BugReporter
&BR
) const {
508 FindIdenticalExprVisitor
Visitor(BR
, this, Mgr
.getAnalysisDeclContext(D
));
509 Visitor
.TraverseDecl(const_cast<Decl
*>(D
));
512 } // end anonymous namespace
514 void ento::registerIdenticalExprChecker(CheckerManager
&Mgr
) {
515 Mgr
.registerChecker
<FindIdenticalExprChecker
>();
518 bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager
&mgr
) {