14 const Type *ExceptionType) {
15 assert(ExceptionType !=
nullptr &&
"Only valid types are accepted");
17 ThrownExceptions.insert(ExceptionType);
22 if (Exceptions.size() == 0)
25 ThrownExceptions.insert(Exceptions.begin(), Exceptions.end());
41 ContainsUnknown = ContainsUnknown || Other.ContainsUnknown;
42 ThrownExceptions.insert(Other.ThrownExceptions.begin(),
43 Other.ThrownExceptions.end());
47 static bool isBaseOf(
const Type *DerivedType,
const Type *BaseType) {
48 const auto *DerivedClass = DerivedType->getAsCXXRecordDecl();
49 const auto *BaseClass = BaseType->getAsCXXRecordDecl();
50 if (!DerivedClass || !BaseClass)
53 return !DerivedClass->forallBases(
54 [BaseClass](
const CXXRecordDecl *Cur) {
return Cur != BaseClass; });
58 llvm::SmallVector<const Type *, 8> TypesToDelete;
59 for (
const Type *T : ThrownExceptions) {
60 if (T == BaseClass ||
isBaseOf(T, BaseClass))
61 TypesToDelete.push_back(T);
64 for (
const Type *T : TypesToDelete)
65 ThrownExceptions.erase(T);
67 reevaluateBehaviour();
68 return TypesToDelete.size() > 0;
73 const llvm::StringSet<> &IgnoredTypes,
bool IgnoreBadAlloc) {
74 llvm::SmallVector<const Type *, 8> TypesToDelete;
77 for (
const Type *T : ThrownExceptions) {
78 if (
const auto *TD = T->getAsTagDecl()) {
79 if (TD->getDeclName().isIdentifier()) {
80 if ((IgnoreBadAlloc &&
81 (TD->getName() ==
"bad_alloc" && TD->isInStdNamespace())) ||
82 (IgnoredTypes.count(TD->getName()) > 0))
83 TypesToDelete.push_back(T);
87 for (
const Type *T : TypesToDelete)
88 ThrownExceptions.erase(T);
90 reevaluateBehaviour();
96 ContainsUnknown =
false;
97 ThrownExceptions.clear();
100 void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
101 if (ThrownExceptions.size() == 0)
111 const FunctionDecl *Func,
112 llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
113 if (CallStack.count(Func))
116 if (
const Stmt *Body = Func->getBody()) {
117 CallStack.insert(Func);
118 ExceptionInfo Result =
122 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(Func)) {
123 for (
const CXXCtorInitializer *Init : Ctor->inits()) {
124 ExceptionInfo Excs = throwsException(
130 CallStack.erase(Func);
135 if (
const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
136 for (
const QualType &Ex : FPT->exceptions())
137 Result.registerException(Ex.getTypePtr());
144 ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
146 llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
151 if (
const auto *Throw = dyn_cast<CXXThrowExpr>(St)) {
152 if (
const auto *ThrownExpr = Throw->getSubExpr()) {
153 const auto *ThrownType =
154 ThrownExpr->getType()->getUnqualifiedDesugaredType();
155 if (ThrownType->isReferenceType())
156 ThrownType = ThrownType->castAs<ReferenceType>()
158 ->getUnqualifiedDesugaredType();
160 ThrownExpr->getType()->getUnqualifiedDesugaredType());
165 Results.registerExceptions(Caught);
166 }
else if (
const auto *Try = dyn_cast<CXXTryStmt>(St)) {
167 ExceptionInfo Uncaught =
168 throwsException(Try->getTryBlock(), Caught, CallStack);
169 for (
unsigned I = 0; I < Try->getNumHandlers(); ++I) {
170 const CXXCatchStmt *Catch = Try->getHandler(I);
173 if (!Catch->getExceptionDecl()) {
174 ExceptionInfo Rethrown = throwsException(
175 Catch->getHandlerBlock(), Uncaught.getExceptionTypes(), CallStack);
179 const auto *CaughtType =
180 Catch->getCaughtType()->getUnqualifiedDesugaredType();
181 if (CaughtType->isReferenceType()) {
182 CaughtType = CaughtType->castAs<ReferenceType>()
184 ->getUnqualifiedDesugaredType();
191 if (Uncaught.filterByCatch(CaughtType)) {
193 CaughtExceptions.insert(CaughtType);
194 ExceptionInfo Rethrown = throwsException(Catch->getHandlerBlock(),
195 CaughtExceptions, CallStack);
201 }
else if (
const auto *Call = dyn_cast<CallExpr>(St)) {
202 if (
const FunctionDecl *Func = Call->getDirectCallee()) {
203 ExceptionInfo Excs = throwsException(Func, CallStack);
206 }
else if (
const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
208 throwsException(Construct->getConstructor(), CallStack);
210 }
else if (
const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
212 throwsException(DefaultInit->getExpr(), Caught, CallStack);
215 for (
const Stmt *Child : St->children()) {
216 ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
223 ExceptionAnalyzer::ExceptionInfo
224 ExceptionAnalyzer::analyzeImpl(
const FunctionDecl *Func) {
225 ExceptionInfo ExceptionList;
228 if (FunctionCache.count(Func) == 0) {
229 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
230 ExceptionList = throwsException(Func, CallStack);
236 FunctionCache.insert(std::make_pair(Func, ExceptionList));
238 ExceptionList = FunctionCache[Func];
240 return ExceptionList;
243 ExceptionAnalyzer::ExceptionInfo
244 ExceptionAnalyzer::analyzeImpl(
const Stmt *Stmt) {
245 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
249 template <
typename T>
250 ExceptionAnalyzer::ExceptionInfo
251 ExceptionAnalyzer::analyzeDispatch(
const T *Node) {
252 ExceptionInfo ExceptionList = analyzeImpl(Node);
256 return ExceptionList;
260 ExceptionList.filterIgnoredExceptions(IgnoredExceptions, IgnoreBadAlloc);
262 return ExceptionList;
265 ExceptionAnalyzer::ExceptionInfo
267 return analyzeDispatch(Func);
272 return analyzeDispatch(Stmt);