1//===--- ReplaceRandomShuffleCheck.cpp - clang-tidy------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "ReplaceRandomShuffleCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Frontend/CompilerInstance.h"
13#include "clang/Lex/Preprocessor.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::modernize {
18
19ReplaceRandomShuffleCheck::ReplaceRandomShuffleCheck(StringRef Name,
20 ClangTidyContext *Context)
21 : ClangTidyCheck(Name, Context),
22 IncludeInserter(Options.getLocalOrGlobal(LocalName: "IncludeStyle",
23 Default: utils::IncludeSorter::IS_LLVM),
24 areDiagsSelfContained()) {}
25
26void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder *Finder) {
27 const auto Begin = hasArgument(N: 0, InnerMatcher: expr());
28 const auto End = hasArgument(N: 1, InnerMatcher: expr());
29 const auto RandomFunc = hasArgument(N: 2, InnerMatcher: expr().bind(ID: "randomFunc"));
30 Finder->addMatcher(
31 NodeMatch: traverse(
32 TK: TK_AsIs,
33 InnerMatcher: callExpr(
34 anyOf(allOf(Begin, End, argumentCountIs(N: 2)),
35 allOf(Begin, End, RandomFunc, argumentCountIs(N: 3))),
36 hasDeclaration(InnerMatcher: functionDecl(hasName(Name: "::std::random_shuffle"))),
37 has(implicitCastExpr(has(declRefExpr().bind(ID: "name")))))
38 .bind(ID: "match")),
39 Action: this);
40}
41
42void ReplaceRandomShuffleCheck::registerPPCallbacks(
43 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
44 IncludeInserter.registerPreprocessor(PP);
45}
46
47void ReplaceRandomShuffleCheck::storeOptions(
48 ClangTidyOptions::OptionMap &Opts) {
49 Options.store(Options&: Opts, LocalName: "IncludeStyle", Value: IncludeInserter.getStyle());
50}
51
52void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) {
53 const auto *MatchedDecl = Result.Nodes.getNodeAs<DeclRefExpr>(ID: "name");
54 const auto *MatchedArgumentThree = Result.Nodes.getNodeAs<Expr>(ID: "randomFunc");
55 const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>(ID: "match");
56
57 if (MatchedCallExpr->getBeginLoc().isMacroID())
58 return;
59
60 auto Diag = [&] {
61 if (MatchedCallExpr->getNumArgs() == 3) {
62 auto DiagL =
63 diag(Loc: MatchedCallExpr->getBeginLoc(),
64 Description: "'std::random_shuffle' has been removed in C++17; use "
65 "'std::shuffle' and an alternative random mechanism instead");
66 DiagL << FixItHint::CreateReplacement(
67 MatchedArgumentThree->getSourceRange(),
68 "std::mt19937(std::random_device()())");
69 return DiagL;
70 }
71 auto DiagL = diag(Loc: MatchedCallExpr->getBeginLoc(),
72 Description: "'std::random_shuffle' has been removed in C++17; use "
73 "'std::shuffle' instead");
74 DiagL << FixItHint::CreateInsertion(
75 InsertionLoc: MatchedCallExpr->getRParenLoc(),
76 Code: ", std::mt19937(std::random_device()())");
77 return DiagL;
78 }();
79
80 std::string NewName = "shuffle";
81 StringRef ContainerText = Lexer::getSourceText(
82 Range: CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
83 SM: *Result.SourceManager, LangOpts: getLangOpts());
84 if (ContainerText.starts_with(Prefix: "std::"))
85 NewName = "std::" + NewName;
86
87 Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange());
88 Diag << FixItHint::CreateInsertion(InsertionLoc: MatchedDecl->getBeginLoc(), Code: NewName);
89 Diag << IncludeInserter.createIncludeInsertion(
90 FileID: Result.Context->getSourceManager().getFileID(
91 SpellingLoc: MatchedCallExpr->getBeginLoc()),
92 Header: "<random>");
93}
94
95} // namespace clang::tidy::modernize
96

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp