[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/116033

Adds a new check that finds calls to substr when its first argument is a 
zero-equivalent expression and can be replaced with starts_with() (introduced 
in C++20). This modernization improves code readability by making the intent 
clearer and can be more efficient as it avoids creating temporary strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Warns about standalone substr calls that might be candidates
- Supports both string literals and string variables
- Handles both == and != operators

>From d95e8338d47ef265dd7d9dfacd475329525ea326 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Warns about standalone substr calls that might be candidates
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 121 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  38 ++
 .../modernize/substr-to-starts-with.cpp   |  41 ++
 6 files changed, 234 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..b185a2a3b0afc2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,121 @@
+//===--- SubstrToStartsWithCheck.cpp - 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.
+// SP

[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 3e3db0d8ee6bf2f87b1c5f51cb02fe9a3ef50ff5 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 104 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  35 ++
 .../modernize/substr-to-starts-with.cpp   |  41 +++
 6 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..253e5ba3ca32ba
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,104 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::basic_string".bind("strvar")));
+
+  auto isSubstrCall = 

[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 2e4fb01caa92c06b17bf93c08c4262a349b74379 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Warns about standalone substr calls that might be candidates
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 112 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  38 ++
 .../modernize/substr-to-starts-with.cpp   |  41 +++
 6 files changed, 225 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..f7d8dbde0fb155
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,112 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::bas

[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 19059d8671d01ae67e2777aadfb1d8addc6bd8eb Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Warns about standalone substr calls that might be candidates
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 104 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  38 +++
 .../modernize/substr-to-starts-with.cpp   |  41 +++
 6 files changed, 217 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..253e5ba3ca32ba
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,104 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::ba

[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

ok will refactor the PR
 
-- 
Helmut Januschka
 

Am 13. November 2024 um 16:28:52, Carlos Galvez ***@***.*** ***@***.***> ) 
schrieb:

 

I think modernize-use-starts-ends-with should be extended instead.

Agreed!

—
Reply to this email directly, view it on GitHub 
 , or 
unsubscribe 

 .
You are receiving this because you authored the thread. 

 Message ID: ***@***.***>



https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 9df25dbf0d66792d7b53ef484cec5a474ea5904d Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 104 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  35 ++
 .../modernize/substr-to-starts-with.cpp   |  42 +++
 6 files changed, 215 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..253e5ba3ca32ba
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,104 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::basic_string".bind("strvar")));
+
+  auto isSubstrCall = 

[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-13 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From adafcceb45853c3e8f797eba51d90e64654dafe6 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 104 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  35 ++
 .../modernize/substr-to-starts-with.cpp   |  42 +++
 6 files changed, 215 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..253e5ba3ca32ba
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,104 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::basic_string".bind("strvar")));
+
+  auto isSubstrCall = 

[clang-tools-extra] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck for flexible … (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka converted_to_draft 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck for flexible … (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/117529

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.


WIP, TODO:
  - add test case.



```
#include 

namespace base {
template 
class scoped_refptr {
 public:
  explicit scoped_refptr(T* p) : ptr_(p) {}

  void reset(T* p) {
delete ptr_;
ptr_ = p;
  }

  // For demonstration purposes
  T* get() const { return ptr_; }

  ~scoped_refptr() {
delete ptr_;
  }

 private:
  T* ptr_;  // Raw pointer to the managed object
};

// Mock MakeRefCounted function
template 
scoped_refptr MakeRefCounted(Args&&... args) {
  return scoped_refptr(new T(std::forward(args)...));
}

class Foo {
 public:
  Foo() { std::cout << "Foo constructed.\n"; }
  ~Foo() { std::cout << "Foo destroyed.\n"; }
};

}  // namespace base

// Test case
int main() {
  auto ptr = base::MakeRefCounted();  // Create a scoped_refptr
  ptr.reset(new base::Foo());  // Reset with a new instance
  return 0;
}

```

works, but need to figure out why turning this into a llvm-lit does not work

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck for
 flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyl

[clang-tools-extra] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck for flexible … (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/2] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] WIP: [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] WIP: [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-25 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka ready_for_review 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/118074

Add new clang-tidy check that suggests using std::span's more expressive 
first() and last() member functions instead of equivalent subspan() calls.

The check modernizes code by replacing:
- subspan(0, n) -> first(n)
- subspan(n) -> last(size() - n)

These dedicated methods were added to the standard to provide clearer 
alternatives to common subspan operations. They improve readability by better 
expressing intent and are less error-prone by eliminating manual offset 
calculations.

For example:
```cpp
std::span s = ...;
auto sub1 = s.subspan(0, n); // transforms to: auto sub1 = s.first(n);
auto sub2 = s.subspan(n);// transforms to: auto sub2 = s.last(s.size() 
- n);
auto sub3 = s.subspan(1, n); // not transformed, no direct equivalent
```


not sure if this is a readability or a modernize check ❓ 

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/2] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  c

[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/3] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+   

[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/4] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+   

[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/6] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+   

[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/7] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+   

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/8] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+   

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/10] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@carlosgalvezp thanks for the feedback. I've removed the transformation:

```c++
auto sub2 = s.subspan(n);// transforms to: auto sub2 = s.last(s.size() 
- n);
```

While I agree that the transformed expression is more complex (due to size() - 
x), I initially included it for two reasons:

Consistency: Using `first()/last()` everywhere possible makes the codebase more 
uniform
The method name `last()` better expresses the intent than `subspan()`, even if 
the calculation is more verbose

Let me know if you think we should revisit this decision.

https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/11] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/12] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/13] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add modernize-make-direct check (PR #118120)

2024-11-29 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/118120

Adds a new check that converts std::make_* function calls to direct constructor 
calls using CTAD. Transforms make_optional, make_unique, make_shared and 
make_pair into their equivalent direct constructor calls, leveraging C++17's 
class template argument deduction.

>From 2bcf868d023b5be2f3c88f1d68dd2084b7db4604 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 19:17:36 +0100
Subject: [PATCH] [clang-tidy] Add modernize-make-direct check

Adds a new check that converts std::make_* function calls to direct constructor
calls using CTAD. Transforms make_optional, make_unique, make_shared and 
make_pair
into their equivalent direct constructor calls, leveraging C++17's class 
template
argument deduction.
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/MakeFunctionToDirectCheck.cpp   | 108 ++
 .../modernize/MakeFunctionToDirectCheck.h |  20 
 .../modernize/ModernizeTidyModule.cpp |   3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   6 +
 .../modernize/modernize-make-direct.rst   |  17 +++
 .../checkers/modernize/make-direct-check.cpp  |  66 +++
 7 files changed, 221 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/modernize-make-direct.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/make-direct-check.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..7e8d9296c6a64c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  MakeFunctionToDirectCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git 
a/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp
new file mode 100644
index 00..0262f77f4992cb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp
@@ -0,0 +1,108 @@
+#include "MakeFunctionToDirectCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void MakeFunctionToDirectCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus17)
+return;
+  // Match make_xxx function calls
+  Finder->addMatcher(callExpr(callee(functionDecl(hasAnyName(
+  "std::make_optional", "std::make_unique",
+  "std::make_shared", "std::make_pair"
+ .bind("make_call"),
+ this);
+}
+
+bool MakeFunctionToDirectCheck::isMakeFunction(
+const std::string &FuncName) const {
+  static const std::array MakeFuncs = {
+  "make_optional", "make_unique", "make_shared", "make_pair"};
+
+  return std::any_of(MakeFuncs.begin(), MakeFuncs.end(),
+ [&](const auto &Prefix) {
+   return FuncName.find(Prefix) != std::string::npos;
+ });
+}
+
+std::string MakeFunctionToDirectCheck::getTemplateType(
+const CXXConstructExpr *Construct) const {
+  if (!Construct)
+return {};
+
+  const auto *RecordType =
+  dyn_cast(Construct->getType().getTypePtr());
+  if (!RecordType)
+return {};
+
+  return RecordType->getDecl()->getNameAsString();
+}
+
+void MakeFunctionToDirectCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("make_call");
+  if (!Call)
+return;
+
+  const auto *FuncDecl = dyn_cast(Call->getCalleeDecl());
+  if (!FuncDecl || !FuncDecl->getTemplateSpecializationArgs())
+return;
+
+  std::string FuncName = FuncDecl->getNameAsString();
+  if (!isMakeFunction(FuncName))
+return;
+
+  std::string Args;
+  if (Call->getNumArgs() > 0) {
+SourceRange ArgRange(Call->getArg(0)->getBeginLoc(),
+ Call->getArg(Call->getNumArgs() - 1)->getEndLoc());
+Args = std::string(Lexer::getSourceText(
+CharSourceRange::getTokenRange(ArgRange), *Result.SourceManager,
+Result.Context->getLangOpts()));
+  }
+
+  std::string Replacement;
+  if (FuncName == "make_unique" || FuncName == "make_shared") {
+const auto *TemplateArgs = FuncDecl->getTemplateSpecializationArgs();
+if (!TemplateArgs || TemplateArgs->size() == 0)
+  return;
+
+QualType Type = T

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-28 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/15] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-28 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/14] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] Add modernize-cleanup-static-cast check (PR #118033)

2024-11-28 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

ohhh TIL! lets close this PR

`readability-redundant-casting` with: `IgnoreTypeAliases` does what i was 
chasing!

/close

https://github.com/llvm/llvm-project/pull/118033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add modernize-cleanup-static-cast check (PR #118033)

2024-11-28 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka closed 
https://github.com/llvm/llvm-project/pull/118033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/7] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/6] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/9] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/8] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/10] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/13] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/12] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-27 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/11] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] Add modernize-cleanup-static-cast check (PR #118033)

2024-11-28 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/118033

> Add a new check that detects and removes redundant static_cast operations 
> where the source and target types are identical. This helps clean up code 
> after type system changes, improving readability and reducing opportunities 
> for errors during future refactoring.


before polishing it and adding documentation, can someone tell me if the check 
makes sense to be picked in modernize?

>From 062aebbdc5bb858cdc25c4995752b9c8a0eb34e8 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Thu, 28 Nov 2024 21:15:25 +0100
Subject: [PATCH 1/2] [clang-tidy] Add modernize-cleanup-static-cast check

Add a new check that detects and removes redundant static_cast operations
where the source and target types are identical. This helps clean up code
after type system changes, improving readability and reducing opportunities
for errors during future refactoring.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/CleanupStaticCastCheck.cpp  | 74 +++
 .../modernize/CleanupStaticCastCheck.h| 38 ++
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize-cleanup-static-cast.cpp | 42 +++
 5 files changed, 158 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-cleanup-static-cast.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..9ce32473c201bc 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  CleanupStaticCastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
new file mode 100644
index 00..545ce4c5a58357
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
@@ -0,0 +1,74 @@
+//===--- CleanupStaticCastCheck.cpp - 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
+//
+//===--===//
+
+#include "CleanupStaticCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace {
+std::string getText(const clang::Expr *E, const clang::ASTContext &Context) {
+  auto &SM = Context.getSourceManager();
+  auto Range = clang::CharSourceRange::getTokenRange(E->getSourceRange());
+  return clang::Lexer::getSourceText(Range, SM, Context.getLangOpts()).str();
+}
+} // namespace
+
+namespace clang::tidy::modernize {
+
+void CleanupStaticCastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match static_cast expressions not in templates
+  Finder->addMatcher(
+  cxxStaticCastExpr(
+  unless(hasAncestor(functionTemplateDecl())),
+  unless(hasAncestor(classTemplateDecl())),
+  unless(isInTemplateInstantiation()))
+  .bind("cast"),
+  this);
+}
+
+void CleanupStaticCastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Cast = Result.Nodes.getNodeAs("cast");
+  if (!Cast)
+return;
+
+  // Get the source expression and its type
+  const Expr *SubExpr = Cast->getSubExpr()->IgnoreParenImpCasts();
+  QualType SourceType = SubExpr->getType();
+  QualType TargetType = Cast->getType();
+
+  // Skip if either type is dependent
+  if (SourceType->isDependentType() || TargetType->isDependentType())
+return;
+
+  // Compare canonical types and qualifiers
+  SourceType = SourceType.getCanonicalType();
+  TargetType = TargetType.getCanonicalType();
+  
+  if (SourceType == TargetType) {
+auto Diag = 
+diag(Cast->getBeginLoc(),
+ "redundant static_cast to the same type %0")  // Removed single 
quotes
+<< TargetType;
+
+// Use our helper function to get the source text
+std::string ReplacementText = getText(SubExpr, *Result.Context);
+
+// Suggest removing the cast
+Diag << FixItHint::CreateReplacement(
+Cast->getSourceRange(),
+ReplacementText);
+  }
+}
+
+} // namespace clang::tidy::modernize
\ No newline at end of file
diff --git a/cla

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -183,40 +209,44 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   const auto *EndsWithFunction =
   Result.Nodes.getNodeAs("ends_with_fun");
   assert(bool(StartsWithFunction) != bool(EndsWithFunction));
+
   const CXXMethodDecl *ReplacementFunction =
   StartsWithFunction ? StartsWithFunction : EndsWithFunction;
 
   if (ComparisonExpr->getBeginLoc().isMacroID())

hjanuschka wrote:

ok - that works, pushed.
this is what you meant with moving down, still not fully understanding why it 
works when its there.

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/6] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -71,6 +71,17 @@ struct NotLengthExprForStringNode {
   ASTContext *Context;
 };
 
+static bool isNegativeComparison(const Expr *ComparisonExpr) {
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }

hjanuschka wrote:

got you! also prefer more braces than less, but as always follow the projects 
styleguide.
(wonder if clang-format, should mention that?)

especially this hurts my inner braces monk:
```
  if (const auto *Op = llvm::dyn_cast(ComparisonExpr))
return Op->getOperator() == OO_ExclaimEqual;

  return false;
```




https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/5] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -183,40 +209,44 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   const auto *EndsWithFunction =
   Result.Nodes.getNodeAs("ends_with_fun");
   assert(bool(StartsWithFunction) != bool(EndsWithFunction));
+
   const CXXMethodDecl *ReplacementFunction =
   StartsWithFunction ? StartsWithFunction : EndsWithFunction;
 
   if (ComparisonExpr->getBeginLoc().isMacroID())

hjanuschka wrote:

this breaks alot of existing tests (not only substr ones):

```c++
#define FIND find
s.FIND("a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
// CHECK-FIXES: s.starts_with("a")
```

not sure if i understand, "move it to the end"

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@nicovank feedback addressed, except macro exclusion, not sure about it, it 
breaks alot of pre-existing tests

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/7] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/3] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-19 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@EugeneZelenko your comments have been resolved, but i am unable to mark them 
due to force push

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/4] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From caddb82d73d49b59dff71547d8ab986039895696 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 185 --
 .../modernize/UseStartsEndsWithCheck.h|   4 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   7 +
 .../checks/modernize/use-starts-ends-with.rst |  45 +++--
 .../clang-tidy/checkers/Inputs/Headers/string |   5 +-
 .../modernize/use-starts-ends-with.cpp|  42 +++-
 6 files changed, 257 insertions(+), 31 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..e7da45198df6c1 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -22,28 +22,46 @@ struct NotLengthExprForStringNode {
   NotLengthExprForStringNode(std::string ID, DynTypedNode Node,
  ASTContext *Context)
   : ID(std::move(ID)), Node(std::move(Node)), Context(Context) {}
+  
   bool operator()(const internal::BoundNodesMap &Nodes) const {
-// Match a string literal and an integer size or strlen() call.
 if (const auto *StringLiteralNode = Nodes.getNodeAs(ID)) {
+  // Match direct integer literals
   if (const auto *IntegerLiteralSizeNode = Node.get()) {
 return StringLiteralNode->getLength() !=
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
-  if (const auto *StrlenNode = Node.get()) {
-if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
-StrlenNode->getNumArgs() != 1) {
-  return true;
+  // Match strlen() calls
+  if (const auto *CallNode = Node.get()) {
+if (const auto *FD = CallNode->getDirectCallee()) {
+  if (FD->getName() == "strlen" && CallNode->getNumArgs() == 1) {
+if (const auto *StrArg = 
CallNode->getArg(0)->IgnoreParenImpCasts()) {
+  // Handle both string literals and string variables in strlen
+  if (const auto *StrLit = dyn_cast(StrArg)) {
+return StrLit->getLength() != StringLiteralNode->getLength();
+  } else if (const auto *StrVar = dyn_cast(StrArg)) {
+return !utils::areStatementsIdentical(StrVar, 
StringLiteralNode, *Context);
+  }
+}
+  }
 }
-
-if (const auto *StrlenArgNode = dyn_cast(
-StrlenNode->getArg(0)->IgnoreParenImpCasts())) {
-  return StrlenArgNode->getLength() != StringLiteralNode->getLength();
+  }
+  
+  // Match size()/length() member calls
+  if (const auto *MemberCall = Node.get()) {
+if (const auto *Method = MemberCall->getMethodDecl()) {
+  StringRef Name = Method->getName();
+  if (Method->isConst() && Method->getNumParams() == 0 &&
+  (Name == "size" || Name == "length")) {
+// For string literals used in comparison, allow size/length calls
+// on any string variable
+return false;
+  }
 }
   }
 }
 
-// Match a string variable and a call to length() or size().
+// Match member function calls on string variables
 if (const auto *ExprNode = Nodes.getNodeAs(ID)) {
   if (const auto *MemberCallNode = Node.get()) {
 const CXXMethodDecl *MethodDeclNode = MemberCallNode->getMethodDecl();
@@ -53,8 +71,8 @@ struct NotLengthExprForStringNode {
   return true;
 }
 
-if (const auto *OnNode =
-dyn_cast(MemberCallNode->getImplicitObjectArgument())) {
+if (const auto *OnNode = dyn_cast(
+MemberCallNode->getImplicitObjectArgument())) {
   return !utils::areStatementsIdentical(OnNode->IgnoreParenImpCasts(),
 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From e549c1a93f242608af2c51a8777b4bb8ab60c228 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 185 --
 .../modernize/UseStartsEndsWithCheck.h|   4 +
 .../checks/modernize/use-starts-ends-with.rst |  45 +++--
 .../clang-tidy/checkers/Inputs/Headers/string |   5 +-
 .../modernize/use-starts-ends-with.cpp|  42 +++-
 5 files changed, 250 insertions(+), 31 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..e7da45198df6c1 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -22,28 +22,46 @@ struct NotLengthExprForStringNode {
   NotLengthExprForStringNode(std::string ID, DynTypedNode Node,
  ASTContext *Context)
   : ID(std::move(ID)), Node(std::move(Node)), Context(Context) {}
+  
   bool operator()(const internal::BoundNodesMap &Nodes) const {
-// Match a string literal and an integer size or strlen() call.
 if (const auto *StringLiteralNode = Nodes.getNodeAs(ID)) {
+  // Match direct integer literals
   if (const auto *IntegerLiteralSizeNode = Node.get()) {
 return StringLiteralNode->getLength() !=
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
-  if (const auto *StrlenNode = Node.get()) {
-if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
-StrlenNode->getNumArgs() != 1) {
-  return true;
+  // Match strlen() calls
+  if (const auto *CallNode = Node.get()) {
+if (const auto *FD = CallNode->getDirectCallee()) {
+  if (FD->getName() == "strlen" && CallNode->getNumArgs() == 1) {
+if (const auto *StrArg = 
CallNode->getArg(0)->IgnoreParenImpCasts()) {
+  // Handle both string literals and string variables in strlen
+  if (const auto *StrLit = dyn_cast(StrArg)) {
+return StrLit->getLength() != StringLiteralNode->getLength();
+  } else if (const auto *StrVar = dyn_cast(StrArg)) {
+return !utils::areStatementsIdentical(StrVar, 
StringLiteralNode, *Context);
+  }
+}
+  }
 }
-
-if (const auto *StrlenArgNode = dyn_cast(
-StrlenNode->getArg(0)->IgnoreParenImpCasts())) {
-  return StrlenArgNode->getLength() != StringLiteralNode->getLength();
+  }
+  
+  // Match size()/length() member calls
+  if (const auto *MemberCall = Node.get()) {
+if (const auto *Method = MemberCall->getMethodDecl()) {
+  StringRef Name = Method->getName();
+  if (Method->isConst() && Method->getNumParams() == 0 &&
+  (Name == "size" || Name == "length")) {
+// For string literals used in comparison, allow size/length calls
+// on any string variable
+return false;
+  }
 }
   }
 }
 
-// Match a string variable and a call to length() or size().
+// Match member function calls on string variables
 if (const auto *ExprNode = Nodes.getNodeAs(ID)) {
   if (const auto *MemberCallNode = Node.get()) {
 const CXXMethodDecl *MethodDeclNode = MemberCallNode->getMethodDecl();
@@ -53,8 +71,8 @@ struct NotLengthExprForStringNode {
   return true;
 }
 
-if (const auto *OnNode =
-dyn_cast(MemberCallNode->getImplicitObjectArgument())) {
+if (const auto *OnNode = dyn_cast(
+MemberCallNode->getImplicitObjectArgument())) {
   return !utils::areStatementsIdentical(OnNode->IgnoreParenImpCasts(),
 
ExprNode->IgnoreParenImpCasts(),
 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits


@@ -7,26 +7,39 @@ Checks for common roundabout ways to express ``starts_with`` 
and ``ends_with``
 and suggests replacing with the simpler method when it is available. Notably, 
 this will work with ``std::string`` and ``std::string_view``.
 
-.. code-block:: c++
+The check handles the following expressions:
 
-  std::string s = "...";
-  if (s.find("prefix") == 0) { /* do something */ }
-  if (s.rfind("prefix", 0) == 0) { /* do something */ }
-  if (s.compare(0, strlen("prefix"), "prefix") == 0) { /* do something */ }
-  if (s.compare(s.size() - strlen("suffix"), strlen("suffix"), "suffix") == 0) 
{
-/* do something */
-  }
-  if (s.rfind("suffix") == (s.length() - 6)) {
-/* do something */
-  }
-
-becomes
+ 
===

hjanuschka wrote:

to what column? it is right now excatly at 80

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From f79bd08bf910512c6c3b9d8ab2cd5162f9c0e5f8 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/2] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 .../modernize/UseStartsEndsWithCheck.h|  4 ++
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  5 +-
 .../modernize/use-starts-ends-with.cpp| 36 +-
 6 files changed, 138 insertions(+), 22 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 4fe224a3d16cff6532674516138fc6ff04678188 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  5 +-
 .../modernize/use-starts-ends-with.cpp| 36 +-
 5 files changed, 134 insertions(+), 22 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->get

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits


@@ -147,6 +147,13 @@ New check aliases
 Changes in existing checks
 ^^
 
+- Improved :doc:`modernize-use-starts-ends-with

hjanuschka wrote:

not really sure if i understand that, see latest upload

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->getS

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From bff5fd8031bbee5f81c17642256215d685965855 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  3 +-
 .../modernize/use-starts-ends-with.cpp| 36 +-
 5 files changed, 133 insertions(+), 21 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->get

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

@nicovank reading release notes! what a great community you folks have 😄 

tried to use your matcher, still required a bit of plumbing in the check() but 
overall WAY better, LMKWYT, happy to address any further feedback.



https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits


@@ -173,7 +222,80 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
   this);
 }
 
+void UseStartsEndsWithCheck::handleSubstrMatch(const MatchFinder::MatchResult 
&Result) {
+  const auto *SubstrCall = 
Result.Nodes.getNodeAs("substr_fun");
+  const auto *PositiveComparison = 
Result.Nodes.getNodeAs("positiveComparison");
+  const auto *NegativeComparison = 
Result.Nodes.getNodeAs("negativeComparison");
+  
+  if (!SubstrCall || (!PositiveComparison && !NegativeComparison))
+return;
+
+  bool Negated = NegativeComparison != nullptr;

hjanuschka wrote:

done

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 27d43534fd54fecc421a048638140fb4a7004b67 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 184 --
 .../modernize/UseStartsEndsWithCheck.h|   4 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  45 +++--
 .../clang-tidy/checkers/Inputs/Headers/string |   5 +-
 .../modernize/use-starts-ends-with.cpp|  42 +++-
 6 files changed, 253 insertions(+), 32 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..925c9120980cc3 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -23,27 +23,44 @@ struct NotLengthExprForStringNode {
  ASTContext *Context)
   : ID(std::move(ID)), Node(std::move(Node)), Context(Context) {}
   bool operator()(const internal::BoundNodesMap &Nodes) const {
-// Match a string literal and an integer size or strlen() call.
 if (const auto *StringLiteralNode = Nodes.getNodeAs(ID)) {
+  // Match direct integer literals
   if (const auto *IntegerLiteralSizeNode = Node.get()) {
 return StringLiteralNode->getLength() !=
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
-  if (const auto *StrlenNode = Node.get()) {
-if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
-StrlenNode->getNumArgs() != 1) {
-  return true;
+  // Match strlen() calls
+  if (const auto *CallNode = Node.get()) {
+if (const auto *FD = CallNode->getDirectCallee()) {
+  if (FD->getName() == "strlen" && CallNode->getNumArgs() == 1) {
+if (const auto *StrArg = 
CallNode->getArg(0)->IgnoreParenImpCasts()) {
+  // Handle both string literals and string variables in strlen
+  if (const auto *StrLit = dyn_cast(StrArg)) {
+return StrLit->getLength() != StringLiteralNode->getLength();
+  } else if (const auto *StrVar = dyn_cast(StrArg)) {
+return !utils::areStatementsIdentical(StrVar, 
StringLiteralNode, *Context);
+  }
+}
+  }
 }
-
-if (const auto *StrlenArgNode = dyn_cast(
-StrlenNode->getArg(0)->IgnoreParenImpCasts())) {
-  return StrlenArgNode->getLength() != StringLiteralNode->getLength();
+  }
+  
+  // Match size()/length() member calls
+  if (const auto *MemberCall = Node.get()) {
+if (const auto *Method = MemberCall->getMethodDecl()) {
+  const StringRef Name = Method->getName();
+  if (Method->isConst() && Method->getNumParams() == 0 &&
+  (Name == "size" || Name == "length")) {
+// For string literals used in comparison, allow size/length calls
+// on any string variable
+return false;
+  }
 }
   }
 }
 
-// Match a string variable and a call to length() or size().
+// Match member function calls on string variables
 if (const auto *ExprNode = Nodes.getNodeAs(ID)) {
   if (const auto *MemberCallNode = Node.get()) {
 const CXXMethodDecl *MethodDeclNode = MemberCallNode->getMethodDecl();
@@ -53,8 +70,8 @@ struct NotLengthExprForStringNode {
   return true;
 }
 
-if (const auto *OnNode =
-dyn_cast(MemberCallNode->getImplicitObjectArgument())) {
+if (const auto *OnNode = dyn_cast(
+MemberCallNode->getImplicitObjectArgument())) {
   return !utils::areStatementsIdentical(OnNode->IgnoreParenImpCasts(),
 
ExprNode->IgnoreParenImpCasts(),

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

@EugeneZelenko @nicovank 
thank you for your feedback, addressed what's possible.

* added tests
* release notes
* various const's

@nicovank about your suggestion, played around few hours with it, but could 
make a sense out of it, that was initially the reason why i started it as a 
standalone new check.


also, is it "ok" to change existing tidy's? like people opted in for one, and 
that changes now without them knowing?


https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@HerrCai0907 about the fixit.

its strange, using the llvm-lit test case it emits a warning, and even shows 
where the substr() comes from:

```
   738: 
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/modernize/Output/use-starts-ends-with.cpp.tmp.cpp:315:17:
 warning: use starts_with instead of substr() == 
[modernize-use-starts-ends-with]
not:imp1

!~~~
  error: no match expected
739:  315 | "prefix" == SUBSTR(STR(), 0, 6);
740:  | ^
741: 
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/modernize/Output/use-starts-ends-with.cpp.tmp.cpp:309:33:
 note: expanded from macro 'SUBSTR'
742:  309 | #define SUBSTR(X, A, B) (X).substr((A), (B))
743:  | ^

```

to reduce the complexity and test it tried to:
```c++
// RUN: %check_clang_tidy -std=c++20 %s modernize-use-starts-ends-with %t -- 
-debug

#include 

void test_macro_case() {
std::string str("hello world");

#define SUBSTR(X, A, B) (X).substr((A), (B))
#define STR() str

"prefix" == SUBSTR(STR(), 0, 6);

}
```

```sh
./bin/clang-tidy test.cpp -checks="-*, modernize-use-starts-ends-with" 
--extra-arg=-std=c++20   -
```

doesnt even come up with a warning. i dont know whats "right" now, warning and 
showing root cause, seems to be fairly good, fixing a macro might be even a bad 
idea?

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 23b4bcdf52041aad1c5581e0f7dc01028770a154 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/2] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 114 ++---
 .../modernize/UseStartsEndsWithCheck.h|   1 +
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 6 files changed, 216 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..12ff31dfa03541 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  
+  return false;
 }
 
 void UseStartsEndsWithCheck::check(const 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
+}
+
+bool UseStartsEndsWithCheck::isNegativeComparison(const Expr* ComparisonExpr) {
+  // Handle direct != operator
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+return BO->getOpcode() == BO_NE;
+  }
+  
+  // Handle operator!= call
+  if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) {
+return Op->getOperator() == OO_ExclaimEqual;
+  }
+  
+  // Handle rewritten !(expr == expr)
+  if (const auto *UO = llvm::dyn_cast(ComparisonExpr)) {
+if (UO->getOpcode() == UO_LNot) {
+  if (const auto *InnerBO = 
+  llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerBO->getOpcode() == BO_EQ;
+  }
+  if (const auto *InnerOp = 
+  
llvm::dyn_cast(UO->getSubExpr()->IgnoreParens())) {
+return InnerOp->getOperator() == OO_EqualEqual;
+  }
+}
+  }
+  

hjanuschka wrote:

ok - can we keep? `isNegativeComparison`? removed the "rewritten" part.

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -171,10 +182,64 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);

hjanuschka wrote:

🙈 i am super impressed, and the more i learn about AST the more i know i know 
nothing!
do you have any good resources to ramp up the knowledge in this area? (trying 
to sourcegraph search, copy&paste, trial-and-error so far)

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-18 Thread Helmut Januschka via cfe-commits


@@ -36,221 +36,224 @@ void test(std::string s, std::string_view sv, sub_string 
ss, sub_sub_string sss,
   string_like sl, string_like_camel slc, prefer_underscore_version puv,
   prefer_underscore_version_flip puvf) {
   s.find("a") == 0;
-  // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead 
of find() == 0
+  // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead 
of find == [modernize-use-starts-ends-with]

hjanuschka wrote:

ok got you, reverted tests, but to prevent showing:

```
use starts_with instead of substr() == 0
```

a small change is needed.
```
  auto Diag = diag(FindExpr->getExprLoc(), 
FindFun->getName() == "substr" 
? "use %0 instead of %1() %select{==|!=}2"
: "use %0 instead of %1() %select{==|!=}2 0")
<< ReplacementFunction->getName() << FindFun->getName() << Neg;
```

but this makes sure the old tests are unchanged.


https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-21 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@nicovank  hows the protocol to get the other reviewers in?, should i ping them 
 - or should i just practice patience?

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-26 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/4] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-26 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 1/5] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[5]

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-26 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-11-26 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

@PiotrZSL 
  - [x]  Add MakeSmartPtrType in MakeSmartPtrCheck as protected (do not 
initialize in constructor)
  - [x]  Add MakeSmartPtrType to storeOptions
  - [x]  Read MakeSmartPtrType in MakeSharedPtrCheck & MakeUniquePtrCheck 
constructors (set different default values)
  - [x]  Use MakeSmartPtrType in getSmartPointerTypeMatcher in both classes
  - [x]  Modify documentation for both checks
  - [x]   Add entry for both checks in release notes
  - [x]   Consider doing same for 'std::make_shared'


> Consider supporting multiple smart ptr types and multiple make functions
a bit unsure about this one, do you have any sample where there is usage of 
multiple?! 
really not sure about this! the rest is addressed, and ready for another review

https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-26 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

@nicovank all good now?

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-26 Thread Helmut Januschka via cfe-commits

hjanuschka wrote:

awesome!  thanks to everyone involved for the patience with me and the great 
guidance! 

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/117529

>From 9466fb73adfb050e9eac426459c18a7a5bca1982 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Mon, 25 Nov 2024 09:59:21 +0100
Subject: [PATCH 01/16] WIP: [clang-tidy] Add SmartPtrName to MakeSmartPtrCheck
 for flexible type matching

Introduced a `SmartPtrName` field in `MakeSmartPtrCheck` to allow matching on 
other smart pointer types, such as `base::scoped_refptr`, in addition to 
`std::shared_ptr`. This enables more versatile usage of the check without 
duplicating matcher logic.
---
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp  | 5 +++--
 clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h| 3 +++
 .../clang-tidy/modernize/MakeSmartPtrCheck.cpp  | 6 +++---
 clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h  | 1 +
 .../docs/clang-tidy/checks/modernize/make-shared.rst| 6 ++
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
index 69f7d9f69eeed0..34009046fec6ae 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -16,13 +16,14 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
-: MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+: MakeSmartPtrCheck(Name, Context, "std::make_shared"),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")) {}
 
 MakeSharedCheck::SmartPtrTypeMatcher
 MakeSharedCheck::getSmartPointerTypeMatcher() const {
   return qualType(hasUnqualifiedDesugaredType(
   recordType(hasDeclaration(classTemplateSpecializationDecl(
-  hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+  hasName(MakeSmartPtrType), templateArgumentCountIs(1),
   hasTemplateArgument(0, templateArgument(refersToType(
  qualType().bind(PointerType);
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h 
b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
index caaf4ae403c34f..932796e3a147f1 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -26,6 +26,9 @@ namespace clang::tidy::modernize {
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-shared.html
 class MakeSharedCheck : public MakeSmartPtrCheck {
+private:
+  const StringRef MakeSmartPtrType;
+
 public:
   MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
 
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index d1d7e9dcfa9c0d..3f77e6727d19f8 100644
--- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -46,6 +46,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
areDiagsSelfContained()),
   MakeSmartPtrFunctionHeader(
   Options.get("MakeSmartPtrFunctionHeader", "")),
+  MakeSmartPtrType(Options.get("MakeSmartPtrType", "::std::shared_ptr")),
   MakeSmartPtrFunctionName(
   Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
   IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
@@ -55,6 +56,7 @@ MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, 
ClangTidyContext *Context,
 void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IncludeStyle", Inserter.getStyle());
   Options.store(Opts, "MakeSmartPtrFunctionHeader", 
MakeSmartPtrFunctionHeader);
+  Options.store(Opts, "MakeSmartPtrType", MakeSmartPtrType);
   Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
   Options.store(Opts, "IgnoreDefaultInitialization",
@@ -115,7 +117,6 @@ void MakeSmartPtrCheck::check(const 
MatchFinder::MatchResult &Result) {
   // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
-
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
   Result.Nodes.getNodeAs(ConstructorCall);
@@ -361,8 +362,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
   Diag << FixItHint::CreateRemoval(
   SourceRange(NewStart, InitRange.getBegin()));
   Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), 
NewEnd));
-}
-else {
+} else {
   // New array expression with default/value initialization:
   //   smart_ptr(new int[

[clang-tools-extra] [clang-tidy] modernize-make-shared: Add MakeSmartPtrType option (PR #117529)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

feedback addressed

https://github.com/llvm/llvm-project/pull/117529
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits


@@ -58,6 +58,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
   UppercaseLiteralSuffixCheck.cpp
   UseAnyOfAllOfCheck.cpp
   UseStdMinMaxCheck.cpp
+  UseSpanFirstLastCheck.cpp

hjanuschka wrote:

fixed, with the 2 "Use" 
(https://github.com/llvm/llvm-project/pull/118074/files/c7fd4d5f508d43cd7fdaf7ed9a0006687a4215ed#diff-4be36b5009d110fd7bf319b8b06cf0e86d91b04f4c30dcd8aaf94825626b2e2aL26)
  filenames, but there is `RedundantInlineSpecifierCheck`  also wrong, should i 
fix this in the same PR?

https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/14] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/15] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/18] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

MANY thanks, yet again, feedback addressed.

https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits




hjanuschka wrote:

🙈

https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka edited 
https://github.com/llvm/llvm-project/pull/118074
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/19] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Add readability-use-span-first-last check (PR #118074)

2024-12-02 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 01/20] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt   |  1 +
 .../modernize/ModernizeTidyModule.cpp |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp   | 97 +++
 .../modernize/UseSpanFirstLastCheck.h | 40 
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 
 .../modernize-subspan-conversion.cpp  | 50 ++
 7 files changed, 214 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+
CheckFactories.registerCheck("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - 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
+//
+//===--===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+  recordType(hasDeclaration(classTemplateSpecializationDecl(
+  hasName("::std::span"));
+
+  Finder->addMatcher(
+  cxxMemberCallExpr(
+  callee(memberExpr(hasDeclaration(
+  cxxMethodDecl(hasName("subspan"),
+  on(expr(HasSpanType)))
+  .bind("subspan"),
+  this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("subspan");
+  if (!Call)
+return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast(OffsetE)) {
+IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+ 

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/4] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/6] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/5] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/2] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-15 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 8a48d6be0b0cf28ab8e98b3a5e7f45628ceadb52 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/3] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  | 65 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 +-
 .../checks/modernize/use-starts-ends-with.rst | 45 -
 .../clang-tidy/checkers/Inputs/Headers/string |  1 +
 .../modernize/use-starts-ends-with.cpp| 34 ++
 5 files changed, 131 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..bcfb7227be722b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,24 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  hasOperands(
+  expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(hasName("substr"),
+   ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr")))
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -189,7 +203,54 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg = BO->getOpcode() == BO_NE;
+  } else {
+assert(llvm::isa(ComparisonExpr));
+Neg = llvm::cast(ComparisonExpr)->getOperator() ==
+  OO_ExclaimEqual;
+  }
+
+  // Check if this is a substr case
+  bool IsSubstr = FindFun->getName() == "substr";
+
+  if (IsSubstr) {
+  const auto *SubstrCall = cast(FindExpr);
+  const Expr *Object = SubstrCall->getImplicitObjectArgument();
+
+  std::string ObjectStr;
+  std::string SearchStr;
+  bool Invalid = false;
+
+  auto &SM = *Result.SourceManager;
+
+  CharSourceRange ObjectRange = CharSourceRange::getTokenRange(
+  Object->getBeginLoc(), Object->getEndLoc());
+  ObjectStr = Lexer::getSourceText(ObjectRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  CharSourceRange SearchRange = CharSourceRange::getTokenRange(
+  SearchExpr->getBeginLoc(), SearchExpr->getEndLoc());
+  SearchStr = Lexer::getSourceText(SearchRange, SM, getLangOpts(), 
&Invalid).str();
+  if (Invalid)
+return;
+
+  // Build the new expression: [!]Object.starts_with(SearchExpr)
+std::string NewExpr =
+  (llvm::Twine(Neg ? "!" : "") + ObjectStr + "." +
+  ReplacementFunction->getName() + "(" + SearchStr + ")").str();
+// Replace the entire comparison expression
+auto Diag = diag(ComparisonExpr->getBeginLoc(),
+"use %0 instead of substr() %select{==|!=}1")
+<< ReplacementFunction->getName() << Neg;
+Diag << FixItHint::CreateReplacement(
+CharSourceRange::getTokenRange(ComparisonExpr->

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-16 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From 5b937c431486d23a696b536aa9dde560447b5756 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  |  94 ---
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 5 files changed, 195 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..7dca11549a32b3 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,37 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  // Use the existing lengthExprForStringNode matcher
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -183,40 +221,50 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   const auto *EndsWithFunction =
   Result.Nodes.getNodeAs("ends_with_fun");
   assert(bool(StartsWithFunction) != bool(EndsWithFunction));
+
   const CXXMethodDecl *ReplacementFunction =
   StartsWithFunction ? StartsWithFunction : EndsWithFunction;
 
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bo

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-16 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From b149670c72ce08ace1f36c44d794f422f70708ed Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH] [clang-tidy] Enhance modernize-use-starts-ends-with with
 substr detection

Enhances the modernize-use-starts-ends-with check to detect substr-based
patterns that can be replaced with starts_with() (C++20). This improves code
readability and efficiency by avoiding temporary string creation.

New patterns detected:
  str.substr(0, n) == "foo"   -> str.starts_with("foo")
  "foo" == str.substr(0, n)   -> str.starts_with("foo")
  str.substr(0, n) != "foo"   -> !str.starts_with("foo")
  str.substr(0, strlen("foo")) == "foo" -> str.starts_with("foo")
  str.substr(0, prefix.size()) == "foo" -> str.starts_with("foo")

The enhancement:
- Integrates with existing starts_with patterns
- Handles substr with zero first argument
- Supports length via literals, strlen(), and size()/length()
- Validates string literal length matches
- Handles both == and != operators

Part of modernize-use-starts-ends-with check.
---
 .../modernize/UseStartsEndsWithCheck.cpp  |  93 +++---
 clang-tools-extra/docs/ReleaseNotes.rst   |   5 +-
 .../checks/modernize/use-starts-ends-with.rst |  34 ++--
 .../clang-tidy/checkers/Inputs/Headers/string |   2 +
 .../modernize/use-starts-ends-with.cpp| 159 --
 5 files changed, 194 insertions(+), 99 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
index 1231f954298adc..0924f834ffc443 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -30,6 +30,17 @@ struct NotLengthExprForStringNode {
IntegerLiteralSizeNode->getValue().getZExtValue();
   }
 
+  if (const auto *DeclRefNode = Node.get()) {
+if (const auto *VD = dyn_cast(DeclRefNode->getDecl())) {
+  if (VD->hasInit() && VD->getType().isConstQualified()) {
+if (const auto *Init = dyn_cast(VD->getInit())) {
+  return StringLiteralNode->getLength() !=
+ Init->getValue().getZExtValue();
+}
+  }
+}
+  }
+
   if (const auto *StrlenNode = Node.get()) {
 if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
 StrlenNode->getNumArgs() != 1) {
@@ -171,10 +182,36 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder 
*Finder) {
  hasRHS(lengthExprForStringNode("needle")
   .bind("expr"),
   this);
+
+  Finder->addMatcher(
+  cxxOperatorCallExpr(
+  hasAnyOperatorName("==", "!="),
+  anyOf(
+  hasOperands(
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, lengthExprForStringNode("needle")),
+  callee(
+  cxxMethodDecl(hasName("substr"),
+ofClass(OnClassWithStartsWithFunction))
+  .bind("find_fun")))
+  .bind("find_expr"),
+  expr().bind("needle")),
+  hasOperands(expr().bind("needle"),
+  cxxMemberCallExpr(
+  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+  hasArgument(1, 
lengthExprForStringNode("needle")),
+  callee(cxxMethodDecl(
+ hasName("substr"),
+ 
ofClass(OnClassWithStartsWithFunction))
+ .bind("find_fun")))
+  .bind("find_expr"
+  .bind("expr"),
+  this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs("expr");
   const auto *FindExpr = 
Result.Nodes.getNodeAs("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs("needle");
@@ -183,40 +220,50 @@ void UseStartsEndsWithCheck::check(const 
MatchFinder::MatchResult &Result) {
   const auto *EndsWithFunction =
   Result.Nodes.getNodeAs("ends_with_fun");
   assert(bool(StartsWithFunction) != bool(EndsWithFunction));
+
   const CXXMethodDecl *ReplacementFunction =
   StartsWithFunction ? StartsWithFunction : EndsWithFunction;
 
   if (ComparisonExpr->getBeginLoc().isMacroID())
 return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) {
+Neg =

[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

2024-11-16 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka commented:

@nicovank feedback addressed

* added support for .size()
* more tests - incl. macros

https://github.com/llvm/llvm-project/pull/116033
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add modernize-substr-to-starts-with check (PR #116033)

2024-11-14 Thread Helmut Januschka via cfe-commits

https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/116033

>From adafcceb45853c3e8f797eba51d90e64654dafe6 Mon Sep 17 00:00:00 2001
From: Helmut Januschka 
Date: Wed, 13 Nov 2024 12:52:36 +0100
Subject: [PATCH 1/6] [clang-tidy] Add modernize-substr-to-starts-with check

Adds a new check that finds calls to substr when its first argument is a
zero-equivalent expression and can be replaced with starts_with()
(introduced in C++20). This modernization improves code readability by making
the intent clearer and can be more efficient as it avoids creating temporary
strings.

Converts patterns like:
  str.substr(0, 3) == "foo"  -> str.starts_with("foo")
  str.substr(x-x, 3) == "foo"-> str.starts_with("foo")
  str.substr(zero, n) == prefix  -> str.starts_with(prefix)
  "bar" == str.substr(i-i, 3)-> str.starts_with("bar")
  str.substr(0, n) != prefix -> !str.starts_with(prefix)

The check:
- Detects zero-equivalent expressions:
  * Direct zero literals (0)
  * Variables initialized to zero
  * Self-canceling expressions (x-x, i-i)
- Only converts when length matches exactly for string literals
- Supports both string literals and string variables
- Handles both == and != operators
---
 .../clang-tidy/modernize/CMakeLists.txt   |   1 +
 .../modernize/ModernizeTidyModule.cpp |   3 +
 .../modernize/SubstrToStartsWithCheck.cpp | 104 ++
 .../modernize/SubstrToStartsWithCheck.h   |  30 +
 .../modernize/substr-to-starts-with.rst   |  35 ++
 .../modernize/substr-to-starts-with.cpp   |  42 +++
 6 files changed, 215 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/substr-to-starts-with.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/substr-to-starts-with.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..ed1ba2ab62a90f 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  SubstrToStartsWithCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..7569211d2552ea 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -50,6 +50,7 @@
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
+#include "SubstrToStartsWithCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
 CheckFactories.registerCheck(
 "modernize-use-uncaught-exceptions");
 CheckFactories.registerCheck("modernize-use-using");
+CheckFactories.registerCheck(
+  "modernize-substr-to-starts-with");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
new file mode 100644
index 00..253e5ba3ca32ba
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/SubstrToStartsWithCheck.cpp
@@ -0,0 +1,104 @@
+//===--- SubstrToStartsWithCheck.cpp - 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
+//
+//===--===//
+
+#include "SubstrToStartsWithCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void SubstrToStartsWithCheck::registerMatchers(MatchFinder *Finder) {
+  auto isZeroExpr = expr(anyOf(
+  integerLiteral(equals(0)),
+  ignoringParenImpCasts(declRefExpr(
+  to(varDecl(hasInitializer(integerLiteral(equals(0))),
+  binaryOperator(hasOperatorName("-"), hasLHS(expr()), hasRHS(expr();
+
+  auto isStringLike = expr(anyOf(
+  stringLiteral().bind("literal"),
+  implicitCastExpr(hasSourceExpression(stringLiteral().bind("literal"))),
+  declRefExpr(to(varDecl(hasType(qualType(hasDeclaration(
+  namedDecl(hasAnyName("::std::string", 
"::std::basic_string".bind("strvar")));
+
+  auto isSubstrCall

  1   2   >