madsravn created this revision.
Herald added subscribers: JDevlieghere, mgorny.

random_shuffle was deprecated by C++14 and will be removed by C++17. This check 
will find and replace usage of random_shuffle with its modern counterpart 
(shuffle).


https://reviews.llvm.org/D30158

Files:
  clang-tidy/modernize/CMakeLists.txt
  clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
  clang-tidy/modernize/ReplaceRandomShuffleCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
  test/clang-tidy/modernize-replace-random-shuffle.cpp

Index: test/clang-tidy/modernize-replace-random-shuffle.cpp
===================================================================
--- test/clang-tidy/modernize-replace-random-shuffle.cpp
+++ test/clang-tidy/modernize-replace-random-shuffle.cpp
@@ -0,0 +1,55 @@
+// RUN: %check_clang_tidy %s modernize-replace-random-shuffle %t -- -- -std=c++11
+
+namespace std {
+template <typename T> struct vec_iterator {
+  T *ptr;
+  vec_iterator operator++(int);
+};
+
+template <typename T> struct vector {
+  typedef vec_iterator<T> iterator;
+
+  iterator begin();
+  iterator end();
+};
+
+template <typename FwIt>
+void random_shuffle(FwIt begin, FwIt end);
+
+template <typename FwIt, typename randomFunc>
+void random_shuffle(FwIt begin, FwIt end, randomFunc& randomfunc);
+
+template <typename FwIt>
+void shuffle(FwIt begin, FwIt end);
+} // namespace std
+
+// Random Func
+int myrandom (int i) { return i;}
+
+int main() {
+  std::vector<int> vec;
+
+  std::random_shuffle(vec.begin(), vec.end());
+  // CHECK-MESSAGE: [[@LINE-1]]:3: warning: do not use 'random_shuffle'. It is deprecated and replaced by 'shuffle'
+  // CHECK-FIXES: std::shuffle(vec.begin(), vec.begin(), std::mt19937(std::random_device()()));
+
+  std::random_shuffle(vec.begin(), vec.end(), myrandom);
+  // CHECK-MESSAGE: [[@LINE-1]]:3: warning: do not use 'random_shuffle'. It is deprecated and replaced by 'shuffle'. The old user defined 'RandomFunction' is not usable for shuffle. You need to make additional changes if you want a specific random function
+  // CHECK-FIXES: std::shuffle(vec.begin(), vec.begin(), std::mt19937(std::random_device()()));
+
+  std::shuffle(vec.begin(), vec.end());
+
+  using namespace std;
+
+  random_shuffle(vec.begin(), vec.end());
+  // CHECK-MESSAGE: [[@LINE-1]]:3: warning: do not use 'random_shuffle'. It is deprecated and replaced by 'shuffle'
+  // CHECK-FIXES: shuffle(vec.begin(), vec.begin(), std::mt19937(std::random_device()()));
+
+  random_shuffle(vec.begin(), vec.end(), myrandom);
+  // CHECK-MESSAGE: [[@LINE-1]]:3: warning: do not use 'random_shuffle'. It is deprecated and replaced by 'shuffle'. The old user defined 'RandomFunction' is not usable for shuffle. You need to make additional changes if you want a specific random function
+  // CHECK-FIXES: shuffle(vec.begin(), vec.begin(), std::mt19937(std::random_device()()));
+
+  shuffle(vec.begin(), vec.end());
+
+  return 0;
+}
Index: docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
===================================================================
--- docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
+++ docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - modernize-replace-random-shuffle
+
+modernize-replace-random-shuffle
+================================
+
+This check will find occurences of ``random_shuffle`` and replace it with ``shuffle``. In C++17 ``random_shuffle`` will no longer be available and thus we need to replace it.
+
+Below is two examples of what kind of occurences will be found and two examples of what it will be replaced with.
+
+.. code-block:: c++
+
+  std::vector<int> v;
+
+  // First example
+  std::random_shuffle(vec.begin(), vec.end());
+
+  // Second example
+  std::random_shuffle(vec.begin(), vec.end(), randomFun);
+
+Both these examples will be replaced with
+
+.. code-block:: c++
+
+  std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+The second example will also receive a warning that ``randomFunc`` is no longer supported in the same way as before so if the user wants the same functionality, the user will need to change the implementation of the ``randomFunc``.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -110,6 +110,7 @@
    modernize-raw-string-literal
    modernize-redundant-void-arg
    modernize-replace-auto-ptr
+   modernize-replace-random-shuffle
    modernize-return-braced-init-list
    modernize-shrink-to-fit
    modernize-use-auto
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -72,6 +72,11 @@
 
   Finds uses of inline assembler.
 
+- New `modernize-replace-random-shuffle
+  <http://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html>`_ check
+
+  Finds and fixes usage of random_shuffle as the function has been removed from C++17.
+
 - New `modernize-return-braced-init-list
   <http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html>`_ check
 
Index: clang-tidy/modernize/ReplaceRandomShuffleCheck.h
===================================================================
--- clang-tidy/modernize/ReplaceRandomShuffleCheck.h
+++ clang-tidy/modernize/ReplaceRandomShuffleCheck.h
@@ -0,0 +1,42 @@
+//===--- ReplaceRandomShuffleCheck.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_REPLACE_RANDOM_SHUFFLE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_RANDOM_SHUFFLE_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// std::random_shuffle will be removed as of C++17. This check will find and
+/// replace all occurences of std::random_shuffle with std::shuffle.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
+class ReplaceRandomShuffleCheck : public ClangTidyCheck {
+public:
+  ReplaceRandomShuffleCheck(StringRef Name, ClangTidyContext *Context);
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::unique_ptr<utils::IncludeInserter> IncludeInserter;
+  const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_RANDOM_SHUFFLE_H
Index: clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
===================================================================
--- clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
+++ clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
@@ -0,0 +1,116 @@
+//===--- ReplaceRandomShuffleCheck.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 "ReplaceRandomShuffleCheck.h"
+#include "../utils/FixItHintUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static const StringRef ReplaceMessage =
+    "do not use 'random_shuffle'. "
+    "It is deprecated and replaced by 'shuffle'.";
+
+static const StringRef RandomFunctionMessage =
+    " The old user defined 'RandomFunction' is not usable for 'shuffle'. You "
+    "need to "
+    "make additional changes if you want a specific random function.";
+
+ReplaceRandomShuffleCheck::ReplaceRandomShuffleCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+          Options.get("IncludeStyle", "llvm"))) {}
+
+void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus11)
+    return;
+
+  Finder->addMatcher(
+      callExpr(hasArgument(0, expr().bind("one")),
+               hasArgument(1, expr().bind("two")),
+               hasDeclaration(functionDecl(hasName("::std::random_shuffle"))),
+               has(implicitCastExpr(has(declRefExpr().bind("name")))))
+          .bind("match"),
+      this);
+}
+
+void ReplaceRandomShuffleCheck::registerPPCallbacks(
+    CompilerInstance &Compiler) {
+  IncludeInserter = llvm::make_unique<utils::IncludeInserter>(
+      Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+  Compiler.getPreprocessor().addPPCallbacks(
+      IncludeInserter->CreatePPCallbacks());
+}
+
+void ReplaceRandomShuffleCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IncludeStyle",
+                utils::IncludeSorter::toString(IncludeStyle));
+}
+
+static bool StartsWithString(const DeclRefExpr *DRef, StringRef Str,
+                             const ASTContext &Ctx) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  DRef->printPretty(Stream, nullptr, Ctx.getPrintingPolicy());
+  StringRef StrRef(Stream.str());
+  return StrRef.startswith(Str);
+}
+
+static void FormatFixit(const Expr *FirstArgument, const Expr *SecondArgument,
+                        const DeclRefExpr *DRef, llvm::raw_ostream &Stream,
+                        const ASTContext &Ctx) {
+  if (StartsWithString(DRef, "std::", Ctx))
+    Stream << "std::";
+  Stream << "shuffle(";
+  FirstArgument->printPretty(Stream, nullptr, Ctx.getPrintingPolicy());
+  Stream << ", ";
+  FirstArgument->printPretty(Stream, nullptr, Ctx.getPrintingPolicy());
+  Stream << ", std::mt19937(std::random_device()()))";
+}
+
+void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Ctx = *Result.Context;
+  const auto *MatchedDecl = Result.Nodes.getNodeAs<DeclRefExpr>("name");
+  const auto *MatchedArgumentOne = Result.Nodes.getNodeAs<Expr>("one");
+  const auto *MatchedArgumentTwo = Result.Nodes.getNodeAs<Expr>("two");
+  const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("match");
+
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  std::string Message = ReplaceMessage;
+
+  if (MatchedCallExpr->getNumArgs() == 3)
+    Message += RandomFunctionMessage;
+
+  auto Diag = diag(MatchedCallExpr->getLocStart(), Message);
+  Diag << FixItHint::CreateRemoval(MatchedCallExpr->getSourceRange());
+  FormatFixit(MatchedArgumentOne, MatchedArgumentTwo, MatchedDecl, Stream, Ctx);
+  Diag << FixItHint::CreateInsertion(MatchedCallExpr->getLocStart(),
+                                     Stream.str());
+
+  if (auto IncludeFixit = IncludeInserter->CreateIncludeInsertion(
+          Result.Context->getSourceManager().getFileID(
+              MatchedCallExpr->getLocStart()),
+          "random", /*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
@@ -19,6 +19,7 @@
 #include "RawStringLiteralCheck.h"
 #include "RedundantVoidArgCheck.h"
 #include "ReplaceAutoPtrCheck.h"
+#include "ReplaceRandomShuffleCheck.h"
 #include "ReturnBracedInitListCheck.h"
 #include "ShrinkToFitCheck.h"
 #include "UseAutoCheck.h"
@@ -54,6 +55,8 @@
         "modernize-redundant-void-arg");
     CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
         "modernize-replace-auto-ptr");
+    CheckFactories.registerCheck<ReplaceRandomShuffleCheck>(
+        "modernize-replace-random-shuffle");
     CheckFactories.registerCheck<ReturnBracedInitListCheck>(
         "modernize-return-braced-init-list");
     CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
Index: clang-tidy/modernize/CMakeLists.txt
===================================================================
--- clang-tidy/modernize/CMakeLists.txt
+++ clang-tidy/modernize/CMakeLists.txt
@@ -13,6 +13,7 @@
   RawStringLiteralCheck.cpp
   RedundantVoidArgCheck.cpp
   ReplaceAutoPtrCheck.cpp
+  ReplaceRandomShuffleCheck.cpp
   ReturnBracedInitListCheck.cpp
   ShrinkToFitCheck.cpp
   UseAutoCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to