clang-tools 22.0.0git
ReplaceRandomShuffleCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
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
20 ClangTidyContext *Context)
21 : ClangTidyCheck(Name, Context),
22 IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
23 utils::IncludeSorter::IS_LLVM),
24 areDiagsSelfContained()) {}
25
27 const auto Begin = hasArgument(0, expr());
28 const auto End = hasArgument(1, expr());
29 const auto RandomFunc = hasArgument(2, expr().bind("randomFunc"));
30 Finder->addMatcher(
31 traverse(
32 TK_AsIs,
33 callExpr(
34 anyOf(allOf(Begin, End, argumentCountIs(2)),
35 allOf(Begin, End, RandomFunc, argumentCountIs(3))),
36 hasDeclaration(functionDecl(hasName("::std::random_shuffle"))),
37 has(implicitCastExpr(has(declRefExpr().bind("name")))))
38 .bind("match")),
39 this);
40}
41
43 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
44 IncludeInserter.registerPreprocessor(PP);
45}
46
49 Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
50}
51
52void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) {
53 const auto *MatchedDecl = Result.Nodes.getNodeAs<DeclRefExpr>("name");
54 const auto *MatchedArgumentThree = Result.Nodes.getNodeAs<Expr>("randomFunc");
55 const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("match");
56
57 if (MatchedCallExpr->getBeginLoc().isMacroID())
58 return;
59
60 auto Diag = [&] {
61 if (MatchedCallExpr->getNumArgs() == 3) {
62 auto DiagL =
63 diag(MatchedCallExpr->getBeginLoc(),
64 "'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(MatchedCallExpr->getBeginLoc(),
72 "'std::random_shuffle' has been removed in C++17; use "
73 "'std::shuffle' instead");
74 DiagL << FixItHint::CreateInsertion(
75 MatchedCallExpr->getRParenLoc(),
76 ", std::mt19937(std::random_device()())");
77 return DiagL;
78 }();
79
80 std::string NewName = "shuffle";
81 StringRef ContainerText = Lexer::getSourceText(
82 CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
83 *Result.SourceManager, getLangOpts());
84 if (ContainerText.starts_with("std::"))
85 NewName = "std::" + NewName;
86
87 Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange());
88 Diag << FixItHint::CreateInsertion(MatchedDecl->getBeginLoc(), NewName);
89 Diag << IncludeInserter.createIncludeInsertion(
90 Result.Context->getSourceManager().getFileID(
91 MatchedCallExpr->getBeginLoc()),
92 "<random>");
93}
94
95} // namespace clang::tidy::modernize
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
ReplaceRandomShuffleCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
llvm::StringMap< ClangTidyValue > OptionMap