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,16 +464,15 @@ void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
454464 else
455465 Behaviour = State::Throwing;
456466}
457-
458467ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException (
459468 const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
460- llvm::SmallSet< const FunctionDecl *, 32 > &CallStack ) {
469+ CallStack &CallStack, SourceLocation CallLoc ) {
461470 if (!Func || CallStack.contains (Func) ||
462471 (!CallStack.empty () && !canThrow (Func)))
463472 return ExceptionInfo::createNonThrowing ();
464473
465474 if (const Stmt *Body = Func->getBody ()) {
466- CallStack.insert (Func);
475+ CallStack.insert ({ Func, CallLoc} );
467476 ExceptionInfo Result = throwsException (Body, Caught, CallStack);
468477
469478 // For a constructor, we also have to check the initializers.
@@ -481,17 +490,23 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
481490
482491 auto Result = ExceptionInfo::createUnknown ();
483492 if (const auto *FPT = Func->getType ()->getAs <FunctionProtoType>()) {
484- for (const QualType &Ex : FPT->exceptions ())
485- Result.registerException (Ex.getTypePtr ());
493+ for (const QualType &Ex : FPT->exceptions ()) {
494+ CallStack.insert ({Func, CallLoc});
495+ Result.registerException (
496+ Ex.getTypePtr (),
497+ {Func->getExceptionSpecSourceRange ().getBegin (), CallStack});
498+ CallStack.erase (Func);
499+ }
486500 }
487501 return Result;
488502}
489503
490504// / Analyzes a single statement on it's throwing behaviour. This is in principle
491505// / 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) {
506+ ExceptionAnalyzer::ExceptionInfo
507+ ExceptionAnalyzer::throwsException (const Stmt *St,
508+ const ExceptionInfo::Throwables &Caught,
509+ CallStack &CallStack) {
495510 auto Results = ExceptionInfo::createNonThrowing ();
496511 if (!St)
497512 return Results;
@@ -505,7 +520,8 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
505520 ->getPointeeType ()
506521 ->getUnqualifiedDesugaredType ();
507522 Results.registerException (
508- ThrownExpr->getType ()->getUnqualifiedDesugaredType ());
523+ ThrownExpr->getType ()->getUnqualifiedDesugaredType (),
524+ {Throw->getBeginLoc (), CallStack});
509525 } else
510526 // A rethrow of a caught exception happens which makes it possible
511527 // to throw all exception that are caught in the 'catch' clause of
@@ -520,7 +536,7 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
520536 // Everything is caught through 'catch(...)'.
521537 if (!Catch->getExceptionDecl ()) {
522538 ExceptionInfo Rethrown = throwsException (
523- Catch->getHandlerBlock (), Uncaught.getExceptionTypes (), CallStack);
539+ Catch->getHandlerBlock (), Uncaught.getExceptions (), CallStack);
524540 Results.merge (Rethrown);
525541 Uncaught.clear ();
526542 } else {
@@ -536,25 +552,26 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
536552 // thrown types (because it's sensitive to inheritance) the throwing
537553 // situation changes. First of all filter the exception types and
538554 // 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);
555+ const ExceptionInfo::Throwables FilteredExceptions =
556+ Uncaught. filterByCatch ( CaughtType,
557+ Catch-> getExceptionDecl ()-> getASTContext ()) ;
558+ if (!FilteredExceptions. empty ()) {
559+ ExceptionInfo Rethrown = throwsException (
560+ Catch-> getHandlerBlock (), FilteredExceptions , CallStack);
545561 Results.merge (Rethrown);
546562 }
547563 }
548564 }
549565 Results.merge (Uncaught);
550566 } else if (const auto *Call = dyn_cast<CallExpr>(St)) {
551567 if (const FunctionDecl *Func = Call->getDirectCallee ()) {
552- ExceptionInfo Excs = throwsException (Func, Caught, CallStack);
568+ ExceptionInfo Excs =
569+ throwsException (Func, Caught, CallStack, Call->getBeginLoc ());
553570 Results.merge (Excs);
554571 }
555572 } else if (const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
556- ExceptionInfo Excs =
557- throwsException ( Construct->getConstructor (), Caught, CallStack );
573+ ExceptionInfo Excs = throwsException (Construct-> getConstructor (), Caught,
574+ CallStack, Construct->getBeginLoc () );
558575 Results.merge (Excs);
559576 } else if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
560577 ExceptionInfo Excs =
@@ -569,11 +586,12 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
569586 }
570587 ExceptionInfo Excs = throwsException (Coro->getBody (), Caught, CallStack);
571588 Results.merge (throwsException (Coro->getExceptionHandler (),
572- Excs.getExceptionTypes (), CallStack));
573- for (const Type *Throwable : Excs.getExceptionTypes ()) {
574- if (const auto *ThrowableRec = Throwable->getAsCXXRecordDecl ()) {
575- ExceptionInfo DestructorExcs =
576- throwsException (ThrowableRec->getDestructor (), Caught, CallStack);
589+ Excs.getExceptions (), CallStack));
590+ for (const auto &Exception : Excs.getExceptions ()) {
591+ const Type *ExcType = Exception.getFirst ();
592+ if (const CXXRecordDecl *ThrowableRec = ExcType->getAsCXXRecordDecl ()) {
593+ ExceptionInfo DestructorExcs = throwsException (
594+ ThrowableRec->getDestructor (), Caught, CallStack, SourceLocation{});
577595 Results.merge (DestructorExcs);
578596 }
579597 }
@@ -593,9 +611,9 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
593611 // Check if the function has already been analyzed and reuse that result.
594612 const auto CacheEntry = FunctionCache.find (Func);
595613 if (CacheEntry == FunctionCache.end ()) {
596- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
597- ExceptionList =
598- throwsException (Func, ExceptionInfo::Throwables (), CallStack );
614+ CallStack CallStack;
615+ ExceptionList = throwsException (Func, ExceptionInfo::Throwables (),
616+ CallStack, Func-> getLocation () );
599617
600618 // Cache the result of the analysis. This is done prior to filtering
601619 // because it is best to keep as much information as possible.
@@ -610,7 +628,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
610628
611629ExceptionAnalyzer::ExceptionInfo
612630ExceptionAnalyzer::analyzeImpl (const Stmt *Stmt) {
613- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
631+ CallStack CallStack;
614632 return throwsException (Stmt, ExceptionInfo::Throwables (), CallStack);
615633}
616634
0 commit comments