NoexceptMoveConstructorCheck.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. //===--- NoexceptMoveConstructorCheck.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 "NoexceptMoveConstructorCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Lex/Lexer.h"
  12. #include "clang/Tooling/FixIt.h"
  13. using namespace clang::ast_matchers;
  14. namespace clang::tidy::performance {
  15. void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
  16. Finder->addMatcher(
  17. cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")),
  18. unless(isImplicit()), unless(isDeleted()))
  19. .bind("decl"),
  20. this);
  21. }
  22. void NoexceptMoveConstructorCheck::check(
  23. const MatchFinder::MatchResult &Result) {
  24. if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
  25. bool IsConstructor = false;
  26. if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) {
  27. if (!Ctor->isMoveConstructor())
  28. return;
  29. IsConstructor = true;
  30. } else if (!Decl->isMoveAssignmentOperator()) {
  31. return;
  32. }
  33. const auto *ProtoType = Decl->getType()->castAs<FunctionProtoType>();
  34. if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType()))
  35. return;
  36. if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
  37. auto Diag = diag(Decl->getLocation(),
  38. "move %select{assignment operator|constructor}0s should "
  39. "be marked noexcept")
  40. << IsConstructor;
  41. // Add FixIt hints.
  42. SourceManager &SM = *Result.SourceManager;
  43. assert(Decl->getNumParams() > 0);
  44. SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1)
  45. ->getSourceRange()
  46. .getEnd();
  47. if (NoexceptLoc.isValid())
  48. NoexceptLoc = Lexer::findLocationAfterToken(
  49. NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
  50. if (NoexceptLoc.isValid())
  51. Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
  52. return;
  53. }
  54. // Don't complain about nothrow(false), but complain on nothrow(expr)
  55. // where expr evaluates to false.
  56. if (ProtoType->canThrow() == CT_Can) {
  57. Expr *E = ProtoType->getNoexceptExpr();
  58. E = E->IgnoreImplicit();
  59. if (!isa<CXXBoolLiteralExpr>(E)) {
  60. diag(E->getExprLoc(),
  61. "noexcept specifier on the move %select{assignment "
  62. "operator|constructor}0 evaluates to 'false'")
  63. << IsConstructor;
  64. }
  65. }
  66. }
  67. }
  68. } // namespace clang::tidy::performance