Skip to content

Commit

Permalink
Merge attempt by ./merge_from_main.sh into branch amd-trunk-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
DominikAdamski committed Jan 23, 2024
2 parents 8e1821b + bb3a515 commit 839c02d
Show file tree
Hide file tree
Showing 681 changed files with 30,259 additions and 5,430 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
/*OwnsHeaderSearch=*/false);
PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
Compiler.getFrontendOpts());
Compiler.getFrontendOpts(), Compiler.getCodeGenOpts());
ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
Compiler.getTarget().getTriple());
}
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -108,6 +109,8 @@ class BugproneModule : public ClangTidyModule {
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>(
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_clang_library(clangTidyBugproneModule
BranchCloneCheck.cpp
BugproneTidyModule.cpp
CastingThroughVoidCheck.cpp
ChainedComparisonCheck.cpp
ComparePointerToMemberVirtualFunctionCheck.cpp
CopyConstructorInitCheck.cpp
DanglingHandleCheck.cpp
Expand Down
150 changes: 150 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/ChainedComparisonCheck.cpp
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/ChainedComparisonCheck.h
Original file line number Diff line number Diff line change
@@ -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
19 changes: 14 additions & 5 deletions clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ static Token getTokenAtLoc(SourceLocation Loc,
return Tok;
}

namespace {
AST_MATCHER(FunctionDecl, isUserDefineLiteral) {
return Node.getLiteralIdentifier() != nullptr;
}
} // namespace

namespace tidy::google::runtime {

IntegerTypesCheck::IntegerTypesCheck(StringRef Name, ClangTidyContext *Context)
Expand All @@ -56,11 +62,14 @@ void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) {
// http://google.github.io/styleguide/cppguide.html#64-bit_Portability
// "Where possible, avoid passing arguments of types specified by
// bitwidth typedefs to printf-based APIs."
Finder->addMatcher(typeLoc(loc(isInteger()),
unless(hasAncestor(callExpr(
callee(functionDecl(hasAttr(attr::Format)))))))
.bind("tl"),
this);
Finder->addMatcher(
typeLoc(loc(isInteger()),
unless(anyOf(hasAncestor(callExpr(
callee(functionDecl(hasAttr(attr::Format))))),
hasParent(parmVarDecl(hasAncestor(
functionDecl(isUserDefineLiteral())))))))
.bind("tl"),
this);
IdentTable = std::make_unique<IdentifierTable>(getLangOpts());
}

Expand Down
12 changes: 11 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -375,6 +381,9 @@ Changes in existing checks
<clang-tidy/checks/google/readability-casting>` check to ignore constructor
calls disguised as functional casts.

- Improved :doc:`google-runtime-int <clang-tidy/checks/google/runtime-int>`
check to ignore false positives on user defined-literals.

- Improved :doc:`llvm-namespace-comment
<clang-tidy/checks/llvm/namespace-comment>` check to provide fixes for
``inline`` namespaces in the same format as :program:`clang-format`.
Expand All @@ -398,7 +407,8 @@ Changes in existing checks
using pointer to member function. Additionally, the check no longer emits
a diagnostic when a variable that is not type-dependent is an operand of a
type-dependent binary operator. Improved performance of the check through
optimizations.
optimizations. The check no longer emits a diagnostic for non-parameter-pack
variables in C++17 fold expressions.

- Improved :doc:`misc-include-cleaner
<clang-tidy/checks/misc/include-cleaner>` check by adding option
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}

3 changes: 2 additions & 1 deletion clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`,
Expand Down Expand Up @@ -354,7 +355,6 @@ Clang-Tidy Checks
:doc:`readability-identifier-length <readability/identifier-length>`,
:doc:`readability-identifier-naming <readability/identifier-naming>`, "Yes"
:doc:`readability-implicit-bool-conversion <readability/implicit-bool-conversion>`, "Yes"
:doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
:doc:`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>`, "Yes"
:doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
:doc:`readability-magic-numbers <readability/magic-numbers>`,
Expand All @@ -370,6 +370,7 @@ Clang-Tidy Checks
:doc:`readability-redundant-control-flow <readability/redundant-control-flow>`, "Yes"
:doc:`readability-redundant-declaration <readability/redundant-declaration>`, "Yes"
:doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
:doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
:doc:`readability-redundant-member-init <readability/redundant-member-init>`, "Yes"
:doc:`readability-redundant-preprocessor <readability/redundant-preprocessor>`,
:doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
Expand Down
Loading

0 comments on commit 839c02d

Please sign in to comment.