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