[clang-tidy] New check: modernize-replace-random-shuffle.

This check will find occurrences of ``std::random_shuffle`` and replace it with ``std::shuffle``. In C++17 ``std::random_shuffle`` will no longer be available and thus we need to replace it.

Example of case that it fixes

```
  std::vector<int> v;

  // First example
  std::random_shuffle(vec.begin(), vec.end());

```

Reviewers: hokein, aaron.ballman, alexfh, malcolm.parsons, mclow.lists

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D30158

llvm-svn: 301167
This commit is contained in:
Mads Ravn 2017-04-24 09:27:20 +00:00
parent f53865daa4
commit a301498783
8 changed files with 246 additions and 0 deletions

View File

@ -13,6 +13,7 @@ add_clang_library(clangTidyModernizeModule
RawStringLiteralCheck.cpp
RedundantVoidArgCheck.cpp
ReplaceAutoPtrCheck.cpp
ReplaceRandomShuffleCheck.cpp
ReturnBracedInitListCheck.cpp
ShrinkToFitCheck.cpp
UseAutoCheck.cpp

View File

@ -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 @@ public:
"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");

View File

@ -0,0 +1,109 @@
//===--- 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 {
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;
const auto Begin = hasArgument(0, expr());
const auto End = hasArgument(1, expr());
const auto RandomFunc = hasArgument(2, expr().bind("randomFunc"));
Finder->addMatcher(
callExpr(anyOf(allOf(Begin, End, argumentCountIs(2)),
allOf(Begin, End, RandomFunc, argumentCountIs(3))),
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));
}
void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedDecl = Result.Nodes.getNodeAs<DeclRefExpr>("name");
const auto *MatchedArgumentThree = Result.Nodes.getNodeAs<Expr>("randomFunc");
const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("match");
if (MatchedCallExpr->getLocStart().isMacroID())
return;
auto Diag = [&] {
if (MatchedCallExpr->getNumArgs() == 3) {
auto DiagL =
diag(MatchedCallExpr->getLocStart(),
"'std::random_shuffle' has been removed in C++17; use "
"'std::shuffle' and an alternative random mechanism instead");
DiagL << FixItHint::CreateReplacement(
MatchedArgumentThree->getSourceRange(),
"std::mt19937(std::random_device()())");
return DiagL;
} else {
auto DiagL = diag(MatchedCallExpr->getLocStart(),
"'std::random_shuffle' has been removed in C++17; use "
"'std::shuffle' instead");
DiagL << FixItHint::CreateInsertion(
MatchedCallExpr->getRParenLoc(),
", std::mt19937(std::random_device()())");
return DiagL;
}
}();
std::string NewName = "shuffle";
StringRef ContainerText = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, getLangOpts());
if (ContainerText.startswith("std::"))
NewName = "std::" + NewName;
Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange());
Diag << FixItHint::CreateInsertion(MatchedDecl->getLocStart(), NewName);
if (Optional<FixItHint> IncludeFixit =
IncludeInserter->CreateIncludeInsertion(
Result.Context->getSourceManager().getFileID(
MatchedCallExpr->getLocStart()),
"random", /*IsAngled=*/true))
Diag << IncludeFixit.getValue();
}
} // namespace modernize
} // namespace tidy
} // namespace clang

View File

@ -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 occurrences 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

View File

@ -81,6 +81,11 @@ Improvements to clang-tidy
Adds checks that implement the `High Integrity C++ Coding Standard <http://www.codingstandard.com/section/index/>`_ and other safety
standards. Many checks are aliased to other modules.
- New `modernize-replace-random-shuffle
<http://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html>`_ check
Finds and fixes usage of ``std::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

View File

@ -124,6 +124,7 @@ Clang-Tidy Checks
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

View File

@ -0,0 +1,28 @@
.. title:: clang-tidy - modernize-replace-random-shuffle
modernize-replace-random-shuffle
================================
This check will find occurrences of ``std::random_shuffle`` and replace it with ``std::shuffle``. In C++17 ``std::random_shuffle`` will no longer be available and thus we need to replace it.
Below are two examples of what kind of occurrences 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 of 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``.
One thing to be aware of here is that ``std::random_device`` is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere.

View File

@ -0,0 +1,57 @@
// RUN: %check_clang_tidy %s modernize-replace-random-shuffle %t -- -- -std=c++11
//CHECK-FIXES: #include <random>
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;}
using namespace std;
int main() {
std::vector<int> vec;
std::random_shuffle(vec.begin(), vec.end());
// CHECK-MESSAGE: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
// CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
std::shuffle(vec.begin(), vec.end());
random_shuffle(vec.begin(), vec.end());
// CHECK-MESSAGE: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
// CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
std::random_shuffle(vec.begin(), vec.end(), myrandom);
// CHECK-MESSAGE: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
// CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
random_shuffle(vec.begin(), vec.end(), myrandom);
// CHECK-MESSAGE: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
// CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
shuffle(vec.begin(), vec.end());
return 0;
}