[clang-tools-extra] [clang-tidy] Add readability-string-view-substr check (PR #120055)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 16 00:55:14 PST 2024
github-actions[bot] wrote:
<!--LLVM CODE FORMAT COMMENT: {clang-format}-->
:warning: C/C++ code formatter, clang-format found issues in your code. :warning:
<details>
<summary>
You can test this locally with the following command:
</summary>
``````````bash
git-clang-format --diff a35db2880a488b62a16f269972ad885fd58033f7 ea6d39ab0f32e81e7633b69648b30f782272ec59 --extensions cpp,h -- clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
``````````
</details>
<details>
<summary>
View the diff from clang-format here.
</summary>
``````````diff
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 0889fbbd86..f36ec8f95e 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -148,7 +148,7 @@ public:
CheckFactories.registerCheck<StringCompareCheck>(
"readability-string-compare");
CheckFactories.registerCheck<StringViewSubstrCheck>(
- "readability-stringview-substr");
+ "readability-stringview-substr");
CheckFactories.registerCheck<readability::NamedParameterCheck>(
"readability-named-parameter");
CheckFactories.registerCheck<NonConstParameterCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp
index 5ed96480c0..711faa584a 100644
--- a/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp
@@ -8,91 +8,110 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
void StringViewSubstrCheck::registerMatchers(MatchFinder *Finder) {
- const auto HasStringViewType = hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(recordDecl(hasName("::std::basic_string_view"))))));
+ const auto HasStringViewType = hasType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(recordDecl(hasName("::std::basic_string_view"))))));
// Match assignment to string_view's substr
Finder->addMatcher(
cxxOperatorCallExpr(
hasOverloadedOperatorName("="),
hasArgument(0, expr(HasStringViewType).bind("target")),
- hasArgument(1, cxxMemberCallExpr(
- callee(memberExpr(hasDeclaration(cxxMethodDecl(hasName("substr"))))),
- on(expr(HasStringViewType).bind("source"))
- ).bind("substr_call"))
- ).bind("assignment"),
+ hasArgument(
+ 1, cxxMemberCallExpr(callee(memberExpr(hasDeclaration(
+ cxxMethodDecl(hasName("substr"))))),
+ on(expr(HasStringViewType).bind("source")))
+ .bind("substr_call")))
+ .bind("assignment"),
this);
}
void StringViewSubstrCheck::check(const MatchFinder::MatchResult &Result) {
- const auto *Assignment = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("assignment");
+ const auto *Assignment =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("assignment");
const auto *Target = Result.Nodes.getNodeAs<Expr>("target");
const auto *Source = Result.Nodes.getNodeAs<Expr>("source");
- const auto *SubstrCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>("substr_call");
-
+ const auto *SubstrCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("substr_call");
+
if (!Assignment || !Target || !Source || !SubstrCall) {
return;
}
// Get the DeclRefExpr for the target and source to compare variables
- const auto* TargetDRE = dyn_cast<DeclRefExpr>(Target->IgnoreParenImpCasts());
- const auto* SourceDRE = dyn_cast<DeclRefExpr>(Source->IgnoreParenImpCasts());
-
+ const auto *TargetDRE = dyn_cast<DeclRefExpr>(Target->IgnoreParenImpCasts());
+ const auto *SourceDRE = dyn_cast<DeclRefExpr>(Source->IgnoreParenImpCasts());
+
// Only handle self-assignment cases
- if (!TargetDRE || !SourceDRE || TargetDRE->getDecl() != SourceDRE->getDecl()) {
+ if (!TargetDRE || !SourceDRE ||
+ TargetDRE->getDecl() != SourceDRE->getDecl()) {
return;
}
- const Expr* StartArg = SubstrCall->getArg(0);
- const Expr* LengthArg = SubstrCall->getNumArgs() > 1 ? SubstrCall->getArg(1) : nullptr;
-
+ const Expr *StartArg = SubstrCall->getArg(0);
+ const Expr *LengthArg =
+ SubstrCall->getNumArgs() > 1 ? SubstrCall->getArg(1) : nullptr;
+
// Get source text of first argument
- std::string StartText = Lexer::getSourceText(
- CharSourceRange::getTokenRange(StartArg->getSourceRange()),
- *Result.SourceManager, Result.Context->getLangOpts()).str();
+ std::string StartText =
+ Lexer::getSourceText(
+ CharSourceRange::getTokenRange(StartArg->getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts())
+ .str();
- // Case 1: Check for remove_prefix pattern - only when the second arg is missing (uses npos)
+ // Case 1: Check for remove_prefix pattern - only when the second arg is
+ // missing (uses npos)
if (!LengthArg || isa<CXXDefaultArgExpr>(LengthArg)) {
- std::string Replacement = TargetDRE->getNameInfo().getAsString() +
- ".remove_prefix(" + StartText + ")";
- diag(Assignment->getBeginLoc(), "prefer 'remove_prefix' over 'substr' for removing characters from the start")
- << FixItHint::CreateReplacement(Assignment->getSourceRange(), Replacement);
+ std::string Replacement = TargetDRE->getNameInfo().getAsString() +
+ ".remove_prefix(" + StartText + ")";
+ diag(Assignment->getBeginLoc(), "prefer 'remove_prefix' over 'substr' for "
+ "removing characters from the start")
+ << FixItHint::CreateReplacement(Assignment->getSourceRange(),
+ Replacement);
return;
}
// Case 2: Check for remove_suffix pattern
if (StartText == "0") {
- if (const auto* BinOp = dyn_cast<BinaryOperator>(LengthArg)) {
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(LengthArg)) {
if (BinOp->getOpcode() == BO_Sub) {
- const Expr* LHS = BinOp->getLHS();
- const Expr* RHS = BinOp->getRHS();
+ const Expr *LHS = BinOp->getLHS();
+ const Expr *RHS = BinOp->getRHS();
// Check if LHS is a length() call on the same string_view
- if (const auto* LengthCall = dyn_cast<CXXMemberCallExpr>(LHS)) {
- if (const auto* LengthMethod = dyn_cast<CXXMethodDecl>(LengthCall->getDirectCallee())) {
+ if (const auto *LengthCall = dyn_cast<CXXMemberCallExpr>(LHS)) {
+ if (const auto *LengthMethod =
+ dyn_cast<CXXMethodDecl>(LengthCall->getDirectCallee())) {
if (LengthMethod->getName() == "length") {
// Verify the length() call is on the same string_view
- const Expr* LengthObject = LengthCall->getImplicitObjectArgument();
- const auto* LengthDRE = dyn_cast<DeclRefExpr>(LengthObject->IgnoreParenImpCasts());
-
+ const Expr *LengthObject =
+ LengthCall->getImplicitObjectArgument();
+ const auto *LengthDRE =
+ dyn_cast<DeclRefExpr>(LengthObject->IgnoreParenImpCasts());
+
if (!LengthDRE || LengthDRE->getDecl() != TargetDRE->getDecl()) {
return;
}
// Must be a simple non-zero integer literal
- const auto *IL = dyn_cast<IntegerLiteral>(RHS->IgnoreParenImpCasts());
+ const auto *IL =
+ dyn_cast<IntegerLiteral>(RHS->IgnoreParenImpCasts());
if (!IL || IL->getValue() == 0) {
return;
}
- std::string RHSText = Lexer::getSourceText(
- CharSourceRange::getTokenRange(RHS->getSourceRange()),
- *Result.SourceManager, Result.Context->getLangOpts()).str();
+ std::string RHSText =
+ Lexer::getSourceText(
+ CharSourceRange::getTokenRange(RHS->getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts())
+ .str();
- std::string Replacement = TargetDRE->getNameInfo().getAsString() +
- ".remove_suffix(" + RHSText + ")";
- diag(Assignment->getBeginLoc(), "prefer 'remove_suffix' over 'substr' for removing characters from the end")
- << FixItHint::CreateReplacement(Assignment->getSourceRange(), Replacement);
+ std::string Replacement = TargetDRE->getNameInfo().getAsString() +
+ ".remove_suffix(" + RHSText + ")";
+ diag(Assignment->getBeginLoc(),
+ "prefer 'remove_suffix' over 'substr' for removing "
+ "characters from the end")
+ << FixItHint::CreateReplacement(Assignment->getSourceRange(),
+ Replacement);
return;
}
}
diff --git a/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h
index 0a3202d3d9..1a2054da1e 100644
--- a/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h
@@ -1,4 +1,5 @@
-//===--- StringViewSubstrCheck.h - clang-tidy---------------------*- C++ -*-===//
+//===--- StringViewSubstrCheck.h - clang-tidy---------------------*- C++
+//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -13,8 +14,8 @@
namespace clang::tidy::readability {
-/// Finds string_view substr() calls that can be replaced with remove_prefix() or
-/// remove_suffix().
+/// Finds string_view substr() calls that can be replaced with remove_prefix()
+/// or remove_suffix().
///
/// For the user-facing documentation see:
/// https://clang.llvm.org/extra/clang-tidy/checks/readability/string-view-substr.html
``````````
</details>
https://github.com/llvm/llvm-project/pull/120055
More information about the cfe-commits
mailing list