Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit d2bd9c6

Browse files
authored
Merge pull request #27 from DougGregor/apinotes-class-properties-3_1
[APINotes] Add support for distinguishing class vs. instance properties.
2 parents df3824c + f02cbff commit d2bd9c6

File tree

14 files changed

+113
-28
lines changed

14 files changed

+113
-28
lines changed

include/clang/APINotes/APINotesReader.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,13 @@ class APINotesReader {
7474
///
7575
/// \param contextID The ID that references the context we are looking for.
7676
/// \param name The name of the property we're looking for.
77+
/// \param isInstance Whether we are looking for an instance property (vs.
78+
/// a class property).
7779
///
7880
/// \returns Information about the property, if known.
7981
Optional<ObjCPropertyInfo> lookupObjCProperty(ContextID contextID,
80-
StringRef name);
82+
StringRef name,
83+
bool isInstance);
8184

8285
/// Look for information regarding the given Objective-C method in
8386
/// the given context.
@@ -147,6 +150,7 @@ class APINotesReader {
147150

148151
/// Visit an Objective-C property.
149152
virtual void visitObjCProperty(ContextID contextID, StringRef name,
153+
bool isInstance,
150154
const ObjCPropertyInfo &info);
151155

152156
/// Visit a global variable.

include/clang/APINotes/APINotesWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class APINotesWriter {
6666
/// \param name The name of this property.
6767
/// \param info Information about this property.
6868
void addObjCProperty(ContextID contextID, StringRef name,
69+
bool isInstanceProperty,
6970
const ObjCPropertyInfo &info);
7071

7172
/// Add information about a specific Objective-C method.

lib/APINotes/APINotesFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const uint16_t VERSION_MAJOR = 0;
3636
/// API notes file minor version number.
3737
///
3838
/// When the format changes IN ANY WAY, this number should be incremented.
39-
const uint16_t VERSION_MINOR = 13; // Function/method parameters
39+
const uint16_t VERSION_MINOR = 14; // Objective-C class properties
4040

4141
using IdentifierID = PointerEmbeddedInt<unsigned, 31>;
4242
using IdentifierIDField = BCVBR<16>;

lib/APINotes/APINotesReader.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ namespace {
175175
/// Used to deserialize the on-disk Objective-C property table.
176176
class ObjCPropertyTableInfo {
177177
public:
178-
// (context ID, name ID)
179-
using internal_key_type = std::pair<unsigned, unsigned>;
178+
// (context ID, name ID, isInstance)
179+
using internal_key_type = std::tuple<unsigned, unsigned, char>;
180180
using external_key_type = internal_key_type;
181181
using data_type = ObjCPropertyInfo;
182182
using hash_value_type = size_t;
@@ -208,7 +208,8 @@ namespace {
208208
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
209209
auto classID = endian::readNext<uint32_t, little, unaligned>(data);
210210
auto nameID = endian::readNext<uint32_t, little, unaligned>(data);
211-
return { classID, nameID };
211+
char isInstance = endian::readNext<uint8_t, little, unaligned>(data);
212+
return std::make_tuple(classID, nameID, isInstance);
212213
}
213214

214215
static data_type ReadData(internal_key_type key, const uint8_t *data,
@@ -1510,15 +1511,18 @@ auto APINotesReader::lookupObjCProtocol(StringRef name)
15101511

15111512
Optional<ObjCPropertyInfo> APINotesReader::lookupObjCProperty(
15121513
ContextID contextID,
1513-
StringRef name) {
1514+
StringRef name,
1515+
bool isInstance) {
15141516
if (!Impl.ObjCPropertyTable)
15151517
return None;
15161518

15171519
Optional<IdentifierID> propertyID = Impl.getIdentifier(name);
15181520
if (!propertyID)
15191521
return None;
15201522

1521-
auto known = Impl.ObjCPropertyTable->find({contextID.Value, *propertyID});
1523+
auto known = Impl.ObjCPropertyTable->find(std::make_tuple(contextID.Value,
1524+
*propertyID,
1525+
(char)isInstance));
15221526
if (known == Impl.ObjCPropertyTable->end())
15231527
return None;
15241528

@@ -1639,6 +1643,7 @@ void APINotesReader::Visitor::visitObjCMethod(ContextID contextID,
16391643

16401644
void APINotesReader::Visitor::visitObjCProperty(ContextID contextID,
16411645
StringRef name,
1646+
bool isInstance,
16421647
const ObjCPropertyInfo &info) { }
16431648

16441649
void APINotesReader::Visitor::visitGlobalVariable(
@@ -1723,10 +1728,11 @@ void APINotesReader::visit(Visitor &visitor) {
17231728
// Visit properties.
17241729
if (Impl.ObjCPropertyTable) {
17251730
for (auto key : Impl.ObjCPropertyTable->keys()) {
1726-
ContextID contextID(key.first);
1727-
auto name = identifiers[key.second];
1731+
ContextID contextID(std::get<0>(key));
1732+
auto name = identifiers[std::get<1>(key)];
1733+
char isInstance = std::get<2>(key);
17281734
auto info = *Impl.ObjCPropertyTable->find(key);
1729-
visitor.visitObjCProperty(contextID, name, info);
1735+
visitor.visitObjCProperty(contextID, name, isInstance, info);
17301736
}
17311737
}
17321738

lib/APINotes/APINotesWriter.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ class APINotesWriter::Implementation {
5858

5959
/// Information about Objective-C properties.
6060
///
61-
/// Indexed by the context ID and property name.
62-
llvm::DenseMap<std::pair<unsigned, unsigned>, ObjCPropertyInfo>
61+
/// Indexed by the context ID, property name, and whether this is an
62+
/// instance property.
63+
llvm::DenseMap<std::tuple<unsigned, unsigned, char>, ObjCPropertyInfo>
6364
ObjCProperties;
6465

6566
/// Information about Objective-C methods.
@@ -430,7 +431,8 @@ namespace {
430431
/// Used to serialize the on-disk Objective-C property table.
431432
class ObjCPropertyTableInfo {
432433
public:
433-
using key_type = std::pair<unsigned, unsigned>; // (class ID, name ID)
434+
// (class ID, name ID, isInstance)
435+
using key_type = std::tuple<unsigned, unsigned, char>;
434436
using key_type_ref = key_type;
435437
using data_type = ObjCPropertyInfo;
436438
using data_type_ref = const data_type &;
@@ -444,7 +446,7 @@ namespace {
444446
std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
445447
key_type_ref key,
446448
data_type_ref data) {
447-
uint32_t keyLength = sizeof(uint32_t) + sizeof(uint32_t);
449+
uint32_t keyLength = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
448450
uint32_t dataLength = getVariableInfoSize(data);
449451
endian::Writer<little> writer(out);
450452
writer.write<uint16_t>(keyLength);
@@ -454,8 +456,9 @@ namespace {
454456

455457
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
456458
endian::Writer<little> writer(out);
457-
writer.write<uint32_t>(key.first);
458-
writer.write<uint32_t>(key.second);
459+
writer.write<uint32_t>(std::get<0>(key));
460+
writer.write<uint32_t>(std::get<1>(key));
461+
writer.write<uint8_t>(std::get<2>(key));
459462
}
460463

461464
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
@@ -1060,10 +1063,11 @@ ContextID APINotesWriter::addObjCProtocol(StringRef name,
10601063
return ContextID(known->second.first);
10611064
}
10621065
void APINotesWriter::addObjCProperty(ContextID contextID, StringRef name,
1066+
bool isInstance,
10631067
const ObjCPropertyInfo &info) {
10641068
IdentifierID nameID = Impl.getIdentifier(name);
1065-
assert(!Impl.ObjCProperties.count({contextID.Value, nameID}));
1066-
Impl.ObjCProperties[{contextID.Value, nameID}] = info;
1069+
assert(!Impl.ObjCProperties.count({contextID.Value, nameID, isInstance}));
1070+
Impl.ObjCProperties[{contextID.Value, nameID, isInstance}] = info;
10671071
}
10681072

10691073
void APINotesWriter::addObjCMethod(ContextID contextID,

lib/APINotes/APINotesYAMLCompiler.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ namespace {
193193

194194
struct Property {
195195
StringRef Name;
196+
llvm::Optional<MethodKind> Kind;
196197
llvm::Optional<NullabilityKind> Nullability;
197198
AvailabilityItem Availability;
198199
bool SwiftPrivate = false;
@@ -348,6 +349,7 @@ namespace llvm {
348349
struct MappingTraits<Property> {
349350
static void mapping(IO &io, Property& p) {
350351
io.mapRequired("Name", p.Name);
352+
io.mapOptional("PropertyKind", p.Kind);
351353
io.mapOptional("Nullability", p.Nullability,
352354
AbsentNullability);
353355
io.mapOptional("Availability", p.Availability.Mode);
@@ -693,11 +695,20 @@ namespace {
693695
}
694696

695697
// Write all properties.
696-
llvm::StringSet<> knownProperties;
698+
llvm::StringSet<> knownInstanceProperties;
699+
llvm::StringSet<> knownClassProperties;
697700
for (const auto &prop : cl.Properties) {
698701
// Check for duplicate property definitions.
699-
if (!knownProperties.insert(prop.Name).second) {
700-
emitError("duplicate definition of property '" + cl.Name + "." +
702+
if ((!prop.Kind || *prop.Kind == MethodKind::Instance) &&
703+
!knownInstanceProperties.insert(prop.Name).second) {
704+
emitError("duplicate definition of instance property '" + cl.Name +
705+
"." + prop.Name + "'");
706+
continue;
707+
}
708+
709+
if ((!prop.Kind || *prop.Kind == MethodKind::Class) &&
710+
!knownClassProperties.insert(prop.Name).second) {
711+
emitError("duplicate definition of class property '" + cl.Name + "." +
701712
prop.Name + "'");
702713
continue;
703714
}
@@ -711,7 +722,14 @@ namespace {
711722
pInfo.SwiftName = prop.SwiftName;
712723
if (prop.Nullability)
713724
pInfo.setNullabilityAudited(*prop.Nullability);
714-
Writer->addObjCProperty(clID, prop.Name, pInfo);
725+
if (prop.Kind) {
726+
Writer->addObjCProperty(clID, prop.Name,
727+
*prop.Kind == MethodKind::Instance, pInfo);
728+
} else {
729+
// Add both instance and class properties with this name.
730+
Writer->addObjCProperty(clID, prop.Name, true, pInfo);
731+
Writer->addObjCProperty(clID, prop.Name, false, pInfo);
732+
}
715733
}
716734
}
717735

@@ -1037,9 +1055,11 @@ namespace {
10371055
}
10381056

10391057
virtual void visitObjCProperty(ContextID contextID, StringRef name,
1058+
bool isInstance,
10401059
const ObjCPropertyInfo &info) {
10411060
Property property;
10421061
property.Name = name;
1062+
property.Kind = isInstance ? MethodKind::Instance : MethodKind::Class;
10431063
handleCommon(property, info);
10441064

10451065
// FIXME: No way to represent "not audited for nullability".
@@ -1109,6 +1129,11 @@ namespace {
11091129
};
11101130
}
11111131

1132+
/// Produce a flattened, numeric value for optional method/property kinds.
1133+
static unsigned flattenPropertyKind(llvm::Optional<MethodKind> kind) {
1134+
return kind ? (*kind == MethodKind::Instance ? 2 : 1) : 0;
1135+
}
1136+
11121137
bool api_notes::decompileAPINotes(std::unique_ptr<llvm::MemoryBuffer> input,
11131138
llvm::raw_ostream &os) {
11141139
// Try to read the file.
@@ -1150,7 +1175,10 @@ bool api_notes::decompileAPINotes(std::unique_ptr<llvm::MemoryBuffer> input,
11501175
// Sort properties.
11511176
std::sort(record.Properties.begin(), record.Properties.end(),
11521177
[](const Property &lhs, const Property &rhs) -> bool {
1153-
return lhs.Name < rhs.Name;
1178+
return lhs.Name < rhs.Name ||
1179+
(lhs.Name == rhs.Name &&
1180+
flattenPropertyKind(lhs.Kind) <
1181+
flattenPropertyKind(rhs.Kind));
11541182
});
11551183

11561184
// Sort methods.

lib/Sema/SemaAPINotes.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,12 @@ void Sema::ProcessAPINotes(Decl *D) {
491491
if (api_notes::APINotesReader *Reader
492492
= APINotes.findAPINotes(D->getLocation())) {
493493
if (auto Context = GetContext(Reader)) {
494+
bool isInstanceProperty =
495+
(Property->getPropertyAttributesAsWritten() &
496+
ObjCPropertyDecl::OBJC_PR_class) == 0;
494497
if (auto Info = Reader->lookupObjCProperty(*Context,
495-
Property->getName())) {
498+
Property->getName(),
499+
isInstanceProperty)) {
496500
::ProcessAPINotes(*this, Property, *Info);
497501
}
498502
}

lib/Sema/SemaObjCProperty.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,15 +636,15 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
636636
PDecl->setInvalidDecl();
637637
}
638638

639-
ProcessDeclAttributes(S, PDecl, FD.D);
640-
641639
// Regardless of setter/getter attribute, we save the default getter/setter
642640
// selector names in anticipation of declaration of setter/getter methods.
643641
PDecl->setGetterName(GetterSel);
644642
PDecl->setSetterName(SetterSel);
645643
PDecl->setPropertyAttributesAsWritten(
646644
makePropertyAttributesAsWritten(AttributesAsWritten));
647645

646+
ProcessDeclAttributes(S, PDecl, FD.D);
647+
648648
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
649649
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
650650

test/APINotes/Inputs/APINotes/SomeKit.apinotes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ Classes:
2020
AvailabilityMsg: "wouldn't work anyway"
2121
- Name: internalProperty
2222
Nullability: N
23+
- Name: nonnullAInstance
24+
PropertyKind: Instance
25+
Nullability: N
26+
- Name: nonnullAClass
27+
PropertyKind: Class
28+
Nullability: N
29+
- Name: nonnullABoth
30+
Nullability: N
2331
- Name: B
2432
Availability: none
2533
AvailabilityMsg: "just don't"

test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,17 @@ Classes:
1212
Nullability: [ N, S ]
1313
Properties:
1414
- Name: intValue
15+
PropertyKind: Instance
1516
Availability: none
1617
AvailabilityMsg: "wouldn't work anyway"
18+
- Name: nonnullAInstance
19+
PropertyKind: Instance
20+
Nullability: N
21+
- Name: nonnullAClass
22+
PropertyKind: Class
23+
Nullability: N
24+
- Name: nonnullABoth
25+
Nullability: N
1726
- Name: B
1827
Availability: none
1928
AvailabilityMsg: "just don't"

0 commit comments

Comments
 (0)