@@ -2548,22 +2548,48 @@ namespace {
25482548
25492549 void validateForeignReferenceType (const clang::CXXRecordDecl *decl,
25502550 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 {
25522561 auto operationFn = dyn_cast<FuncDecl>(operation);
25532562 if (!operationFn)
2554- return false ;
2563+ return RetainReleaseOperatonKind::notAfunction ;
25552564
25562565 if (!operationFn->getResultInterfaceType ()->isVoid ())
2557- return false ;
2566+ return RetainReleaseOperatonKind::doesntReturnVoid ;
25582567
25592568 if (operationFn->getParameters ()->size () != 1 )
2560- return false ;
2569+ return RetainReleaseOperatonKind::invalidParameters ;
25612570
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+ }
25652577
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;
25672593 };
25682594
25692595 auto retainOperation = evaluateOrDefault (
@@ -2574,24 +2600,50 @@ namespace {
25742600 if (retainOperation.kind ==
25752601 CustomRefCountingOperationResult::noAttribute) {
25762602 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 ());
25792610 } else if (retainOperation.kind ==
25802611 CustomRefCountingOperationResult::notFound) {
25812612 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 ());
25842616 } else if (retainOperation.kind ==
25852617 CustomRefCountingOperationResult::tooManyFound) {
25862618 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 ());
25892622 } else if (retainOperation.kind ==
25902623 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 ;
25952647 }
25962648 } else {
25972649 // Nothing to do.
@@ -2607,24 +2659,50 @@ namespace {
26072659 if (releaseOperation.kind ==
26082660 CustomRefCountingOperationResult::noAttribute) {
26092661 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 ());
26122669 } else if (releaseOperation.kind ==
26132670 CustomRefCountingOperationResult::notFound) {
26142671 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 ());
26172675 } else if (releaseOperation.kind ==
26182676 CustomRefCountingOperationResult::tooManyFound) {
26192677 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 ());
26222681 } else if (releaseOperation.kind ==
26232682 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 ;
26282706 }
26292707 } else {
26302708 // Nothing to do.
0 commit comments