llvm-project
76 строк · 2.9 Кб
1//===--- UndelegatedConstructorCheck.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
9#include "UndelegatedConstructorCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/Lex/Lexer.h"12
13using namespace clang::ast_matchers;14
15namespace clang::tidy::bugprone {16
17namespace {18AST_MATCHER_P(Stmt, ignoringTemporaryExpr,19ast_matchers::internal::Matcher<Stmt>, InnerMatcher) {20const Stmt *E = &Node;21for (;;) {22// Temporaries with non-trivial dtors.23if (const auto *EWC = dyn_cast<ExprWithCleanups>(E))24E = EWC->getSubExpr();25// Temporaries with zero or more than two ctor arguments.26else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))27E = BTE->getSubExpr();28// Temporaries with exactly one ctor argument.29else if (const auto *FCE = dyn_cast<CXXFunctionalCastExpr>(E))30E = FCE->getSubExpr();31else32break;33}34
35return InnerMatcher.matches(*E, Finder, Builder);36}
37
38// Finds a node if it's a base of an already bound node.
39AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) {40return Builder->removeBindings(41[&](const ast_matchers::internal::BoundNodesMap &Nodes) {42const auto *Derived = Nodes.getNodeAs<CXXRecordDecl>(ID);43return Derived != &Node && !Derived->isDerivedFrom(&Node);44});45}
46} // namespace47
48void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) {49// We look for calls to constructors of the same type in constructors. To do50// this we have to look through a variety of nodes that occur in the path,51// depending on the type's destructor and the number of arguments on the52// constructor call, this is handled by ignoringTemporaryExpr. Ignore template53// instantiations to reduce the number of duplicated warnings.54
55Finder->addMatcher(56traverse(57TK_AsIs,58compoundStmt(hasParent(cxxConstructorDecl(59ofClass(cxxRecordDecl().bind("parent")))),60forEach(ignoringTemporaryExpr(61cxxConstructExpr(62hasDeclaration(cxxConstructorDecl(ofClass(63cxxRecordDecl(baseOfBoundNode("parent"))))))64.bind("construct"))),65unless(isInTemplateInstantiation()))),66this);67}
68
69void UndelegatedConstructorCheck::check(70const MatchFinder::MatchResult &Result) {71const auto *E = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");72diag(E->getBeginLoc(), "did you intend to call a delegated constructor? "73"A temporary object is created here instead");74}
75
76} // namespace clang::tidy::bugprone77