//===--- TriviallyDestructibleCheck.cpp - clang-tidy ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "TriviallyDestructibleCheck.h" #include "../utils/LexerUtils.h" #include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; using namespace clang::ast_matchers::internal; using namespace clang::tidy::matchers; namespace clang { namespace tidy { namespace performance { namespace { AST_MATCHER(Decl, isFirstDecl) { return Node.isFirstDecl(); } AST_MATCHER_P(CXXRecordDecl, hasBase, Matcher, InnerMatcher) { for (const CXXBaseSpecifier &BaseSpec : Node.bases()) { QualType BaseType = BaseSpec.getType(); if (InnerMatcher.matches(BaseType, Finder, Builder)) return true; } return false; } } // namespace void TriviallyDestructibleCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( cxxDestructorDecl( isDefaulted(), unless(anyOf(isFirstDecl(), isVirtual(), ofClass(cxxRecordDecl( anyOf(hasBase(unless(isTriviallyDestructible())), has(fieldDecl(unless( hasType(isTriviallyDestructible())))))))))) .bind("decl"), this); } void TriviallyDestructibleCheck::check(const MatchFinder::MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs("decl"); // Get locations of both first and out-of-line declarations. SourceManager &SM = *Result.SourceManager; const auto *FirstDecl = cast(MatchedDecl->getFirstDecl()); const SourceLocation FirstDeclEnd = utils::lexer::findNextTerminator( FirstDecl->getEndLoc(), SM, getLangOpts()); const CharSourceRange SecondDeclRange = CharSourceRange::getTokenRange( MatchedDecl->getBeginLoc(), utils::lexer::findNextTerminator(MatchedDecl->getEndLoc(), SM, getLangOpts())); if (FirstDeclEnd.isInvalid() || SecondDeclRange.isInvalid()) return; // Report diagnostic. diag(FirstDecl->getLocation(), "class %0 can be made trivially destructible by defaulting the " "destructor on its first declaration") << FirstDecl->getParent() << FixItHint::CreateInsertion(FirstDeclEnd, " = default") << FixItHint::CreateRemoval(SecondDeclRange); diag(MatchedDecl->getLocation(), "destructor definition is here", DiagnosticIDs::Note); } } // namespace performance } // namespace tidy } // namespace clang