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
;
19 namespace clang::tidy::modernize
{
21 ReplaceRandomShuffleCheck::ReplaceRandomShuffleCheck(StringRef Name
,
22 ClangTidyContext
*Context
)
23 : ClangTidyCheck(Name
, Context
),
24 IncludeInserter(Options
.getLocalOrGlobal("IncludeStyle",
25 utils::IncludeSorter::IS_LLVM
),
26 areDiagsSelfContained()) {}
28 void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder
*Finder
) {
29 const auto Begin
= hasArgument(0, expr());
30 const auto End
= hasArgument(1, expr());
31 const auto RandomFunc
= hasArgument(2, expr().bind("randomFunc"));
36 anyOf(allOf(Begin
, End
, argumentCountIs(2)),
37 allOf(Begin
, End
, RandomFunc
, argumentCountIs(3))),
38 hasDeclaration(functionDecl(hasName("::std::random_shuffle"))),
39 has(implicitCastExpr(has(declRefExpr().bind("name")))))
44 void ReplaceRandomShuffleCheck::registerPPCallbacks(
45 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
46 IncludeInserter
.registerPreprocessor(PP
);
49 void ReplaceRandomShuffleCheck::storeOptions(
50 ClangTidyOptions::OptionMap
&Opts
) {
51 Options
.store(Opts
, "IncludeStyle", IncludeInserter
.getStyle());
54 void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult
&Result
) {
55 const auto *MatchedDecl
= Result
.Nodes
.getNodeAs
<DeclRefExpr
>("name");
56 const auto *MatchedArgumentThree
= Result
.Nodes
.getNodeAs
<Expr
>("randomFunc");
57 const auto *MatchedCallExpr
= Result
.Nodes
.getNodeAs
<CallExpr
>("match");
59 if (MatchedCallExpr
->getBeginLoc().isMacroID())
63 if (MatchedCallExpr
->getNumArgs() == 3) {
65 diag(MatchedCallExpr
->getBeginLoc(),
66 "'std::random_shuffle' has been removed in C++17; use "
67 "'std::shuffle' and an alternative random mechanism instead");
68 DiagL
<< FixItHint::CreateReplacement(
69 MatchedArgumentThree
->getSourceRange(),
70 "std::mt19937(std::random_device()())");
73 auto DiagL
= diag(MatchedCallExpr
->getBeginLoc(),
74 "'std::random_shuffle' has been removed in C++17; use "
75 "'std::shuffle' instead");
76 DiagL
<< FixItHint::CreateInsertion(
77 MatchedCallExpr
->getRParenLoc(),
78 ", std::mt19937(std::random_device()())");
82 std::string NewName
= "shuffle";
83 StringRef ContainerText
= Lexer::getSourceText(
84 CharSourceRange::getTokenRange(MatchedDecl
->getSourceRange()),
85 *Result
.SourceManager
, getLangOpts());
86 if (ContainerText
.startswith("std::"))
87 NewName
= "std::" + NewName
;
89 Diag
<< FixItHint::CreateRemoval(MatchedDecl
->getSourceRange());
90 Diag
<< FixItHint::CreateInsertion(MatchedDecl
->getBeginLoc(), NewName
);
91 Diag
<< IncludeInserter
.createIncludeInsertion(
92 Result
.Context
->getSourceManager().getFileID(
93 MatchedCallExpr
->getBeginLoc()),
97 } // namespace clang::tidy::modernize