acoster updated this revision to Diff 486582.
acoster added a comment.

Fix length of comment at the top of StrlenStringCStrCheck.h


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140968/new/

https://reviews.llvm.org/D140968

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/strlen-string-cstr.rst
  clang-tools-extra/test/clang-tidy/checkers/readability/strlen-string-cstr.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/strlen-string-cstr.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/strlen-string-cstr.cpp
@@ -0,0 +1,117 @@
+// RUN: %check_clang_tidy %s readability-strlen-string-cstr %t
+int strlen(const char *);
+int strnlen(const char *, int);
+int strnlen_s(const char *, int);
+
+int wcslen(const wchar_t *);
+int wcsnlen_s(const wchar_t *, int);
+
+namespace std {
+template <typename T> class allocator {};
+template <typename T> class char_traits {};
+
+template <typename C, typename T = std::char_traits<C>>
+class basic_string_view {
+public:
+  basic_string_view();
+  basic_string_view(const basic_string_view &other);
+  const C *data() const;
+  int size() const;
+  int length() const;
+};
+
+using string_view = basic_string_view<char>;
+using wstring_view = basic_string_view<wchar_t>;
+
+template <typename C, typename T = std::char_traits<C>,
+          typename A = std::allocator<C>>
+class basic_string {
+public:
+  basic_string();
+  basic_string(const C *, unsigned int size);
+  basic_string(const C *, const A &allocator = A());
+  const C *c_str() const;
+  const C *data() const;
+  int size() const;
+  int length() const;
+  operator basic_string_view<C, T>() const;
+};
+
+using wstring = basic_string<wchar_t>;
+using string = basic_string<char>;
+
+int strlen(const char *);
+int wcslen(const wchar_t *);
+} // namespace std
+
+void handlesBasicString() {
+  std::string str1("a", 1);
+  int length = strlen(str1.c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant call to 'strlen' {{.*}}
+  // CHECK-FIXES: {{^  }}int length = str1.size();{{$}}
+
+  length = strnlen(str1.data(), 30);
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant call to 'strnlen' {{.*}}
+  // CHECK-FIXES: {{^  }}length = str1.size();{{$}}
+
+  const std::string *p1 = &str1;
+  length = std::strlen(p1->c_str()) + 30;
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant call {{.*}}
+  // CHECK-FIXES: {{^  }}length = p1->size() + 30;{{$}}
+
+  std::wstring wstr1;
+  length = wcslen(wstr1.c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant call to 'wcslen' {{.*}}
+  // CHECK-FIXES: {{^  }}length = wstr1.size();{{$}}
+
+  const std::wstring &wstr2 = wstr1;
+  length = std::wcslen(wstr2.data());
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant call to {{.*}}
+  // CHECK-FIXES: {{^  }}length = wstr2.size();{{$}}
+}
+
+void handlesStringView() {
+  std::string str1("foo");
+  std::string_view view = str1;
+  int length = strnlen_s(view.data(), 300);
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant call to 'strnlen_s'
+  // {{.*}} CHECK-FIXES: {{^  }}int length = view.size();{{$}}
+
+  std::wstring wstr1;
+  std::wstring_view wview = wstr1;
+  length = wcsnlen_s(wview.data(), 300);
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant call to 'wcsnlen_s'
+  // {{.*}} CHECK-FIXES: {{^  }}length = wview.size();{{$}}
+}
+
+class CustomStringClass {
+public:
+  CustomStringClass(int, char);
+  const char *data() const;
+  int length() const;
+
+private:
+  int size() const;
+};
+
+void handlesStringLikeTypes() {
+  CustomStringClass str(123, 'f');
+  int size = strlen(str.data());
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: redundant call to
+  // CHECK-FIXES: {{^  }}int size = str.length();{{$}}
+}
+
+class StringWithoutPublicSizeMethod {
+public:
+  StringWithoutPublicSizeMethod(const char *);
+  const char *c_str();
+
+private:
+  int size() const;
+  int length() const;
+};
+
+void ignoresStringTypesWithoutPublicSizeMethod() {
+  StringWithoutPublicSizeMethod str("foo");
+  int length = strlen(str.c_str());
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability/strlen-string-cstr.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/readability/strlen-string-cstr.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - readability-strlen-string-cstr
+
+readability-strlen-string-cstr
+==============================
+
+Warns when the return value of ``c_str()`` or ``data()`` is used as an argument
+for ``strlen``, and suggests using ``size()``or ``length()`` if one of them is
+a member function.
+
+Example
+-------
+
+.. code-block:: c++
+
+    std::string str1{"foo"}
+
+    // Use str1.size()
+    size_t length = strlen(str1.c_str());
+
+    std::string_view view(str1);
+    // Use view.size()
+    length = strlen(view.data());
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -362,6 +362,7 @@
    `readability-static-accessed-through-instance <readability/static-accessed-through-instance.html>`_, "Yes"
    `readability-static-definition-in-anonymous-namespace <readability/static-definition-in-anonymous-namespace.html>`_, "Yes"
    `readability-string-compare <readability/string-compare.html>`_, "Yes"
+   `readability-strlen-string-cstr <readability/strlen-string-cstr.html>`_, "Yes"
    `readability-suspicious-call-argument <readability/suspicious-call-argument.html>`_,
    `readability-uniqueptr-delete-release <readability/uniqueptr-delete-release.html>`_, "Yes"
    `readability-uppercase-literal-suffix <readability/uppercase-literal-suffix.html>`_, "Yes"
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -129,6 +129,13 @@
   Warns when `empty()` is used on a range and the result is ignored. Suggests `clear()`
   if it is an existing member function.
 
+- New :doc:`readability-strlen-string-cstr
+  <clang-tidy/checks/readability/strlen-string-cstr>` check.
+
+  Warns when the return value of ``c_str()`` or ``data()`` is used as an argument for
+  ``strlen``, and suggests using ``size()``or ``length()`` if one of them is a member
+  function.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
Index: clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.h
@@ -0,0 +1,35 @@
+//===--- StrlenStringCStrCheck.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_STRLENSTRINGCSTRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRLENSTRINGCSTRCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds calls to `strlen(std::string::c_str())`.
+class StrlenStringCStrCheck : public ClangTidyCheck {
+public:
+  StrlenStringCStrCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRLENSTRINGCSTRCHECK_H
Index: clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/StrlenStringCStrCheck.cpp
@@ -0,0 +1,65 @@
+//===- StrlenStringCStrCheck.cpp - Check for strlen(string::c_str()) calls-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a check for calls to `strlen(std::string::c_str())`.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StrlenStringCStrCheck.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void StrlenStringCStrCheck::registerMatchers(
+    ast_matchers::MatchFinder *Finder) {
+  const auto StrlenFunctions = functionDecl(
+      hasAnyName("::strlen", "::std::strlen", "::strnlen", "::strnlen_s",
+                 "::wcslen", "::std::wcslen", "::wcsnlen_s"));
+  const auto CStrCall = cxxMemberCallExpr(callee(
+      cxxMethodDecl(hasAnyName("c_str", "data"),
+                    ofClass(cxxRecordDecl(has(
+                        cxxMethodDecl(hasAnyName("size", "length"), isPublic())
+                            .bind("size-method")))))));
+  const auto StrlenCall =
+      callExpr(callee(StrlenFunctions), hasArgument(0, CStrCall.bind("arg")))
+          .bind("strlen");
+  Finder->addMatcher(StrlenCall, this);
+}
+
+void StrlenStringCStrCheck::check(
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  const auto *StrlenCall = Result.Nodes.getNodeAs<CallExpr>("strlen");
+  const auto *Arg = Result.Nodes.getNodeAs<CXXMemberCallExpr>("arg");
+  const auto *SizeMethod = Result.Nodes.getNodeAs<CXXMethodDecl>("size-method");
+
+  // Remove the `strlen(` (or similar) prefix.
+  CharSourceRange StrlenRange = CharSourceRange::getCharRange(
+      StrlenCall->getBeginLoc(), Arg->getBeginLoc());
+  // Remove the `)` (and additional strnlen arguments, if any) from the strlen
+  // call.
+  CharSourceRange CloseParenRange =
+      CharSourceRange::getCharRange(Arg->getEndLoc(), StrlenCall->getEndLoc());
+
+  const auto *CStrCallee = cast<MemberExpr>(Arg->getCallee());
+  diag(StrlenCall->getBeginLoc(), "redundant call to %0 and %1")
+      << StrlenCall->getDirectCallee() << Arg->getMethodDecl()
+      << FixItHint::CreateRemoval(StrlenRange)
+      << FixItHint::CreateRemoval(CloseParenRange)
+      << FixItHint::CreateReplacement(CStrCallee->getMemberLoc(),
+                                      SizeMethod->getName());
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -47,6 +47,7 @@
 #include "StaticAccessedThroughInstanceCheck.h"
 #include "StaticDefinitionInAnonymousNamespaceCheck.h"
 #include "StringCompareCheck.h"
+#include "StrlenStringCStrCheck.h"
 #include "SuspiciousCallArgumentCheck.h"
 #include "UniqueptrDeleteReleaseCheck.h"
 #include "UppercaseLiteralSuffixCheck.h"
@@ -135,6 +136,8 @@
         "readability-redundant-string-init");
     CheckFactories.registerCheck<SimplifyBooleanExprCheck>(
         "readability-simplify-boolean-expr");
+    CheckFactories.registerCheck<StrlenStringCStrCheck>(
+        "readability-strlen-string-cstr");
     CheckFactories.registerCheck<SuspiciousCallArgumentCheck>(
         "readability-suspicious-call-argument");
     CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
Index: clang-tools-extra/clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -44,6 +44,7 @@
   StaticAccessedThroughInstanceCheck.cpp
   StaticDefinitionInAnonymousNamespaceCheck.cpp
   StringCompareCheck.cpp
+  StrlenStringCStrCheck.cpp
   SuspiciousCallArgumentCheck.cpp
   UniqueptrDeleteReleaseCheck.cpp
   UppercaseLiteralSuffixCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to