TriviallyDestructibleCheck.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. //===--- TriviallyDestructibleCheck.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 "TriviallyDestructibleCheck.h"
  9. #include "../utils/LexerUtils.h"
  10. #include "../utils/Matchers.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/ASTMatchers/ASTMatchFinder.h"
  13. using namespace clang::ast_matchers;
  14. using namespace clang::ast_matchers::internal;
  15. using namespace clang::tidy::matchers;
  16. namespace clang::tidy::performance {
  17. namespace {
  18. AST_MATCHER(Decl, isFirstDecl) { return Node.isFirstDecl(); }
  19. AST_MATCHER_P(CXXRecordDecl, hasBase, Matcher<QualType>, InnerMatcher) {
  20. for (const CXXBaseSpecifier &BaseSpec : Node.bases()) {
  21. QualType BaseType = BaseSpec.getType();
  22. if (InnerMatcher.matches(BaseType, Finder, Builder))
  23. return true;
  24. }
  25. return false;
  26. }
  27. } // namespace
  28. void TriviallyDestructibleCheck::registerMatchers(MatchFinder *Finder) {
  29. Finder->addMatcher(
  30. cxxDestructorDecl(
  31. isDefaulted(),
  32. unless(anyOf(isFirstDecl(), isVirtual(),
  33. ofClass(cxxRecordDecl(
  34. anyOf(hasBase(unless(isTriviallyDestructible())),
  35. has(fieldDecl(unless(
  36. hasType(isTriviallyDestructible()))))))))))
  37. .bind("decl"),
  38. this);
  39. }
  40. void TriviallyDestructibleCheck::check(const MatchFinder::MatchResult &Result) {
  41. const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXDestructorDecl>("decl");
  42. // Get locations of both first and out-of-line declarations.
  43. SourceManager &SM = *Result.SourceManager;
  44. const auto *FirstDecl = cast<CXXMethodDecl>(MatchedDecl->getFirstDecl());
  45. const SourceLocation FirstDeclEnd = utils::lexer::findNextTerminator(
  46. FirstDecl->getEndLoc(), SM, getLangOpts());
  47. const CharSourceRange SecondDeclRange = CharSourceRange::getTokenRange(
  48. MatchedDecl->getBeginLoc(),
  49. utils::lexer::findNextTerminator(MatchedDecl->getEndLoc(), SM,
  50. getLangOpts()));
  51. if (FirstDeclEnd.isInvalid() || SecondDeclRange.isInvalid())
  52. return;
  53. // Report diagnostic.
  54. diag(FirstDecl->getLocation(),
  55. "class %0 can be made trivially destructible by defaulting the "
  56. "destructor on its first declaration")
  57. << FirstDecl->getParent()
  58. << FixItHint::CreateInsertion(FirstDeclEnd, " = default")
  59. << FixItHint::CreateRemoval(SecondDeclRange);
  60. diag(MatchedDecl->getLocation(), "destructor definition is here",
  61. DiagnosticIDs::Note);
  62. }
  63. } // namespace clang::tidy::performance