teak-llvm/clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.cpp
Anton Bikineev d36a033310 [clang-tidy] New checker performance-trivially-destructible-check
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
2019-11-01 16:16:49 +01:00

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