1 //===--- ReplaceRandomShuffleCheck.cpp - clang-tidy------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ReplaceRandomShuffleCheck.h"
10 #include "../utils/FixItHintUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Lex/Preprocessor.h"
15 #include "clang/Tooling/FixIt.h"
17 using namespace clang::ast_matchers
;
23 ReplaceRandomShuffleCheck::ReplaceRandomShuffleCheck(StringRef Name
,
24 ClangTidyContext
*Context
)
25 : ClangTidyCheck(Name
, Context
),
26 IncludeInserter(Options
.getLocalOrGlobal("IncludeStyle",
27 utils::IncludeSorter::IS_LLVM
),
28 areDiagsSelfContained()) {}
30 void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder
*Finder
) {
31 const auto Begin
= hasArgument(0, expr());
32 const auto End
= hasArgument(1, expr());
33 const auto RandomFunc
= hasArgument(2, expr().bind("randomFunc"));
38 anyOf(allOf(Begin
, End
, argumentCountIs(2)),
39 allOf(Begin
, End
, RandomFunc
, argumentCountIs(3))),
40 hasDeclaration(functionDecl(hasName("::std::random_shuffle"))),
41 has(implicitCastExpr(has(declRefExpr().bind("name")))))
46 void ReplaceRandomShuffleCheck::registerPPCallbacks(
47 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
48 IncludeInserter
.registerPreprocessor(PP
);
51 void ReplaceRandomShuffleCheck::storeOptions(
52 ClangTidyOptions::OptionMap
&Opts
) {
53 Options
.store(Opts
, "IncludeStyle", IncludeInserter
.getStyle());
56 void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult
&Result
) {
57 const auto *MatchedDecl
= Result
.Nodes
.getNodeAs
<DeclRefExpr
>("name");
58 const auto *MatchedArgumentThree
= Result
.Nodes
.getNodeAs
<Expr
>("randomFunc");
59 const auto *MatchedCallExpr
= Result
.Nodes
.getNodeAs
<CallExpr
>("match");
61 if (MatchedCallExpr
->getBeginLoc().isMacroID())
65 if (MatchedCallExpr
->getNumArgs() == 3) {
67 diag(MatchedCallExpr
->getBeginLoc(),
68 "'std::random_shuffle' has been removed in C++17; use "
69 "'std::shuffle' and an alternative random mechanism instead");
70 DiagL
<< FixItHint::CreateReplacement(
71 MatchedArgumentThree
->getSourceRange(),
72 "std::mt19937(std::random_device()())");
75 auto DiagL
= diag(MatchedCallExpr
->getBeginLoc(),
76 "'std::random_shuffle' has been removed in C++17; use "
77 "'std::shuffle' instead");
78 DiagL
<< FixItHint::CreateInsertion(
79 MatchedCallExpr
->getRParenLoc(),
80 ", std::mt19937(std::random_device()())");
84 std::string NewName
= "shuffle";
85 StringRef ContainerText
= Lexer::getSourceText(
86 CharSourceRange::getTokenRange(MatchedDecl
->getSourceRange()),
87 *Result
.SourceManager
, getLangOpts());
88 if (ContainerText
.startswith("std::"))
89 NewName
= "std::" + NewName
;
91 Diag
<< FixItHint::CreateRemoval(MatchedDecl
->getSourceRange());
92 Diag
<< FixItHint::CreateInsertion(MatchedDecl
->getBeginLoc(), NewName
);
93 Diag
<< IncludeInserter
.createIncludeInsertion(
94 Result
.Context
->getSourceManager().getFileID(
95 MatchedCallExpr
->getBeginLoc()),
99 } // namespace modernize