@@ -53,63 +53,58 @@ static bool isIndirectPointerType(QualType Type) {
5353 Pointee->isMemberPointerType ();
5454}
5555
56- // / Apply nullability to the given declaration.
57- static void applyNullability (Sema &S, Decl *D, NullabilityKind Nullability,
58- VersionedInfoMetadata Metadata) {
59- if (!Metadata.IsActive )
60- return ;
61-
62- auto GetModified =
63- [&](Decl *D, QualType QT,
64- NullabilityKind Nullability) -> std::optional<QualType> {
65- QualType Original = QT;
66- S.CheckImplicitNullabilityTypeSpecifier (QT, Nullability, D->getLocation (),
67- isa<ParmVarDecl>(D),
68- /* OverrideExisting=*/ true );
69- return (QT.getTypePtr () != Original.getTypePtr ()) ? std::optional (QT)
70- : std::nullopt ;
71- };
56+ static void applyAPINotesType (Sema &S, Decl *decl, StringRef typeString,
57+ VersionedInfoMetadata metadata) {
58+ if (typeString.empty ())
7259
73- if (auto Function = dyn_cast<FunctionDecl>(D)) {
74- if (auto Modified =
75- GetModified (D, Function->getReturnType (), Nullability)) {
76- const FunctionType *FnType = Function->getType ()->castAs <FunctionType>();
77- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
78- Function->setType (S.Context .getFunctionType (
79- *Modified, proto->getParamTypes (), proto->getExtProtoInfo ()));
80- else
81- Function->setType (
82- S.Context .getFunctionNoProtoType (*Modified, FnType->getExtInfo ()));
83- }
84- } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
85- if (auto Modified = GetModified (D, Method->getReturnType (), Nullability)) {
86- Method->setReturnType (*Modified);
60+ return ;
8761
88- // Make it a context-sensitive keyword if we can.
89- if (!isIndirectPointerType (*Modified))
90- Method->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
91- Method->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
92- }
93- } else if (auto Value = dyn_cast<ValueDecl>(D)) {
94- if (auto Modified = GetModified (D, Value->getType (), Nullability)) {
95- Value->setType (*Modified);
62+ // Version-independent APINotes add "type" annotations
63+ // with a versioned attribute for the client to select and apply.
64+ if (S.captureSwiftVersionIndependentAPINotes ()) {
65+ auto *typeAttr = SwiftTypeAttr::CreateImplicit (S.Context , typeString);
66+ auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit (
67+ S.Context , metadata.Version , typeAttr, metadata.IsReplacement );
68+ decl->addAttr (versioned);
69+ } else {
70+ if (!metadata.IsActive )
71+ return ;
72+ S.ApplyAPINotesType (decl, typeString);
73+ }
74+ }
9675
97- // Make it a context-sensitive keyword if we can.
98- if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
99- if (Parm->isObjCMethodParameter () && !isIndirectPointerType (*Modified))
100- Parm->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
101- Parm->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
102- }
76+ // / Apply nullability to the given declaration.
77+ static void applyNullability (Sema &S, Decl *decl, NullabilityKind nullability,
78+ VersionedInfoMetadata metadata) {
79+ // Version-independent APINotes add "nullability" annotations
80+ // with a versioned attribute for the client to select and apply.
81+ if (S.captureSwiftVersionIndependentAPINotes ()) {
82+ SwiftNullabilityAttr::Kind attrNullabilityKind;
83+ switch (nullability) {
84+ case NullabilityKind::NonNull:
85+ attrNullabilityKind = SwiftNullabilityAttr::Kind::NonNull;
86+ break ;
87+ case NullabilityKind::Nullable:
88+ attrNullabilityKind = SwiftNullabilityAttr::Kind::Nullable;
89+ break ;
90+ case NullabilityKind::Unspecified:
91+ attrNullabilityKind = SwiftNullabilityAttr::Kind::Unspecified;
92+ break ;
93+ case NullabilityKind::NullableResult:
94+ attrNullabilityKind = SwiftNullabilityAttr::Kind::NullableResult;
95+ break ;
10396 }
104- } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
105- if (auto Modified = GetModified (D, Property->getType (), Nullability)) {
106- Property->setType (*Modified, Property->getTypeSourceInfo ());
97+ auto *nullabilityAttr =
98+ SwiftNullabilityAttr::CreateImplicit (S.Context , attrNullabilityKind);
99+ auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit (
100+ S.Context , metadata.Version , nullabilityAttr, metadata.IsReplacement );
101+ decl->addAttr (versioned);
102+ return ;
103+ } else {
104+ if (!metadata.IsActive )
105+ return ;
107106
108- // Make it a property attribute if we can.
109- if (!isIndirectPointerType (*Modified))
110- Property->setPropertyAttributes (
111- ObjCPropertyAttribute::kind_null_resettable);
112- }
107+ S.ApplyNullability (decl, nullability);
113108 }
114109}
115110
@@ -363,42 +358,99 @@ static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
363358 return false ;
364359}
365360
366- // / Process API notes for a variable or property.
367- static void ProcessAPINotes (Sema &S, Decl *D,
368- const api_notes::VariableInfo &Info,
369- VersionedInfoMetadata Metadata) {
370- // Type override.
371- if (Metadata.IsActive && !Info.getType ().empty () &&
372- S.ParseTypeFromStringCallback ) {
373- auto ParsedType = S.ParseTypeFromStringCallback (
374- Info.getType (), " <API Notes>" , D->getLocation ());
361+ void Sema::ApplyAPINotesType (Decl *D, StringRef TypeString) {
362+ if (!TypeString.empty () && ParseTypeFromStringCallback) {
363+ auto ParsedType = ParseTypeFromStringCallback (TypeString, " <API Notes>" ,
364+ D->getLocation ());
375365 if (ParsedType.isUsable ()) {
376366 QualType Type = Sema::GetTypeFromParser (ParsedType.get ());
377- auto TypeInfo =
378- S.Context .getTrivialTypeSourceInfo (Type, D->getLocation ());
379-
367+ auto TypeInfo = Context.getTrivialTypeSourceInfo (Type, D->getLocation ());
380368 if (auto Var = dyn_cast<VarDecl>(D)) {
381369 // Make adjustments to parameter types.
382370 if (isa<ParmVarDecl>(Var)) {
383- Type = S. ObjC ().AdjustParameterTypeForObjCAutoRefCount (
371+ Type = ObjC ().AdjustParameterTypeForObjCAutoRefCount (
384372 Type, D->getLocation (), TypeInfo);
385- Type = S. Context .getAdjustedParameterType (Type);
373+ Type = Context.getAdjustedParameterType (Type);
386374 }
387375
388- if (!checkAPINotesReplacementType (S , Var->getLocation (), Var-> getType (),
389- Type)) {
376+ if (!checkAPINotesReplacementType (* this , Var->getLocation (),
377+ Var-> getType (), Type)) {
390378 Var->setType (Type);
391379 Var->setTypeSourceInfo (TypeInfo);
392380 }
393- } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
394- if (!checkAPINotesReplacementType (S, Property ->getLocation (),
395- Property ->getType (), Type))
396- Property ->setType (Type, TypeInfo);
397-
398- } else
381+ } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
382+ if (!checkAPINotesReplacementType (* this , property ->getLocation (),
383+ property ->getType (), Type)) {
384+ property ->setType (Type, TypeInfo);
385+ }
386+ } else {
399387 llvm_unreachable (" API notes allowed a type on an unknown declaration" );
388+ }
389+ }
390+ }
391+ }
392+
393+ void Sema::ApplyNullability (Decl *D, NullabilityKind Nullability) {
394+ auto GetModified =
395+ [&](class Decl *D, QualType QT,
396+ NullabilityKind Nullability) -> std::optional<QualType> {
397+ QualType Original = QT;
398+ CheckImplicitNullabilityTypeSpecifier (QT, Nullability, D->getLocation (),
399+ isa<ParmVarDecl>(D),
400+ /* OverrideExisting=*/ true );
401+ return (QT.getTypePtr () != Original.getTypePtr ()) ? std::optional (QT)
402+ : std::nullopt ;
403+ };
404+
405+ if (auto Function = dyn_cast<FunctionDecl>(D)) {
406+ if (auto Modified =
407+ GetModified (D, Function->getReturnType (), Nullability)) {
408+ const FunctionType *FnType = Function->getType ()->castAs <FunctionType>();
409+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
410+ Function->setType (Context.getFunctionType (
411+ *Modified, proto->getParamTypes (), proto->getExtProtoInfo ()));
412+ else
413+ Function->setType (
414+ Context.getFunctionNoProtoType (*Modified, FnType->getExtInfo ()));
415+ }
416+ } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
417+ if (auto Modified = GetModified (D, Method->getReturnType (), Nullability)) {
418+ Method->setReturnType (*Modified);
419+
420+ // Make it a context-sensitive keyword if we can.
421+ if (!isIndirectPointerType (*Modified))
422+ Method->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
423+ Method->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
424+ }
425+ } else if (auto Value = dyn_cast<ValueDecl>(D)) {
426+ if (auto Modified = GetModified (D, Value->getType (), Nullability)) {
427+ Value->setType (*Modified);
428+
429+ // Make it a context-sensitive keyword if we can.
430+ if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
431+ if (Parm->isObjCMethodParameter () && !isIndirectPointerType (*Modified))
432+ Parm->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
433+ Parm->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
434+ }
435+ }
436+ } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
437+ if (auto Modified = GetModified (D, Property->getType (), Nullability)) {
438+ Property->setType (*Modified, Property->getTypeSourceInfo ());
439+
440+ // Make it a property attribute if we can.
441+ if (!isIndirectPointerType (*Modified))
442+ Property->setPropertyAttributes (
443+ ObjCPropertyAttribute::kind_null_resettable);
400444 }
401445 }
446+ }
447+
448+ // / Process API notes for a variable or property.
449+ static void ProcessAPINotes (Sema &S, Decl *D,
450+ const api_notes::VariableInfo &Info,
451+ VersionedInfoMetadata Metadata) {
452+ // Type override.
453+ applyAPINotesType (S, D, Info.getType (), Metadata);
402454
403455 // Nullability.
404456 if (auto Nullability = Info.getNullability ())
@@ -892,7 +944,8 @@ static void ProcessVersionedAPINotes(
892944 Sema &S, SpecificDecl *D,
893945 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
894946
895- maybeAttachUnversionedSwiftName (S, D, Info);
947+ if (!S.captureSwiftVersionIndependentAPINotes ())
948+ maybeAttachUnversionedSwiftName (S, D, Info);
896949
897950 unsigned Selected = Info.getSelected ().value_or (Info.size ());
898951
@@ -902,10 +955,18 @@ static void ProcessVersionedAPINotes(
902955 std::tie (Version, InfoSlice) = Info[i];
903956 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
904957 auto Replacement = IsSubstitution_t::Original;
905- if (Active == IsActive_t::Inactive && Version.empty ()) {
958+
959+ // When collection all APINotes as version-independent,
960+ // capture all as inactive and defer to the client select the
961+ // right one.
962+ if (S.captureSwiftVersionIndependentAPINotes ()) {
963+ Active = IsActive_t::Inactive;
964+ Replacement = IsSubstitution_t::Original;
965+ } else if (Active == IsActive_t::Inactive && Version.empty ()) {
906966 Replacement = IsSubstitution_t::Replacement;
907967 Version = Info[Selected].first ;
908968 }
969+
909970 ProcessAPINotes (S, D, InfoSlice,
910971 VersionedInfoMetadata (Version, Active, Replacement));
911972 }
0 commit comments