ReplaceRandomShuffleCheck.cpp 3.8 KB

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