Skip to content

Commit

Permalink
[APINotes] Upstream the remaining API Notes fixes and tests
Browse files Browse the repository at this point in the history
This upstreams the last bits of Clang API Notes functionality that is
currently implemented in the Apple fork:
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
  • Loading branch information
egorzhdan committed Mar 27, 2024
1 parent 26464f2 commit 932949d
Show file tree
Hide file tree
Showing 96 changed files with 1,829 additions and 20 deletions.
41 changes: 23 additions & 18 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,49 +52,54 @@ static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability,
if (!Metadata.IsActive)
return;

auto IsModified = [&](Decl *D, QualType QT,
NullabilityKind Nullability) -> bool {
auto GetModified =
[&](Decl *D, QualType QT,
NullabilityKind Nullability) -> std::optional<QualType> {
QualType Original = QT;
S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
isa<ParmVarDecl>(D),
/*OverrideExisting=*/true);
return QT.getTypePtr() != Original.getTypePtr();
return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
: std::nullopt;
};

if (auto Function = dyn_cast<FunctionDecl>(D)) {
if (IsModified(D, Function->getReturnType(), Nullability)) {
QualType FnType = Function->getType();
Function->setType(FnType);
if (auto Modified =
GetModified(D, Function->getReturnType(), Nullability)) {
const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
Function->setType(S.Context.getFunctionType(
*Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
else
Function->setType(
S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
}
} else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
QualType Type = Method->getReturnType();
if (IsModified(D, Type, Nullability)) {
Method->setReturnType(Type);
if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
Method->setReturnType(*Modified);

// Make it a context-sensitive keyword if we can.
if (!isIndirectPointerType(Type))
if (!isIndirectPointerType(*Modified))
Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
}
} else if (auto Value = dyn_cast<ValueDecl>(D)) {
QualType Type = Value->getType();
if (IsModified(D, Type, Nullability)) {
Value->setType(Type);
if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
Value->setType(*Modified);

// Make it a context-sensitive keyword if we can.
if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
}
}
} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
QualType Type = Property->getType();
if (IsModified(D, Type, Nullability)) {
Property->setType(Type, Property->getTypeSourceInfo());
if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
Property->setType(*Modified, Property->getTypeSourceInfo());

// Make it a property attribute if we can.
if (!isIndirectPointerType(Type))
if (!isIndirectPointerType(*Modified))
Property->setPropertyAttributes(
ObjCPropertyAttribute::kind_null_resettable);
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaObjCProperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,15 +638,15 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PDecl->setInvalidDecl();
}

ProcessDeclAttributes(S, PDecl, FD.D);

// Regardless of setter/getter attribute, we save the default getter/setter
// selector names in anticipation of declaration of setter/getter methods.
PDecl->setGetterName(GetterSel, GetterNameLoc);
PDecl->setSetterName(SetterSel, SetterNameLoc);
PDecl->setPropertyAttributesAsWritten(
makePropertyAttributesAsWritten(AttributesAsWritten));

ProcessDeclAttributes(S, PDecl, FD.D);

if (Attributes & ObjCPropertyAttribute::kind_readonly)
PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);

Expand Down
8 changes: 8 additions & 0 deletions clang/test/APINotes/Inputs/APINotes/SomeOtherKit.apinotes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Name: SomeOtherKit
Classes:
- Name: A
Methods:
- Selector: "methodB"
MethodKind: Instance
Availability: none
AvailabilityMsg: "anything but this"
5 changes: 5 additions & 0 deletions clang/test/APINotes/Inputs/BrokenHeaders/APINotes.apinotes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Name: SomeBrokenLib
Functions:
- Name: do_something_with_pointers
Nu llabilityOfRet: O
# the space is intentional, to make sure we don't crash on malformed API Notes
6 changes: 6 additions & 0 deletions clang/test/APINotes/Inputs/BrokenHeaders/SomeBrokenLib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef SOME_BROKEN_LIB_H
#define SOME_BROKEN_LIB_H

void do_something_with_pointers(int *ptr1, int *ptr2);

#endif // SOME_BROKEN_LIB_H
7 changes: 7 additions & 0 deletions clang/test/APINotes/Inputs/BrokenHeaders2/APINotes.apinotes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Name: SomeBrokenLib
Functions:
- Name: do_something_with_pointers
NullabilityOfRet: O
- Name: do_something_with_pointers
NullabilityOfRet: O

6 changes: 6 additions & 0 deletions clang/test/APINotes/Inputs/BrokenHeaders2/SomeBrokenLib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef SOME_BROKEN_LIB_H
#define SOME_BROKEN_LIB_H

void do_something_with_pointers(int *ptr1, int *ptr2);

#endif // SOME_BROKEN_LIB_H
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern int FrameworkWithActualPrivateModule;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module FrameworkWithActualPrivateModule {
umbrella header "FrameworkWithActualPrivateModule.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module FrameworkWithActualPrivateModule_Private {
umbrella header "FrameworkWithActualPrivateModule_Private.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Name: FrameworkWithActualPrivateModule_Private
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <FrameworkWithActualPrivateModule/FrameworkWithActualPrivateModule.h>
extern int FrameworkWithActualPrivateModule_Private;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern int FrameworkWithWrongCase;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module FrameworkWithWrongCase {
umbrella header "FrameworkWithWrongCase.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Name: FrameworkWithWrongCase
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern int FrameworkWithWrongCasePrivate;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module FrameworkWithWrongCasePrivate {
umbrella header "FrameworkWithWrongCasePrivate.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module FrameworkWithWrongCasePrivate.Inner {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Name: FrameworkWithWrongCasePrivate
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import LayeredKitImpl;

// @interface declarations already don't inherit attributes from forward
// declarations, so in order to test this properly we have to /not/ define
// UpwardClass anywhere.

// @interface UpwardClass
// @end

@protocol UpwardProto
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module LayeredKit {
umbrella header "LayeredKit.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Name: LayeredKitImpl
Classes:
- Name: PerfectlyNormalClass
Availability: none
- Name: UpwardClass
Availability: none
Protocols:
- Name: UpwardProto
Availability: none
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@protocol UpwardProto;
@class UpwardClass;

@interface PerfectlyNormalClass
@end

void doImplementationThings(UpwardClass *first, id <UpwardProto> second) __attribute((unavailable));
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module LayeredKitImpl {
umbrella header "LayeredKitImpl.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module SimpleKit {
umbrella header "SimpleKit.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Name: SomeKit
Classes:
- Name: A
Methods:
- Selector: "transform:"
MethodKind: Instance
Availability: none
AvailabilityMsg: "anything but this"
- Selector: "transform:integer:"
MethodKind: Instance
NullabilityOfRet: N
Nullability: [ N, S ]
Properties:
- Name: intValue
PropertyKind: Instance
Availability: none
AvailabilityMsg: "wouldn't work anyway"
- Name: nonnullAInstance
PropertyKind: Instance
Nullability: N
- Name: nonnullAClass
PropertyKind: Class
Nullability: N
- Name: nonnullABoth
Nullability: N
- Name: B
Availability: none
AvailabilityMsg: "just don't"
- Name: C
Methods:
- Selector: "initWithA:"
MethodKind: Instance
DesignatedInit: true
- Name: OverriddenTypes
Methods:
- Selector: "methodToMangle:second:"
MethodKind: Instance
ResultType: 'char *'
Parameters:
- Position: 0
Type: 'SOMEKIT_DOUBLE *'
- Position: 1
Type: 'float *'
Properties:
- Name: intPropertyToMangle
PropertyKind: Instance
Type: 'double *'
Functions:
- Name: global_int_fun
ResultType: 'char *'
Parameters:
- Position: 0
Type: 'double *'
- Position: 1
Type: 'float *'
Globals:
- Name: global_int_ptr
Type: 'double *'
SwiftVersions:
- Version: 3.0
Classes:
- Name: A
Methods:
- Selector: "transform:integer:"
MethodKind: Instance
NullabilityOfRet: O
Nullability: [ O, S ]
Properties:
- Name: explicitNonnullInstance
PropertyKind: Instance
Nullability: O
- Name: explicitNullableInstance
PropertyKind: Instance
Nullability: N
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Name: SomeKit
Classes:
- Name: A
Methods:
- Selector: "privateTransform:input:"
MethodKind: Instance
NullabilityOfRet: N
Nullability: [ N, S ]
Properties:
- Name: internalProperty
Nullability: N
Protocols:
- Name: InternalProtocol
Availability: none
AvailabilityMsg: "not for you"
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef SOMEKIT_H
#define SOMEKIT_H

#define ROOT_CLASS __attribute__((objc_root_class))

ROOT_CLASS
@interface A
-(A*)transform:(A*)input;
-(A*)transform:(A*)input integer:(int)integer;

@property (nonatomic, readonly, retain) A* someA;
@property (nonatomic, retain) A* someOtherA;

@property (nonatomic) int intValue;
@end

@interface B : A
@end

@interface C : A
- (instancetype)init;
- (instancetype)initWithA:(A*)a;
@end


@interface MyClass : A
- Inst;
+ Clas;
@end

struct CGRect {
float origin;
float size;
};
typedef struct CGRect NSRect;

@interface I
- (void) Meth : (NSRect[4])exposedRects;
- (void) Meth1 : (const I*)exposedRects;
- (void) Meth2 : (const I*)exposedRects;
- (void) Meth3 : (I*)exposedRects;
- (const I*) Meth4;
- (const I*) Meth5 : (int) Arg1 : (const I*)Arg2 : (double)Arg3 : (const I*) Arg4 :(const volatile id) Arg5;
- (volatile const I*) Meth6 : (const char *)Arg1 : (const char *)Arg2 : (double)Arg3 : (const I*) Arg4 :(const volatile id) Arg5;
@end

@class NSURL, NSArray, NSError;
@interface INTF_BLOCKS
+ (void)getNonLocalVersionsOfItemAtURL:(NSURL *)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ (void *)getNonLocalVersionsOfItemAtURL2:(NSURL *)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ (NSError **)getNonLocalVersionsOfItemAtURL3:(int)url completionHandler:(void (^)(NSArray *nonLocalFileVersions, NSError *error))completionHandler;
+ (id)getNonLocalVersionsOfItemAtURL4:(NSURL *)url completionHandler:(void (^)(int nonLocalFileVersions, NSError *error, NSURL*))completionHandler;
@end

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework module SomeKit {
umbrella header "SomeKit.h"
export *
module * { export * }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module SomeKit.Private {
header "SomeKit_Private.h"
export *

explicit module NullAnnotation {
header "SomeKit_PrivateForNullAnnotation.h"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
explicit framework module SomeKit.Private {
header "SomeKit_Private.h"
explicit NullAnnotation { header "SomeKit_PrivateForNullAnnotation.h" }
export *
module * { export * }
syntax error

}

0 comments on commit 932949d

Please sign in to comment.