Skip to content

Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max #77816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1883d98
Add readability check to suggest replacement of conditional statement…
11happy Jan 11, 2024
89be4ba
Formatted the code
11happy Jan 11, 2024
e1b65a9
small fix
11happy Jan 11, 2024
042ddc3
Revert "small fix"
11happy Jan 12, 2024
c17b298
Revert "Formatted the code"
11happy Jan 12, 2024
9aad658
Revert "Add readability check to suggest replacement of conditional s…
11happy Jan 12, 2024
2fc0938
Added Suggested Changes
11happy Jan 12, 2024
1139ac4
Formatted the Code
11happy Jan 12, 2024
f73e9f0
Added Release Notes
11happy Jan 12, 2024
faf3312
corrected file name
11happy Jan 12, 2024
5ed9896
corrected title length in docs
11happy Jan 12, 2024
19c4b63
Suggested Changes
11happy Jan 12, 2024
8167787
body indentation
11happy Jan 12, 2024
3a28399
added intialisation,constexpr tests
11happy Jan 13, 2024
2ecd08a
small fixes
11happy Jan 13, 2024
00d4080
Addded Suggested Changes
11happy Jan 15, 2024
6db0820
formatted the code
11happy Jan 15, 2024
5073650
Added Include Check
11happy Jan 15, 2024
c728a39
Formatted the code
11happy Jan 15, 2024
b8202ae
Added tests for macro & if with brackets
11happy Jan 17, 2024
3b57307
Fixed merge Conflict
11happy Jan 17, 2024
5e31665
Added suggested changes
11happy Jan 19, 2024
a2cfcdc
Formatted the code
11happy Jan 19, 2024
f5a0f12
Converted to Lambdas,placed at sorted location
11happy Jan 19, 2024
e239576
Single Lambda
11happy Jan 20, 2024
b868d5b
CamelCase,const auto*
11happy Jan 20, 2024
0797e0c
fixes
11happy Jan 20, 2024
c6028b0
few nits
11happy Jan 21, 2024
6acf645
formatted the code
11happy Jan 21, 2024
0eb4aca
extra checks
11happy Jan 21, 2024
d5b8dc2
ensure if has no else if
11happy Jan 22, 2024
a92160c
correct style issue
11happy Jan 22, 2024
5eafb59
correct docs
11happy Jan 22, 2024
26bfbdc
correct docs
11happy Jan 22, 2024
57bccd6
static functions
11happy Jan 22, 2024
61fd66a
small fix
11happy Jan 22, 2024
a841ebc
style issues
11happy Jan 23, 2024
7d2c085
corrrect style issue
11happy Jan 23, 2024
399c4c5
Merge branch 'SecondPR' of https://github.com/11happy/llvm-project in…
11happy Jan 23, 2024
abec9b5
correct functional bugs
11happy Jan 26, 2024
6a0e495
pass dependent types
11happy Jan 26, 2024
274b55f
filter implicit cast expr
11happy Jan 26, 2024
b7ca014
resolved merge conflict
11happy Jan 26, 2024
8bf8235
Add mising type, optimise
11happy Jan 27, 2024
d8df8c8
removed whitespace
11happy Jan 27, 2024
8a5d585
remove unsed initialisation
11happy Jan 27, 2024
85fb67d
small change
11happy Jan 27, 2024
1214547
simplify
11happy Jan 29, 2024
6aef713
small fix
11happy Jan 30, 2024
f03b2ff
non template alias
11happy Feb 1, 2024
5d504a7
simplify pointer dereference
11happy Feb 5, 2024
19cc1f3
remove extra parentheses
11happy Feb 5, 2024
a316744
use spefici type instead of auto
11happy Feb 5, 2024
f0ef998
use auto for cast kind
11happy Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_clang_library(clangTidyReadabilityModule
AvoidReturnWithVoidValueCheck.cpp
AvoidUnconditionalPreprocessorIfCheck.cpp
BracesAroundStatementsCheck.cpp
ConditionaltostdminmaxCheck.cpp
ConstReturnTypeCheck.cpp
ContainerContainsCheck.cpp
ContainerDataPointerCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//===--- ConditionaltostdminmaxCheck.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 "ConditionaltostdminmaxCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;

namespace clang::tidy::readability {

void ConditionaltostdminmaxCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
ifStmt(has(binaryOperator(
anyOf(hasOperatorName("<"), hasOperatorName(">")),
hasLHS(ignoringImpCasts(declRefExpr().bind("lhsVar1"))),
hasRHS(ignoringImpCasts(declRefExpr().bind("rhsVar1"))))),
hasThen(stmt(binaryOperator(
hasOperatorName("="),
hasLHS(ignoringImpCasts(declRefExpr().bind("lhsVar2"))),
hasRHS(ignoringImpCasts(declRefExpr().bind("rhsVar2")))))))
.bind("ifStmt"),
this);
}

void ConditionaltostdminmaxCheck::check(
const MatchFinder::MatchResult &Result) {
const DeclRefExpr *lhsVar1 = Result.Nodes.getNodeAs<DeclRefExpr>("lhsVar1");
const DeclRefExpr *rhsVar1 = Result.Nodes.getNodeAs<DeclRefExpr>("rhsVar1");
const DeclRefExpr *lhsVar2 = Result.Nodes.getNodeAs<DeclRefExpr>("lhsVar2");
const DeclRefExpr *rhsVar2 = Result.Nodes.getNodeAs<DeclRefExpr>("rhsVar2");
const IfStmt *ifStmt = Result.Nodes.getNodeAs<IfStmt>("ifStmt");

if (!lhsVar1 || !rhsVar1 || !lhsVar2 || !rhsVar2 || !ifStmt)
return;

const BinaryOperator *binaryOp = dyn_cast<BinaryOperator>(ifStmt->getCond());
if (!binaryOp)
return;

SourceLocation ifLocation = ifStmt->getIfLoc();
SourceLocation thenLocation = ifStmt->getEndLoc();

if (binaryOp->getOpcode() == BO_LT) {
if (lhsVar1->getDecl() == lhsVar2->getDecl() &&
rhsVar1->getDecl() == rhsVar2->getDecl()) {
diag(ifStmt->getIfLoc(), "use std::max instead of <")
<< FixItHint::CreateReplacement(
SourceRange(ifLocation, thenLocation),
lhsVar2->getNameInfo().getAsString() + " = std::max(" +
lhsVar1->getNameInfo().getAsString() + ", " +
rhsVar1->getNameInfo().getAsString() + ")");
} else if (lhsVar1->getDecl() == rhsVar2->getDecl() &&
rhsVar1->getDecl() == lhsVar2->getDecl()) {
diag(ifStmt->getIfLoc(), "use std::min instead of <")
<< FixItHint::CreateReplacement(
SourceRange(ifLocation, thenLocation),
lhsVar2->getNameInfo().getAsString() + " = std::min(" +
lhsVar1->getNameInfo().getAsString() + ", " +
rhsVar1->getNameInfo().getAsString() + ")");
}
} else if (binaryOp->getOpcode() == BO_GT) {
if (lhsVar1->getDecl() == lhsVar2->getDecl() &&
rhsVar1->getDecl() == rhsVar2->getDecl()) {
diag(ifStmt->getIfLoc(), "use std::min instead of >")
<< FixItHint::CreateReplacement(
SourceRange(ifLocation, thenLocation),
lhsVar2->getNameInfo().getAsString() + " = std::min(" +
lhsVar1->getNameInfo().getAsString() + ", " +
rhsVar1->getNameInfo().getAsString() + ")");
} else if (lhsVar1->getDecl() == rhsVar2->getDecl() &&
rhsVar1->getDecl() == lhsVar2->getDecl()) {
diag(ifStmt->getIfLoc(), "use std::max instead of >")
<< FixItHint::CreateReplacement(
SourceRange(ifLocation, thenLocation),
lhsVar2->getNameInfo().getAsString() + " = std::max(" +
lhsVar1->getNameInfo().getAsString() + ", " +
rhsVar1->getNameInfo().getAsString() + ")");
}
}
}

} // namespace clang::tidy::readability
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===--- ConditionaltostdminmaxCheck.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_READABILITY_CONDITIONALTOSTDMINMAXCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONDITIONALTOSTDMINMAXCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::readability {

/// FIXME: replaces certain conditional statements with equivalent std::min or
/// std::max expressions, improving readability and promoting the use of
/// standard library functions."
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/ConditionalToStdMinMax.html
class ConditionaltostdminmaxCheck : public ClangTidyCheck {
public:
ConditionaltostdminmaxCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};

} // namespace clang::tidy::readability

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONDITIONALTOSTDMINMAXCHECK_H
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "AvoidReturnWithVoidValueCheck.h"
#include "AvoidUnconditionalPreprocessorIfCheck.h"
#include "BracesAroundStatementsCheck.h"
#include "ConditionaltostdminmaxCheck.h"
#include "ConstReturnTypeCheck.h"
#include "ContainerContainsCheck.h"
#include "ContainerDataPointerCheck.h"
Expand Down Expand Up @@ -62,6 +63,8 @@ namespace readability {
class ReadabilityModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<ConditionaltostdminmaxCheck>(
"readability-ConditionalToStdMinMax");
CheckFactories.registerCheck<AvoidConstParamsInDecls>(
"readability-avoid-const-params-in-decls");
CheckFactories.registerCheck<AvoidReturnWithVoidValueCheck>(
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ New checks
Recommends the smallest possible underlying type for an ``enum`` or ``enum``
class based on the range of its enumerators.

- New :doc:`readability-ConditionalToStdMinMax
<clang-tidy/checks/readability/ConditionalToStdMinMax>` check.

Replaces certain conditional statements with equivalent std::min or std::max expressions,
improving readability and promoting the use of standard library functions.

- New :doc:`readability-reference-to-constructed-temporary
<clang-tidy/checks/readability/reference-to-constructed-temporary>` check.

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ Clang-Tidy Checks
:doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
:doc:`readability-ConditionalToStdMinMax <readability/ConditionalToStdMinMax>`, "Yes"
:doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
:doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`,
:doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.. title:: clang-tidy - readability-ConditionalToStdMinMax

readability-ConditionalToStdMinMax
==================================

Replaces certain conditional statements with equivalent std::min or std::max expressions,
improving readability and promoting the use of standard library functions.

Examples:

Before:

.. code-block:: c++

void foo(){
int a,b;
if(a < b)
a = b;
}


After:

.. code-block:: c++

void foo(){
a = std::max(a, b);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %check_clang_tidy %s readability-ConditionalToStdMinMax %t

void foo() {
int value1,value2;

// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use std::max instead of < [readability-ConditionalToStdMinMax]
if (value1 < value2)
value1 = value2; // CHECK-FIXES: value1 = std::max(value1, value2);

// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use std::min instead of < [readability-ConditionalToStdMinMax]
if (value1 < value2)
value2 = value1; // CHECK-FIXES: value2 = std::min(value1, value2);

// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use std::min instead of > [readability-ConditionalToStdMinMax]
if (value2 > value1)
value2 = value1; // CHECK-FIXES: value2 = std::min(value2, value1);

// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use std::max instead of > [readability-ConditionalToStdMinMax]
if (value2 > value1)
value1 = value2; // CHECK-FIXES: value1 = std::max(value2, value1);

// No suggestion needed here
if (value1 == value2)
value1 = value2;


}