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());
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);
122 CallStack.erase(Func);
127 if (
const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
128 for (
const QualType Ex : FPT->exceptions())
129 Result.registerException(Ex.getTypePtr());
138 llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
143 if (
const auto *Throw = dyn_cast<CXXThrowExpr>(St)) {
144 if (
const auto *ThrownExpr = Throw->getSubExpr()) {
145 const auto *ThrownType =
146 ThrownExpr->getType()->getUnqualifiedDesugaredType();
147 if (ThrownType->isReferenceType())
148 ThrownType = ThrownType->castAs<ReferenceType>()
150 ->getUnqualifiedDesugaredType();
152 ThrownExpr->getType()->getUnqualifiedDesugaredType());
157 Results.registerExceptions(Caught);
158 }
else if (
const auto *Try = dyn_cast<CXXTryStmt>(St)) {
160 throwsException(Try->getTryBlock(), Caught, CallStack);
161 for (
unsigned i = 0; i < Try->getNumHandlers(); ++i) {
162 const CXXCatchStmt *Catch = Try->getHandler(i);
165 if (!Catch->getExceptionDecl()) {
171 const auto *CaughtType =
172 Catch->getCaughtType()->getUnqualifiedDesugaredType();
173 if (CaughtType->isReferenceType()) {
174 CaughtType = CaughtType->castAs<ReferenceType>()
176 ->getUnqualifiedDesugaredType();
185 CaughtExceptions.insert(CaughtType);
186 ExceptionInfo Rethrown = throwsException(Catch->getHandlerBlock(),
187 CaughtExceptions, CallStack);
193 }
else if (
const auto *Call = dyn_cast<CallExpr>(St)) {
194 if (
const FunctionDecl *Func = Call->getDirectCallee()) {
199 for (
const Stmt *Child : St->children()) {
200 ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
208 ExceptionAnalyzer::analyzeImpl(
const FunctionDecl *Func) {
212 if (FunctionCache.count(Func) == 0) {
213 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
214 ExceptionList = throwsException(Func, CallStack);
220 FunctionCache.insert(std::make_pair(Func, ExceptionList));
222 ExceptionList = FunctionCache[Func];
224 return ExceptionList;
228 ExceptionAnalyzer::analyzeImpl(
const Stmt *Stmt) {
229 llvm::SmallSet<const FunctionDecl *, 32> CallStack;
233 template <
typename T>
235 ExceptionAnalyzer::analyzeDispatch(
const T *Node) {
240 return ExceptionList;
246 return ExceptionList;
251 return analyzeDispatch(Func);
256 return analyzeDispatch(Stmt);
llvm::SmallSet< const Type *, 2 > Throwables
Bundle the gathered information about an entity like a function regarding it's exception behaviour...
void registerExceptions(const Throwables &Exceptions)
Registers a SmallVector of exception types as recognized potential exceptions to be thrown...
void registerException(const Type *ExceptionType)
Register a single exception type as recognized potential exception to be thrown.
std::vector< CodeCompletionResult > Results
ExceptionInfo & merge(const ExceptionInfo &Other)
Updates the local state according to the other state.
static ExceptionInfo createNonThrowing()
State getBehaviour() const
This function can not throw, given an AST.
This can happen for extern functions without available definition.
const Throwables & getExceptionTypes() const
References the set of known exception types that can escape from the corresponding entity...
static bool isBaseOf(const Type *DerivedType, const Type *BaseType)
bool filterByCatch(const Type *BaseClass)
This method is useful in case 'catch' clauses are analyzed as it is possible to catch multiple except...
The function can definitly throw given an AST.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
ExceptionInfo analyze(const FunctionDecl *Func)
void clear()
Clear the state to 'NonThrowing' to make the corresponding entity neutral.
static ExceptionInfo createUnknown()
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
ExceptionInfo & filterIgnoredExceptions(const llvm::StringSet<> &IgnoredTypes, bool IgnoreBadAlloc)
Filter the set of thrown exception type against a set of ignored types that shall not be considered i...