AST_MATCHER_P(FunctionDecl, throws, internal::Matcher<Type>, InnerMatcher) { TypeVec ExceptionList = throwsException(&Node); auto NewEnd = llvm::remove_if( ExceptionList, [this, Finder, Builder](const Type *Exception) { return !InnerMatcher.matches(*Exception, Finder, Builder); }); ExceptionList.erase(NewEnd, ExceptionList.end()); return ExceptionList.size(); }
static const TypeVec throwsException(const Stmt *St, const TypeVec &Caught, llvm::SmallSet<const FunctionDecl *, 32> &CallStack) { TypeVec Results; if (!St) return Results; if (const auto *Throw = dyn_cast<CXXThrowExpr>(St)) { if (const auto *ThrownExpr = Throw->getSubExpr()) { const auto *ThrownType = ThrownExpr->getType()->getUnqualifiedDesugaredType(); if (ThrownType->isReferenceType()) { ThrownType = ThrownType->castAs<ReferenceType>() ->getPointeeType() ->getUnqualifiedDesugaredType(); } if (const auto *TD = ThrownType->getAsTagDecl()) { if (TD->getDeclName().isIdentifier() && TD->getName() == "bad_alloc" && TD->isInStdNamespace()) return Results; } Results.push_back(ThrownExpr->getType()->getUnqualifiedDesugaredType()); } else { Results.append(Caught.begin(), Caught.end()); } } else if (const auto *Try = dyn_cast<CXXTryStmt>(St)) { TypeVec Uncaught = throwsException(Try->getTryBlock(), Caught, CallStack); for (unsigned i = 0; i < Try->getNumHandlers(); ++i) { const CXXCatchStmt *Catch = Try->getHandler(i); if (!Catch->getExceptionDecl()) { const TypeVec Rethrown = throwsException(Catch->getHandlerBlock(), Uncaught, CallStack); Results.append(Rethrown.begin(), Rethrown.end()); Uncaught.clear(); } else { const auto *CaughtType = Catch->getCaughtType()->getUnqualifiedDesugaredType(); if (CaughtType->isReferenceType()) { CaughtType = CaughtType->castAs<ReferenceType>() ->getPointeeType() ->getUnqualifiedDesugaredType(); } auto NewEnd = llvm::remove_if(Uncaught, [&CaughtType](const Type *ThrownType) { return ThrownType == CaughtType || isBaseOf(ThrownType, CaughtType); }); if (NewEnd != Uncaught.end()) { Uncaught.erase(NewEnd, Uncaught.end()); const TypeVec Rethrown = throwsException( Catch->getHandlerBlock(), TypeVec(1, CaughtType), CallStack); Results.append(Rethrown.begin(), Rethrown.end()); } } } Results.append(Uncaught.begin(), Uncaught.end()); } else if (const auto *Call = dyn_cast<CallExpr>(St)) { if (const FunctionDecl *Func = Call->getDirectCallee()) { TypeVec Excs = throwsException(Func, CallStack); Results.append(Excs.begin(), Excs.end()); } } else { for (const Stmt *Child : St->children()) { TypeVec Excs = throwsException(Child, Caught, CallStack); Results.append(Excs.begin(), Excs.end()); } } return Results; }