96 lines · cpp
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-exception6//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("IncludeStyle",23 utils::IncludeSorter::IS_LLVM),24 areDiagsSelfContained()) {}25 26void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder *Finder) {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 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(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 const 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::modernize96