11
11
namespace clang ::tidy::utils {
12
12
13
13
void ExceptionAnalyzer::ExceptionInfo::registerException (
14
- const Type *ExceptionType) {
14
+ const Type *ExceptionType, const ThrowInfo &ThrowInfo ) {
15
15
assert (ExceptionType != nullptr && " Only valid types are accepted" );
16
16
Behaviour = State::Throwing;
17
- ThrownExceptions.insert (ExceptionType);
17
+ ThrownExceptions.insert ({ ExceptionType, ThrowInfo} );
18
18
}
19
19
20
20
void ExceptionAnalyzer::ExceptionInfo::registerExceptions (
@@ -356,10 +356,12 @@ static bool canThrow(const FunctionDecl *Func) {
356
356
};
357
357
}
358
358
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) {
361
362
llvm::SmallVector<const Type *, 8 > TypesToDelete;
362
- for (const Type *ExceptionTy : ThrownExceptions) {
363
+ for (const auto &ThrownException : ThrownExceptions) {
364
+ const Type *ExceptionTy = ThrownException.getFirst ();
363
365
CanQualType ExceptionCanTy = ExceptionTy->getCanonicalTypeUnqualified ();
364
366
CanQualType HandlerCanTy = HandlerTy->getCanonicalTypeUnqualified ();
365
367
@@ -409,11 +411,18 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
409
411
}
410
412
}
411
413
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
+ }
414
423
415
424
reevaluateBehaviour ();
416
- return !TypesToDelete. empty () ;
425
+ return DeletedExceptions ;
417
426
}
418
427
419
428
ExceptionAnalyzer::ExceptionInfo &
@@ -422,7 +431,8 @@ ExceptionAnalyzer::ExceptionInfo::filterIgnoredExceptions(
422
431
llvm::SmallVector<const Type *, 8 > TypesToDelete;
423
432
// Note: Using a 'SmallSet' with 'llvm::remove_if()' is not possible.
424
433
// 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 ();
426
436
if (const auto *TD = T->getAsTagDecl ()) {
427
437
if (TD->getDeclName ().isIdentifier ()) {
428
438
if ((IgnoreBadAlloc &&
@@ -454,16 +464,15 @@ void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
454
464
else
455
465
Behaviour = State::Throwing;
456
466
}
457
-
458
467
ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException (
459
468
const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
460
- llvm::SmallSet< const FunctionDecl *, 32 > &CallStack ) {
469
+ CallStack &CallStack, SourceLocation CallLoc ) {
461
470
if (!Func || CallStack.contains (Func) ||
462
471
(!CallStack.empty () && !canThrow (Func)))
463
472
return ExceptionInfo::createNonThrowing ();
464
473
465
474
if (const Stmt *Body = Func->getBody ()) {
466
- CallStack.insert (Func);
475
+ CallStack.insert ({ Func, CallLoc} );
467
476
ExceptionInfo Result = throwsException (Body, Caught, CallStack);
468
477
469
478
// For a constructor, we also have to check the initializers.
@@ -481,17 +490,23 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
481
490
482
491
auto Result = ExceptionInfo::createUnknown ();
483
492
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
+ }
486
500
}
487
501
return Result;
488
502
}
489
503
490
504
// / Analyzes a single statement on it's throwing behaviour. This is in principle
491
505
// / 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) {
495
510
auto Results = ExceptionInfo::createNonThrowing ();
496
511
if (!St)
497
512
return Results;
@@ -505,7 +520,8 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
505
520
->getPointeeType ()
506
521
->getUnqualifiedDesugaredType ();
507
522
Results.registerException (
508
- ThrownExpr->getType ()->getUnqualifiedDesugaredType ());
523
+ ThrownExpr->getType ()->getUnqualifiedDesugaredType (),
524
+ {Throw->getBeginLoc (), CallStack});
509
525
} else
510
526
// A rethrow of a caught exception happens which makes it possible
511
527
// to throw all exception that are caught in the 'catch' clause of
@@ -520,7 +536,7 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
520
536
// Everything is caught through 'catch(...)'.
521
537
if (!Catch->getExceptionDecl ()) {
522
538
ExceptionInfo Rethrown = throwsException (
523
- Catch->getHandlerBlock (), Uncaught.getExceptionTypes (), CallStack);
539
+ Catch->getHandlerBlock (), Uncaught.getExceptions (), CallStack);
524
540
Results.merge (Rethrown);
525
541
Uncaught.clear ();
526
542
} else {
@@ -536,25 +552,26 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
536
552
// thrown types (because it's sensitive to inheritance) the throwing
537
553
// situation changes. First of all filter the exception types and
538
554
// 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);
545
561
Results.merge (Rethrown);
546
562
}
547
563
}
548
564
}
549
565
Results.merge (Uncaught);
550
566
} else if (const auto *Call = dyn_cast<CallExpr>(St)) {
551
567
if (const FunctionDecl *Func = Call->getDirectCallee ()) {
552
- ExceptionInfo Excs = throwsException (Func, Caught, CallStack);
568
+ ExceptionInfo Excs =
569
+ throwsException (Func, Caught, CallStack, Call->getBeginLoc ());
553
570
Results.merge (Excs);
554
571
}
555
572
} 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 () );
558
575
Results.merge (Excs);
559
576
} else if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
560
577
ExceptionInfo Excs =
@@ -569,11 +586,12 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
569
586
}
570
587
ExceptionInfo Excs = throwsException (Coro->getBody (), Caught, CallStack);
571
588
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{});
577
595
Results.merge (DestructorExcs);
578
596
}
579
597
}
@@ -593,9 +611,9 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
593
611
// Check if the function has already been analyzed and reuse that result.
594
612
const auto CacheEntry = FunctionCache.find (Func);
595
613
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 () );
599
617
600
618
// Cache the result of the analysis. This is done prior to filtering
601
619
// because it is best to keep as much information as possible.
@@ -610,7 +628,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
610
628
611
629
ExceptionAnalyzer::ExceptionInfo
612
630
ExceptionAnalyzer::analyzeImpl (const Stmt *Stmt) {
613
- llvm::SmallSet< const FunctionDecl *, 32 > CallStack;
631
+ CallStack CallStack;
614
632
return throwsException (Stmt, ExceptionInfo::Throwables (), CallStack);
615
633
}
616
634
0 commit comments