mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-15 23:06:32 +00:00
[clang-tidy] modernize-use-starts-ends-with: fix false positives on find
and rfind
(#129564)
Also document cases with two or three arguments (matching default arguments) this check matches. Closes https://github.com/llvm/llvm-project/issues/129498.
This commit is contained in:
parent
2a4522229c
commit
2909c420f6
@ -113,21 +113,33 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
|
||||
const auto OnClassWithEndsWithFunction = ClassTypeWithMethod(
|
||||
"ends_with_fun", "ends_with", "endsWith", "endswith", "EndsWith");
|
||||
|
||||
// Case 1: X.find(Y) [!=]= 0 -> starts_with.
|
||||
// Case 1: X.find(Y, [0], [LEN(Y)]) [!=]= 0 -> starts_with.
|
||||
const auto FindExpr = cxxMemberCallExpr(
|
||||
anyOf(argumentCountIs(1), hasArgument(1, ZeroLiteral)),
|
||||
callee(
|
||||
cxxMethodDecl(hasName("find"), ofClass(OnClassWithStartsWithFunction))
|
||||
.bind("find_fun")),
|
||||
hasArgument(0, expr().bind("needle")));
|
||||
hasArgument(0, expr().bind("needle")),
|
||||
anyOf(
|
||||
// Detect the expression: X.find(Y);
|
||||
argumentCountIs(1),
|
||||
// Detect the expression: X.find(Y, 0);
|
||||
allOf(argumentCountIs(2), hasArgument(1, ZeroLiteral)),
|
||||
// Detect the expression: X.find(Y, 0, LEN(Y));
|
||||
allOf(argumentCountIs(3), hasArgument(1, ZeroLiteral),
|
||||
hasArgument(2, lengthExprForStringNode("needle")))));
|
||||
|
||||
// Case 2: X.rfind(Y, 0) [!=]= 0 -> starts_with.
|
||||
// Case 2: X.rfind(Y, 0, [LEN(Y)]) [!=]= 0 -> starts_with.
|
||||
const auto RFindExpr = cxxMemberCallExpr(
|
||||
hasArgument(1, ZeroLiteral),
|
||||
callee(cxxMethodDecl(hasName("rfind"),
|
||||
ofClass(OnClassWithStartsWithFunction))
|
||||
.bind("find_fun")),
|
||||
hasArgument(0, expr().bind("needle")));
|
||||
hasArgument(0, expr().bind("needle")),
|
||||
anyOf(
|
||||
// Detect the expression: X.rfind(Y, 0);
|
||||
allOf(argumentCountIs(2), hasArgument(1, ZeroLiteral)),
|
||||
// Detect the expression: X.rfind(Y, 0, LEN(Y));
|
||||
allOf(argumentCountIs(3), hasArgument(1, ZeroLiteral),
|
||||
hasArgument(2, lengthExprForStringNode("needle")))));
|
||||
|
||||
// Case 3: X.compare(0, LEN(Y), Y) [!=]= 0 -> starts_with.
|
||||
const auto CompareExpr = cxxMemberCallExpr(
|
||||
|
@ -175,6 +175,11 @@ Changes in existing checks
|
||||
<clang-tidy/checks/modernize/use-ranges>` check by updating suppress
|
||||
warnings logic for ``nullptr`` in ``std::find``.
|
||||
|
||||
- Improved :doc:`modernize-use-starts-ends-with
|
||||
<clang-tidy/checks/modernize/use-starts-ends-with>` check by adding more
|
||||
matched scenarios of ``find`` and ``rfind`` methods and fixing false
|
||||
positives when those methods were called with 3 arguments.
|
||||
|
||||
- Improved :doc:`modernize-use-std-numbers
|
||||
<clang-tidy/checks/modernize/use-std-numbers>` check to support math
|
||||
functions of different precisions.
|
||||
|
@ -13,7 +13,10 @@ Covered scenarios:
|
||||
Expression Replacement
|
||||
---------------------------------------------------- ---------------------
|
||||
``u.find(v) == 0`` ``u.starts_with(v)``
|
||||
``u.find(v, 0) == 0`` ``u.starts_with(v)``
|
||||
``u.find(v, 0, v.size()) == 0`` ``u.starts_with(v)``
|
||||
``u.rfind(v, 0) != 0`` ``!u.starts_with(v)``
|
||||
``u.rfind(v, 0, v.size()) != 0`` ``!u.starts_with(v)``
|
||||
``u.compare(0, v.size(), v) == 0`` ``u.starts_with(v)``
|
||||
``u.substr(0, v.size()) == v`` ``u.starts_with(v)``
|
||||
``v != u.substr(0, v.size())`` ``!u.starts_with(v)``
|
||||
|
@ -236,6 +236,42 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
|
||||
// CHECK-FIXES: s.ends_with(suffix);
|
||||
|
||||
s.find("a", 0) == 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with("a");
|
||||
|
||||
s.find(s, ZERO) == 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with(s);
|
||||
|
||||
s.find(s, 0) == ZERO;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with(s);
|
||||
|
||||
s.find("aaa", 0, 3) == 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with("aaa");
|
||||
|
||||
s.find("aaa", ZERO, 3) == 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with("aaa");
|
||||
|
||||
s.find("aaa", ZERO, strlen(("aaa"))) == ZERO;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with("aaa");
|
||||
|
||||
s.rfind("aaa", 0, 3) != 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: !s.starts_with("aaa");
|
||||
|
||||
s.rfind("aaa", ZERO, 3) != 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: !s.starts_with("aaa");
|
||||
|
||||
s.rfind("aaa", ZERO, strlen(("aaa"))) == ZERO;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
|
||||
// CHECK-FIXES: s.starts_with("aaa");
|
||||
|
||||
struct S {
|
||||
std::string s;
|
||||
} t;
|
||||
@ -261,6 +297,12 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
|
||||
|
||||
#define STRING s
|
||||
if (0 == STRING.find("ala")) { /* do something */}
|
||||
|
||||
// Cases when literal-size and size parameters are different are not being matched.
|
||||
s.find("aaa", 0, 2) == 0;
|
||||
s.find("aaa", 0, strlen("aa")) == 0;
|
||||
s.rfind("aaa", 0, 2) == 0;
|
||||
s.rfind("aaa", 0, strlen("aa")) == 0;
|
||||
}
|
||||
|
||||
void test_substr() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user