[clang-tidy] Add bugprone-chained-comparison check (#76365)
Check that flags chained comparison expressions, such as a < b < c or a == b == c, which may have unintended behavior due to implicit operator associativity. Moved from Phabricator (D144429).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "BoolPointerImplicitConversionCheck.h"
|
||||
#include "BranchCloneCheck.h"
|
||||
#include "CastingThroughVoidCheck.h"
|
||||
#include "ChainedComparisonCheck.h"
|
||||
#include "ComparePointerToMemberVirtualFunctionCheck.h"
|
||||
#include "CopyConstructorInitCheck.h"
|
||||
#include "DanglingHandleCheck.h"
|
||||
@@ -108,6 +109,8 @@ public:
|
||||
CheckFactories.registerCheck<BranchCloneCheck>("bugprone-branch-clone");
|
||||
CheckFactories.registerCheck<CastingThroughVoidCheck>(
|
||||
"bugprone-casting-through-void");
|
||||
CheckFactories.registerCheck<ChainedComparisonCheck>(
|
||||
"bugprone-chained-comparison");
|
||||
CheckFactories.registerCheck<ComparePointerToMemberVirtualFunctionCheck>(
|
||||
"bugprone-compare-pointer-to-member-virtual-function");
|
||||
CheckFactories.registerCheck<CopyConstructorInitCheck>(
|
||||
|
||||
@@ -12,6 +12,7 @@ add_clang_library(clangTidyBugproneModule
|
||||
BranchCloneCheck.cpp
|
||||
BugproneTidyModule.cpp
|
||||
CastingThroughVoidCheck.cpp
|
||||
ChainedComparisonCheck.cpp
|
||||
ComparePointerToMemberVirtualFunctionCheck.cpp
|
||||
CopyConstructorInitCheck.cpp
|
||||
DanglingHandleCheck.cpp
|
||||
|
||||
150
clang-tools-extra/clang-tidy/bugprone/ChainedComparisonCheck.cpp
Normal file
150
clang-tools-extra/clang-tidy/bugprone/ChainedComparisonCheck.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
//===--- ChainedComparisonCheck.cpp - clang-tidy --------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ChainedComparisonCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
static bool isExprAComparisonOperator(const Expr *E) {
|
||||
if (const auto *Op = dyn_cast_or_null<BinaryOperator>(E->IgnoreImplicit()))
|
||||
return Op->isComparisonOp();
|
||||
if (const auto *Op =
|
||||
dyn_cast_or_null<CXXOperatorCallExpr>(E->IgnoreImplicit()))
|
||||
return Op->isComparisonOp();
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
AST_MATCHER(BinaryOperator,
|
||||
hasBinaryOperatorAChildComparisonOperatorWithoutParen) {
|
||||
return isExprAComparisonOperator(Node.getLHS()) ||
|
||||
isExprAComparisonOperator(Node.getRHS());
|
||||
}
|
||||
|
||||
AST_MATCHER(CXXOperatorCallExpr,
|
||||
hasCppOperatorAChildComparisonOperatorWithoutParen) {
|
||||
return std::any_of(Node.arg_begin(), Node.arg_end(),
|
||||
isExprAComparisonOperator);
|
||||
}
|
||||
|
||||
struct ChainedComparisonData {
|
||||
llvm::SmallString<256U> Name;
|
||||
llvm::SmallVector<const Expr *, 32U> Operands;
|
||||
|
||||
explicit ChainedComparisonData(const Expr *Op) { extract(Op); }
|
||||
|
||||
private:
|
||||
void add(const Expr *Operand);
|
||||
void add(llvm::StringRef Opcode);
|
||||
void extract(const Expr *Op);
|
||||
void extract(const BinaryOperator *Op);
|
||||
void extract(const CXXOperatorCallExpr *Op);
|
||||
};
|
||||
|
||||
void ChainedComparisonData::add(const Expr *Operand) {
|
||||
if (!Name.empty())
|
||||
Name += ' ';
|
||||
Name += 'v';
|
||||
Name += std::to_string(Operands.size());
|
||||
Operands.push_back(Operand);
|
||||
}
|
||||
|
||||
void ChainedComparisonData::add(llvm::StringRef Opcode) {
|
||||
Name += ' ';
|
||||
Name += Opcode;
|
||||
}
|
||||
|
||||
void ChainedComparisonData::extract(const BinaryOperator *Op) {
|
||||
const Expr *LHS = Op->getLHS()->IgnoreImplicit();
|
||||
if (isExprAComparisonOperator(LHS))
|
||||
extract(LHS);
|
||||
else
|
||||
add(LHS);
|
||||
|
||||
add(Op->getOpcodeStr());
|
||||
|
||||
const Expr *RHS = Op->getRHS()->IgnoreImplicit();
|
||||
if (isExprAComparisonOperator(RHS))
|
||||
extract(RHS);
|
||||
else
|
||||
add(RHS);
|
||||
}
|
||||
|
||||
void ChainedComparisonData::extract(const CXXOperatorCallExpr *Op) {
|
||||
const Expr *FirstArg = Op->getArg(0U)->IgnoreImplicit();
|
||||
if (isExprAComparisonOperator(FirstArg))
|
||||
extract(FirstArg);
|
||||
else
|
||||
add(FirstArg);
|
||||
|
||||
add(getOperatorSpelling(Op->getOperator()));
|
||||
|
||||
const Expr *SecondArg = Op->getArg(1U)->IgnoreImplicit();
|
||||
if (isExprAComparisonOperator(SecondArg))
|
||||
extract(SecondArg);
|
||||
else
|
||||
add(SecondArg);
|
||||
}
|
||||
|
||||
void ChainedComparisonData::extract(const Expr *Op) {
|
||||
if (!Op)
|
||||
return;
|
||||
|
||||
if (const auto *BinaryOp = dyn_cast<BinaryOperator>(Op)) {
|
||||
extract(BinaryOp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *OverloadedOp = dyn_cast<CXXOperatorCallExpr>(Op)) {
|
||||
if (OverloadedOp->getNumArgs() == 2U)
|
||||
extract(OverloadedOp);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ChainedComparisonCheck::registerMatchers(MatchFinder *Finder) {
|
||||
const auto OperatorMatcher = expr(anyOf(
|
||||
binaryOperator(isComparisonOperator(),
|
||||
hasBinaryOperatorAChildComparisonOperatorWithoutParen()),
|
||||
cxxOperatorCallExpr(
|
||||
isComparisonOperator(),
|
||||
hasCppOperatorAChildComparisonOperatorWithoutParen())));
|
||||
|
||||
Finder->addMatcher(
|
||||
expr(OperatorMatcher, unless(hasParent(OperatorMatcher))).bind("op"),
|
||||
this);
|
||||
}
|
||||
|
||||
void ChainedComparisonCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *MatchedOperator = Result.Nodes.getNodeAs<Expr>("op");
|
||||
|
||||
ChainedComparisonData Data(MatchedOperator);
|
||||
if (Data.Operands.empty())
|
||||
return;
|
||||
|
||||
diag(MatchedOperator->getBeginLoc(),
|
||||
"chained comparison '%0' may generate unintended results, use "
|
||||
"parentheses to specify order of evaluation or a logical operator to "
|
||||
"separate comparison expressions")
|
||||
<< llvm::StringRef(Data.Name).trim() << MatchedOperator->getSourceRange();
|
||||
|
||||
for (std::size_t Index = 0U; Index < Data.Operands.size(); ++Index) {
|
||||
diag(Data.Operands[Index]->getBeginLoc(), "operand 'v%0' is here",
|
||||
DiagnosticIDs::Note)
|
||||
<< Index << Data.Operands[Index]->getSourceRange();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clang::tidy::bugprone
|
||||
@@ -0,0 +1,34 @@
|
||||
//===--- ChainedComparisonCheck.h - clang-tidy ------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CHAINEDCOMPARISONCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CHAINEDCOMPARISONCHECK_H
|
||||
|
||||
#include "../ClangTidyCheck.h"
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
|
||||
/// Check detects chained comparison operators that can lead to unintended
|
||||
/// behavior or logical errors.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/chained-comparison.html
|
||||
class ChainedComparisonCheck : public ClangTidyCheck {
|
||||
public:
|
||||
ChainedComparisonCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
std::optional<TraversalKind> getCheckTraversalKind() const override {
|
||||
return TK_IgnoreUnlessSpelledInSource;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::bugprone
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CHAINEDCOMPARISONCHECK_H
|
||||
@@ -143,6 +143,12 @@ New checks
|
||||
|
||||
Detects unsafe or redundant two-step casting operations involving ``void*``.
|
||||
|
||||
- New :doc:`bugprone-chained-comparison
|
||||
<clang-tidy/checks/bugprone/chained-comparison>` check.
|
||||
|
||||
Check detects chained comparison operators that can lead to unintended
|
||||
behavior or logical errors.
|
||||
|
||||
- New :doc:`bugprone-compare-pointer-to-member-virtual-function
|
||||
<clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check.
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
.. title:: clang-tidy - bugprone-chained-comparison
|
||||
|
||||
bugprone-chained-comparison
|
||||
===========================
|
||||
|
||||
Check detects chained comparison operators that can lead to unintended
|
||||
behavior or logical errors.
|
||||
|
||||
Chained comparisons are expressions that use multiple comparison operators
|
||||
to compare three or more values. For example, the expression ``a < b < c``
|
||||
compares the values of ``a``, ``b``, and ``c``. However, this expression does
|
||||
not evaluate as ``(a < b) && (b < c)``, which is probably what the developer
|
||||
intended. Instead, it evaluates as ``(a < b) < c``, which may produce
|
||||
unintended results, especially when the types of ``a``, ``b``, and ``c`` are
|
||||
different.
|
||||
|
||||
To avoid such errors, the check will issue a warning when a chained
|
||||
comparison operator is detected, suggesting to use parentheses to specify
|
||||
the order of evaluation or to use a logical operator to separate comparison
|
||||
expressions.
|
||||
|
||||
Consider the following examples:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int a = 2, b = 6, c = 4;
|
||||
if (a < b < c) {
|
||||
// This block will be executed
|
||||
}
|
||||
|
||||
|
||||
In this example, the developer intended to check if ``a`` is less than ``b``
|
||||
and ``b`` is less than ``c``. However, the expression ``a < b < c`` is
|
||||
equivalent to ``(a < b) < c``. Since ``a < b`` is ``true``, the expression
|
||||
``(a < b) < c`` is evaluated as ``1 < c``, which is equivalent to ``true < c``
|
||||
and is invalid in this case as ``b < c`` is ``false``.
|
||||
|
||||
Even that above issue could be detected as comparison of ``int`` to ``bool``,
|
||||
there is more dangerous example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
bool a = false, b = false, c = true;
|
||||
if (a == b == c) {
|
||||
// This block will be executed
|
||||
}
|
||||
|
||||
In this example, the developer intended to check if ``a``, ``b``, and ``c`` are
|
||||
all equal. However, the expression ``a == b == c`` is evaluated as
|
||||
``(a == b) == c``. Since ``a == b`` is true, the expression ``(a == b) == c``
|
||||
is evaluated as ``true == c``, which is equivalent to ``true == true``.
|
||||
This comparison yields ``true``, even though ``a`` and ``b`` are ``false``, and
|
||||
are not equal to ``c``.
|
||||
|
||||
To avoid this issue, the developer can use a logical operator to separate the
|
||||
comparison expressions, like this:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
if (a == b && b == c) {
|
||||
// This block will not be executed
|
||||
}
|
||||
|
||||
|
||||
Alternatively, use of parentheses in the comparison expressions can make the
|
||||
developer's intention more explicit and help avoid misunderstanding.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
if ((a == b) == c) {
|
||||
// This block will be executed
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ Clang-Tidy Checks
|
||||
:doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
|
||||
:doc:`bugprone-branch-clone <bugprone/branch-clone>`,
|
||||
:doc:`bugprone-casting-through-void <bugprone/casting-through-void>`,
|
||||
:doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
|
||||
:doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
|
||||
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
|
||||
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// RUN: %check_clang_tidy %s bugprone-chained-comparison %t
|
||||
|
||||
void badly_chained_1(int x, int y, int z)
|
||||
{
|
||||
int result = x < y < z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_2(int x, int y, int z)
|
||||
{
|
||||
int result = x <= y <= z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 <= v1 <= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_3(int x, int y, int z)
|
||||
{
|
||||
int result = x > y > z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 > v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_4(int x, int y, int z)
|
||||
{
|
||||
int result = x >= y >= z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 >= v1 >= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_5(int x, int y, int z)
|
||||
{
|
||||
int result = x == y != z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 == v1 != v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_6(int x, int y, int z)
|
||||
{
|
||||
int result = x != y == z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 != v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_multiple(int a, int b, int c, int d, int e, int f, int g, int h)
|
||||
{
|
||||
int result = a == b == c == d == e == f == g == h;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_limit(int v[29])
|
||||
{
|
||||
// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7 == v8 == v9 == v10 == v11 == v12 == v13 == v14 == v15 == v16 == v17 == v18 == v19 == v20 == v21 == v22 == v23 == v24 == v25 == v26 == v27 == v28' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
int result = v[0] == v[1] == v[2] == v[3] == v[4] == v[5] == v[6] == v[7] ==
|
||||
v[8] == v[9] == v[10] == v[11] == v[12] == v[13] == v[14] ==
|
||||
v[15] == v[16] == v[17] == v[18] == v[19] == v[20] == v[21] ==
|
||||
v[22] == v[23] == v[24] == v[25] == v[26] == v[27] == v[28];
|
||||
|
||||
}
|
||||
|
||||
void badly_chained_parens2(int x, int y, int z, int t, int a, int b)
|
||||
{
|
||||
int result = (x < y) < (z && t) > (a == b);
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 < v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_inner(int x, int y, int z, int t, int u)
|
||||
{
|
||||
int result = x && y < z < t && u;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void properly_chained_1(int x, int y, int z)
|
||||
{
|
||||
int result = x < y && y < z;
|
||||
}
|
||||
|
||||
void properly_chained_2(int x, int y, int z)
|
||||
{
|
||||
int result = (x < y) == z;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-chained-comparison %t
|
||||
|
||||
void badly_chained_1(int x, int y, int z)
|
||||
{
|
||||
bool result = x < y < z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_2(int x, int y, int z)
|
||||
{
|
||||
bool result = x <= y <= z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 <= v1 <= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_3(int x, int y, int z)
|
||||
{
|
||||
bool result = x > y > z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 > v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_4(int x, int y, int z)
|
||||
{
|
||||
bool result = x >= y >= z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 >= v1 >= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_5(int x, int y, int z)
|
||||
{
|
||||
bool result = x == y != z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 == v1 != v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_6(bool x, bool y, bool z)
|
||||
{
|
||||
bool result = x != y == z;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 != v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_multiple(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h)
|
||||
{
|
||||
bool result = a == b == c == d == e == f == g == h;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_limit(bool v[29])
|
||||
{
|
||||
// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7 == v8 == v9 == v10 == v11 == v12 == v13 == v14 == v15 == v16 == v17 == v18 == v19 == v20 == v21 == v22 == v23 == v24 == v25 == v26 == v27 == v28' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
bool result = v[0] == v[1] == v[2] == v[3] == v[4] == v[5] == v[6] == v[7] ==
|
||||
v[8] == v[9] == v[10] == v[11] == v[12] == v[13] == v[14] ==
|
||||
v[15] == v[16] == v[17] == v[18] == v[19] == v[20] == v[21] ==
|
||||
v[22] == v[23] == v[24] == v[25] == v[26] == v[27] == v[28];
|
||||
|
||||
}
|
||||
|
||||
void badly_chained_parens2(int x, int y, int z, int t, int a, int b)
|
||||
{
|
||||
bool result = (x < y) < (z && t) > (a == b);
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 < v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void badly_chained_inner(int x, int y, int z, int t, int u)
|
||||
{
|
||||
bool result = x && y < z < t && u;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
void properly_chained_1(int x, int y, int z)
|
||||
{
|
||||
bool result = x < y && y < z;
|
||||
}
|
||||
|
||||
void properly_chained_2(int x, int y, bool z)
|
||||
{
|
||||
bool result = (x < y) == z;
|
||||
}
|
||||
|
||||
struct Value {
|
||||
bool operator<(const Value&) const;
|
||||
};
|
||||
|
||||
bool operator==(bool, const Value&);
|
||||
|
||||
bool badWithCppOperator(Value a, Value b, Value c) {
|
||||
return a < b == c;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: chained comparison 'v0 < v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
|
||||
bool mixedBinaryAndCpp(Value a, Value b, bool c) {
|
||||
return a < b == c;
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: chained comparison 'v0 < v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
|
||||
Reference in New Issue
Block a user