UseNoexceptCheck.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //===--- UseNoexceptCheck.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 "UseNoexceptCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/Lex/Lexer.h"
  11. using namespace clang::ast_matchers;
  12. namespace clang::tidy::modernize {
  13. namespace {
  14. AST_MATCHER(NamedDecl, isValid) { return !Node.isInvalidDecl(); }
  15. } // namespace
  16. UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context)
  17. : ClangTidyCheck(Name, Context),
  18. NoexceptMacro(Options.get("ReplacementString", "")),
  19. UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {}
  20. void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
  21. Options.store(Opts, "ReplacementString", NoexceptMacro);
  22. Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse);
  23. }
  24. void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) {
  25. Finder->addMatcher(
  26. functionDecl(
  27. isValid(),
  28. hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),
  29. optionally(cxxMethodDecl(anyOf(hasAnyOverloadedOperatorName(
  30. "delete[]", "delete"),
  31. cxxDestructorDecl()))
  32. .bind("del-dtor")))
  33. .bind("funcDecl"),
  34. this);
  35. Finder->addMatcher(
  36. parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType(
  37. functionProtoType(hasDynamicExceptionSpec())))))),
  38. hasType(memberPointerType(pointee(parenType(innerType(
  39. functionProtoType(hasDynamicExceptionSpec()))))))))
  40. .bind("parmVarDecl"),
  41. this);
  42. }
  43. void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) {
  44. const FunctionProtoType *FnTy = nullptr;
  45. bool DtorOrOperatorDel = false;
  46. SourceRange Range;
  47. if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {
  48. DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor");
  49. FnTy = FuncDecl->getType()->getAs<FunctionProtoType>();
  50. if (const auto *TSI = FuncDecl->getTypeSourceInfo())
  51. Range =
  52. TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange();
  53. } else if (const auto *ParmDecl =
  54. Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) {
  55. FnTy = ParmDecl->getType()
  56. ->castAs<Type>()
  57. ->getPointeeType()
  58. ->getAs<FunctionProtoType>();
  59. if (const auto *TSI = ParmDecl->getTypeSourceInfo())
  60. Range = TSI->getTypeLoc()
  61. .getNextTypeLoc()
  62. .IgnoreParens()
  63. .castAs<FunctionProtoTypeLoc>()
  64. .getExceptionSpecRange();
  65. }
  66. assert(FnTy && "FunctionProtoType is null.");
  67. if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType()))
  68. return;
  69. assert(Range.isValid() && "Exception Source Range is invalid.");
  70. CharSourceRange CRange = Lexer::makeFileCharRange(
  71. CharSourceRange::getTokenRange(Range), *Result.SourceManager,
  72. Result.Context->getLangOpts());
  73. bool IsNoThrow = FnTy->isNothrow();
  74. StringRef ReplacementStr =
  75. IsNoThrow ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro
  76. : NoexceptMacro.empty()
  77. ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" : ""
  78. : "";
  79. FixItHint FixIt;
  80. if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid())
  81. FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr);
  82. diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; "
  83. "consider %select{using '%2'|removing it}1 instead")
  84. << Lexer::getSourceText(CRange, *Result.SourceManager,
  85. Result.Context->getLangOpts())
  86. << ReplacementStr.empty() << ReplacementStr << FixIt;
  87. }
  88. } // namespace clang::tidy::modernize