| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| .. title:: clang-tidy - readability-use-std-min-max | ||
|
|
||
| readability-use-std-min-max | ||
| =========================== | ||
|
|
||
| Replaces certain conditional statements with equivalent calls to | ||
| ``std::min`` or ``std::max``. | ||
| Note: This may impact performance in critical code due to potential | ||
| additional stores compared to the original if statement. | ||
|
|
||
| Before: | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| void foo() { | ||
| int a = 2, b = 3; | ||
| if (a < b) | ||
| a = b; | ||
| } | ||
|
|
||
|
|
||
| After: | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| void foo() { | ||
| int a = 2, b = 3; | ||
| a = std::max(a, b); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| // RUN: %check_clang_tidy -std=c++11-or-later %s readability-use-std-min-max %t -- -- -fno-delayed-template-parsing | ||
| #define MY_MACRO_MIN(a, b) ((a) < (b) ? (a) : (b)) | ||
|
|
||
| constexpr int myConstexprMin(int a, int b) { | ||
| return a < b ? a : b; | ||
| } | ||
|
|
||
| constexpr int myConstexprMax(int a, int b) { | ||
| return a > b ? a : b; | ||
| } | ||
|
|
||
| #define MY_IF_MACRO(condition, statement) \ | ||
| if (condition) { \ | ||
| statement \ | ||
| } | ||
|
|
||
| class MyClass { | ||
| public: | ||
| int member1; | ||
| int member2; | ||
| }; | ||
|
|
||
| template<typename T> | ||
|
|
||
| void foo(T value7) { | ||
| int value1,value2,value3; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value1, value2); | ||
| if (value1 < value2) | ||
| value1 = value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value2 = std::min(value1, value2); | ||
| if (value1 < value2) | ||
| value2 = value1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value2 = std::min(value2, value1); | ||
| if (value2 > value1) | ||
| value2 = value1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value2, value1); | ||
| if (value2 > value1) | ||
| value1 = value2; | ||
|
|
||
| // No suggestion needed here | ||
| if (value1 == value2) | ||
| value1 = value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+3]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max<int>(value1, value4); | ||
| short value4; | ||
| if(value1<value4) | ||
| value1=value4; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value3 = std::min(value1+value2, value3); | ||
| if(value1+value2<value3) | ||
| value3 = value1+value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value1, myConstexprMin(value2, value3)); | ||
| if (value1 < myConstexprMin(value2, value3)) | ||
| value1 = myConstexprMin(value2, value3); | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::min(value1, myConstexprMax(value2, value3)); | ||
| if (value1 > myConstexprMax(value2, value3)) | ||
| value1 = myConstexprMax(value2, value3); | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value2 = std::min(value1, value2); | ||
| if (value1 <= value2) | ||
| value2 = value1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value1, value2); | ||
| if (value1 <= value2) | ||
| value1 = value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value2, value1); | ||
| if (value2 >= value1) | ||
| value1 = value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value2 = std::min(value2, value1); | ||
| if (value2 >= value1) | ||
| value2 = value1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+3]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member1 = std::max(obj.member1, obj.member2); | ||
| MyClass obj; | ||
| if (obj.member1 < obj.member2) | ||
| obj.member1 = obj.member2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member2 = std::min(obj.member1, obj.member2); | ||
| if (obj.member1 < obj.member2) | ||
| obj.member2 = obj.member1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member2 = std::min(obj.member2, obj.member1); | ||
| if (obj.member2 > obj.member1) | ||
| obj.member2 = obj.member1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member1 = std::max(obj.member2, obj.member1); | ||
| if (obj.member2 > obj.member1) | ||
| obj.member1 = obj.member2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member1 = std::max<int>(obj.member1, value4); | ||
| if (obj.member1 < value4) | ||
| obj.member1 = value4; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value3 = std::min(obj.member1 + value2, value3); | ||
| if (obj.member1 + value2 < value3) | ||
| value3 = obj.member1 + value2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member2 = std::min(value1, obj.member2); | ||
| if (value1 <= obj.member2) | ||
| obj.member2 = value1; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value1, obj.member2); | ||
| if (value1 <= obj.member2) | ||
| value1 = obj.member2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(obj.member2, value1); | ||
| if (obj.member2 >= value1) | ||
| value1 = obj.member2; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` [readability-use-std-min-max] | ||
| // CHECK-FIXES: obj.member2 = std::min(obj.member2, value1); | ||
| if (obj.member2 >= value1) | ||
| obj.member2 = value1; | ||
|
|
||
| // No suggestion needed here | ||
| if (MY_MACRO_MIN(value1, value2) < value3) | ||
| value3 = MY_MACRO_MIN(value1, value2); | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value4 = std::max<int>(value4, value2); | ||
| if (value4 < value2){ | ||
| value4 = value2; | ||
| } | ||
|
|
||
| // No suggestion needed here | ||
| if(value1 < value2) | ||
| value2 = value1; | ||
| else | ||
| value2 = value3; | ||
|
|
||
| // No suggestion needed here | ||
| if(value1<value2){ | ||
| value2 = value1; | ||
| } | ||
| else{ | ||
| value2 = value3; | ||
| } | ||
|
|
||
| // No suggestion needed here | ||
| if(value1<value2){ | ||
| value2 = value1; | ||
| int res = value1 + value2; | ||
| } | ||
|
|
||
| // No suggestion needed here | ||
| MY_IF_MACRO(value1 < value2, value1 = value2;) | ||
|
|
||
| // No suggestion needed here | ||
| if(value1<value2){ | ||
| value1 = value2; | ||
| } | ||
| else if(value1>value2){ | ||
| value2 = value1; | ||
| } | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+3]]:5: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max(value1, value3); | ||
| if(value1 == value2){ | ||
| if(value1<value3) | ||
| value1 = value3; | ||
| } | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+5]]:7: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value1 = std::max<int>(value1, value4); | ||
| if(value1 == value2){ | ||
| if(value2 == value3){ | ||
| value3+=1; | ||
| if(value1<value4){ | ||
| value1 = value4; | ||
| } | ||
| } | ||
| else if(value3>value2){ | ||
| value2 = value3; | ||
| } | ||
| } | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+4]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value6 = std::min<unsigned int>(value5, value6); | ||
| unsigned int value5; | ||
| unsigned char value6; | ||
| if(value5<value6){ | ||
| value6 = value5; | ||
| } | ||
|
|
||
| //No suggestion needed here | ||
| if(value7<value6){ | ||
| value6 = value7; | ||
| } | ||
|
|
||
| //CHECK-MESSAGES: :[[@LINE+3]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| //CHECK-FIXES: value1 = std::min(value8, value1); | ||
| const int value8 = 5; | ||
| if(value8<value1) | ||
| value1 = value8; | ||
|
|
||
| //CHECK-MESSAGES: :[[@LINE+3]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max] | ||
| //CHECK-FIXES: value1 = std::min(value9, value1); | ||
| volatile int value9 = 6; | ||
| if(value9<value1) | ||
| value1 = value9; | ||
| } | ||
|
|
||
| using my_size = unsigned long long; | ||
|
|
||
| template<typename T> | ||
| struct MyVector | ||
| { | ||
| using size_type = my_size; | ||
| size_type size() const; | ||
| }; | ||
|
|
||
| void testVectorSizeType() { | ||
| MyVector<int> v; | ||
| unsigned int value; | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value = std::max<my_size>(v.size(), value); | ||
| if (v.size() > value) | ||
| value = v.size(); | ||
|
|
||
| // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max] | ||
| // CHECK-FIXES: value = std::max<my_size>(value, v.size()); | ||
| if (value < v.size()) | ||
| value = v.size(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // RUN: %clang_cc1 -ffixed-point %s -verify | ||
| // expected-no-diagnostics | ||
|
|
||
| constexpr _Accum a[2] = {}; | ||
| static_assert(a[0] == 0 && a[0] != 1); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedLocalVarsChecker -verify %s | ||
|
|
||
| #include "mock-types.h" | ||
|
|
||
| class RenderStyle; | ||
|
|
||
| class FillLayer { | ||
| public: | ||
| void ref() const; | ||
| void deref() const; | ||
| }; | ||
|
|
||
| class FillLayersPropertyWrapper { | ||
| public: | ||
| typedef const FillLayer& (RenderStyle::*LayersGetter)() const; | ||
|
|
||
| private: | ||
| bool canInterpolate(const RenderStyle& from) const | ||
| { | ||
| auto* fromLayer = &(from.*m_layersGetter)(); | ||
| // expected-warning@-1{{Local variable 'fromLayer' is uncounted and unsafe}} | ||
| return true; | ||
| } | ||
|
|
||
| LayersGetter m_layersGetter; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // RUN: %clang_cc1 -std=c++98 -verify=expected %s | ||
| // RUN: %clang_cc1 -std=c++11 -verify=expected %s | ||
| // RUN: %clang_cc1 -std=c++14 -verify=expected %s | ||
| // RUN: %clang_cc1 -std=c++17 -verify=expected %s | ||
| // RUN: %clang_cc1 -std=c++20 -verify=expected,since-cxx20 %s | ||
| // RUN: %clang_cc1 -std=c++23 -verify=expected,since-cxx20,since-cxx23 %s | ||
| // RUN: %clang_cc1 -std=c++2c -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s | ||
|
|
||
| #if __cplusplus < 202002L | ||
| // expected-no-diagnostics | ||
| #endif | ||
|
|
||
| namespace dr2847 { // dr2847: 19 | ||
|
|
||
| #if __cplusplus >= 202002L | ||
|
|
||
| template<typename> | ||
| void i(); | ||
|
|
||
| struct A { | ||
| template<typename> | ||
| void f() requires true; | ||
|
|
||
| template<> | ||
| void f<int>() requires true; | ||
| // since-cxx20-error@-1 {{explicit specialization cannot have a trailing requires clause unless it declares a function template}} | ||
|
|
||
| friend void i<int>() requires true; | ||
| // since-cxx20-error@-1 {{friend specialization cannot have a trailing requires clause unless it declares a function template}} | ||
| }; | ||
|
|
||
| template<typename> | ||
| struct B { | ||
| void f() requires true; | ||
|
|
||
| template<typename> | ||
| void g() requires true; | ||
|
|
||
| template<typename> | ||
| void h() requires true; | ||
|
|
||
| template<> | ||
| void h<int>() requires true; | ||
| // since-cxx20-error@-1 {{explicit specialization cannot have a trailing requires clause unless it declares a function template}} | ||
|
|
||
| friend void i<int>() requires true; | ||
| // since-cxx20-error@-1 {{friend specialization cannot have a trailing requires clause unless it declares a function template}} | ||
| }; | ||
|
|
||
| template<> | ||
| void B<int>::f() requires true; | ||
| // since-cxx20-error@-1 {{explicit specialization cannot have a trailing requires clause unless it declares a function template}} | ||
|
|
||
| template<> | ||
| template<typename T> | ||
| void B<int>::g() requires true; | ||
|
|
||
| #endif | ||
|
|
||
| } // namespace dr2847 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // RUN: %clang_cc1 %s -O0 -fsanitize=shift-exponent -emit-llvm -std=c2x -triple=x86_64-unknown-linux -o - | FileCheck %s | ||
|
|
||
| // Checking that the code generation is using the unextended/untruncated | ||
| // exponent values and capping the values accordingly | ||
|
|
||
| // CHECK-LABEL: define{{.*}} i32 @test_left_variable | ||
| int test_left_variable(unsigned _BitInt(5) b, unsigned _BitInt(2) e) { | ||
| // CHECK: [[E_REG:%.+]] = load [[E_SIZE:i2]] | ||
| // CHECK: icmp ule [[E_SIZE]] [[E_REG]], -1 | ||
| return b << e; | ||
| } | ||
|
|
||
| // CHECK-LABEL: define{{.*}} i32 @test_right_variable | ||
| int test_right_variable(unsigned _BitInt(2) b, unsigned _BitInt(3) e) { | ||
| // CHECK: [[E_REG:%.+]] = load [[E_SIZE:i3]] | ||
| // CHECK: icmp ule [[E_SIZE]] [[E_REG]], 1 | ||
| return b >> e; | ||
| } | ||
|
|
||
| // Old code generation would give false positives on left shifts when: | ||
| // value(e) > (width(b) - 1 % 2 ** width(e)) | ||
| // CHECK-LABEL: define{{.*}} i32 @test_left_literal | ||
| int test_left_literal(unsigned _BitInt(5) b) { | ||
| // CHECK-NOT: br i1 false, label %cont, label %handler.shift_out_of_bounds | ||
| // CHECK: br i1 true, label %cont, label %handler.shift_out_of_bounds | ||
| return b << 3uwb; | ||
| } | ||
|
|
||
| // Old code generation would give false positives on right shifts when: | ||
| // (value(e) % 2 ** width(b)) < width(b) | ||
| // CHECK-LABEL: define{{.*}} i32 @test_right_literal | ||
| int test_right_literal(unsigned _BitInt(2) b) { | ||
| // CHECK-NOT: br i1 true, label %cont, label %handler.shift_out_of_bounds | ||
| // CHECK: br i1 false, label %cont, label %handler.shift_out_of_bounds | ||
| return b >> 4uwb; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| // RUN: rm -rf %t.dir | ||
| // RUN: mkdir -p %t.dir/level1/level2 | ||
|
|
||
|
|
||