16 const Type *ExceptionType) {
17 assert(ExceptionType !=
nullptr &&
"Only valid types are accepted");
19 ThrownExceptions.insert(ExceptionType);
24 if (Exceptions.size() == 0)
27 ThrownExceptions.insert(Exceptions.begin(), Exceptions.end());
43 ContainsUnknown = ContainsUnknown || Other.ContainsUnknown;
44 ThrownExceptions.insert(Other.ThrownExceptions.begin(),
45 Other.ThrownExceptions.end());
49 static bool isBaseOf(
const Type *DerivedType,
const Type *BaseType) {
50 const auto *DerivedClass = DerivedType->getAsCXXRecordDecl();
51 const auto *BaseClass = BaseType->getAsCXXRecordDecl();
52 if (!DerivedClass || !BaseClass)
55 return !DerivedClass->forallBases(
56 [BaseClass](
const CXXRecordDecl *Cur) {
return Cur != BaseClass; });
60 llvm::SmallVector<const Type *, 8> TypesToDelete;
61 for (
const Type *T : ThrownExceptions) {
62 if (T == BaseClass ||
isBaseOf(T, BaseClass))
63 TypesToDelete.push_back(T);
66 for (
const Type *T : TypesToDelete)
67 ThrownExceptions.erase(T);
69 reevaluateBehaviour();
70 return TypesToDelete.size() > 0;
75 const llvm::StringSet<> &IgnoredTypes,
bool IgnoreBadAlloc) {
76 llvm::SmallVector<const Type *, 8> TypesToDelete;
79 for (
const Type *T : ThrownExceptions) {
80 if (
const auto *TD = T->getAsTagDecl()) {
81 if (TD->getDeclName().isIdentifier()) {
82 if ((IgnoreBadAlloc &&
83 (TD->getName() ==
"bad_alloc" && TD->isInStdNamespace())) ||
84 (IgnoredTypes.count(TD->getName()) > 0))
85 TypesToDelete.push_back(T);
89 for (
const Type *T : TypesToDelete)
90 ThrownExceptions.erase(T);
92 reevaluateBehaviour();
98 ContainsUnknown =
false;
99 ThrownExceptions.clear();
102 void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
103 if (ThrownExceptions.size() == 0)
113 const FunctionDecl *Func,
114 llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
115 if (CallStack.count(Func))
118 if (
const Stmt *Body = Func->getBody()) {
119 CallStack.insert(Func);
120 ExceptionInfo Result =
124 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(Func)) {
125 for (
const CXXCtorInitializer *Init : Ctor->inits()) {
126 ExceptionInfo Excs = throwsException(
132 CallStack.erase(Func);
137 if (
const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
138 for (
const QualType &Ex : FPT->exceptions())
139 Result.registerException(Ex.getTypePtr());
146 ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
148 llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
153 if (
const auto *Throw = dyn_cast<CXXThrowExpr>(St)) {
154 if (
const auto *ThrownExpr = Throw->getSubExpr()) {
155 const auto *ThrownType =
156 ThrownExpr->getType()->getUnqualifiedDesugaredType();
157 if (ThrownType->isReferenceType())
158 ThrownType = ThrownType->castAs<ReferenceType>()
160 ->getUnqualifiedDesugaredType();
162 ThrownExpr->getType()->getUnqualifiedDesugaredType());
167 Results.registerExceptions(Caught);
168 }
else if (
const auto *Try = dyn_cast<CXXTryStmt>(St)) {
169 ExceptionInfo Uncaught =
170 throwsException(Try->getTryBlock(), Caught, CallStack);
171 for (
unsigned I = 0; I < Try->getNumHandlers(); ++I) {
172 const CXXCatchStmt *Catch = Try->getHandler(I);
175 if (!Catch->getExceptionDecl()) {
176 ExceptionInfo Rethrown = throwsException(
177 Catch->getHandlerBlock(), Uncaught.getExceptionTypes(), CallStack);
181 const auto *CaughtType =
182 Catch->getCaughtType()->getUnqualifiedDesugaredType();
183 if (CaughtType->isReferenceType()) {
184 CaughtType = CaughtType->castAs<ReferenceType>()
186 ->getUnqualifiedDesugaredType();
193 if (Uncaught.filterByCatch(CaughtType)) {
195 CaughtExceptions.insert(CaughtType);
196 ExceptionInfo Rethrown = throwsException(Catch->getHandlerBlock(),
197 CaughtExceptions, CallStack);
203 }
else if (
const auto *Call = dyn_cast<CallExpr>(St)) {
204 if (
const FunctionDecl *Func = Call->getDirectCallee()) {
205 ExceptionInfo Excs = throwsException(Func, CallStack);
208 }
else if (
const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
210 throwsException(Construct->getConstructor(), CallStack);
212 }
else if (
const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
214 throwsException(DefaultInit->getExpr(), Caught, CallStack);
217 for (
const Stmt *Child : St->children()) {
218 ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
225 ExceptionAnalyzer::ExceptionInfo
226 ExceptionAnalyzer::analyzeImpl(
const FunctionDecl *Func) {
227 ExceptionInfo ExceptionList;
230 if (FunctionCache.count(Func) == 0) {
231 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
232 ExceptionList = throwsException(Func, CallStack);
238 FunctionCache.insert(std::make_pair(Func, ExceptionList));
240 ExceptionList = FunctionCache[Func];
242 return ExceptionList;
245 ExceptionAnalyzer::ExceptionInfo
246 ExceptionAnalyzer::analyzeImpl(
const Stmt *Stmt) {
247 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
251 template <
typename T>
252 ExceptionAnalyzer::ExceptionInfo
253 ExceptionAnalyzer::analyzeDispatch(
const T *Node) {
254 ExceptionInfo ExceptionList = analyzeImpl(Node);
258 return ExceptionList;
262 ExceptionList.filterIgnoredExceptions(IgnoredExceptions, IgnoreBadAlloc);
264 return ExceptionList;
267 ExceptionAnalyzer::ExceptionInfo
269 return analyzeDispatch(Func);
274 return analyzeDispatch(Stmt);