1 //===--- UnhandledExceptionAtNewCheck.cpp - clang-tidy --------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "UnhandledExceptionAtNewCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::bugprone
{
17 AST_MATCHER_P(CXXTryStmt
, hasHandlerFor
,
18 ast_matchers::internal::Matcher
<QualType
>, InnerMatcher
) {
19 for (unsigned NH
= Node
.getNumHandlers(), I
= 0; I
< NH
; ++I
) {
20 const CXXCatchStmt
*CatchS
= Node
.getHandler(I
);
21 // Check for generic catch handler (match anything).
22 if (CatchS
->getCaughtType().isNull())
24 ast_matchers::internal::BoundNodesTreeBuilder
Result(*Builder
);
25 if (InnerMatcher
.matches(CatchS
->getCaughtType(), Finder
, &Result
)) {
26 *Builder
= std::move(Result
);
33 AST_MATCHER(CXXNewExpr
, mayThrow
) {
34 FunctionDecl
*OperatorNew
= Node
.getOperatorNew();
37 return !OperatorNew
->getType()->castAs
<FunctionProtoType
>()->isNothrow();
40 UnhandledExceptionAtNewCheck::UnhandledExceptionAtNewCheck(
41 StringRef Name
, ClangTidyContext
*Context
)
42 : ClangTidyCheck(Name
, Context
) {}
44 void UnhandledExceptionAtNewCheck::registerMatchers(MatchFinder
*Finder
) {
46 recordType(hasDeclaration(cxxRecordDecl(hasName("::std::bad_alloc"))));
48 recordType(hasDeclaration(cxxRecordDecl(hasName("::std::exception"))));
49 auto BadAllocReferenceType
= referenceType(pointee(BadAllocType
));
50 auto ExceptionReferenceType
= referenceType(pointee(ExceptionType
));
52 auto CatchBadAllocType
=
53 qualType(hasCanonicalType(anyOf(BadAllocType
, BadAllocReferenceType
,
54 ExceptionType
, ExceptionReferenceType
)));
55 auto BadAllocCatchingTryBlock
= cxxTryStmt(hasHandlerFor(CatchBadAllocType
));
57 auto FunctionMayNotThrow
= functionDecl(isNoThrow());
59 Finder
->addMatcher(cxxNewExpr(mayThrow(),
60 unless(hasAncestor(BadAllocCatchingTryBlock
)),
61 hasAncestor(FunctionMayNotThrow
))
66 void UnhandledExceptionAtNewCheck::check(
67 const MatchFinder::MatchResult
&Result
) {
68 const auto *MatchedExpr
= Result
.Nodes
.getNodeAs
<CXXNewExpr
>("new-expr");
70 diag(MatchedExpr
->getBeginLoc(),
71 "missing exception handler for allocation failure at 'new'");
74 } // namespace clang::tidy::bugprone