1111namespace clang ::tidy::utils {
1212
1313void ExceptionAnalyzer::ExceptionInfo::registerException (
14- const Type *ExceptionType) {
14+ const Type *ExceptionType, const ThrowInfo &ThrowInfo ) {
1515 assert (ExceptionType != nullptr && " Only valid types are accepted" );
1616 Behaviour = State::Throwing;
17- ThrownExceptions.insert (ExceptionType);
17+ ThrownExceptions.insert ({ ExceptionType, ThrowInfo} );
1818}
1919
2020void ExceptionAnalyzer::ExceptionInfo::registerExceptions (
@@ -354,10 +354,12 @@ static bool canThrow(const FunctionDecl *Func) {
354354 };
355355}
356356
357- bool ExceptionAnalyzer::ExceptionInfo::filterByCatch (
358- const Type *HandlerTy, const ASTContext &Context) {
357+ ExceptionAnalyzer::ExceptionInfo::Throwables
358+ ExceptionAnalyzer::ExceptionInfo::filterByCatch (const Type *HandlerTy,
359+ const ASTContext &Context) {
359360 llvm::SmallVector<const Type *, 8 > TypesToDelete;
360- for (const Type *ExceptionTy : ThrownExceptions) {
361+ for (const auto &ThrownException : ThrownExceptions) {
362+ const Type *ExceptionTy = ThrownException.getFirst ();
361363 CanQualType ExceptionCanTy = ExceptionTy->getCanonicalTypeUnqualified ();
362364 CanQualType HandlerCanTy = HandlerTy->getCanonicalTypeUnqualified ();
363365
@@ -407,11 +409,18 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
407409 }
408410 }
409411
410- for (const Type *T : TypesToDelete)
411- ThrownExceptions.erase (T);
412+ Throwables DeletedExceptions;
413+
414+ for (const Type *TypeToDelete : TypesToDelete) {
415+ const auto DeleteIt = ThrownExceptions.find (TypeToDelete);
416+ if (DeleteIt != ThrownExceptions.end ()) {
417+ DeletedExceptions.insert (*DeleteIt);
418+ ThrownExceptions.erase (DeleteIt);
419+ }
420+ }
412421
413422 reevaluateBehaviour ();
414- return !TypesToDelete. empty () ;
423+ return DeletedExceptions ;
415424}
416425
417426ExceptionAnalyzer::ExceptionInfo &
@@ -420,7 +429,8 @@ ExceptionAnalyzer::ExceptionInfo::filterIgnoredExceptions(
420429 llvm::SmallVector<const Type *, 8 > TypesToDelete;
421430 // Note: Using a 'SmallSet' with 'llvm::remove_if()' is not possible.
422431 // Therefore this slightly hacky implementation is required.
423- for (const Type *T : ThrownExceptions) {
432+ for (const auto &ThrownException : ThrownExceptions) {
433+ const Type *T = ThrownException.getFirst ();
424434 if (const auto *TD = T->getAsTagDecl ()) {
425435 if (TD->getDeclName ().isIdentifier ()) {
426436 if ((IgnoreBadAlloc &&
@@ -452,10 +462,10 @@ void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
452462 else
453463 Behaviour = State::Throwing;
454464}
455-
456- ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer:: throwsException (
457- const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
458- llvm::SmallSet< const FunctionDecl *, 32 > &CallStack) {
465+ ExceptionAnalyzer::ExceptionInfo
466+ ExceptionAnalyzer::throwsException (const FunctionDecl *Func,
467+ const ExceptionInfo::Throwables &Caught,
468+ CallStack &CallStack) {
459469 if (!Func || CallStack.contains (Func) ||
460470 (!CallStack.empty () && !canThrow (Func)))
461471 return ExceptionInfo::createNonThrowing ();
@@ -473,23 +483,25 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
473483 }
474484 }
475485
476- CallStack.erase (Func);
486+ CallStack.remove (Func);
477487 return Result;
478488 }
479489
480490 auto Result = ExceptionInfo::createUnknown ();
481491 if (const auto *FPT = Func->getType ()->getAs <FunctionProtoType>()) {
482492 for (const QualType &Ex : FPT->exceptions ())
483- Result.registerException (Ex.getTypePtr ());
493+ // FIXME add something to ThrowInfo
494+ Result.registerException (Ex.getTypePtr (), {});
484495 }
485496 return Result;
486497}
487498
488499// / Analyzes a single statement on it's throwing behaviour. This is in principle
489500// / possible except some 'Unknown' functions are called.
490- ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException (
491- const Stmt *St, const ExceptionInfo::Throwables &Caught,
492- llvm::SmallSet<const FunctionDecl *, 32 > &CallStack) {
501+ ExceptionAnalyzer::ExceptionInfo
502+ ExceptionAnalyzer::throwsException (const Stmt *St,
503+ const ExceptionInfo::Throwables &Caught,
504+ CallStack &CallStack) {
493505 auto Results = ExceptionInfo::createNonThrowing ();
494506 if (!St)
495507 return Results;
@@ -503,7 +515,8 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
503515 ->getPointeeType ()
504516 ->getUnqualifiedDesugaredType ();
505517 Results.registerException (
506- ThrownExpr->getType ()->getUnqualifiedDesugaredType ());
518+ ThrownExpr->getType ()->getUnqualifiedDesugaredType (),
519+ {Throw->getBeginLoc (), CallStack});
507520 } else
508521 // A rethrow of a caught exception happens which makes it possible
509522 // to throw all exception that are caught in the 'catch' clause of
@@ -518,7 +531,7 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
518531 // Everything is caught through 'catch(...)'.
519532 if (!Catch->getExceptionDecl ()) {
520533 ExceptionInfo Rethrown = throwsException (
521- Catch->getHandlerBlock (), Uncaught.getExceptionTypes (), CallStack);
534+ Catch->getHandlerBlock (), Uncaught.getExceptions (), CallStack);
522535 Results.merge (Rethrown);
523536 Uncaught.clear ();
524537 } else {
@@ -534,12 +547,12 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
534547 // thrown types (because it's sensitive to inheritance) the throwing
535548 // situation changes. First of all filter the exception types and
536549 // analyze if the baseclass-exception is rethrown.
537- if (Uncaught. filterByCatch (
538- CaughtType, Catch-> getExceptionDecl ()-> getASTContext ())) {
539- ExceptionInfo::Throwables CaughtExceptions ;
540- CaughtExceptions. insert (CaughtType);
541- ExceptionInfo Rethrown = throwsException (Catch-> getHandlerBlock (),
542- CaughtExceptions , CallStack);
550+ const ExceptionInfo::Throwables FilteredExceptions =
551+ Uncaught. filterByCatch ( CaughtType,
552+ Catch-> getExceptionDecl ()-> getASTContext ()) ;
553+ if (!FilteredExceptions. empty ()) {
554+ ExceptionInfo Rethrown = throwsException (
555+ Catch-> getHandlerBlock (), FilteredExceptions , CallStack);
543556 Results.merge (Rethrown);
544557 }
545558 }
@@ -567,9 +580,10 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
567580 }
568581 ExceptionInfo Excs = throwsException (Coro->getBody (), Caught, CallStack);
569582 Results.merge (throwsException (Coro->getExceptionHandler (),
570- Excs.getExceptionTypes (), CallStack));
571- for (const Type *Throwable : Excs.getExceptionTypes ()) {
572- if (const auto ThrowableRec = Throwable->getAsCXXRecordDecl ()) {
583+ Excs.getExceptions (), CallStack));
584+ for (const auto &Exception : Excs.getExceptions ()) {
585+ const Type *ExcType = Exception.getFirst ();
586+ if (const CXXRecordDecl *ThrowableRec = ExcType->getAsCXXRecordDecl ()) {
573587 ExceptionInfo DestructorExcs =
574588 throwsException (ThrowableRec->getDestructor (), Caught, CallStack);
575589 Results.merge (DestructorExcs);
@@ -591,7 +605,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
591605 // Check if the function has already been analyzed and reuse that result.
592606 const auto CacheEntry = FunctionCache.find (Func);
593607 if (CacheEntry == FunctionCache.end ()) {
594- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
608+ CallStack CallStack;
595609 ExceptionList =
596610 throwsException (Func, ExceptionInfo::Throwables (), CallStack);
597611
@@ -608,7 +622,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
608622
609623ExceptionAnalyzer::ExceptionInfo
610624ExceptionAnalyzer::analyzeImpl (const Stmt *Stmt) {
611- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
625+ CallStack CallStack;
612626 return throwsException (Stmt, ExceptionInfo::Throwables (), CallStack);
613627}
614628
0 commit comments