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 (
@@ -356,10 +356,12 @@ static bool canThrow(const FunctionDecl *Func) {
356356 };
357357}
358358
359- bool ExceptionAnalyzer::ExceptionInfo::filterByCatch (
360- const Type *HandlerTy, const ASTContext &Context) {
359+ ExceptionAnalyzer::ExceptionInfo::Throwables
360+ ExceptionAnalyzer::ExceptionInfo::filterByCatch (const Type *HandlerTy,
361+ const ASTContext &Context) {
361362 llvm::SmallVector<const Type *, 8 > TypesToDelete;
362- for (const Type *ExceptionTy : ThrownExceptions) {
363+ for (const auto &ThrownException : ThrownExceptions) {
364+ const Type *ExceptionTy = ThrownException.getFirst ();
363365 CanQualType ExceptionCanTy = ExceptionTy->getCanonicalTypeUnqualified ();
364366 CanQualType HandlerCanTy = HandlerTy->getCanonicalTypeUnqualified ();
365367
@@ -409,11 +411,18 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
409411 }
410412 }
411413
412- for (const Type *T : TypesToDelete)
413- ThrownExceptions.erase (T);
414+ Throwables DeletedExceptions;
415+
416+ for (const Type *TypeToDelete : TypesToDelete) {
417+ const auto DeleteIt = ThrownExceptions.find (TypeToDelete);
418+ if (DeleteIt != ThrownExceptions.end ()) {
419+ DeletedExceptions.insert (*DeleteIt);
420+ ThrownExceptions.erase (DeleteIt);
421+ }
422+ }
414423
415424 reevaluateBehaviour ();
416- return !TypesToDelete. empty () ;
425+ return DeletedExceptions ;
417426}
418427
419428ExceptionAnalyzer::ExceptionInfo &
@@ -422,7 +431,8 @@ ExceptionAnalyzer::ExceptionInfo::filterIgnoredExceptions(
422431 llvm::SmallVector<const Type *, 8 > TypesToDelete;
423432 // Note: Using a 'SmallSet' with 'llvm::remove_if()' is not possible.
424433 // Therefore this slightly hacky implementation is required.
425- for (const Type *T : ThrownExceptions) {
434+ for (const auto &ThrownException : ThrownExceptions) {
435+ const Type *T = ThrownException.getFirst ();
426436 if (const auto *TD = T->getAsTagDecl ()) {
427437 if (TD->getDeclName ().isIdentifier ()) {
428438 if ((IgnoreBadAlloc &&
@@ -454,10 +464,10 @@ void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
454464 else
455465 Behaviour = State::Throwing;
456466}
457-
458- ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer:: throwsException (
459- const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
460- llvm::SmallSet< const FunctionDecl *, 32 > &CallStack) {
467+ ExceptionAnalyzer::ExceptionInfo
468+ ExceptionAnalyzer::throwsException (const FunctionDecl *Func,
469+ const ExceptionInfo::Throwables &Caught,
470+ CallStack &CallStack) {
461471 if (!Func || CallStack.contains (Func) ||
462472 (!CallStack.empty () && !canThrow (Func)))
463473 return ExceptionInfo::createNonThrowing ();
@@ -475,23 +485,25 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
475485 }
476486 }
477487
478- CallStack.erase (Func);
488+ CallStack.remove (Func);
479489 return Result;
480490 }
481491
482492 auto Result = ExceptionInfo::createUnknown ();
483493 if (const auto *FPT = Func->getType ()->getAs <FunctionProtoType>()) {
484494 for (const QualType &Ex : FPT->exceptions ())
485- Result.registerException (Ex.getTypePtr ());
495+ // Nothing in ThrowInfo because there is no location of 'throw'
496+ Result.registerException (Ex.getTypePtr (), {});
486497 }
487498 return Result;
488499}
489500
490501// / Analyzes a single statement on it's throwing behaviour. This is in principle
491502// / possible except some 'Unknown' functions are called.
492- ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException (
493- const Stmt *St, const ExceptionInfo::Throwables &Caught,
494- llvm::SmallSet<const FunctionDecl *, 32 > &CallStack) {
503+ ExceptionAnalyzer::ExceptionInfo
504+ ExceptionAnalyzer::throwsException (const Stmt *St,
505+ const ExceptionInfo::Throwables &Caught,
506+ CallStack &CallStack) {
495507 auto Results = ExceptionInfo::createNonThrowing ();
496508 if (!St)
497509 return Results;
@@ -505,7 +517,8 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
505517 ->getPointeeType ()
506518 ->getUnqualifiedDesugaredType ();
507519 Results.registerException (
508- ThrownExpr->getType ()->getUnqualifiedDesugaredType ());
520+ ThrownExpr->getType ()->getUnqualifiedDesugaredType (),
521+ {Throw->getBeginLoc (), CallStack});
509522 } else
510523 // A rethrow of a caught exception happens which makes it possible
511524 // to throw all exception that are caught in the 'catch' clause of
@@ -520,7 +533,7 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
520533 // Everything is caught through 'catch(...)'.
521534 if (!Catch->getExceptionDecl ()) {
522535 ExceptionInfo Rethrown = throwsException (
523- Catch->getHandlerBlock (), Uncaught.getExceptionTypes (), CallStack);
536+ Catch->getHandlerBlock (), Uncaught.getExceptions (), CallStack);
524537 Results.merge (Rethrown);
525538 Uncaught.clear ();
526539 } else {
@@ -536,12 +549,12 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
536549 // thrown types (because it's sensitive to inheritance) the throwing
537550 // situation changes. First of all filter the exception types and
538551 // analyze if the baseclass-exception is rethrown.
539- if (Uncaught. filterByCatch (
540- CaughtType, Catch-> getExceptionDecl ()-> getASTContext ())) {
541- ExceptionInfo::Throwables CaughtExceptions ;
542- CaughtExceptions. insert (CaughtType);
543- ExceptionInfo Rethrown = throwsException (Catch-> getHandlerBlock (),
544- CaughtExceptions , CallStack);
552+ const ExceptionInfo::Throwables FilteredExceptions =
553+ Uncaught. filterByCatch ( CaughtType,
554+ Catch-> getExceptionDecl ()-> getASTContext ()) ;
555+ if (!FilteredExceptions. empty ()) {
556+ ExceptionInfo Rethrown = throwsException (
557+ Catch-> getHandlerBlock (), FilteredExceptions , CallStack);
545558 Results.merge (Rethrown);
546559 }
547560 }
@@ -569,9 +582,10 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
569582 }
570583 ExceptionInfo Excs = throwsException (Coro->getBody (), Caught, CallStack);
571584 Results.merge (throwsException (Coro->getExceptionHandler (),
572- Excs.getExceptionTypes (), CallStack));
573- for (const Type *Throwable : Excs.getExceptionTypes ()) {
574- if (const auto *ThrowableRec = Throwable->getAsCXXRecordDecl ()) {
585+ Excs.getExceptions (), CallStack));
586+ for (const auto &Exception : Excs.getExceptions ()) {
587+ const Type *ExcType = Exception.getFirst ();
588+ if (const CXXRecordDecl *ThrowableRec = ExcType->getAsCXXRecordDecl ()) {
575589 ExceptionInfo DestructorExcs =
576590 throwsException (ThrowableRec->getDestructor (), Caught, CallStack);
577591 Results.merge (DestructorExcs);
@@ -593,7 +607,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
593607 // Check if the function has already been analyzed and reuse that result.
594608 const auto CacheEntry = FunctionCache.find (Func);
595609 if (CacheEntry == FunctionCache.end ()) {
596- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
610+ CallStack CallStack;
597611 ExceptionList =
598612 throwsException (Func, ExceptionInfo::Throwables (), CallStack);
599613
@@ -610,7 +624,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
610624
611625ExceptionAnalyzer::ExceptionInfo
612626ExceptionAnalyzer::analyzeImpl (const Stmt *Stmt) {
613- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
627+ CallStack CallStack;
614628 return throwsException (Stmt, ExceptionInfo::Throwables (), CallStack);
615629}
616630
0 commit comments