Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
35269 views
1
//== IdenticalExprChecker.cpp - Identical expression checker----------------==//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This defines IdenticalExprChecker, a check that warns about
11
/// unintended use of identical expressions.
12
///
13
/// It checks for use of identical expressions with comparison operators and
14
/// inside conditional expressions.
15
///
16
//===----------------------------------------------------------------------===//
17
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"
24
25
using namespace clang;
26
using namespace ento;
27
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
//===----------------------------------------------------------------------===//
33
34
namespace {
35
class FindIdenticalExprVisitor
36
: public RecursiveASTVisitor<FindIdenticalExprVisitor> {
37
BugReporter &BR;
38
const CheckerBase *Checker;
39
AnalysisDeclContext *AC;
40
public:
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);
51
52
private:
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);
57
};
58
} // end anonymous namespace
59
60
void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
61
bool CheckBitwise,
62
ArrayRef<SourceRange> Sr) {
63
StringRef Message;
64
if (CheckBitwise)
65
Message = "identical expressions on both sides of bitwise operator";
66
else
67
Message = "identical expressions on both sides of logical operator";
68
69
PathDiagnosticLocation ELoc =
70
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
71
BR.EmitBasicReport(AC->getDecl(), Checker,
72
"Use of identical expressions",
73
categories::LogicError,
74
Message, ELoc, Sr);
75
}
76
77
void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
78
bool CheckBitwise) {
79
SourceRange Sr[2];
80
81
const Expr *LHS = B->getLHS();
82
const Expr *RHS = B->getRHS();
83
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
87
// the others.
88
while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
89
if (B->getOpcode() != B2->getOpcode())
90
break;
91
if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
92
Sr[0] = RHS->getSourceRange();
93
Sr[1] = B2->getRHS()->getSourceRange();
94
reportIdenticalExpr(B, CheckBitwise, Sr);
95
}
96
LHS = B2->getLHS();
97
}
98
99
if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
100
Sr[0] = RHS->getSourceRange();
101
Sr[1] = LHS->getSourceRange();
102
reportIdenticalExpr(B, CheckBitwise, Sr);
103
}
104
}
105
106
bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
107
const Stmt *Stmt1 = I->getThen();
108
const Stmt *Stmt2 = I->getElse();
109
110
// Check for identical inner condition:
111
//
112
// if (x<10) {
113
// if (x<10) {
114
// ..
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",
123
ELoc);
124
}
125
}
126
}
127
128
// Check for identical conditions:
129
//
130
// if (b) {
131
// foo1();
132
// } else if (b) {
133
// foo2();
134
// }
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",
146
ELoc, Sr);
147
}
148
Else = I2->getElse();
149
}
150
}
151
152
if (!Stmt1 || !Stmt2)
153
return true;
154
155
// Special handling for code like:
156
//
157
// if (b) {
158
// i = 1;
159
// } else
160
// i = 1;
161
if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
162
if (CompStmt->size() == 1)
163
Stmt1 = CompStmt->body_back();
164
}
165
if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
166
if (CompStmt->size() == 1)
167
Stmt2 = CompStmt->body_back();
168
}
169
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);
177
}
178
return true;
179
}
180
181
bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
182
BinaryOperator::Opcode Op = B->getOpcode();
183
184
if (BinaryOperator::isBitwiseOp(Op))
185
checkBitwiseOrLogicalOp(B, true);
186
187
if (BinaryOperator::isLogicalOp(Op))
188
checkBitwiseOrLogicalOp(B, false);
189
190
if (BinaryOperator::isComparisonOp(Op))
191
checkComparisonOp(B);
192
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.
196
return true;
197
}
198
199
void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
200
BinaryOperator::Opcode Op = B->getOpcode();
201
202
//
203
// Special case for floating-point representation.
204
//
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.
210
//
211
// != and == between float literals that have the same value should NOT warn.
212
// < > between float literals that have the same value SHOULD warn.
213
//
214
// != and == between the same float declaration should NOT warn.
215
// < > between the same float declaration SHOULD warn.
216
//
217
// != and == between eq. expressions that evaluates into float
218
// should NOT warn.
219
// < > between eq. expressions that evaluates into float
220
// should NOT warn.
221
//
222
const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
223
const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
224
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)) {
234
return;
235
}
236
}
237
}
238
} else if ((FloatLit1) && (FloatLit2)) {
239
if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
240
if ((Op == BO_EQ) || (Op == BO_NE)) {
241
return;
242
}
243
}
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.
248
return;
249
} else {
250
// No special case with floating-point representation, report as usual.
251
}
252
253
if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
254
PathDiagnosticLocation ELoc =
255
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
256
StringRef Message;
257
if (Op == BO_Cmp)
258
Message = "comparison of identical expressions always evaluates to "
259
"'equal'";
260
else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
261
Message = "comparison of identical expressions always evaluates to true";
262
else
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);
267
}
268
}
269
270
bool FindIdenticalExprVisitor::VisitConditionalOperator(
271
const ConditionalOperator *C) {
272
273
// Check if expressions in conditional expression are identical
274
// from a symbolic point of view.
275
276
if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
277
C->getFalseExpr(), true)) {
278
PathDiagnosticLocation ELoc =
279
PathDiagnosticLocation::createConditionalColonLoc(
280
C, BR.getSourceManager());
281
282
SourceRange Sr[2];
283
Sr[0] = C->getTrueExpr()->getSourceRange();
284
Sr[1] = C->getFalseExpr()->getSourceRange();
285
BR.EmitBasicReport(
286
AC->getDecl(), Checker,
287
"Identical expressions in conditional expression",
288
categories::LogicError,
289
"identical expressions on both sides of ':' in conditional expression",
290
ELoc, Sr);
291
}
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.
295
return true;
296
}
297
298
/// Determines whether two statement trees are identical regarding
299
/// operators and symbols.
300
///
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.
305
///
306
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
307
const Stmt *Stmt2, bool IgnoreSideEffects) {
308
309
if (!Stmt1 || !Stmt2) {
310
return !Stmt1 && !Stmt2;
311
}
312
313
// If Stmt1 & Stmt2 are of different class then they are not
314
// identical statements.
315
if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
316
return false;
317
318
const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
319
const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
320
321
if (Expr1 && Expr2) {
322
// If Stmt1 has side effects then don't warn even if expressions
323
// are identical.
324
if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
325
return false;
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()))
329
return false;
330
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))
336
return false;
337
++I1;
338
++I2;
339
}
340
// If there are different number of children in the statements, return
341
// false.
342
if (I1 != Expr1->child_end())
343
return false;
344
if (I2 != Expr2->child_end())
345
return false;
346
}
347
348
switch (Stmt1->getStmtClass()) {
349
default:
350
return false;
351
case Stmt::CallExprClass:
352
case Stmt::ArraySubscriptExprClass:
353
case Stmt::ArraySectionExprClass:
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:
361
return true;
362
case Stmt::CStyleCastExprClass: {
363
const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
364
const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
365
366
return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
367
}
368
case Stmt::ReturnStmtClass: {
369
const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
370
const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
371
372
return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
373
ReturnStmt2->getRetValue(), IgnoreSideEffects);
374
}
375
case Stmt::ForStmtClass: {
376
const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
377
const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
378
379
if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
380
IgnoreSideEffects))
381
return false;
382
if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
383
IgnoreSideEffects))
384
return false;
385
if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
386
IgnoreSideEffects))
387
return false;
388
if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
389
IgnoreSideEffects))
390
return false;
391
return true;
392
}
393
case Stmt::DoStmtClass: {
394
const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
395
const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
396
397
if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
398
IgnoreSideEffects))
399
return false;
400
if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
401
IgnoreSideEffects))
402
return false;
403
return true;
404
}
405
case Stmt::WhileStmtClass: {
406
const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
407
const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
408
409
if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
410
IgnoreSideEffects))
411
return false;
412
if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
413
IgnoreSideEffects))
414
return false;
415
return true;
416
}
417
case Stmt::IfStmtClass: {
418
const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
419
const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
420
421
if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
422
IgnoreSideEffects))
423
return false;
424
if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
425
IgnoreSideEffects))
426
return false;
427
if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
428
IgnoreSideEffects))
429
return false;
430
return true;
431
}
432
case Stmt::CompoundStmtClass: {
433
const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
434
const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
435
436
if (CompStmt1->size() != CompStmt2->size())
437
return false;
438
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))
443
return false;
444
++I1;
445
++I2;
446
}
447
448
return true;
449
}
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();
455
}
456
case Stmt::CharacterLiteralClass: {
457
const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
458
const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
459
return CharLit1->getValue() == CharLit2->getValue();
460
}
461
case Stmt::DeclRefExprClass: {
462
const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
463
const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
464
return DeclRef1->getDecl() == DeclRef2->getDecl();
465
}
466
case Stmt::IntegerLiteralClass: {
467
const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
468
const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
469
470
llvm::APInt I1 = IntLit1->getValue();
471
llvm::APInt I2 = IntLit2->getValue();
472
if (I1.getBitWidth() != I2.getBitWidth())
473
return false;
474
return I1 == I2;
475
}
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());
480
}
481
case Stmt::StringLiteralClass: {
482
const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
483
const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
484
return StringLit1->getBytes() == StringLit2->getBytes();
485
}
486
case Stmt::MemberExprClass: {
487
const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
488
const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
489
return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
490
}
491
case Stmt::UnaryOperatorClass: {
492
const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
493
const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
494
return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
495
}
496
}
497
}
498
499
//===----------------------------------------------------------------------===//
500
// FindIdenticalExprChecker
501
//===----------------------------------------------------------------------===//
502
503
namespace {
504
class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
505
public:
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));
510
}
511
};
512
} // end anonymous namespace
513
514
void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
515
Mgr.registerChecker<FindIdenticalExprChecker>();
516
}
517
518
bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) {
519
return true;
520
}
521
522