[clang-tools-extra] r277677 - [clang-tidy] Inefficient string operation

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 3 16:06:03 PDT 2016


Author: alexfh
Date: Wed Aug  3 18:06:03 2016
New Revision: 277677

URL: http://llvm.org/viewvc/llvm-project?rev=277677&view=rev
Log:
[clang-tidy] Inefficient string operation

Patch by Bittner Barni!

Differential revision: https://reviews.llvm.org/D20196

Added:
    clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.cpp
    clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst
    clang-tools-extra/trunk/test/clang-tidy/performance-inefficient-string-concatenation.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt?rev=277677&r1=277676&r2=277677&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/performance/CMakeLists.txt Wed Aug  3 18:06:03 2016
@@ -4,6 +4,7 @@ add_clang_library(clangTidyPerformanceMo
   FasterStringFindCheck.cpp
   ForRangeCopyCheck.cpp
   ImplicitCastInLoopCheck.cpp
+  InefficientStringConcatenationCheck.cpp
   PerformanceTidyModule.cpp
   UnnecessaryCopyInitialization.cpp
   UnnecessaryValueParamCheck.cpp

Added: clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.cpp?rev=277677&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.cpp Wed Aug  3 18:06:03 2016
@@ -0,0 +1,86 @@
+//===--- InefficientStringConcatenationCheck.cpp - clang-tidy--------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InefficientStringConcatenationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+void InefficientStringConcatenationCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "StrictMode", StrictMode);
+}
+
+InefficientStringConcatenationCheck::InefficientStringConcatenationCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context), StrictMode(Options.get("StrictMode", 0)) {}
+
+void InefficientStringConcatenationCheck::registerMatchers(
+    MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  const auto BasicStringType =
+      hasType(cxxRecordDecl(hasName("::std::basic_string")));
+
+  const auto BasicStringPlusOperator = cxxOperatorCallExpr(
+      hasOverloadedOperatorName("+"),
+      hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))));
+
+  const auto PlusOperator =
+      cxxOperatorCallExpr(
+          hasOverloadedOperatorName("+"),
+          hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))),
+          hasDescendant(BasicStringPlusOperator))
+          .bind("plusOperator");
+
+  const auto AssignOperator = cxxOperatorCallExpr(
+      hasOverloadedOperatorName("="),
+      hasArgument(0, declRefExpr(BasicStringType,
+                                 hasDeclaration(decl().bind("lhsStrT")))
+                         .bind("lhsStr")),
+      hasArgument(1, stmt(hasDescendant(declRefExpr(
+                         hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))),
+      hasDescendant(BasicStringPlusOperator));
+
+  if (StrictMode) {
+    Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)),
+                       this);
+  } else {
+    Finder->addMatcher(
+        cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator),
+                            hasAncestor(stmt(anyOf(cxxForRangeStmt(),
+                                                   whileStmt(), forStmt())))),
+        this);
+  }
+}
+
+void InefficientStringConcatenationCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>("lhsStr");
+  const auto *PlusOperator =
+      Result.Nodes.getNodeAs<CXXOperatorCallExpr>("plusOperator");
+  const auto DiagMsg =
+      "string concatenation results in allocation of unnecessary temporary "
+      "strings; consider using 'operator+=' or 'string::append()' instead";
+
+  if (LhsStr)
+    diag(LhsStr->getExprLoc(), DiagMsg);
+  else if (PlusOperator)
+    diag(PlusOperator->getExprLoc(), DiagMsg);
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.h?rev=277677&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/performance/InefficientStringConcatenationCheck.h Wed Aug  3 18:06:03 2016
@@ -0,0 +1,41 @@
+//===--- InefficientStringConcatenationCheck.h - clang-tidy-----------*- C++
+//-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// This check is to warn about the performance overhead arising from
+/// concatenating strings, using the operator+, instead of operator+=.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-string-concatenation.html
+class InefficientStringConcatenationCheck : public ClangTidyCheck {
+public:
+  InefficientStringConcatenationCheck(StringRef Name,
+                                      ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  const bool StrictMode;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H

Modified: clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp?rev=277677&r1=277676&r2=277677&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/performance/PerformanceTidyModule.cpp Wed Aug  3 18:06:03 2016
@@ -10,6 +10,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "InefficientStringConcatenationCheck.h"
 
 #include "FasterStringFindCheck.h"
 #include "ForRangeCopyCheck.h"
@@ -30,6 +31,8 @@ public:
         "performance-for-range-copy");
     CheckFactories.registerCheck<ImplicitCastInLoopCheck>(
         "performance-implicit-cast-in-loop");
+    CheckFactories.registerCheck<InefficientStringConcatenationCheck>(
+        "performance-inefficient-string-concatenation");
     CheckFactories.registerCheck<UnnecessaryCopyInitialization>(
         "performance-unnecessary-copy-initialization");
     CheckFactories.registerCheck<UnnecessaryValueParamCheck>(

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=277677&r1=277676&r2=277677&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Wed Aug  3 18:06:03 2016
@@ -69,6 +69,13 @@ Improvements to clang-tidy
 
   Flags classes where some, but not all, special member functions are user-defined.
 
+- New `performance-inefficient-string-concatenation
+  <http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-string-concatenation.html>`_ check
+
+  This check warns about the performance overhead arising from concatenating
+  strings using the ``operator+``, instead of ``operator+=``.
+
+
 Improvements to include-fixer
 -----------------------------
 

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=277677&r1=277676&r2=277677&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Wed Aug  3 18:06:03 2016
@@ -114,6 +114,7 @@ Clang-Tidy Checks
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-cast-in-loop
+   performance-inefficient-string-concatenation
    performance-unnecessary-copy-initialization
    performance-unnecessary-value-param
    readability-avoid-const-params-in-decls

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst?rev=277677&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst Wed Aug  3 18:06:03 2016
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - performance-inefficient-string-concatenation
+
+performance-inefficient-string-concatenation
+============================================
+
+This check warns about the performance overhead arising from concatenating strings using the ``operator+``, for instance:
+    
+.. code:: c++
+
+    std::string a("Foo"), b("Bar");
+    a = a + b;
+
+Instead of this structure you should use ``operator+=`` or ``std::string``'s (``std::basic_string``) class member function ``append()``. For instance:
+   
+.. code:: c++
+
+   std::string a("Foo"), b("Baz");
+   for (int i = 0; i < 20000; ++i) {
+       a = a + "Bar" + b;
+   }
+
+Could be rewritten in a greatly more efficient way like:
+
+.. code:: c++
+
+   std::string a("Foo"), b("Baz");
+   for (int i = 0; i < 20000; ++i) {
+       a.append("Bar").append(b);
+   } 
+
+And this can be rewritten too:
+
+.. code:: c++
+
+   void f(const std::string&) {}
+   std::string a("Foo"), b("Baz");
+   void g() {
+       f(a + "Bar" + b);
+   }
+
+In a slightly more efficient way like:
+
+.. code:: c++
+
+   void f(const std::string&) {}
+   std::string a("Foo"), b("Baz");
+   void g() {
+       f(std::string(a).append("Bar").append(b));
+   }

Added: clang-tools-extra/trunk/test/clang-tidy/performance-inefficient-string-concatenation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-inefficient-string-concatenation.cpp?rev=277677&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/performance-inefficient-string-concatenation.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/performance-inefficient-string-concatenation.cpp Wed Aug  3 18:06:03 2016
@@ -0,0 +1,44 @@
+// RUN: %check_clang_tidy %s performance-inefficient-string-concatenation %t
+
+namespace std {
+template <typename T>
+class basic_string {
+public:
+  basic_string() {}
+  ~basic_string() {}
+  basic_string<T> *operator+=(const basic_string<T> &) {}
+  friend basic_string<T> operator+(const basic_string<T> &, const basic_string<T> &) {}
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f(std::string) {}
+std::string g(std::string) {}
+
+int main() {
+  std::string mystr1, mystr2;
+  std::wstring mywstr1, mywstr2;
+
+  for (int i = 0; i < 10; ++i) {
+    f(mystr1 + mystr2 + mystr1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: string concatenation results in allocation of unnecessary temporary strings; consider using 'operator+=' or 'string::append()' instead
+    mystr1 = mystr1 + mystr2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+    mystr1 = mystr2 + mystr2 + mystr2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: string concatenation
+    mystr1 = mystr2 + mystr1;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+    mywstr1 = mywstr2 + mywstr1;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+    mywstr1 = mywstr2 + mywstr2 + mywstr2;
+    // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: string concatenation
+
+    mywstr1 = mywstr2 + mywstr2;
+    mystr1 = mystr2 + mystr2;
+    mystr1 += mystr2;
+    f(mystr2 + mystr1);
+    mystr1 = g(mystr1);
+  }
+  return 0;
+}




More information about the cfe-commits mailing list