JDevlieghere removed rL LLVM as the repository for this revision.
JDevlieghere updated this revision to Diff 65273.
JDevlieghere added a comment.

- Extended check to replace memmove with std::move and memset with std::fill
- Renamed check to modernize-use-algorithm (I'd be equally fine with moving it 
to misc again)
- Added more documentation to better describe the goal of this check
- Fixed macro test and added cases for memmove and memset


https://reviews.llvm.org/D22725

Files:
  clang-tidy/modernize/CMakeLists.txt
  clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tidy/modernize/UseAlgorithmCheck.cpp
  clang-tidy/modernize/UseAlgorithmCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/modernize-use-algorithm.rst
  test/clang-tidy/modernize-use-algorithm.cpp

Index: test/clang-tidy/modernize-use-algorithm.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-algorithm.cpp
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s modernize-use-algorithm %t
+
+// CHECK-FIXES: #include <algorithm>
+
+namespace std {
+typedef unsigned int size_t;
+void *memcpy(void *dest, const void *src, std::size_t count);
+void *memset(void* dest, int ch, std::size_t count);
+void *memmove(void* dest, const void* src, std::size_t count);
+
+template <class InputIt, class OutputIt>
+OutputIt copy(InputIt first, InputIt last, OutputIt d_first);
+
+template<class InputIt, class OutputIt>
+OutputIt move(InputIt first, InputIt last, OutputIt d_first);
+
+template<class ForwardIt, class T>
+void fill(ForwardIt first, ForwardIt last, const T& value);
+}
+
+void a() {
+  char foo[] = "foo", bar[3];
+  std::memcpy(bar, foo, sizeof bar);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::copy instead of memcpy [modernize-use-algorithm]
+  // CHECK-FIXES: std::copy(foo, foo + sizeof bar, bar);
+
+  std::copy(foo, foo + sizeof bar, bar);
+}
+
+void b() {
+  char foo[] = "foobar";
+  std::memmove(foo + 1, foo , 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::move instead of memmove [modernize-use-algorithm]
+  // CHECK-FIXES: std::move(foo, foo + 3, foo + 1);
+
+  std::move(foo, foo + 2, foo + 2);
+}
+
+void c() {
+  char foo[] = "foobar";
+  std::memset(foo, 1, 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::fill instead of memset [modernize-use-algorithm]
+  // CHECK-FIXES: std::fill(foo, foo + 3, 1);
+
+  std::move(foo, foo + 2, 'a');
+}
+
+#define MEMCPY(dest, src) std::memcpy((dest), (src), sizeof (dest))
+void d() {
+  char foo[] = "foo", bar[3];
+  MEMCPY(bar, foo);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::copy instead of memcpy [modernize-use-algorithm]
+}
Index: docs/clang-tidy/checks/modernize-use-algorithm.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/modernize-use-algorithm.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - modernize-use-algorithm
+
+modernize-use-algorithm
+=======================
+
+Replaces calls to ``memcpy``, ``memmove`` and ``memset`` with ``std::copy``,
+``std::move`` and ``std::fill`` respectively. The advantages of using these
+algorithm functions is that they are at least as efficient, more general and
+type-aware.
+
+Furthermore, by using the algorithms the types remain intact as opposed to
+being discarded by the C-style functions. This allows the implementation to
+make use use of type information to further optimize. One example of such
+optimization is taking advantage of 64-bit alignment when copying an array of
+``std::uint64_t``.
+
+memcpy
+------
+
+.. code:: c++
+
+    std::memcpy(dest, source, sizeof dest);
+
+    // transforms to:
+
+    std::copy(source, source + sizeof dest, dest);
+
+memmove
+-------
+
+.. code:: c++
+
+    std::memmove(dest, source, sizeof dest);
+
+    // transforms to:
+
+    std::move(source, source + sizeof dest, dest);
+
+memset
+------
+
+.. code:: c++
+
+    std::memset(dest, ch, count);
+
+    // transforms to:
+
+    std::fill(dest, dest + count, ch)
+
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -29,6 +29,7 @@
    cppcoreguidelines-pro-type-static-cast-downcast
    cppcoreguidelines-pro-type-union-access
    cppcoreguidelines-pro-type-vararg
+   cppcoreguidelines-slicing
    google-build-explicit-make-pair
    google-build-namespaces
    google-build-using-namespace
@@ -103,6 +104,7 @@
    modernize-shrink-to-fit
    modernize-use-auto
    modernize-use-bool-literals
+   modernize-use-algorithm
    modernize-use-default
    modernize-use-emplace
    modernize-use-nullptr
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -64,6 +64,13 @@
 
   Flags slicing of member variables or vtable.
 
+- New `modernize-use-algorithm
+  <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-algorithm.html>`_ check
+
+  Replaces calls to ``memcpy``, ``memmove`` and ``memset`` with their
+  respective algorithm counterparts ``std::copy``, ``std::move`` and
+  ``std::fill``.
+
 Improvements to include-fixer
 -----------------------------
 
Index: clang-tidy/modernize/UseAlgorithmCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseAlgorithmCheck.h
@@ -0,0 +1,42 @@
+//===--- UseAlgorithmCheck.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_MODERNIZE_USE_ALGORITHM_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_ALGORITHM_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replaces memcpy with std::copy
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-algorithm.html
+class UseAlgorithmCheck : public ClangTidyCheck {
+public:
+  UseAlgorithmCheck(StringRef Name, ClangTidyContext *Context);
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::unique_ptr<utils::IncludeInserter> Inserter;
+  const utils::IncludeSorter::IncludeStyle IncludeStyle;
+  llvm::StringMap<std::string> Replacements;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_ALGORITHM_H
Index: clang-tidy/modernize/UseAlgorithmCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseAlgorithmCheck.cpp
@@ -0,0 +1,148 @@
+//===--- UseAlgorithmCheck.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 "UseAlgorithmCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static StringRef getText(const Expr *Expression, const SourceManager &SM,
+                         const LangOptions &LangOpts) {
+  return Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Expression->getSourceRange()), SM,
+      LangOpts);
+}
+
+static std::string getReplacement(const StringRef Function,
+                                  const StringRef Arg0, const StringRef Arg1,
+                                  const StringRef Arg2) {
+  return Function.str() + "(" + Arg0.str() + ", " + Arg1.str() + ", " +
+         Arg2.str() + ")";
+}
+
+static const CallExpr *getCallExpr(const MatchFinder::MatchResult &Result) {
+  if (const auto *MemcpyExpr = Result.Nodes.getNodeAs<CallExpr>("memcpy")) {
+    return MemcpyExpr;
+  } else if (const auto *MemmoveExpr =
+                 Result.Nodes.getNodeAs<CallExpr>("memmove")) {
+    return MemmoveExpr;
+  } else if (const auto *MemsetExpr =
+                 Result.Nodes.getNodeAs<CallExpr>("memset")) {
+    return MemsetExpr;
+  }
+  return nullptr;
+}
+
+UseAlgorithmCheck::UseAlgorithmCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+          Options.get("IncludeStyle", "llvm"))) {
+
+  for (const auto &KeyValue :
+       std::vector<std::pair<llvm::StringRef, std::string>>(
+           {{"memcpy", "std::copy"},
+            {"memmove", "std::move"},
+            {"memset", "std::fill"}})) {
+    Replacements.insert(KeyValue);
+  }
+}
+
+void UseAlgorithmCheck::registerMatchers(MatchFinder *Finder) {
+  // Only register the matchers for C++
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  // Match calls to memcpy with 3 arguments.
+  Finder->addMatcher(
+      callExpr(allOf(callee(functionDecl(matchesName("::memcpy"))),
+                     argumentCountIs(3)))
+          .bind("memcpy"),
+      this);
+
+  // Match calls to memmove with 3 arguments.
+  Finder->addMatcher(
+      callExpr(allOf(callee(functionDecl(matchesName("::memmove"))),
+                     argumentCountIs(3)))
+          .bind("memmove"),
+      this);
+
+  // Match calls to memset with 3 arguments.
+  Finder->addMatcher(
+      callExpr(allOf(callee(functionDecl(matchesName("::memset"))),
+                     argumentCountIs(3)))
+          .bind("memset"),
+      this);
+}
+
+void UseAlgorithmCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+  // Only register the preprocessor callbacks for C++; the functionality
+  // currently does not provide any benefit to other languages, despite being
+  // benign.
+  if (getLangOpts().CPlusPlus) {
+    Inserter = llvm::make_unique<utils::IncludeInserter>(
+        Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+    Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+  }
+}
+
+void UseAlgorithmCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *MatchedExpr = getCallExpr(Result);
+  const auto MatchedName = MatchedExpr->getDirectCallee()->getNameAsString();
+  const auto ReplacedName = Replacements[MatchedName];
+
+  const auto Loc = MatchedExpr->getExprLoc();
+  auto Diag = diag(Loc, "Use " + ReplacedName + " instead of " + MatchedName);
+
+  // Don't make replacements in macro.
+  if (Loc.isMacroID())
+    return;
+
+  const auto &SM = *Result.SourceManager;
+  const auto &LangOptions = Result.Context->getLangOpts();
+
+  StringRef Arg0Text = getText(MatchedExpr->getArg(0), SM, LangOptions);
+  StringRef Arg1Text = getText(MatchedExpr->getArg(1), SM, LangOptions);
+  StringRef Arg2Text = getText(MatchedExpr->getArg(2), SM, LangOptions);
+
+  std::string Insertion;
+  if (MatchedName == "memset") {
+    // Rearrangement of arguments for memset:
+    // (dest, ch, count) becomes (dest, dest + count, ch).
+    Insertion = getReplacement(ReplacedName, Arg0Text,
+                               (Arg0Text + " + " + Arg2Text).str(), Arg1Text);
+  } else {
+    // Rearrangement of arguments for memcpy and memmove:
+    // (dest, src, count) becomes (src, src + count, dest).
+    Insertion = getReplacement(ReplacedName, Arg1Text,
+                               (Arg1Text + " + " + Arg2Text).str(), Arg0Text);
+  }
+
+  Diag << FixItHint::CreateReplacement(MatchedExpr->getSourceRange(),
+                                       Insertion);
+
+  if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
+          Result.SourceManager->getFileID(Loc), "algorithm",
+          /*IsAngled=*/true)) {
+    Diag << *IncludeFixit;
+  }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/modernize/ModernizeTidyModule.cpp
===================================================================
--- clang-tidy/modernize/ModernizeTidyModule.cpp
+++ clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -22,6 +22,7 @@
 #include "ShrinkToFitCheck.h"
 #include "UseAutoCheck.h"
 #include "UseBoolLiteralsCheck.h"
+#include "UseAlgorithmCheck.h"
 #include "UseDefaultCheck.h"
 #include "UseEmplaceCheck.h"
 #include "UseNullptrCheck.h"
@@ -55,6 +56,8 @@
     CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
     CheckFactories.registerCheck<UseBoolLiteralsCheck>(
         "modernize-use-bool-literals");
+    CheckFactories.registerCheck<UseAlgorithmCheck>(
+        "modernize-use-algorithm");
     CheckFactories.registerCheck<UseDefaultCheck>("modernize-use-default");
     CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace");
     CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
Index: clang-tidy/modernize/CMakeLists.txt
===================================================================
--- clang-tidy/modernize/CMakeLists.txt
+++ clang-tidy/modernize/CMakeLists.txt
@@ -16,6 +16,7 @@
   ShrinkToFitCheck.cpp
   UseAutoCheck.cpp
   UseBoolLiteralsCheck.cpp
+  UseAlgorithmCheck.cpp
   UseDefaultCheck.cpp
   UseEmplaceCheck.cpp
   UseNullptrCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to