poelmanc created this revision.
poelmanc added a reviewer: MyDeveloperDay.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

This patch adds a feature requested by @MyDeveloperDay at 
https://reviews.llvm.org/D69238, @MyDeveloperDay to enable 
`readability-redundant-string-init` to take a list of strings to apply the fix 
to rather than hard-coding `basic_string`. It adds a `StringNames` option of 
semicolon-delimited names of string classes to which to apply this fix. Tests 
ensure this works with test class OurTestString as well as std::string and 
std::wstring as before. It should be applicable to llvm::StringRef, QString, 
etc.

This diff is currently based on https://reviews.llvm.org/D69238. Both make 
changes to the top of readability-redundant-string-init.cpp. I'm happy to 
rebase it on any version desired.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D69548

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h

Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2551,6 +2551,19 @@
                                         internal::hasAnyNameFunc>
     hasAnyName;
 
+/// Matches NamedDecl nodes that have any of the specified names.
+///
+/// \code
+///     hasListedName({a, b, c,...})
+/// \endcode
+///  is equivalent to
+/// \code
+///     anyOf(hasName(a), hasName(b), hasName(c),...)
+/// \endcode
+inline internal::Matcher<NamedDecl> hasListedName(const std::vector<std::string> &Names) {
+  return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Names));
+}
+
 /// Matches NamedDecl nodes whose fully qualified names contain
 /// a substring matched by the given RegExp.
 ///
Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-init.cpp
@@ -1,4 +1,8 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-init %t
+// RUN:   -config="{CheckOptions: \
+// RUN:             [{key: readability-redundant-string-init.StringNames, \
+// RUN:               value: "basic_string;OurTestString"}] \
+// RUN:             }"
 
 namespace std {
 template <typename T>
@@ -139,3 +143,31 @@
 void Param3(std::string param = "") {}
 void Param4(STRING param = "") {}
 
+struct OurTestString {
+  OurTestString();
+  OurTestString(const OurTestString &);
+  // MSVC headers define two constructors instead of using optional arguments.
+  OurTestString(const char *);
+  ~OurTestString();
+};
+
+void OurTestStringTests() {
+  OurTestString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString a;
+  OurTestString b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString b;
+  OurTestString c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString c;
+  OurTestString d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: redundant string initialization
+  // CHECK-FIXES: OurTestString d;
+
+  OurTestString u = "u";
+  OurTestString w("w");
+  OurTestString x = R"(x)";
+  OurTestString y(R"(y)");
+  OurTestString z;
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -5,7 +5,8 @@
 
 Finds unnecessary string initializations.
 
-Examples:
+Examples
+--------
 
 .. code-block:: c++
 
@@ -17,3 +18,16 @@
 
   std::string a;
   std::string b;
+
+Options
+-------
+
+.. option:: StringNames
+
+    Default is ``basic_string``.
+
+    Semicolon-delimited list of base class names to apply this check to.
+    By default ``basic_string`` applies to std::string and std::wstring.
+    Set to e.g. ``basic_string;StringRef;QString`` to perform this check on
+    custom classes as well.
+
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
@@ -11,6 +11,9 @@
 
 #include "../ClangTidyCheck.h"
 
+#include <string>
+#include <vector>
+
 namespace clang {
 namespace tidy {
 namespace readability {
@@ -18,10 +21,13 @@
 /// Finds unnecessary string initializations.
 class RedundantStringInitCheck : public ClangTidyCheck {
 public:
-  RedundantStringInitCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+  RedundantStringInitCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::vector<std::string> StringNames;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -8,6 +8,7 @@
 
 #include "RedundantStringInitCheck.h"
 #include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 
 using namespace clang::ast_matchers;
@@ -17,19 +18,32 @@
 namespace tidy {
 namespace readability {
 
+const char DefaultStringNames[] = "basic_string";
+
+RedundantStringInitCheck::RedundantStringInitCheck(StringRef Name,
+                                                   ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      StringNames(utils::options::parseStringList(
+          Options.get("StringNames", DefaultStringNames))) {}
+
+void RedundantStringInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "StringNames", DefaultStringNames);
+}
+
 void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
     return;
-
   // Match string constructor.
-  const auto StringConstructorExpr = expr(anyOf(
-      cxxConstructExpr(argumentCountIs(1),
-                       hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
-      // If present, the second argument is the alloc object which must not
-      // be present explicitly.
-      cxxConstructExpr(argumentCountIs(2),
-                       hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
-                       hasArgument(1, cxxDefaultArgExpr()))));
+  const auto StringConstructorExpr =
+      expr(anyOf(cxxConstructExpr(
+                     argumentCountIs(1),
+                     hasDeclaration(cxxMethodDecl(hasListedName(StringNames)))),
+                 // If present, the second argument is the alloc object which
+                 // must not be present explicitly.
+                 cxxConstructExpr(
+                     argumentCountIs(2),
+                     hasDeclaration(cxxMethodDecl(hasListedName(StringNames))),
+                     hasArgument(1, cxxDefaultArgExpr()))));
 
   // Match a string constructor expression with an empty string literal.
   const auto EmptyStringCtorExpr = cxxConstructExpr(
@@ -46,8 +60,8 @@
   //     string bar("");
   Finder->addMatcher(
       namedDecl(
-          varDecl(hasType(hasUnqualifiedDesugaredType(recordType(
-                      hasDeclaration(cxxRecordDecl(hasName("basic_string")))))),
+          varDecl(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+                      cxxRecordDecl(hasListedName(StringNames)))))),
                   hasInitializer(expr(ignoringImplicit(anyOf(
                                           EmptyStringCtorExpr,
                                           EmptyStringCtorExprWithTemporaries)))
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to