clang-tools 24.0.0git
RedundantExpressionCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "../utils/Matchers.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Basic/LLVM.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Lex/Lexer.h"
17#include "llvm/ADT/APInt.h"
18#include "llvm/ADT/APSInt.h"
19#include "llvm/ADT/SmallBitVector.h"
20#include "llvm/Support/FormatVariadic.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
23#include <cassert>
24#include <cstdint>
25#include <optional>
26#include <string>
27
28using namespace clang::ast_matchers;
29using namespace clang::tidy::matchers;
30
31namespace clang::tidy::misc {
32using llvm::APSInt;
33
34static constexpr StringRef KnownBannedMacroNames[] = {
35 "EAGAIN",
36 "EWOULDBLOCK",
37 "SIGCLD",
38 "SIGCHLD",
39};
40
41static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
42 Result = Value;
43 ++Result;
44 return Value < Result;
45}
46
47static bool areEquivalentDeclRefExpr(const DeclRefExpr *L,
48 const DeclRefExpr *R) {
49 if (L->getDecl() != R->getDecl())
50 return false;
51
52 const PrintingPolicy &Policy =
53 L->getDecl()->getASTContext().getPrintingPolicy();
54
55 if (L->hasQualifier() && R->hasQualifier()) {
56 std::string LQual, RQual;
57 llvm::raw_string_ostream LOS(LQual), ROS(RQual);
58 L->getQualifier().print(LOS, Policy);
59 R->getQualifier().print(ROS, Policy);
60 if (LQual != RQual)
61 return false;
62 }
63
64 if (L->hasExplicitTemplateArgs() != R->hasExplicitTemplateArgs())
65 return false;
66 if (L->hasExplicitTemplateArgs()) {
67 if (L->getNumTemplateArgs() != R->getNumTemplateArgs())
68 return false;
69
70 return llvm::equal(L->template_arguments(), R->template_arguments(),
71 [&Policy](const TemplateArgumentLoc &LArg,
72 const TemplateArgumentLoc &RArg) {
73 std::string LStr, RStr;
74 llvm::raw_string_ostream LOS(LStr), ROS(RStr);
75 LArg.getArgument().print(Policy, LOS, true);
76 RArg.getArgument().print(Policy, ROS, true);
77 return LStr == RStr;
78 });
79 }
80 return true;
81}
82
83static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
84 if (!Left || !Right)
85 return !Left && !Right;
86
87 Left = Left->IgnoreParens();
88 Right = Right->IgnoreParens();
89
90 // Compare classes.
91 if (Left->getStmtClass() != Right->getStmtClass())
92 return false;
93
94 // Compare children.
95 Expr::const_child_iterator LeftIter = Left->child_begin();
96 Expr::const_child_iterator RightIter = Right->child_begin();
97 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
98 if (!areEquivalentExpr(dyn_cast_or_null<Expr>(*LeftIter),
99 dyn_cast_or_null<Expr>(*RightIter)))
100 return false;
101 ++LeftIter;
102 ++RightIter;
103 }
104 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
105 return false;
106
107 // Perform extra checks.
108 switch (Left->getStmtClass()) {
109 default:
110 return false;
111
112 case Stmt::CharacterLiteralClass:
113 return cast<CharacterLiteral>(Left)->getValue() ==
114 cast<CharacterLiteral>(Right)->getValue();
115 case Stmt::IntegerLiteralClass: {
116 const llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
117 const llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
118 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
119 LeftLit == RightLit;
120 }
121 case Stmt::FloatingLiteralClass:
122 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
123 cast<FloatingLiteral>(Right)->getValue());
124 case Stmt::StringLiteralClass:
125 return cast<StringLiteral>(Left)->getBytes() ==
126 cast<StringLiteral>(Right)->getBytes();
127 case Stmt::CXXOperatorCallExprClass:
128 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
129 cast<CXXOperatorCallExpr>(Right)->getOperator();
130 case Stmt::DependentScopeDeclRefExprClass:
131 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
132 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
133 return false;
134 return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() ==
135 cast<DependentScopeDeclRefExpr>(Right)->getQualifier();
136 case Stmt::DeclRefExprClass:
137 return areEquivalentDeclRefExpr(cast<DeclRefExpr>(Left),
138 cast<DeclRefExpr>(Right));
139 case Stmt::MemberExprClass:
140 return cast<MemberExpr>(Left)->getMemberDecl() ==
141 cast<MemberExpr>(Right)->getMemberDecl();
142 case Stmt::CXXFoldExprClass:
143 return cast<CXXFoldExpr>(Left)->getOperator() ==
144 cast<CXXFoldExpr>(Right)->getOperator();
145 case Stmt::CXXFunctionalCastExprClass:
146 case Stmt::CStyleCastExprClass:
147 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
148 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
149 case Stmt::CallExprClass:
150 case Stmt::ImplicitCastExprClass:
151 case Stmt::ArraySubscriptExprClass:
152 return true;
153 case Stmt::UnaryOperatorClass:
154 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
155 return false;
156 return cast<UnaryOperator>(Left)->getOpcode() ==
157 cast<UnaryOperator>(Right)->getOpcode();
158 case Stmt::BinaryOperatorClass:
159 if (cast<BinaryOperator>(Left)->isAssignmentOp())
160 return false;
161 return cast<BinaryOperator>(Left)->getOpcode() ==
162 cast<BinaryOperator>(Right)->getOpcode();
163 case Stmt::UnaryExprOrTypeTraitExprClass:
164 const auto *LeftUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Left);
165 const auto *RightUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Right);
166 if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType())
167 return LeftUnaryExpr->getKind() == RightUnaryExpr->getKind() &&
168 LeftUnaryExpr->getArgumentType() ==
169 RightUnaryExpr->getArgumentType();
170 if (!LeftUnaryExpr->isArgumentType() && !RightUnaryExpr->isArgumentType())
171 return areEquivalentExpr(LeftUnaryExpr->getArgumentExpr(),
172 RightUnaryExpr->getArgumentExpr());
173
174 return false;
175 }
176}
177
178// For a given expression 'x', returns whether the ranges covered by the
179// relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5).
180static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
181 const APSInt &ValueLHS,
182 BinaryOperatorKind OpcodeRHS,
183 const APSInt &ValueRHS) {
184 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
185 "Values must be ordered");
186 // Handle the case where constants are the same: x <= 4 <==> x <= 4.
187 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
188 return OpcodeLHS == OpcodeRHS;
189
190 // Handle the case where constants are off by one: x <= 4 <==> x < 5.
191 APSInt ValueLhsPlus1;
192 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
193 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
194 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
195 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0;
196}
197
198// For a given expression 'x', returns whether the ranges covered by the
199// relational operators are fully disjoint (i.e. x < 4 and x > 7).
200static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
201 const APSInt &ValueLHS,
202 BinaryOperatorKind OpcodeRHS,
203 const APSInt &ValueRHS) {
204 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
205 "Values must be ordered");
206
207 // Handle cases where the constants are the same.
208 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
209 switch (OpcodeLHS) {
210 case BO_EQ:
211 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
212 case BO_NE:
213 return OpcodeRHS == BO_EQ;
214 case BO_LE:
215 return OpcodeRHS == BO_GT;
216 case BO_GE:
217 return OpcodeRHS == BO_LT;
218 case BO_LT:
219 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
220 case BO_GT:
221 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
222 default:
223 return false;
224 }
225 }
226
227 // Handle cases where the constants are different.
228 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
229 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
230 return true;
231
232 // Handle the case where constants are off by one: x > 5 && x < 6.
233 APSInt ValueLhsPlus1;
234 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
235 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
236 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0)
237 return true;
238
239 return false;
240}
241
242// Returns whether the ranges covered by the union of both relational
243// expressions cover the whole domain (i.e. x < 10 and x > 0).
244static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
245 const APSInt &ValueLHS,
246 BinaryOperatorKind OpcodeRHS,
247 const APSInt &ValueRHS) {
248 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
249 "Values must be ordered");
250
251 // Handle cases where the constants are the same: x < 5 || x >= 5.
252 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
253 switch (OpcodeLHS) {
254 case BO_EQ:
255 return OpcodeRHS == BO_NE;
256 case BO_NE:
257 return OpcodeRHS == BO_EQ;
258 case BO_LE:
259 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
260 case BO_LT:
261 return OpcodeRHS == BO_GE;
262 case BO_GE:
263 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
264 case BO_GT:
265 return OpcodeRHS == BO_LE;
266 default:
267 return false;
268 }
269 }
270
271 // Handle the case where constants are off by one: x <= 4 || x >= 5.
272 APSInt ValueLhsPlus1;
273 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
274 incrementWithoutOverflow(ValueLHS, ValueLhsPlus1) &&
275 APSInt::compareValues(ValueLhsPlus1, ValueRHS) == 0)
276 return true;
277
278 // Handle cases where the constants are different: x > 4 || x <= 7.
279 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
280 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
281 return true;
282
283 // Handle cases where constants are different but both ops are !=, like:
284 // x != 5 || x != 10
285 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
286 return true;
287
288 return false;
289}
290
291static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
292 const APSInt &ValueLHS,
293 BinaryOperatorKind OpcodeRHS,
294 const APSInt &ValueRHS) {
295 const int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
296 switch (OpcodeLHS) {
297 case BO_EQ:
298 return OpcodeRHS == BO_EQ && Comparison == 0;
299 case BO_NE:
300 return (OpcodeRHS == BO_NE && Comparison == 0) ||
301 (OpcodeRHS == BO_EQ && Comparison != 0) ||
302 (OpcodeRHS == BO_LT && Comparison >= 0) ||
303 (OpcodeRHS == BO_LE && Comparison > 0) ||
304 (OpcodeRHS == BO_GT && Comparison <= 0) ||
305 (OpcodeRHS == BO_GE && Comparison < 0);
306
307 case BO_LT:
308 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
309 (OpcodeRHS == BO_LE && Comparison > 0) ||
310 (OpcodeRHS == BO_EQ && Comparison > 0));
311 case BO_GT:
312 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
313 (OpcodeRHS == BO_GE && Comparison < 0) ||
314 (OpcodeRHS == BO_EQ && Comparison < 0));
315 case BO_LE:
316 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
317 Comparison >= 0;
318 case BO_GE:
319 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
320 Comparison <= 0;
321 default:
322 return false;
323 }
324}
325
326static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
327 APSInt &Value) {
328 if (Opcode == BO_Sub) {
329 Opcode = BO_Add;
330 Value = -Value;
331 }
332}
333
334// to use in the template below
335static OverloadedOperatorKind getOp(const BinaryOperator *Op) {
336 return BinaryOperator::getOverloadedOperator(Op->getOpcode());
337}
338
339static OverloadedOperatorKind getOp(const CXXOperatorCallExpr *Op) {
340 if (Op->getNumArgs() != 2)
341 return OO_None;
342 return Op->getOperator();
343}
344
345static std::pair<const Expr *, const Expr *>
346getOperands(const BinaryOperator *Op) {
347 return {Op->getLHS()->IgnoreParenImpCasts(),
348 Op->getRHS()->IgnoreParenImpCasts()};
349}
350
351static std::pair<const Expr *, const Expr *>
352getOperands(const CXXOperatorCallExpr *Op) {
353 return {Op->getArg(0)->IgnoreParenImpCasts(),
354 Op->getArg(1)->IgnoreParenImpCasts()};
355}
356
357template <typename TExpr>
358static const TExpr *checkOpKind(const Expr *TheExpr,
359 OverloadedOperatorKind OpKind) {
360 const auto *AsTExpr = dyn_cast_or_null<TExpr>(TheExpr);
361 if (AsTExpr && getOp(AsTExpr) == OpKind)
362 return AsTExpr;
363
364 return nullptr;
365}
366
367// returns true if a subexpression has two directly equivalent operands and
368// is already handled by operands/parametersAreEquivalent
369template <typename TExpr, unsigned N>
370static bool collectOperands(const Expr *Part,
371 SmallVector<const Expr *, N> &AllOperands,
372 OverloadedOperatorKind OpKind) {
373 if (const auto *BinOp = checkOpKind<TExpr>(Part, OpKind)) {
374 const std::pair<const Expr *, const Expr *> Operands = getOperands(BinOp);
375 if (areEquivalentExpr(Operands.first, Operands.second))
376 return true;
377 return collectOperands<TExpr>(Operands.first, AllOperands, OpKind) ||
378 collectOperands<TExpr>(Operands.second, AllOperands, OpKind);
379 }
380
381 AllOperands.push_back(Part);
382 return false;
383}
384
385template <typename TExpr>
386static bool hasSameOperatorParent(const Expr *TheExpr,
387 OverloadedOperatorKind OpKind,
388 ASTContext &Context) {
389 // IgnoreParenImpCasts logic in reverse: skip surrounding uninteresting nodes
390 const DynTypedNodeList Parents = Context.getParents(*TheExpr);
391 for (const DynTypedNode DynParent : Parents) {
392 if (const auto *Parent = DynParent.get<Expr>()) {
393 const bool Skip =
394 isa<ParenExpr>(Parent) || isa<ImplicitCastExpr>(Parent) ||
395 isa<FullExpr>(Parent) || isa<MaterializeTemporaryExpr>(Parent);
396 if (Skip && hasSameOperatorParent<TExpr>(Parent, OpKind, Context))
397 return true;
398 if (checkOpKind<TExpr>(Parent, OpKind))
399 return true;
400 }
401 }
402
403 return false;
404}
405
406static bool isSameRawIdentifierToken(const Token &T1, const Token &T2,
407 const SourceManager &SM) {
408 if (T1.getKind() != T2.getKind())
409 return false;
410 if (T1.isNot(tok::raw_identifier))
411 return true;
412 if (T1.getLength() != T2.getLength())
413 return false;
414 return StringRef(SM.getCharacterData(T1.getLocation()), T1.getLength()) ==
415 StringRef(SM.getCharacterData(T2.getLocation()), T2.getLength());
416}
417
418static bool isTokAtEndOfExpr(SourceRange ExprSR, Token T,
419 const SourceManager &SM) {
420 return SM.getExpansionLoc(ExprSR.getEnd()) == T.getLocation();
421}
422
423/// Returns true if both LhsExpr and RhsExpr are
424/// macro expressions and they are expanded
425/// from different macros.
426static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
427 const Expr *RhsExpr,
428 const ASTContext *AstCtx) {
429 if (!LhsExpr || !RhsExpr)
430 return false;
431 const SourceRange Lsr = LhsExpr->getSourceRange();
432 const SourceRange Rsr = RhsExpr->getSourceRange();
433 if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID())
434 return false;
435
436 const SourceManager &SM = AstCtx->getSourceManager();
437 const LangOptions &LO = AstCtx->getLangOpts();
438
439 const std::pair<FileID, unsigned> LsrLocInfo =
440 SM.getDecomposedLoc(SM.getExpansionLoc(Lsr.getBegin()));
441 const std::pair<FileID, unsigned> RsrLocInfo =
442 SM.getDecomposedLoc(SM.getExpansionLoc(Rsr.getBegin()));
443 const llvm::MemoryBufferRef MB = SM.getBufferOrFake(LsrLocInfo.first);
444
445 const char *LTokenPos = MB.getBufferStart() + LsrLocInfo.second;
446 const char *RTokenPos = MB.getBufferStart() + RsrLocInfo.second;
447 Lexer LRawLex(SM.getLocForStartOfFile(LsrLocInfo.first), LO,
448 MB.getBufferStart(), LTokenPos, MB.getBufferEnd());
449 Lexer RRawLex(SM.getLocForStartOfFile(RsrLocInfo.first), LO,
450 MB.getBufferStart(), RTokenPos, MB.getBufferEnd());
451
452 Token LTok, RTok;
453 do { // Compare the expressions token-by-token.
454 LRawLex.LexFromRawLexer(LTok);
455 RRawLex.LexFromRawLexer(RTok);
456 } while (!LTok.is(tok::eof) && !RTok.is(tok::eof) &&
457 isSameRawIdentifierToken(LTok, RTok, SM) &&
458 !isTokAtEndOfExpr(Lsr, LTok, SM) &&
459 !isTokAtEndOfExpr(Rsr, RTok, SM));
460 return (!isTokAtEndOfExpr(Lsr, LTok, SM) ||
461 !isTokAtEndOfExpr(Rsr, RTok, SM)) ||
462 !isSameRawIdentifierToken(LTok, RTok, SM);
463}
464
465static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
466 const Expr *&RhsExpr) {
467 if (!LhsExpr || !RhsExpr)
468 return false;
469
470 const SourceLocation LhsLoc = LhsExpr->getExprLoc();
471 const SourceLocation RhsLoc = RhsExpr->getExprLoc();
472
473 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
474}
475
476template <typename TExpr>
477static bool
478markDuplicateOperands(const TExpr *TheExpr,
479 ast_matchers::internal::BoundNodesTreeBuilder *Builder,
480 ASTContext &Context) {
481 const OverloadedOperatorKind OpKind = getOp(TheExpr);
482 if (OpKind == OO_None)
483 return false;
484 // if there are no nested operators of the same kind, it's handled by
485 // operands/parametersAreEquivalent
486 const std::pair<const Expr *, const Expr *> Operands = getOperands(TheExpr);
487 if (!(checkOpKind<TExpr>(Operands.first, OpKind) ||
488 checkOpKind<TExpr>(Operands.second, OpKind)))
489 return false;
490
491 // if parent is the same kind of operator, it's handled by a previous call to
492 // markDuplicateOperands
493 if (hasSameOperatorParent<TExpr>(TheExpr, OpKind, Context))
494 return false;
495
497 if (collectOperands<TExpr>(Operands.first, AllOperands, OpKind))
498 return false;
499 if (collectOperands<TExpr>(Operands.second, AllOperands, OpKind))
500 return false;
501 const size_t NumOperands = AllOperands.size();
502 llvm::SmallBitVector Duplicates(NumOperands);
503 for (size_t I = 0; I < NumOperands; I++) {
504 if (Duplicates[I])
505 continue;
506 bool FoundDuplicates = false;
507
508 for (size_t J = I + 1; J < NumOperands; J++) {
509 if (AllOperands[J]->HasSideEffects(Context))
510 break;
511
512 const Expr *Lhs = AllOperands[I];
513 const Expr *Rhs = AllOperands[J];
514 if (!areEquivalentExpr(Lhs, Rhs) ||
515 areExprsFromDifferentMacros(Lhs, Rhs, &Context) ||
516 areExprsMacroAndNonMacro(Lhs, Rhs))
517 continue;
518
519 FoundDuplicates = true;
520 Duplicates.set(J);
521 Builder->setBinding(SmallString<11>(llvm::formatv("duplicate{0}", J)),
522 DynTypedNode::create(*Rhs));
523 }
524
525 if (FoundDuplicates)
526 Builder->setBinding(SmallString<11>(llvm::formatv("duplicate{0}", I)),
527 DynTypedNode::create(*AllOperands[I]));
528 }
529
530 return Duplicates.any();
531}
532
533namespace {
534
535AST_MATCHER(Expr, isIntegerConstantExpr) {
536 if (Node.isInstantiationDependent())
537 return false;
538 return Node.isIntegerConstantExpr(Finder->getASTContext());
539}
540
541AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
542 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
543}
544
545AST_MATCHER(BinaryOperator, nestedOperandsAreEquivalent) {
546 return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
547}
548
549AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
550 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
551}
552
553AST_MATCHER(CallExpr, parametersAreEquivalent) {
554 return Node.getNumArgs() == 2 &&
555 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
556}
557
558AST_MATCHER(CXXOperatorCallExpr, nestedParametersAreEquivalent) {
559 return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
560}
561
562AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
563 return Node.getOperatorLoc().isMacroID();
564}
565
566AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
567 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
568}
569
570AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
571
572AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<StringRef>, Names) {
573 const SourceManager &SM = Finder->getASTContext().getSourceManager();
574 const LangOptions &LO = Finder->getASTContext().getLangOpts();
575 SourceLocation Loc = Node.getExprLoc();
576 while (Loc.isMacroID()) {
577 const StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
578 if (llvm::is_contained(Names, MacroName))
579 return true;
580 Loc = SM.getImmediateMacroCallerLoc(Loc);
581 }
582 return false;
583}
584
585} // namespace
586
587// Returns a matcher for integer constant expressions.
588static ast_matchers::internal::Matcher<Expr>
590 const std::string CstId = (Id + "-const").str();
591 return expr(isIntegerConstantExpr()).bind(CstId);
592}
593
594// Retrieves the integer expression matched by 'matchIntegerConstantExpr' with
595// name 'Id' and stores it into 'ConstExpr', the value of the expression is
596// stored into `Value`.
597static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
598 StringRef Id, APSInt &Value,
599 const Expr *&ConstExpr) {
600 const std::string CstId = (Id + "-const").str();
601 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
602 if (!ConstExpr)
603 return false;
604 std::optional<llvm::APSInt> R =
605 ConstExpr->getIntegerConstantExpr(*Result.Context);
606 if (!R)
607 return false;
608 Value = *R;
609 return true;
610}
611
612// Overloaded `retrieveIntegerConstantExpr` for compatibility.
613static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
614 StringRef Id, APSInt &Value) {
615 const Expr *ConstExpr = nullptr;
616 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
617}
618
619// Returns a matcher for symbolic expressions (matches every expression except
620// ingeter constant expressions).
621static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
622 const std::string SymId = (Id + "-sym").str();
623 return ignoringParenImpCasts(
624 expr(unless(isIntegerConstantExpr())).bind(SymId));
625}
626
627// Retrieves the expression matched by 'matchSymbolicExpr' with name 'Id' and
628// stores it into 'SymExpr'.
629static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
630 StringRef Id, const Expr *&SymExpr) {
631 const std::string SymId = (Id + "-sym").str();
632 if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
633 SymExpr = Node;
634 return true;
635 }
636 return false;
637}
638
639// Match a binary operator between a symbolic expression and an integer constant
640// expression.
641static ast_matchers::internal::Matcher<Expr>
643 const auto BinOpCstExpr =
644 expr(anyOf(binaryOperator(hasAnyOperatorName("+", "|", "&"),
645 hasOperands(matchSymbolicExpr(Id),
647 binaryOperator(hasOperatorName("-"),
648 hasLHS(matchSymbolicExpr(Id)),
649 hasRHS(matchIntegerConstantExpr(Id)))))
650 .bind(Id);
651 return ignoringParenImpCasts(BinOpCstExpr);
652}
653
654// Retrieves sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
655// name 'Id'.
656static bool
657retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
658 StringRef Id, BinaryOperatorKind &Opcode,
659 const Expr *&Symbol, APSInt &Value) {
660 if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
661 Opcode = BinExpr->getOpcode();
662 return retrieveSymbolicExpr(Result, Id, Symbol) &&
663 retrieveIntegerConstantExpr(Result, Id, Value);
664 }
665 return false;
666}
667
668// Matches relational expressions: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
669static ast_matchers::internal::Matcher<Expr>
671 const std::string CastId = (Id + "-cast").str();
672 const std::string SwapId = (Id + "-swap").str();
673 const std::string NegateId = (Id + "-negate").str();
674 const std::string OverloadId = (Id + "-overload").str();
675 const std::string ConstId = (Id + "-const").str();
676
677 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
678 isComparisonOperator(), expr().bind(Id),
679 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
680 hasRHS(matchIntegerConstantExpr(Id))),
681 allOf(hasLHS(matchIntegerConstantExpr(Id)),
682 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
683
684 // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
685 // to if (x != 0)).
686 const auto CastExpr =
687 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
688 hasSourceExpression(matchSymbolicExpr(Id)))
689 .bind(CastId);
690
691 const auto NegateRelationalExpr =
692 unaryOperator(hasOperatorName("!"),
693 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
694 .bind(NegateId);
695
696 // Do not bind to double negation.
697 const auto NegateNegateRelationalExpr =
698 unaryOperator(hasOperatorName("!"),
699 hasUnaryOperand(unaryOperator(
700 hasOperatorName("!"),
701 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
702
703 const auto OverloadedOperatorExpr =
704 cxxOperatorCallExpr(
705 hasAnyOverloadedOperatorName("==", "!=", "<", "<=", ">", ">="),
706 // Filter noisy false positives.
707 unless(isMacro()), unless(isInTemplateInstantiation()),
708 anyOf(hasLHS(ignoringParenImpCasts(integerLiteral().bind(ConstId))),
709 hasRHS(ignoringParenImpCasts(integerLiteral().bind(ConstId)))))
710 .bind(OverloadId);
711
712 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
713 NegateNegateRelationalExpr, OverloadedOperatorExpr);
714}
715
716// Checks whether a function param is non constant reference type, and may
717// be modified in the function.
718static bool isNonConstReferenceType(QualType ParamType) {
719 return ParamType->isReferenceType() &&
720 !ParamType.getNonReferenceType().isConstQualified();
721}
722
723// Checks whether the arguments of an overloaded operator can be modified in the
724// function.
725// For operators that take an instance and a constant as arguments, only the
726// first argument (the instance) needs to be checked, since the constant itself
727// is a temporary expression. Whether the second parameter is checked is
728// controlled by the parameter `ParamsToCheckCount`.
729static bool
730canOverloadedOperatorArgsBeModified(const CXXOperatorCallExpr *OperatorCall,
731 bool CheckSecondParam) {
732 const auto *OperatorDecl =
733 dyn_cast_or_null<FunctionDecl>(OperatorCall->getCalleeDecl());
734 // if we can't find the declaration, conservatively assume it can modify
735 // arguments
736 if (!OperatorDecl)
737 return true;
738
739 const unsigned ParamCount = OperatorDecl->getNumParams();
740
741 // Overloaded operators declared inside a class have only one param.
742 // These functions must be declared const in order to not be able to modify
743 // the instance of the class they are called through.
744 if (ParamCount == 1 &&
745 !OperatorDecl->getType()->castAs<FunctionType>()->isConst())
746 return true;
747
748 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
749 return true;
750
751 return CheckSecondParam && ParamCount == 2 &&
752 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
753}
754
755// Retrieves sub-expressions matched by 'matchRelationalIntegerConstantExpr'
756// with name 'Id'.
758 const MatchFinder::MatchResult &Result, StringRef Id,
759 const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol,
760 APSInt &Value, const Expr *&ConstExpr) {
761 const std::string CastId = (Id + "-cast").str();
762 const std::string SwapId = (Id + "-swap").str();
763 const std::string NegateId = (Id + "-negate").str();
764 const std::string OverloadId = (Id + "-overload").str();
765
766 if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
767 // Operand received with explicit comparator.
768 Opcode = Bin->getOpcode();
769 OperandExpr = Bin;
770
771 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
772 return false;
773 } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
774 // Operand received with implicit comparator (cast).
775 Opcode = BO_NE;
776 OperandExpr = Cast;
777 Value = APSInt(32, false);
778 } else if (const auto *OverloadedOperatorExpr =
779 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
780 if (canOverloadedOperatorArgsBeModified(OverloadedOperatorExpr, false))
781 return false;
782
783 bool IntegerConstantIsFirstArg = false;
784
785 if (const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
786 if (!Arg->isValueDependent() &&
787 !Arg->isIntegerConstantExpr(*Result.Context)) {
788 IntegerConstantIsFirstArg = true;
789 if (const auto *Arg = OverloadedOperatorExpr->getArg(0)) {
790 if (!Arg->isValueDependent() &&
791 !Arg->isIntegerConstantExpr(*Result.Context))
792 return false;
793 } else {
794 return false;
795 }
796 }
797 } else {
798 return false;
799 }
800
801 Symbol = OverloadedOperatorExpr->getArg(IntegerConstantIsFirstArg ? 1 : 0);
802 OperandExpr = OverloadedOperatorExpr;
803 Opcode = BinaryOperator::getOverloadedOpcode(
804 OverloadedOperatorExpr->getOperator());
805
806 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
807 return false;
808
809 if (!BinaryOperator::isComparisonOp(Opcode))
810 return false;
811
812 // The call site of this function expects the constant on the RHS,
813 // so change the opcode accordingly.
814 if (IntegerConstantIsFirstArg)
815 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
816
817 return true;
818 } else {
819 return false;
820 }
821
822 if (!retrieveSymbolicExpr(Result, Id, Symbol))
823 return false;
824
825 if (Result.Nodes.getNodeAs<Expr>(SwapId))
826 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
827 if (Result.Nodes.getNodeAs<Expr>(NegateId))
828 Opcode = BinaryOperator::negateComparisonOp(Opcode);
829 return true;
830}
831
832// Checks for expressions like (X == 4) && (Y != 9)
833static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp,
834 const ASTContext *AstCtx) {
835 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
836 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
837
838 if (!LhsBinOp || !RhsBinOp)
839 return false;
840
841 const auto IsIntegerConstantExpr = [AstCtx](const Expr *E) {
842 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
843 };
844
845 if ((IsIntegerConstantExpr(LhsBinOp->getLHS()) ||
846 IsIntegerConstantExpr(LhsBinOp->getRHS())) &&
847 (IsIntegerConstantExpr(RhsBinOp->getLHS()) ||
848 IsIntegerConstantExpr(RhsBinOp->getRHS())))
849 return true;
850 return false;
851}
852
854 const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
855 if (areSidesBinaryConstExpressions(BinOp, AstCtx))
856 return true;
857
858 const Expr *Lhs = BinOp->getLHS();
859 const Expr *Rhs = BinOp->getRHS();
860
861 if (!Lhs || !Rhs)
862 return false;
863
864 const auto IsDefineExpr = [AstCtx](const Expr *E) {
865 const SourceRange Lsr = E->getSourceRange();
866 if (!Lsr.getBegin().isMacroID() || E->isValueDependent() ||
867 !E->isIntegerConstantExpr(*AstCtx))
868 return false;
869 return true;
870 };
871
872 return IsDefineExpr(Lhs) || IsDefineExpr(Rhs);
873}
874
875// Retrieves integer constant subexpressions from binary operator expressions
876// that have two equivalent sides.
877// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
878static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
879 BinaryOperatorKind &MainOpcode,
880 BinaryOperatorKind &SideOpcode,
881 const Expr *&LhsConst,
882 const Expr *&RhsConst,
883 const ASTContext *AstCtx) {
884 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
885 "Both sides of binary operator must be constant expressions!");
886
887 MainOpcode = BinOp->getOpcode();
888
889 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
890 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
891
892 const auto IsIntegerConstantExpr = [AstCtx](const Expr *E) {
893 return !E->isValueDependent() && E->isIntegerConstantExpr(*AstCtx);
894 };
895
896 LhsConst = IsIntegerConstantExpr(BinOpLhs->getLHS()) ? BinOpLhs->getLHS()
897 : BinOpLhs->getRHS();
898 RhsConst = IsIntegerConstantExpr(BinOpRhs->getLHS()) ? BinOpRhs->getLHS()
899 : BinOpRhs->getRHS();
900
901 if (!LhsConst || !RhsConst)
902 return false;
903
904 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
905 "Sides of the binary operator must be equivalent expressions!");
906
907 SideOpcode = BinOpLhs->getOpcode();
908
909 return true;
910}
911
912static bool areStringsSameIgnoreSpaces(const StringRef Left,
913 const StringRef Right) {
914 if (Left == Right)
915 return true;
916
917 // Do running comparison ignoring spaces
918 StringRef L = Left.trim();
919 StringRef R = Right.trim();
920 while (!L.empty() && !R.empty()) {
921 L = L.ltrim();
922 R = R.ltrim();
923 if (L.empty() && R.empty())
924 return true;
925 // If symbol compared are different ==> strings are not the same
926 if (L.front() != R.front())
927 return false;
928 L = L.drop_front();
929 R = R.drop_front();
930 }
931 return L.empty() && R.empty();
932}
933
934static bool areExprsSameMacroOrLiteral(const BinaryOperator *BinOp,
935 const ASTContext *Context) {
936 if (!BinOp)
937 return false;
938
939 const Expr *Lhs = BinOp->getLHS();
940 const Expr *Rhs = BinOp->getRHS();
941 const SourceManager &SM = Context->getSourceManager();
942
943 const SourceRange Lsr = Lhs->getSourceRange();
944 const SourceRange Rsr = Rhs->getSourceRange();
945 if (Lsr.getBegin().isMacroID()) {
946 // Left is macro so right macro too
947 if (Rsr.getBegin().isMacroID()) {
948 // Both sides are macros so they are same macro or literal
949 const StringRef L = Lexer::getSourceText(
950 CharSourceRange::getTokenRange(Lsr), SM, Context->getLangOpts());
951 const StringRef R = Lexer::getSourceText(
952 CharSourceRange::getTokenRange(Rsr), SM, Context->getLangOpts());
953 return areStringsSameIgnoreSpaces(L, R);
954 }
955 // Left is macro but right is not so they are not same macro or literal
956 return false;
957 }
958 const auto *Lil = dyn_cast<IntegerLiteral>(Lhs);
959 const auto *Ril = dyn_cast<IntegerLiteral>(Rhs);
960 if (Lil && Ril)
961 return Lil->getValue() == Ril->getValue();
962
963 const auto *Lbl = dyn_cast<CXXBoolLiteralExpr>(Lhs);
964 const auto *Rbl = dyn_cast<CXXBoolLiteralExpr>(Rhs);
965 if (Lbl && Rbl)
966 return Lbl->getValue() == Rbl->getValue();
967
968 return false;
969}
970
972 const auto BannedIntegerLiteral =
973 integerLiteral(expandedByMacro(KnownBannedMacroNames));
974 const auto IsInUnevaluatedContext = expr(anyOf(
975 hasAncestor(expr(hasUnevaluatedContext())), hasAncestor(typeLoc())));
976
977 // Binary with equivalent operands, like (X != 2 && X != 2).
978 Finder->addMatcher(
979 traverse(TK_AsIs,
980 binaryOperator(anyOf(isComparisonOperator(),
981 hasAnyOperatorName("-", "/", "%", "|", "&",
982 "^", "&&", "||", "=")),
983 operandsAreEquivalent(),
984 // Filter noisy false positives.
985 unless(isInTemplateInstantiation()),
986 unless(binaryOperatorIsInMacro()),
987 unless(hasAncestor(arraySubscriptExpr())),
988 unless(hasDescendant(BannedIntegerLiteral)),
989 unless(IsInUnevaluatedContext))
990 .bind("binary")),
991 this);
992
993 // Logical or bitwise operator with equivalent nested operands, like (X && Y
994 // && X) or (X && (Y && X))
995 Finder->addMatcher(
996 binaryOperator(hasAnyOperatorName("|", "&", "||", "&&", "^"),
997 nestedOperandsAreEquivalent(),
998 // Filter noisy false positives.
999 unless(isInTemplateInstantiation()),
1000 unless(binaryOperatorIsInMacro()),
1001 // TODO: if the banned macros are themselves duplicated
1002 unless(hasDescendant(BannedIntegerLiteral)),
1003 unless(IsInUnevaluatedContext))
1004 .bind("nested-duplicates"),
1005 this);
1006
1007 // Conditional (ternary) operator with equivalent operands, like (Y ? X : X).
1008 Finder->addMatcher(
1009 traverse(TK_AsIs,
1010 conditionalOperator(expressionsAreEquivalent(),
1011 // Filter noisy false positives.
1012 unless(conditionalOperatorIsInMacro()),
1013 unless(isInTemplateInstantiation()),
1014 unless(IsInUnevaluatedContext))
1015 .bind("cond")),
1016 this);
1017
1018 // Overloaded operators with equivalent operands.
1019 Finder->addMatcher(
1020 traverse(TK_AsIs,
1021 cxxOperatorCallExpr(
1022 hasAnyOverloadedOperatorName("-", "/", "%", "|", "&", "^",
1023 "==", "!=", "<", "<=", ">",
1024 ">=", "&&", "||", "="),
1025 parametersAreEquivalent(),
1026 // Filter noisy false positives.
1027 unless(isMacro()), unless(isInTemplateInstantiation()),
1028 unless(IsInUnevaluatedContext))
1029 .bind("call")),
1030 this);
1031
1032 // Overloaded operators with equivalent operands.
1033 Finder->addMatcher(
1034 cxxOperatorCallExpr(
1035 hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
1036 nestedParametersAreEquivalent(), argumentCountIs(2),
1037 // Filter noisy false positives.
1038 unless(isMacro()), unless(isInTemplateInstantiation()),
1039 unless(IsInUnevaluatedContext))
1040 .bind("nested-duplicates"),
1041 this);
1042
1043 // Match expressions like: !(1 | 2 | 3)
1044 Finder->addMatcher(
1045 traverse(TK_AsIs,
1046 implicitCastExpr(
1047 hasImplicitDestinationType(isInteger()),
1048 has(unaryOperator(
1049 hasOperatorName("!"),
1050 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
1051 hasAnyOperatorName("|", "&"),
1052 hasLHS(anyOf(
1053 binaryOperator(hasAnyOperatorName("|", "&")),
1054 integerLiteral())),
1055 hasRHS(integerLiteral())))))
1056 .bind("logical-bitwise-confusion")),
1057 unless(IsInUnevaluatedContext))),
1058 this);
1059
1060 // Match expressions like: (X << 8) & 0xFF
1061 Finder->addMatcher(
1062 traverse(TK_AsIs,
1063 binaryOperator(
1064 hasOperatorName("&"),
1065 hasOperands(ignoringParenImpCasts(binaryOperator(
1066 hasOperatorName("<<"),
1067 hasRHS(ignoringParenImpCasts(
1068 integerLiteral().bind("shift-const"))))),
1069 ignoringParenImpCasts(
1070 integerLiteral().bind("and-const"))),
1071 unless(IsInUnevaluatedContext))
1072 .bind("left-right-shift-confusion")),
1073 this);
1074
1075 // Match common expressions and apply more checks to find redundant
1076 // sub-expressions.
1077 // a) Expr <op> K1 == K2
1078 // b) Expr <op> K1 == Expr
1079 // c) Expr <op> K1 == Expr <op> K2
1080 // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
1081 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
1082 const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
1083 const auto CstRight = matchIntegerConstantExpr("rhs");
1084 const auto SymRight = matchSymbolicExpr("rhs");
1085
1086 // Match expressions like: x <op> 0xFF == 0xF00.
1087 Finder->addMatcher(
1088 traverse(TK_AsIs, binaryOperator(isComparisonOperator(),
1089 hasOperands(BinOpCstLeft, CstRight),
1090 unless(IsInUnevaluatedContext))
1091 .bind("binop-const-compare-to-const")),
1092 this);
1093
1094 // Match expressions like: x <op> 0xFF == x.
1095 Finder->addMatcher(
1096 traverse(
1097 TK_AsIs,
1098 binaryOperator(isComparisonOperator(),
1099 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
1100 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))),
1101 unless(IsInUnevaluatedContext))
1102 .bind("binop-const-compare-to-sym")),
1103 this);
1104
1105 // Match expressions like: x <op> 10 == x <op> 12.
1106 Finder->addMatcher(
1107 traverse(TK_AsIs,
1108 binaryOperator(isComparisonOperator(), hasLHS(BinOpCstLeft),
1109 hasRHS(BinOpCstRight),
1110 // Already reported as redundant.
1111 unless(operandsAreEquivalent()),
1112 unless(IsInUnevaluatedContext))
1113 .bind("binop-const-compare-to-binop-const")),
1114 this);
1115
1116 // Match relational expressions combined with logical operators and find
1117 // redundant sub-expressions.
1118 // see: 'checkRelationalExpr'
1119
1120 // Match expressions like: x < 2 && x > 2.
1121 const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
1122 const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
1123 Finder->addMatcher(
1124 traverse(TK_AsIs,
1125 binaryOperator(hasAnyOperatorName("||", "&&"),
1126 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
1127 // Already reported as redundant.
1128 unless(operandsAreEquivalent()),
1129 unless(IsInUnevaluatedContext))
1130 .bind("comparisons-of-symbol-and-const")),
1131 this);
1132}
1133
1134void RedundantExpressionCheck::checkArithmeticExpr(
1135 const MatchFinder::MatchResult &Result) {
1136 APSInt LhsValue, RhsValue;
1137 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
1138 BinaryOperatorKind LhsOpcode{}, RhsOpcode{};
1139
1140 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1141 "binop-const-compare-to-sym")) {
1142 const BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1143 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
1144 LhsValue) ||
1145 !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
1146 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1147 return;
1148
1149 // Check expressions: x + k == x or x - k == x.
1150 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
1151 if ((LhsValue != 0 && Opcode == BO_EQ) ||
1152 (LhsValue == 0 && Opcode == BO_NE))
1153 diag(ComparisonOperator->getOperatorLoc(),
1154 "logical expression is always false");
1155 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
1156 (LhsValue != 0 && Opcode == BO_NE))
1157 diag(ComparisonOperator->getOperatorLoc(),
1158 "logical expression is always true");
1159 }
1160 } else if (const auto *ComparisonOperator =
1161 Result.Nodes.getNodeAs<BinaryOperator>(
1162 "binop-const-compare-to-binop-const")) {
1163 const BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1164
1165 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
1166 LhsValue) ||
1167 !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
1168 RhsValue) ||
1169 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1170 return;
1171
1172 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
1173 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
1174
1175 // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
1176 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
1177 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
1178 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
1179 diag(ComparisonOperator->getOperatorLoc(),
1180 "logical expression is always true");
1181 } else if ((Opcode == BO_EQ &&
1182 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
1183 (Opcode == BO_NE &&
1184 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
1185 diag(ComparisonOperator->getOperatorLoc(),
1186 "logical expression is always false");
1187 }
1188 }
1189 }
1190}
1191
1192static bool exprEvaluatesToZero(BinaryOperatorKind Opcode,
1193 const APSInt &Value) {
1194 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
1195}
1196
1197static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode,
1198 const APSInt &Value) {
1199 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
1200}
1201
1202static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode,
1203 const APSInt &Value) {
1204 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
1205 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
1206}
1207
1208void RedundantExpressionCheck::checkBitwiseExpr(
1209 const MatchFinder::MatchResult &Result) {
1210 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1211 "binop-const-compare-to-const")) {
1212 const BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1213
1214 APSInt LhsValue, RhsValue;
1215 const Expr *LhsSymbol = nullptr;
1216 BinaryOperatorKind LhsOpcode{};
1217 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
1218 LhsValue) ||
1219 !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
1220 return;
1221
1222 const unsigned ConstantWidth =
1223 std::max(LhsValue.getBitWidth(), RhsValue.getBitWidth());
1224 const llvm::APInt LhsConstant = LhsValue.extOrTrunc(ConstantWidth);
1225 const llvm::APInt RhsConstant = RhsValue.extOrTrunc(ConstantWidth);
1226 const SourceLocation Loc = ComparisonOperator->getOperatorLoc();
1227
1228 // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
1229 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
1230 if (Opcode == BO_EQ)
1231 diag(Loc, "logical expression is always false");
1232 else if (Opcode == BO_NE)
1233 diag(Loc, "logical expression is always true");
1234 }
1235
1236 // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
1237 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
1238 if (Opcode == BO_EQ)
1239 diag(Loc, "logical expression is always false");
1240 else if (Opcode == BO_NE)
1241 diag(Loc, "logical expression is always true");
1242 }
1243 } else if (const auto *IneffectiveOperator =
1244 Result.Nodes.getNodeAs<BinaryOperator>(
1245 "ineffective-bitwise")) {
1246 APSInt Value;
1247 const Expr *Sym = nullptr, *ConstExpr = nullptr;
1248
1249 if (!retrieveSymbolicExpr(Result, "ineffective-bitwise", Sym) ||
1250 !retrieveIntegerConstantExpr(Result, "ineffective-bitwise", Value,
1251 ConstExpr))
1252 return;
1253
1254 if ((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
1255 return;
1256
1257 const SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
1258
1259 const BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
1260 if (exprEvaluatesToZero(Opcode, Value)) {
1261 diag(Loc, "expression always evaluates to 0");
1262 } else if (exprEvaluatesToBitwiseNegatedZero(Opcode, Value)) {
1263 const SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
1264 ConstExpr->getEndLoc());
1265 const StringRef ConstExprText = Lexer::getSourceText(
1266 CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
1267 Result.Context->getLangOpts());
1268
1269 diag(Loc, "expression always evaluates to '%0'") << ConstExprText;
1270
1271 } else if (exprEvaluatesToSymbolic(Opcode, Value)) {
1272 const SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
1273
1274 const StringRef ExprText = Lexer::getSourceText(
1275 CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
1276 Result.Context->getLangOpts());
1277
1278 diag(Loc, "expression always evaluates to '%0'") << ExprText;
1279 }
1280 }
1281}
1282
1283void RedundantExpressionCheck::checkRelationalExpr(
1284 const MatchFinder::MatchResult &Result) {
1285 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
1286 "comparisons-of-symbol-and-const")) {
1287 // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
1288 // E.g.: (X < 2) && (X > 4)
1289 const BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
1290
1291 const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
1292 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
1293 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
1294 BinaryOperatorKind LhsOpcode{}, RhsOpcode{};
1295 APSInt LhsValue, RhsValue;
1296
1298 Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
1300 Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
1301 !areEquivalentExpr(LhsSymbol, RhsSymbol))
1302 return;
1303
1304 // Bring expr to a canonical form: smallest constant must be on the left.
1305 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
1306 std::swap(LhsExpr, RhsExpr);
1307 std::swap(LhsValue, RhsValue);
1308 std::swap(LhsSymbol, RhsSymbol);
1309 std::swap(LhsOpcode, RhsOpcode);
1310 }
1311
1312 // Constants come from two different macros, or one of them is a macro.
1313 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1314 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1315 return;
1316
1317 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
1318 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1319 diag(ComparisonOperator->getOperatorLoc(),
1320 "equivalent expression on both sides of logical operator");
1321 return;
1322 }
1323
1324 if (Opcode == BO_LAnd) {
1325 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1326 diag(ComparisonOperator->getOperatorLoc(),
1327 "logical expression is always false");
1328 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1329 diag(LhsExpr->getExprLoc(), "expression is redundant");
1330 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1331 diag(RhsExpr->getExprLoc(), "expression is redundant");
1332 }
1333 }
1334
1335 if (Opcode == BO_LOr) {
1336 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1337 diag(ComparisonOperator->getOperatorLoc(),
1338 "logical expression is always true");
1339 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
1340 diag(RhsExpr->getExprLoc(), "expression is redundant");
1341 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
1342 diag(LhsExpr->getExprLoc(), "expression is redundant");
1343 }
1344 }
1345 }
1346}
1347
1348void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
1349 if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
1350 // If the expression's constants are macros, check whether they are
1351 // intentional.
1352
1353 //
1354 // Special case for floating-point representation.
1355 //
1356 // If expressions on both sides of comparison operator are of type float,
1357 // then for some comparison operators no warning shall be
1358 // reported even if the expressions are identical from a symbolic point of
1359 // view. Comparison between expressions, declared variables and literals
1360 // are treated differently.
1361 //
1362 // != and == between float literals that have the same value should NOT
1363 // warn. < > between float literals that have the same value SHOULD warn.
1364 //
1365 // != and == between the same float declaration should NOT warn.
1366 // < > between the same float declaration SHOULD warn.
1367 //
1368 // != and == between eq. expressions that evaluates into float
1369 // should NOT warn.
1370 // < > between eq. expressions that evaluates into float
1371 // should NOT warn.
1372 //
1373 const Expr *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
1374 const Expr *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
1375 const BinaryOperator::Opcode Op = BinOp->getOpcode();
1376 const bool OpEqualEQorNE = ((Op == BO_EQ) || (Op == BO_NE));
1377
1378 const auto *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
1379 const auto *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
1380 const auto *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
1381 const auto *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
1382
1383 if (DeclRef1 && DeclRef2 &&
1384 DeclRef1->getType()->hasFloatingRepresentation() &&
1385 DeclRef2->getType()->hasFloatingRepresentation() &&
1386 (DeclRef1->getDecl() == DeclRef2->getDecl()) && OpEqualEQorNE) {
1387 return;
1388 }
1389
1390 if (FloatLit1 && FloatLit2 &&
1391 FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()) &&
1392 OpEqualEQorNE) {
1393 return;
1394 }
1395
1397 BinOp, Result.Context)) {
1398 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
1399 BinaryOperatorKind MainOpcode{}, SideOpcode{};
1400 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
1401 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
1402 LhsConst, RhsConst, Result.Context))
1403 return;
1404
1405 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1406 areExprsMacroAndNonMacro(LhsConst, RhsConst))
1407 return;
1408 } else {
1409 if (!areExprsSameMacroOrLiteral(BinOp, Result.Context))
1410 return;
1411 }
1412 }
1413 diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
1414 }
1415
1416 if (const auto *CondOp =
1417 Result.Nodes.getNodeAs<ConditionalOperator>("cond")) {
1418 const Expr *TrueExpr = CondOp->getTrueExpr();
1419 const Expr *FalseExpr = CondOp->getFalseExpr();
1420
1421 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
1422 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
1423 return;
1424 diag(CondOp->getColonLoc(),
1425 "'true' and 'false' expressions are equivalent");
1426 }
1427
1428 if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
1430 return;
1431
1432 diag(Call->getOperatorLoc(),
1433 "both sides of overloaded operator are equivalent");
1434 }
1435
1436 if (const auto *Op = Result.Nodes.getNodeAs<Expr>("nested-duplicates")) {
1437 const auto *Call = dyn_cast<CXXOperatorCallExpr>(Op);
1438 if (Call && canOverloadedOperatorArgsBeModified(Call, true))
1439 return;
1440
1441 const StringRef Message =
1442 Call ? "overloaded operator has equivalent nested operands"
1443 : "operator has equivalent nested operands";
1444
1445 const auto Diag = diag(Op->getExprLoc(), Message);
1446 for (const auto &KeyValue : Result.Nodes.getMap())
1447 if (StringRef(KeyValue.first).starts_with("duplicate"))
1448 Diag << KeyValue.second.getSourceRange();
1449 }
1450
1451 if (const auto *NegateOperator =
1452 Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
1453 const SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1454
1455 const auto Diag =
1456 diag(OperatorLoc,
1457 "ineffective logical negation operator used; did you mean '~'?");
1458 const SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1459
1460 if (!LogicalNotLocation.isMacroID())
1461 Diag << FixItHint::CreateReplacement(
1462 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation), "~");
1463 }
1464
1465 if (const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1466 "left-right-shift-confusion")) {
1467 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>("shift-const");
1468 assert(ShiftingConst && "Expr* 'ShiftingConst' is nullptr!");
1469 std::optional<llvm::APSInt> ShiftingValue =
1470 ShiftingConst->getIntegerConstantExpr(*Result.Context);
1471
1472 if (!ShiftingValue)
1473 return;
1474
1475 const auto *AndConst = Result.Nodes.getNodeAs<Expr>("and-const");
1476 assert(AndConst && "Expr* 'AndCont' is nullptr!");
1477 std::optional<llvm::APSInt> AndValue =
1478 AndConst->getIntegerConstantExpr(*Result.Context);
1479 if (!AndValue)
1480 return;
1481
1482 // If ShiftingConst is shifted left with more bits than the position of the
1483 // leftmost 1 in the bit representation of AndValue, AndConstant is
1484 // ineffective.
1485 if (AndValue->getActiveBits() > *ShiftingValue)
1486 return;
1487
1488 const auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1489 "ineffective bitwise and operation");
1490 }
1491
1492 // Check for the following bound expressions:
1493 // - "binop-const-compare-to-sym",
1494 // - "binop-const-compare-to-binop-const",
1495 // Produced message:
1496 // -> "logical expression is always false/true"
1497 checkArithmeticExpr(Result);
1498
1499 // Check for the following bound expression:
1500 // - "binop-const-compare-to-const",
1501 // - "ineffective-bitwise"
1502 // Produced message:
1503 // -> "logical expression is always false/true"
1504 // -> "expression always evaluates to ..."
1505 checkBitwiseExpr(Result);
1506
1507 // Check for te following bound expression:
1508 // - "comparisons-of-symbol-and-const",
1509 // Produced messages:
1510 // -> "equivalent expression on both sides of logical operator",
1511 // -> "logical expression is always false/true"
1512 // -> "expression is redundant"
1513 checkRelationalExpr(Result);
1514}
1515
1516} // namespace clang::tidy::misc
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
static bool areExprsFromDifferentMacros(const Expr *LhsExpr, const Expr *RhsExpr, const ASTContext *AstCtx)
Returns true if both LhsExpr and RhsExpr are macro expressions and they are expanded from different m...
static const TExpr * checkOpKind(const Expr *TheExpr, OverloadedOperatorKind OpKind)
static constexpr StringRef KnownBannedMacroNames[]
static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx)
static bool markDuplicateOperands(const TExpr *TheExpr, ast_matchers::internal::BoundNodesTreeBuilder *Builder, ASTContext &Context)
static bool areEquivalentDeclRefExpr(const DeclRefExpr *L, const DeclRefExpr *R)
static bool collectOperands(const Expr *Part, SmallVector< const Expr *, N > &AllOperands, OverloadedOperatorKind OpKind)
static std::pair< const Expr *, const Expr * > getOperands(const BinaryOperator *Op)
static constexpr StringRef Message
static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp, BinaryOperatorKind &MainOpcode, BinaryOperatorKind &SideOpcode, const Expr *&LhsConst, const Expr *&RhsConst, const ASTContext *AstCtx)
static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode, APSInt &Value)
static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, APSInt &Value, const Expr *&ConstExpr)
static bool retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value, const Expr *&ConstExpr)
static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static ast_matchers::internal::Matcher< Expr > matchSymbolicExpr(StringRef Id)
static bool areStringsSameIgnoreSpaces(const StringRef Left, const StringRef Right)
static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result)
static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr, const Expr *&RhsExpr)
static bool isSameRawIdentifierToken(const Token &T1, const Token &T2, const SourceManager &SM)
static bool areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant(const BinaryOperator *&BinOp, const ASTContext *AstCtx)
static bool isTokAtEndOfExpr(SourceRange ExprSR, Token T, const SourceManager &SM)
static bool areEquivalentExpr(const Expr *Left, const Expr *Right)
static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool isNonConstReferenceType(QualType ParamType)
static ast_matchers::internal::Matcher< Expr > matchIntegerConstantExpr(StringRef Id)
static OverloadedOperatorKind getOp(const BinaryOperator *Op)
static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode, const APSInt &Value)
static ast_matchers::internal::Matcher< Expr > matchBinOpIntegerConstantExpr(StringRef Id)
static bool hasSameOperatorParent(const Expr *TheExpr, OverloadedOperatorKind OpKind, ASTContext &Context)
static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&SymExpr)
static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areExprsSameMacroOrLiteral(const BinaryOperator *BinOp, const ASTContext *Context)
static bool retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
static ast_matchers::internal::Matcher< Expr > matchRelationalIntegerConstantExpr(StringRef Id)
static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, const APSInt &Value)
static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, const APSInt &Value)
static bool canOverloadedOperatorArgsBeModified(const CXXOperatorCallExpr *OperatorCall, bool CheckSecondParam)