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