clang-tools 24.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 const auto Diag = [&] {
61 if (MatchedCallExpr->getNumArgs() == 3) {
62 const 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 const auto DiagL =
72 diag(MatchedCallExpr->getBeginLoc(),
73 "'std::random_shuffle' has been removed in C++17; use "
74 "'std::shuffle' instead");
75 DiagL << FixItHint::CreateInsertion(
76 MatchedCallExpr->getRParenLoc(),
77 ", std::mt19937(std::random_device()())");
78 return DiagL;
79 }();
80
81 std::string NewName = "shuffle";
82 const StringRef ContainerText = Lexer::getSourceText(
83 CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
84 *Result.SourceManager, getLangOpts());
85 if (ContainerText.starts_with("std::"))
86 NewName = "std::" + NewName;
87
88 Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange());
89 Diag << FixItHint::CreateInsertion(MatchedDecl->getBeginLoc(), NewName);
90 Diag << IncludeInserter.createIncludeInsertion(
91 Result.Context->getSourceManager().getFileID(
92 MatchedCallExpr->getBeginLoc()),
93 "<random>");
94}
95
96} // 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