Skip to content

[clang-tidy] Add readability-string-view-substr check #120055

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

hjanuschka
Copy link
Contributor

@hjanuschka hjanuschka commented Dec 16, 2024

Add a new check that suggests using string_view::remove_prefix() and remove_suffix() instead of substr() when the intent is to remove characters from either end of a string_view.

edit: have not found an existing check, if there is any, please let me know

Expression Replacement
sv = sv.substr(n) sv.remove_prefix(n)
sv = sv.substr(0, sv.length()-n) sv.remove_suffix(n)
sv = sv.substr(0, sv.length()) Redundant self-copy
sv1 = sv.substr(0, sv.length()) sv1 = sv

@hjanuschka hjanuschka force-pushed the stringview_substring_check branch from ea6d39a to bcee24d Compare December 16, 2024 08:53
Copy link

github-actions bot commented Dec 16, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Add a new check that suggests using string_view::remove_prefix() and
remove_suffix() instead of substr() when the intent is to remove
characters from either end of a string_view.
@hjanuschka hjanuschka force-pushed the stringview_substring_check branch from c32769b to 8b2dc9a Compare December 16, 2024 09:51
@hjanuschka hjanuschka marked this pull request as ready for review December 17, 2024 08:26
@llvmbot
Copy link
Member

llvmbot commented Dec 17, 2024

@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: Helmut Januschka (hjanuschka)

Changes

Add a new check that suggests using string_view::remove_prefix() and remove_suffix() instead of substr() when the intent is to remove characters from either end of a string_view.

edit: have not found an existing check, if there is any, please let me know


Full diff: https://github.com/llvm/llvm-project/pull/120055.diff

7 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/readability/CMakeLists.txt (+1)
  • (modified) clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp (+3)
  • (added) clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp (+201)
  • (added) clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h (+39)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+7)
  • (added) clang-tools-extra/docs/clang-tidy/checks/readability/string-view-substr.rst (+18)
  • (added) clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp (+108)
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 8f303c51e1b0da..8b44fc339441ac 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -53,6 +53,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
   StaticAccessedThroughInstanceCheck.cpp
   StaticDefinitionInAnonymousNamespaceCheck.cpp
   StringCompareCheck.cpp
+  StringViewSubstrCheck.cpp
   SuspiciousCallArgumentCheck.cpp
   UniqueptrDeleteReleaseCheck.cpp
   UppercaseLiteralSuffixCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index d61c0ba39658e5..f36ec8f95ede60 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -56,6 +56,7 @@
 #include "StaticAccessedThroughInstanceCheck.h"
 #include "StaticDefinitionInAnonymousNamespaceCheck.h"
 #include "StringCompareCheck.h"
+#include "StringViewSubstrCheck.h"
 #include "SuspiciousCallArgumentCheck.h"
 #include "UniqueptrDeleteReleaseCheck.h"
 #include "UppercaseLiteralSuffixCheck.h"
@@ -146,6 +147,8 @@ class ReadabilityModule : public ClangTidyModule {
         "readability-static-definition-in-anonymous-namespace");
     CheckFactories.registerCheck<StringCompareCheck>(
         "readability-string-compare");
+    CheckFactories.registerCheck<StringViewSubstrCheck>(
+        "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
new file mode 100644
index 00000000000000..5c079e3203c989
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.cpp
@@ -0,0 +1,201 @@
+//===--- StringViewSubstrCheck.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 "StringViewSubstrCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+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"))))));
+
+  // 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"),
+      this);
+}
+
+void StringViewSubstrCheck::check(const MatchFinder::MatchResult &Result) {
+  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");
+
+  if (!Assignment || !Target || !Source || !SubstrCall) {
+    return;
+  }
+
+  // Get the DeclRefExpr for the target and source
+  const auto *TargetDRE = dyn_cast<DeclRefExpr>(Target->IgnoreParenImpCasts());
+  const auto *SourceDRE = dyn_cast<DeclRefExpr>(Source->IgnoreParenImpCasts());
+
+  if (!TargetDRE || !SourceDRE) {
+    return;
+  }
+
+  const Expr *StartArg = SubstrCall->getArg(0);
+  const Expr *LengthArg =
+      SubstrCall->getNumArgs() > 1 ? SubstrCall->getArg(1) : nullptr;
+
+  std::string StartText =
+      Lexer::getSourceText(
+          CharSourceRange::getTokenRange(StartArg->getSourceRange()),
+          *Result.SourceManager, Result.Context->getLangOpts())
+          .str();
+
+  const bool IsSameVar = (TargetDRE->getDecl() == SourceDRE->getDecl());
+
+  // Case 1: Check for remove_prefix pattern
+  if (!LengthArg || isa<CXXDefaultArgExpr>(LengthArg)) {
+    if (IsSameVar) {
+      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;
+  }
+
+  // Check if StartArg resolves to 0
+  bool IsZero = false;
+
+  // Handle cases where StartArg is an integer literal
+  if (const auto *IL =
+          dyn_cast<IntegerLiteral>(StartArg->IgnoreParenImpCasts())) {
+    IsZero = IL->getValue() == 0;
+  }
+
+  // Optional: Handle cases where StartArg evaluates to zero
+  if (!IsZero) {
+    // Add logic for other constant evaluation (e.g., constexpr evaluation)
+    const auto &EvalResult = StartArg->EvaluateKnownConstInt(*Result.Context);
+    IsZero = !EvalResult.isNegative() && EvalResult == 0;
+  }
+
+  // If StartArg resolves to 0, handle the case
+  if (IsZero) {
+    bool isFullCopy = false;
+
+    // Check for length() or length() - expr pattern
+    if (const auto *BinOp = dyn_cast<BinaryOperator>(LengthArg)) {
+      if (BinOp->getOpcode() == BO_Sub) {
+        const Expr *LHS = BinOp->getLHS();
+        const Expr *RHS = BinOp->getRHS();
+
+        // Check for length() call
+        if (const auto *LengthCall = dyn_cast<CXXMemberCallExpr>(LHS)) {
+          if (const auto *LengthMethod =
+                  dyn_cast<CXXMethodDecl>(LengthCall->getDirectCallee())) {
+            if (LengthMethod->getName() == "length") {
+              const Expr *LengthObject =
+                  LengthCall->getImplicitObjectArgument();
+              const auto *LengthDRE =
+                  dyn_cast<DeclRefExpr>(LengthObject->IgnoreParenImpCasts());
+
+              if (!LengthDRE || LengthDRE->getDecl() != SourceDRE->getDecl()) {
+                return;
+              }
+
+              // Check if RHS is 0 or evaluates to 0
+              bool IsZero = false;
+              if (const auto *IL =
+                      dyn_cast<IntegerLiteral>(RHS->IgnoreParenImpCasts())) {
+                IsZero = IL->getValue() == 0;
+              }
+
+              if (IsZero) {
+                isFullCopy = true;
+              } else if (IsSameVar) {
+                // remove_suffix case (only for self-assignment)
+                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);
+                return;
+              }
+            }
+          }
+        }
+      }
+    } else if (const auto *LengthCall =
+                   dyn_cast<CXXMemberCallExpr>(LengthArg)) {
+      // Handle direct length() call
+      if (const auto *LengthMethod =
+              dyn_cast<CXXMethodDecl>(LengthCall->getDirectCallee())) {
+        if (LengthMethod->getName() == "length") {
+          const Expr *LengthObject = LengthCall->getImplicitObjectArgument();
+          const auto *LengthDRE =
+              dyn_cast<DeclRefExpr>(LengthObject->IgnoreParenImpCasts());
+
+          if (LengthDRE && LengthDRE->getDecl() == SourceDRE->getDecl()) {
+            isFullCopy = true;
+          }
+        }
+      }
+    }
+    if (isFullCopy) {
+      if (IsSameVar) {
+        // Remove redundant self-copy, including the semicolon
+        SourceLocation EndLoc = Assignment->getEndLoc();
+        while (EndLoc.isValid()) {
+          const char *endPtr = Result.SourceManager->getCharacterData(EndLoc);
+          if (*endPtr == ';')
+            break;
+          EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, *Result.SourceManager,
+                                              Result.Context->getLangOpts());
+        }
+        if (EndLoc.isValid()) {
+          diag(Assignment->getBeginLoc(), "redundant self-copy")
+              << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
+                     Assignment->getBeginLoc(),
+                     EndLoc.getLocWithOffset(
+                         1))); // +1 to include the semicolon.
+        }
+      } else {
+        // Simplify copy between different variables
+        std::string Replacement = TargetDRE->getNameInfo().getAsString() +
+                                  " = " +
+                                  SourceDRE->getNameInfo().getAsString();
+        diag(Assignment->getBeginLoc(), "prefer direct copy over substr")
+            << FixItHint::CreateReplacement(Assignment->getSourceRange(),
+                                            Replacement);
+      }
+
+      return;
+    }
+  }
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h
new file mode 100644
index 00000000000000..1a2054da1ed9cc
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/StringViewSubstrCheck.h
@@ -0,0 +1,39 @@
+//===--- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGVIEWSUBSTRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGVIEWSUBSTRCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// 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
+///
+/// The check matches two patterns:
+///   sv = sv.substr(N) -> sv.remove_prefix(N)
+///   sv = sv.substr(0, sv.length() - N) -> sv.remove_suffix(N)
+///
+/// These replacements make the intent clearer and are more efficient as they
+/// modify the string_view in place rather than creating a new one.
+class StringViewSubstrCheck : public ClangTidyCheck {
+public:
+  StringViewSubstrCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGVIEWSUBSTRCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6803842106791b..6e0352f8c619cd 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -136,6 +136,13 @@ New checks
   Gives warnings for tagged unions, where the number of tags is
   different from the number of data members inside the union.
 
+- New :doc:`readability-string-view-substr 
+  <clang-tidy/checks/readability/string-view-substr>` check.
+
+  Finds ``std::string_view::substr()`` calls that can be replaced with clearer 
+  alternatives using ``remove_prefix()`` or ``remove_suffix()``. This makes the 
+  intent clearer and is more efficient as it modifies the string_view in place.
+
 - New :doc:`modernize-use-integer-sign-comparison
   <clang-tidy/checks/modernize/use-integer-sign-comparison>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/string-view-substr.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/string-view-substr.rst
new file mode 100644
index 00000000000000..c4e25a1d621c8f
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/string-view-substr.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - readability-string-view-substr
+
+readability-string-view-substr
+==============================
+
+Finds ``string_view substr()`` calls that can be replaced with clearer alternatives
+using ``remove_prefix()`` or ``remove_suffix()``.
+
+The check suggests the following transformations:
+
+===========================================  =======================
+Expression                                   Replacement
+===========================================  =======================
+``sv = sv.substr(n)``                        ``sv.remove_prefix(n)``
+``sv = sv.substr(0, sv.length()-n)``         ``sv.remove_suffix(n)``
+``sv = sv.substr(0, sv.length())``           Redundant self-copy
+``sv1 = sv.substr(0, sv.length())``          ``sv1 = sv``
+===========================================  =======================
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp
new file mode 100644
index 00000000000000..908c664e329b2f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s readability-stringview-substr %t
+
+namespace std {
+template <typename T>
+class basic_string_view {
+public:
+  using size_type = unsigned long;
+  static constexpr size_type npos = -1;
+
+  basic_string_view(const char*) {}
+  basic_string_view substr(size_type pos, size_type count = npos) const { return *this; }
+  void remove_prefix(size_type n) {}
+  void remove_suffix(size_type n) {}
+  size_type length() const { return 0; }
+  basic_string_view& operator=(const basic_string_view&) { return *this; }
+};
+
+using string_view = basic_string_view<char>;
+} // namespace std
+
+void test_basic() {
+  std::string_view sv("test");
+  std::string_view sv1("test");
+  std::string_view sv2("test");
+
+  // Should match: remove_prefix
+  sv = sv.substr(5);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_prefix' over 'substr' for removing characters from the start [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_prefix(5)
+
+  // Should match: remove_suffix
+  sv = sv.substr(0, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  // Should match: remove_suffix with complex expression
+  sv = sv.substr(0, sv.length() - (3 + 2));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix((3 + 2))
+}
+
+void test_copies() {
+  std::string_view sv("test");
+  std::string_view sv1("test");
+  std::string_view sv2("test");
+
+  // Should match: remove redundant self copies
+  sv = sv.substr(0, sv.length());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant self-copy [readability-stringview-substr]
+
+  sv = sv.substr(0, sv.length() - 0);
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant self-copy [readability-stringview-substr]
+
+  // Should match: simplify copies between different variables
+  sv1 = sv.substr(0, sv.length());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer direct copy over substr [readability-stringview-substr]
+  // CHECK-FIXES: sv1 = sv
+
+  sv2 = sv.substr(0, sv.length() - 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer direct copy over substr [readability-stringview-substr]
+  // CHECK-FIXES: sv2 = sv
+}
+
+void test_zero_forms() {
+  std::string_view sv("test");
+  const int kZero = 0;
+  constexpr std::string_view::size_type Zero = 0;
+  #define START_POS 0
+
+  // Should match: various forms of zero in first argument
+  sv = sv.substr(kZero, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  sv = sv.substr(Zero, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  sv = sv.substr(START_POS, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  sv = sv.substr((0), sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  sv = sv.substr(0u, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+
+  sv = sv.substr(0UL, sv.length() - 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
+  // CHECK-FIXES: sv.remove_suffix(3)
+}
+
+void test_should_not_match() {
+  std::string_view sv("test");
+  std::string_view sv1("test");
+  std::string_view sv2("test");
+
+  // No match: substr used for prefix or mid-view
+  sv = sv.substr(1, sv.length() - 3); // No warning
+
+  // No match: Different string_views
+  sv = sv2.substr(0, sv2.length() - 3); // No warning
+
+  
+}

@HerrCai0907 HerrCai0907 requested a review from 5chmidti December 17, 2024 14:49
Copy link
Contributor

@5chmidti 5chmidti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detected issues together with the fixes can currently produce code that can't compile. For example:

void f(std::string_view sv);
void g(std::string_view sv) {
-  const auto copy = sv = sv.substr(0, sv.length() - 3);                                                                                                                                                                                   
+  const auto copy = sv.remove_suffix(3);                                                                                                                                                                                        
-  f(sv = sv.substr(0, sv.length() - 3));                                                                                                                                                                                                               
+  f(sv.remove_suffix(3));
}

I think the solution is to detect if the parent of the CXXoperatorCallExpr is an ExprWithCleanup: https://godbolt.org/z/d79MhEEea
Displaying a warning for these cases could still be done, just without the fix.

this);
}

void StringViewSubstrCheck::check(const MatchFinder::MatchResult &Result) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to do as much of the checking inside the matchers. I think everything can be done inside the matcher.

Copy link
Contributor Author

@hjanuschka hjanuschka Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all other feedback addressed, and pushed, will go and kind of mentally restart this, to get the most logic moved to matchers() 🙈

Copy link
Contributor

@5chmidti 5chmidti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move even more into the matchers. Here is a mock-up of what I mean (untested):

m cxxMemberCallExpr(
  anyOf(
    cxxMemberCallExpr(
        argumentCountIs(1)
       # is substr, and bind arg 1
    ),
    cxxMemberCallExpr(
        argumentCountIs(2),
        hasArgument(0, 
            expr(anyOf(integerLiteral(equals(0)), 
                     # evaluatesTo(0) # custom matcher
        )).bind("zero")),
        hasArgument(1, 
            expr(anyOf(
                lengthMatcher, 
                binaryOperator(hasOperatorName("-"),
                    hasLHS(lengthMatcher), hasRHS(expr().bind("n")))
            ))
        )
    )
    )
)

Then you can discern which case you have by checking what is bound.

// gettiung bound nodes
if (!Zero) {
  if (N)
    /*case 1*/;
  return;
}
if (N) {
  /*case 2*/
  return;
}
if (/*LHS and RHS of assign are equal*/) {// could technically be in the matcher, but this looks a bit better actually, IMO
  /*case 3*/;
  return;
}

/*case 4*/

Copy link
Contributor

@HerrCai0907 HerrCai0907 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, please update release note

Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be readability-stringview-substr
There are already 2 other checks that use "stringview" instead of "string-view".

@hjanuschka
Copy link
Contributor Author

hjanuschka commented Jan 17, 2025

@PiotrZSL feedback addressed

@5chmidti - thank you for your feedback, i have now invested multiple days over a few weeks to somehow make this work.
started multiple attempts from scratch, at this point i don't even know what i have tried and what not, the last commit.

1736884

seems to produce the right result, yet llvm-lit fails, and i have no clou.

Test Output
-- Testing: 1 tests, 1 workers --
FAIL: Clang Tools :: clang-tidy/checkers/readability/stringview_substr.cpp (1 of 1)
******************** TEST 'Clang Tools :: clang-tidy/checkers/readability/stringview_substr.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
Running ['clang-tidy', '/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp', '-fix', '--checks=-*,readability-stringview-substr', '--config={}', '--', '-std=c++17', '-nostdinc++']...
------------------------ clang-tidy output -----------------------
17 warnings generated.
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:28:3: warning: prefer 'remove_prefix' over 'substr' for removing characters from the start [readability-stringview-substr]
   28 |   sv = sv.substr(5);
      |   ^~~~~~~~~~~~~~~~~
      |   sv.remove_prefix(5)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:28:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:33:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
   33 |   sv = sv.substr(0, sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:33:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:38:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
   38 |   sv = sv.substr(0, sv.length() - (3 + 2));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix((3 + 2))
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:38:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:48:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
   48 |   sv = sv.substr(0, sv.size() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:48:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:53:3: warning: redundant self-copy [readability-stringview-substr]
   53 |   sv = sv.substr(0, sv.size());
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:53:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:56:3: warning: redundant self-copy [readability-stringview-substr]
   56 |   sv = sv.substr(0, sv.size() - 0);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:56:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:60:3: warning: prefer direct copy over substr [readability-stringview-substr]
   60 |   sv2 = sv.substr(0, sv.size());
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv2 = sv
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:60:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:88:3: warning: redundant self-copy [readability-stringview-substr]
   88 |   sv = sv.substr(0, sv.length());
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:88:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:91:3: warning: redundant self-copy [readability-stringview-substr]
   91 |   sv = sv.substr(0, sv.length() - 0);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:91:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:95:3: warning: prefer direct copy over substr [readability-stringview-substr]
   95 |   sv1 = sv.substr(0, sv.length());
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv1 = sv
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:95:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:99:3: warning: prefer direct copy over substr [readability-stringview-substr]
   99 |   sv2 = sv.substr(0, sv.length() - 0);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv2 = sv
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:99:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:111:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
  111 |   sv = sv.substr(kZero, sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:111:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:119:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
  119 |   sv = sv.substr(START_POS, sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:119:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:123:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
  123 |   sv = sv.substr((0), sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:123:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:127:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
  127 |   sv = sv.substr(0u, sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:127:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:131:3: warning: prefer 'remove_suffix' over 'substr' for removing characters from the end [readability-stringview-substr]
  131 |   sv = sv.substr(0UL, sv.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   sv.remove_suffix(3)
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:131:3: note: FIX-IT applied suggested code changes
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:145:3: warning: prefer assignment and remove_suffix over substr [readability-stringview-substr]
  145 |   sv = sv2.substr(0, sv2.length() - 3);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:145:3: note: FIX-IT applied suggested code changes
clang-tidy applied 17 of 17 suggested fixes.

------------------------------------------------------------------
diff -u /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.orig /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp failed:
--- /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.orig	2025-01-17 10:58:28.139518728 +0100
+++ /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp	2025-01-17 10:58:28.151518945 +0100
@@ -25,17 +25,17 @@
   std::string_view sv2("test");
 
   // Should match: remove_prefix
-  sv = sv.substr(5);
+  sv.remove_prefix(5);
   //
   //
 
   // Should match: remove_suffix
-  sv = sv.substr(0, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
   // Should match: remove_suffix with complex expression
-  sv = sv.substr(0, sv.length() - (3 + 2));
+  sv.remove_suffix((3 + 2));
   //
   //
 }
@@ -45,19 +45,19 @@
   std::string_view sv2("test");
 
   // Should match: remove_suffix with size()
-  sv = sv.substr(0, sv.size() - 3);
+  sv.remove_suffix(3);
   //
   //
   
   // Should match: remove redundant self copies
-  sv = sv.substr(0, sv.size());
+  
   //
   
-  sv = sv.substr(0, sv.size() - 0);
+  
   //
   
   // Should match: simplify copies between different variables 
-  sv2 = sv.substr(0, sv.size());
+  sv2 = sv;
   //
   //
 }
@@ -85,18 +85,18 @@
   std::string_view sv2("test");
 
   // Should match: remove redundant self copies
-  sv = sv.substr(0, sv.length());
+  
   //
 
-  sv = sv.substr(0, sv.length() - 0);
+  
     //
 
   // Should match: simplify copies between different variables
-  sv1 = sv.substr(0, sv.length());
+  sv1 = sv;
   //
   //
 
-  sv2 = sv.substr(0, sv.length() - 0);
+  sv2 = sv;
   //
   //
 }
@@ -108,7 +108,7 @@
   #define START_POS 0
 
   // Should match: various forms of zero in first argument
-  sv = sv.substr(kZero, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
@@ -116,19 +116,19 @@
   //
   //
 
-  sv = sv.substr(START_POS, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr((0), sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr(0u, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr(0UL, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 }
@@ -142,7 +142,8 @@
   sv = sv.substr(1, sv.length() - 3); // No warning
 
   // Should match: Different string_views with remove_suffix pattern
-  sv = sv2.substr(0, sv2.length() - 3);
+  sv = sv2;
+  sv.remove_suffix(3);
   //
   //
   //

------------------------------ Fixes -----------------------------
--- /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.orig	2025-01-17 10:58:28.139518728 +0100
+++ /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp	2025-01-17 10:58:28.151518945 +0100
@@ -25,17 +25,17 @@
   std::string_view sv2("test");
 
   // Should match: remove_prefix
-  sv = sv.substr(5);
+  sv.remove_prefix(5);
   //
   //
 
   // Should match: remove_suffix
-  sv = sv.substr(0, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
   // Should match: remove_suffix with complex expression
-  sv = sv.substr(0, sv.length() - (3 + 2));
+  sv.remove_suffix((3 + 2));
   //
   //
 }
@@ -45,19 +45,19 @@
   std::string_view sv2("test");
 
   // Should match: remove_suffix with size()
-  sv = sv.substr(0, sv.size() - 3);
+  sv.remove_suffix(3);
   //
   //
   
   // Should match: remove redundant self copies
-  sv = sv.substr(0, sv.size());
+  
   //
   
-  sv = sv.substr(0, sv.size() - 0);
+  
   //
   
   // Should match: simplify copies between different variables 
-  sv2 = sv.substr(0, sv.size());
+  sv2 = sv;
   //
   //
 }
@@ -85,18 +85,18 @@
   std::string_view sv2("test");
 
   // Should match: remove redundant self copies
-  sv = sv.substr(0, sv.length());
+  
   //
 
-  sv = sv.substr(0, sv.length() - 0);
+  
     //
 
   // Should match: simplify copies between different variables
-  sv1 = sv.substr(0, sv.length());
+  sv1 = sv;
   //
   //
 
-  sv2 = sv.substr(0, sv.length() - 0);
+  sv2 = sv;
   //
   //
 }
@@ -108,7 +108,7 @@
   #define START_POS 0
 
   // Should match: various forms of zero in first argument
-  sv = sv.substr(kZero, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
@@ -116,19 +116,19 @@
   //
   //
 
-  sv = sv.substr(START_POS, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr((0), sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr(0u, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 
-  sv = sv.substr(0UL, sv.length() - 3);
+  sv.remove_suffix(3);
   //
   //
 }
@@ -142,7 +142,8 @@
   sv = sv.substr(1, sv.length() - 3); // No warning
 
   // Should match: Different string_views with remove_suffix pattern
-  sv = sv2.substr(0, sv2.length() - 3);
+  sv = sv2;
+  sv.remove_suffix(3);
   //
   //
   //

------------------------------------------------------------------
FileCheck -input-file=/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp /home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp -check-prefixes=CHECK-FIXES -strict-whitespace failed:
/home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp:147:19: error: CHECK-FIXES: expected string not found in input
  // CHECK-FIXES: sv = sv2;
                  ^
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:146:22: note: scanning from here
  sv.remove_suffix(3);
                     ^
/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp:155:20: note: possible intended match here
 const auto copy = sv = sv.substr(0, sv.length() - 3); // No warning
                   ^

Input file: /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp
Check file: /home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp

-dump-input=help explains the following input dump.

Input was:
<<<<<<
             .
             .
             .
           141:   // No match: substr used for prefix or mid-view 
           142:   sv = sv.substr(1, sv.length() - 3); // No warning 
           143:  
           144:   // Should match: Different string_views with remove_suffix pattern 
           145:   sv = sv2; 
           146:   sv.remove_suffix(3); 
check:147'0                          X~ error: no match found
           147:   // 
check:147'0     ~~~~~
           148:   // 
check:147'0     ~~~~~
           149:   // 
check:147'0     ~~~~~
           150: } 
check:147'0     ~~
           151:  
check:147'0     ~
           152: void f(std::string_view) {} 
check:147'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           153: void test_expr_with_cleanups() { 
check:147'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           154:  std::string_view sv("test"); 
check:147'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           155:  const auto copy = sv = sv.substr(0, sv.length() - 3); // No warning 
check:147'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:147'1                        ?                                                  possible intended match
           156:   f(sv = sv.substr(0, sv.length() - 3)); // No warning 
check:147'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           157: } 
check:147'0     ~~
           158:  
check:147'0     ~
>>>>>>


--
Command Output (stderr):
--
RUN: at line 1: /usr/bin/python3 /home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py /home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp readability-stringview-substr -std=c++17 /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp
+ /usr/bin/python3 /home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py /home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp readability-stringview-substr -std=c++17 /home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp
Traceback (most recent call last):
  File "/home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py", line 388, in <module>
    main()
  File "/home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py", line 384, in main
    CheckRunner(args, extra_args).run()
  File "/home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py", line 299, in run
    self.check_fixes()
  File "/home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py", line 247, in check_fixes
    try_run(
  File "/home/chrome/llvm-project/clang-tools-extra/test/../test/clang-tidy/check_clang_tidy.py", line 61, in try_run
    process_output = subprocess.check_output(args, stderr=subprocess.STDOUT).decode(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 466, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['FileCheck', '-input-file=/home/chrome/llvm-project/build/tools/clang/tools/extra/test/clang-tidy/checkers/readability/Output/stringview_substr.cpp.tmp.cpp', '/home/chrome/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/stringview_substr.cpp', '-check-prefixes=CHECK-FIXES', '-strict-whitespace']' returned non-zero exit status 1.

--

********************
********************
Failed Tests (1):
  Clang Tools :: clang-tidy/checkers/readability/stringview_substr.cpp


Testing Time: 0.14s

Total Discovered Tests: 1
  Failed: 1 (100.00%)

in the diff that shows on top of the output it "feels" like it is ok, but the multiline replacement is not confirmed working.

so i am here to ask for help.

  • any ideas how to fix the test file?
  • in general is the approach correctly understood as you mentioned it.

overall - at the end this would require a full re-review.

edit: i didn't touch the test file, as it worked before without the recent commit and the check() approach

@hjanuschka
Copy link
Contributor Author

@5chmidti may i ping you? could you help me out, it feels like its only inches away from being done. or could we go with the prev. commit as mentioned above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants