@@ -2548,22 +2548,48 @@ namespace {
2548
2548
2549
2549
void validateForeignReferenceType (const clang::CXXRecordDecl *decl,
2550
2550
ClassDecl *classDecl) {
2551
- auto isValidOperation = [&](ValueDecl *operation) -> bool {
2551
+
2552
+ enum class RetainReleaseOperatonKind {
2553
+ notAfunction,
2554
+ doesntReturnVoid,
2555
+ invalidParameters,
2556
+ valid
2557
+ };
2558
+
2559
+ auto getOperationValidity =
2560
+ [&](ValueDecl *operation) -> RetainReleaseOperatonKind {
2552
2561
auto operationFn = dyn_cast<FuncDecl>(operation);
2553
2562
if (!operationFn)
2554
- return false ;
2563
+ return RetainReleaseOperatonKind::notAfunction ;
2555
2564
2556
2565
if (!operationFn->getResultInterfaceType ()->isVoid ())
2557
- return false ;
2566
+ return RetainReleaseOperatonKind::doesntReturnVoid ;
2558
2567
2559
2568
if (operationFn->getParameters ()->size () != 1 )
2560
- return false ;
2569
+ return RetainReleaseOperatonKind::invalidParameters ;
2561
2570
2562
- if (operationFn->getParameters ()->get (0 )->getInterfaceType ()->isEqual (
2563
- classDecl->getInterfaceType ()))
2564
- return false ;
2571
+ Type paramType =
2572
+ operationFn->getParameters ()->get (0 )->getInterfaceType ();
2573
+ // Unwrap if paramType is an OptionalType
2574
+ if (Type optionalType = paramType->getOptionalObjectType ()) {
2575
+ paramType = optionalType;
2576
+ }
2565
2577
2566
- return true ;
2578
+ swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal ();
2579
+ // The parameter of the retain/release function should be pointer to the
2580
+ // same FRT or a base FRT.
2581
+ if (paramDecl != classDecl) {
2582
+ if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl ()) {
2583
+ if (const auto *paramTypeDecl =
2584
+ dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
2585
+ if (decl->isDerivedFrom (paramTypeDecl)) {
2586
+ return RetainReleaseOperatonKind::valid;
2587
+ }
2588
+ }
2589
+ }
2590
+ return RetainReleaseOperatonKind::invalidParameters;
2591
+ }
2592
+ return RetainReleaseOperatonKind::valid;
2567
2593
};
2568
2594
2569
2595
auto retainOperation = evaluateOrDefault (
@@ -2574,24 +2600,50 @@ namespace {
2574
2600
if (retainOperation.kind ==
2575
2601
CustomRefCountingOperationResult::noAttribute) {
2576
2602
HeaderLoc loc (decl->getLocation ());
2577
- Impl.diagnose (loc, diag::reference_type_must_have_retain_attr,
2578
- decl->getNameAsString ());
2603
+ Impl.diagnose (loc, diag::reference_type_must_have_retain_release_attr,
2604
+ false , decl->getNameAsString ());
2605
+ } else if (retainOperation.kind ==
2606
+ CustomRefCountingOperationResult::tooManyAttributes) {
2607
+ HeaderLoc loc (decl->getLocation ());
2608
+ Impl.diagnose (loc, diag::too_many_reference_type_retain_release_attr,
2609
+ false , decl->getNameAsString ());
2579
2610
} else if (retainOperation.kind ==
2580
2611
CustomRefCountingOperationResult::notFound) {
2581
2612
HeaderLoc loc (decl->getLocation ());
2582
- Impl.diagnose (loc, diag::foreign_reference_types_cannot_find_retain,
2583
- retainOperation.name , decl->getNameAsString ());
2613
+ Impl.diagnose (loc,
2614
+ diag::foreign_reference_types_cannot_find_retain_release,
2615
+ false , retainOperation.name , decl->getNameAsString ());
2584
2616
} else if (retainOperation.kind ==
2585
2617
CustomRefCountingOperationResult::tooManyFound) {
2586
2618
HeaderLoc loc (decl->getLocation ());
2587
- Impl.diagnose (loc, diag::too_many_reference_type_retain_operations,
2588
- retainOperation.name , decl->getNameAsString ());
2619
+ Impl.diagnose (loc,
2620
+ diag::too_many_reference_type_retain_release_operations,
2621
+ false , retainOperation.name , decl->getNameAsString ());
2589
2622
} else if (retainOperation.kind ==
2590
2623
CustomRefCountingOperationResult::foundOperation) {
2591
- if (!isValidOperation (retainOperation.operation )) {
2592
- HeaderLoc loc (decl->getLocation ());
2593
- Impl.diagnose (loc, diag::foreign_reference_types_invalid_retain,
2594
- retainOperation.name , decl->getNameAsString ());
2624
+ RetainReleaseOperatonKind operationKind =
2625
+ getOperationValidity (retainOperation.operation );
2626
+ HeaderLoc loc (decl->getLocation ());
2627
+ switch (operationKind) {
2628
+ case RetainReleaseOperatonKind::notAfunction:
2629
+ Impl.diagnose (
2630
+ loc,
2631
+ diag::foreign_reference_types_retain_release_not_a_function_decl,
2632
+ false , retainOperation.name );
2633
+ break ;
2634
+ case RetainReleaseOperatonKind::doesntReturnVoid:
2635
+ Impl.diagnose (
2636
+ loc,
2637
+ diag::foreign_reference_types_retain_release_non_void_return_type,
2638
+ false , retainOperation.name );
2639
+ break ;
2640
+ case RetainReleaseOperatonKind::invalidParameters:
2641
+ Impl.diagnose (loc,
2642
+ diag::foreign_reference_types_invalid_retain_release,
2643
+ false , retainOperation.name , classDecl->getNameStr ());
2644
+ break ;
2645
+ case RetainReleaseOperatonKind::valid:
2646
+ break ;
2595
2647
}
2596
2648
} else {
2597
2649
// Nothing to do.
@@ -2607,24 +2659,50 @@ namespace {
2607
2659
if (releaseOperation.kind ==
2608
2660
CustomRefCountingOperationResult::noAttribute) {
2609
2661
HeaderLoc loc (decl->getLocation ());
2610
- Impl.diagnose (loc, diag::reference_type_must_have_release_attr,
2611
- decl->getNameAsString ());
2662
+ Impl.diagnose (loc, diag::reference_type_must_have_retain_release_attr,
2663
+ true , decl->getNameAsString ());
2664
+ } else if (releaseOperation.kind ==
2665
+ CustomRefCountingOperationResult::tooManyAttributes) {
2666
+ HeaderLoc loc (decl->getLocation ());
2667
+ Impl.diagnose (loc, diag::too_many_reference_type_retain_release_attr,
2668
+ true , decl->getNameAsString ());
2612
2669
} else if (releaseOperation.kind ==
2613
2670
CustomRefCountingOperationResult::notFound) {
2614
2671
HeaderLoc loc (decl->getLocation ());
2615
- Impl.diagnose (loc, diag::foreign_reference_types_cannot_find_release,
2616
- releaseOperation.name , decl->getNameAsString ());
2672
+ Impl.diagnose (loc,
2673
+ diag::foreign_reference_types_cannot_find_retain_release,
2674
+ true , releaseOperation.name , decl->getNameAsString ());
2617
2675
} else if (releaseOperation.kind ==
2618
2676
CustomRefCountingOperationResult::tooManyFound) {
2619
2677
HeaderLoc loc (decl->getLocation ());
2620
- Impl.diagnose (loc, diag::too_many_reference_type_release_operations,
2621
- releaseOperation.name , decl->getNameAsString ());
2678
+ Impl.diagnose (loc,
2679
+ diag::too_many_reference_type_retain_release_operations,
2680
+ true , releaseOperation.name , decl->getNameAsString ());
2622
2681
} else if (releaseOperation.kind ==
2623
2682
CustomRefCountingOperationResult::foundOperation) {
2624
- if (!isValidOperation (releaseOperation.operation )) {
2625
- HeaderLoc loc (decl->getLocation ());
2626
- Impl.diagnose (loc, diag::foreign_reference_types_invalid_release,
2627
- releaseOperation.name , decl->getNameAsString ());
2683
+ RetainReleaseOperatonKind operationKind =
2684
+ getOperationValidity (releaseOperation.operation );
2685
+ HeaderLoc loc (decl->getLocation ());
2686
+ switch (operationKind) {
2687
+ case RetainReleaseOperatonKind::notAfunction:
2688
+ Impl.diagnose (
2689
+ loc,
2690
+ diag::foreign_reference_types_retain_release_not_a_function_decl,
2691
+ true , releaseOperation.name );
2692
+ break ;
2693
+ case RetainReleaseOperatonKind::doesntReturnVoid:
2694
+ Impl.diagnose (
2695
+ loc,
2696
+ diag::foreign_reference_types_retain_release_non_void_return_type,
2697
+ true , releaseOperation.name );
2698
+ break ;
2699
+ case RetainReleaseOperatonKind::invalidParameters:
2700
+ Impl.diagnose (loc,
2701
+ diag::foreign_reference_types_invalid_retain_release,
2702
+ true , releaseOperation.name , classDecl->getNameStr ());
2703
+ break ;
2704
+ case RetainReleaseOperatonKind::valid:
2705
+ break ;
2628
2706
}
2629
2707
} else {
2630
2708
// Nothing to do.
0 commit comments