@@ -52,63 +52,58 @@ static bool isIndirectPointerType(QualType Type) {
5252 Pointee->isMemberPointerType ();
5353}
5454
55- // / Apply nullability to the given declaration.
56- static void applyNullability (Sema &S, Decl *D, NullabilityKind Nullability,
57- VersionedInfoMetadata Metadata) {
58- if (!Metadata.IsActive )
59- return ;
55+ static void applyAPINotesType (Sema &S, Decl *decl, StringRef typeString,
56+ VersionedInfoMetadata metadata) {
57+ if (typeString.empty ())
6058
61- auto GetModified =
62- [&](Decl *D, QualType QT,
63- NullabilityKind Nullability) -> std::optional<QualType> {
64- QualType Original = QT;
65- S.CheckImplicitNullabilityTypeSpecifier (QT, Nullability, D->getLocation (),
66- isa<ParmVarDecl>(D),
67- /* OverrideExisting=*/ true );
68- return (QT.getTypePtr () != Original.getTypePtr ()) ? std::optional (QT)
69- : std::nullopt ;
70- };
71-
72- if (auto Function = dyn_cast<FunctionDecl>(D)) {
73- if (auto Modified =
74- GetModified (D, Function->getReturnType (), Nullability)) {
75- const FunctionType *FnType = Function->getType ()->castAs <FunctionType>();
76- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
77- Function->setType (S.Context .getFunctionType (
78- *Modified, proto->getParamTypes (), proto->getExtProtoInfo ()));
79- else
80- Function->setType (
81- S.Context .getFunctionNoProtoType (*Modified, FnType->getExtInfo ()));
82- }
83- } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
84- if (auto Modified = GetModified (D, Method->getReturnType (), Nullability)) {
85- Method->setReturnType (*Modified);
59+ return ;
8660
87- // Make it a context-sensitive keyword if we can.
88- if (!isIndirectPointerType (*Modified))
89- Method->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
90- Method->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
91- }
92- } else if (auto Value = dyn_cast<ValueDecl>(D)) {
93- if (auto Modified = GetModified (D, Value->getType (), Nullability)) {
94- Value->setType (*Modified);
61+ // Version-independent APINotes add "type" annotations
62+ // with a versioned attribute for the client to select and apply.
63+ if (S.captureSwiftVersionIndependentAPINotes ()) {
64+ auto *typeAttr = SwiftTypeAttr::CreateImplicit (S.Context , typeString);
65+ auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit (
66+ S.Context , metadata.Version , typeAttr, metadata.IsReplacement );
67+ decl->addAttr (versioned);
68+ } else {
69+ if (!metadata.IsActive )
70+ return ;
71+ S.ApplyAPINotesType (decl, typeString);
72+ }
73+ }
9574
96- // Make it a context-sensitive keyword if we can.
97- if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
98- if (Parm->isObjCMethodParameter () && !isIndirectPointerType (*Modified))
99- Parm->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
100- Parm->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
101- }
75+ // / Apply nullability to the given declaration.
76+ static void applyNullability (Sema &S, Decl *decl, NullabilityKind nullability,
77+ VersionedInfoMetadata metadata) {
78+ // Version-independent APINotes add "nullability" annotations
79+ // with a versioned attribute for the client to select and apply.
80+ if (S.captureSwiftVersionIndependentAPINotes ()) {
81+ SwiftNullabilityAttr::Kind attrNullabilityKind;
82+ switch (nullability) {
83+ case NullabilityKind::NonNull:
84+ attrNullabilityKind = SwiftNullabilityAttr::Kind::NonNull;
85+ break ;
86+ case NullabilityKind::Nullable:
87+ attrNullabilityKind = SwiftNullabilityAttr::Kind::Nullable;
88+ break ;
89+ case NullabilityKind::Unspecified:
90+ attrNullabilityKind = SwiftNullabilityAttr::Kind::Unspecified;
91+ break ;
92+ case NullabilityKind::NullableResult:
93+ attrNullabilityKind = SwiftNullabilityAttr::Kind::NullableResult;
94+ break ;
10295 }
103- } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
104- if (auto Modified = GetModified (D, Property->getType (), Nullability)) {
105- Property->setType (*Modified, Property->getTypeSourceInfo ());
96+ auto *nullabilityAttr =
97+ SwiftNullabilityAttr::CreateImplicit (S.Context , attrNullabilityKind);
98+ auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit (
99+ S.Context , metadata.Version , nullabilityAttr, metadata.IsReplacement );
100+ decl->addAttr (versioned);
101+ return ;
102+ } else {
103+ if (!metadata.IsActive )
104+ return ;
106105
107- // Make it a property attribute if we can.
108- if (!isIndirectPointerType (*Modified))
109- Property->setPropertyAttributes (
110- ObjCPropertyAttribute::kind_null_resettable);
111- }
106+ S.ApplyNullability (decl, nullability);
112107 }
113108}
114109
@@ -361,42 +356,99 @@ static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
361356 return false ;
362357}
363358
364- // / Process API notes for a variable or property.
365- static void ProcessAPINotes (Sema &S, Decl *D,
366- const api_notes::VariableInfo &Info,
367- VersionedInfoMetadata Metadata) {
368- // Type override.
369- if (Metadata.IsActive && !Info.getType ().empty () &&
370- S.ParseTypeFromStringCallback ) {
371- auto ParsedType = S.ParseTypeFromStringCallback (
372- Info.getType (), " <API Notes>" , D->getLocation ());
359+ void Sema::ApplyAPINotesType (Decl *D, StringRef TypeString) {
360+ if (!TypeString.empty () && ParseTypeFromStringCallback) {
361+ auto ParsedType = ParseTypeFromStringCallback (TypeString, " <API Notes>" ,
362+ D->getLocation ());
373363 if (ParsedType.isUsable ()) {
374364 QualType Type = Sema::GetTypeFromParser (ParsedType.get ());
375- auto TypeInfo =
376- S.Context .getTrivialTypeSourceInfo (Type, D->getLocation ());
377-
365+ auto TypeInfo = Context.getTrivialTypeSourceInfo (Type, D->getLocation ());
378366 if (auto Var = dyn_cast<VarDecl>(D)) {
379367 // Make adjustments to parameter types.
380368 if (isa<ParmVarDecl>(Var)) {
381- Type = S. ObjC ().AdjustParameterTypeForObjCAutoRefCount (
369+ Type = ObjC ().AdjustParameterTypeForObjCAutoRefCount (
382370 Type, D->getLocation (), TypeInfo);
383- Type = S. Context .getAdjustedParameterType (Type);
371+ Type = Context.getAdjustedParameterType (Type);
384372 }
385373
386- if (!checkAPINotesReplacementType (S , Var->getLocation (), Var-> getType (),
387- Type)) {
374+ if (!checkAPINotesReplacementType (* this , Var->getLocation (),
375+ Var-> getType (), Type)) {
388376 Var->setType (Type);
389377 Var->setTypeSourceInfo (TypeInfo);
390378 }
391- } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
392- if (!checkAPINotesReplacementType (S, Property ->getLocation (),
393- Property ->getType (), Type))
394- Property ->setType (Type, TypeInfo);
395-
396- } else
379+ } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
380+ if (!checkAPINotesReplacementType (* this , property ->getLocation (),
381+ property ->getType (), Type)) {
382+ property ->setType (Type, TypeInfo);
383+ }
384+ } else {
397385 llvm_unreachable (" API notes allowed a type on an unknown declaration" );
386+ }
387+ }
388+ }
389+ }
390+
391+ void Sema::ApplyNullability (Decl *D, NullabilityKind Nullability) {
392+ auto GetModified =
393+ [&](class Decl *D, QualType QT,
394+ NullabilityKind Nullability) -> std::optional<QualType> {
395+ QualType Original = QT;
396+ CheckImplicitNullabilityTypeSpecifier (QT, Nullability, D->getLocation (),
397+ isa<ParmVarDecl>(D),
398+ /* OverrideExisting=*/ true );
399+ return (QT.getTypePtr () != Original.getTypePtr ()) ? std::optional (QT)
400+ : std::nullopt ;
401+ };
402+
403+ if (auto Function = dyn_cast<FunctionDecl>(D)) {
404+ if (auto Modified =
405+ GetModified (D, Function->getReturnType (), Nullability)) {
406+ const FunctionType *FnType = Function->getType ()->castAs <FunctionType>();
407+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
408+ Function->setType (Context.getFunctionType (
409+ *Modified, proto->getParamTypes (), proto->getExtProtoInfo ()));
410+ else
411+ Function->setType (
412+ Context.getFunctionNoProtoType (*Modified, FnType->getExtInfo ()));
413+ }
414+ } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
415+ if (auto Modified = GetModified (D, Method->getReturnType (), Nullability)) {
416+ Method->setReturnType (*Modified);
417+
418+ // Make it a context-sensitive keyword if we can.
419+ if (!isIndirectPointerType (*Modified))
420+ Method->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
421+ Method->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
422+ }
423+ } else if (auto Value = dyn_cast<ValueDecl>(D)) {
424+ if (auto Modified = GetModified (D, Value->getType (), Nullability)) {
425+ Value->setType (*Modified);
426+
427+ // Make it a context-sensitive keyword if we can.
428+ if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
429+ if (Parm->isObjCMethodParameter () && !isIndirectPointerType (*Modified))
430+ Parm->setObjCDeclQualifier (Decl::ObjCDeclQualifier (
431+ Parm->getObjCDeclQualifier () | Decl::OBJC_TQ_CSNullability));
432+ }
433+ }
434+ } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
435+ if (auto Modified = GetModified (D, Property->getType (), Nullability)) {
436+ Property->setType (*Modified, Property->getTypeSourceInfo ());
437+
438+ // Make it a property attribute if we can.
439+ if (!isIndirectPointerType (*Modified))
440+ Property->setPropertyAttributes (
441+ ObjCPropertyAttribute::kind_null_resettable);
398442 }
399443 }
444+ }
445+
446+ // / Process API notes for a variable or property.
447+ static void ProcessAPINotes (Sema &S, Decl *D,
448+ const api_notes::VariableInfo &Info,
449+ VersionedInfoMetadata Metadata) {
450+ // Type override.
451+ applyAPINotesType (S, D, Info.getType (), Metadata);
400452
401453 // Nullability.
402454 if (auto Nullability = Info.getNullability ())
@@ -814,7 +866,8 @@ static void ProcessVersionedAPINotes(
814866 Sema &S, SpecificDecl *D,
815867 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
816868
817- maybeAttachUnversionedSwiftName (S, D, Info);
869+ if (!S.captureSwiftVersionIndependentAPINotes ())
870+ maybeAttachUnversionedSwiftName (S, D, Info);
818871
819872 unsigned Selected = Info.getSelected ().value_or (Info.size ());
820873
@@ -824,10 +877,18 @@ static void ProcessVersionedAPINotes(
824877 std::tie (Version, InfoSlice) = Info[i];
825878 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
826879 auto Replacement = IsSubstitution_t::Original;
827- if (Active == IsActive_t::Inactive && Version.empty ()) {
880+
881+ // When collection all APINotes as version-independent,
882+ // capture all as inactive and defer to the client select the
883+ // right one.
884+ if (S.captureSwiftVersionIndependentAPINotes ()) {
885+ Active = IsActive_t::Inactive;
886+ Replacement = IsSubstitution_t::Original;
887+ } else if (Active == IsActive_t::Inactive && Version.empty ()) {
828888 Replacement = IsSubstitution_t::Replacement;
829889 Version = Info[Selected].first ;
830890 }
891+
831892 ProcessAPINotes (S, D, InfoSlice,
832893 VersionedInfoMetadata (Version, Active, Replacement));
833894 }
0 commit comments