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 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( "modernize-replace-auto-ptr"); + CheckFactories.registerCheck( + "modernize-replace-random-shuffle"); CheckFactories.registerCheck( "modernize-return-braced-init-list"); CheckFactories.registerCheck("modernize-shrink-to-fit"); 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 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( + 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("name"); + const auto *MatchedArgumentOne = Result.Nodes.getNodeAs("one"); + const auto *MatchedArgumentTwo = Result.Nodes.getNodeAs("two"); + const auto *MatchedCallExpr = Result.Nodes.getNodeAs("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: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -72,6 +72,11 @@ Finds uses of inline assembler. +- New `modernize-replace-random-shuffle + `_ check + + Finds and fixes usage of random_shuffle as the function has been removed from C++17. + - New `modernize-return-braced-init-list `_ check 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/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 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: 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 struct vec_iterator { + T *ptr; + vec_iterator operator++(int); +}; + +template struct vector { + typedef vec_iterator iterator; + + iterator begin(); + iterator end(); +}; + +template +void random_shuffle(FwIt begin, FwIt end); + +template +void random_shuffle(FwIt begin, FwIt end, randomFunc& randomfunc); + +template +void shuffle(FwIt begin, FwIt end); +} // namespace std + +// Random Func +int myrandom (int i) { return i;} + +int main() { + std::vector 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; +}