mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 03:25:54 -04:00

Checks for types which can be made trivially-destructible by removing out-of-line defaulted destructor declarations. The check is motivated by the work on C++ garbage collector in Blink (rendering engine for Chrome), which strives to minimize destructors and improve runtime of sweeping phase. In the entire chromium codebase the check hits over 2000 times. Differential Revision: https://reviews.llvm.org/D69435
83 lines
2.8 KiB
C++
83 lines
2.8 KiB
C++
//===--- 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<QualType>, 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) {
|
|
if (!getLangOpts().CPlusPlus11)
|
|
return;
|
|
|
|
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<CXXDestructorDecl>("decl");
|
|
|
|
// Get locations of both first and out-of-line declarations.
|
|
SourceManager &SM = *Result.SourceManager;
|
|
const auto *FirstDecl = cast<CXXMethodDecl>(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
|