[ObjC] Add helper for IsCreateName for the CF Create Rule.

Also add tests for all of the Is*Name helpers.
pull/10597/head
Thomas Van Lenten 2 years ago
parent 96d19e7ce4
commit b67bd3309b
  1. 49
      src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
  2. 4
      src/google/protobuf/compiler/objectivec/objectivec_helpers.h
  3. 84
      src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc

@ -513,13 +513,14 @@ void PathSplit(const std::string& path, std::string* directory,
}
}
bool IsSpecialName(const std::string& name, const std::string* special_names,
size_t count) {
bool IsSpecialNamePrefix(const std::string& name,
const std::string* special_names,
size_t count) {
for (size_t i = 0; i < count; ++i) {
size_t length = special_names[i].length();
const size_t length = special_names[i].length();
if (name.compare(0, length, special_names[i]) == 0) {
if (name.length() > length) {
// If name is longer than the retained_name[i] that it matches
// If name is longer than the special_names[i] that it matches
// the next character must be not lower case (newton vs newTon vs
// new_ton).
return !absl::ascii_islower(name[length]);
@ -589,14 +590,46 @@ bool IsRetainedName(const std::string& name) {
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
static const std::string retained_names[] = {"new", "alloc", "copy",
"mutableCopy"};
return IsSpecialName(name, retained_names,
sizeof(retained_names) / sizeof(retained_names[0]));
return IsSpecialNamePrefix(name, retained_names,
sizeof(retained_names) / sizeof(retained_names[0]));
}
bool IsInitName(const std::string& name) {
static const std::string init_names[] = {"init"};
return IsSpecialName(name, init_names,
sizeof(init_names) / sizeof(init_names[0]));
return IsSpecialNamePrefix(name, init_names,
sizeof(init_names) / sizeof(init_names[0]));
}
bool IsCreateName(const std::string& name) {
// List of segments from
// https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029
static const std::string create_names[] = {"Create", "Copy"};
const size_t count = sizeof(create_names) / sizeof(create_names[0]);
for (size_t i = 0; i < count; ++i) {
const size_t length = create_names[i].length();
size_t pos = name.find(create_names[i]);
if (pos != std::string::npos) {
// The above docs don't actually call out anything about the characters
// before the special words. So it's not clear if something like
// "FOOCreate" would or would not match the "The Create Rule", but by not
// checking, and claiming it does match, then callers will annotate with
// `cf_returns_not_retained` which will ensure things work as desired.
//
// The footnote here is the docs do have a passing reference to "NoCopy",
// but again, not looking for that and just returning `true` will cause
// callers to annotate the api as not being a Create Rule function.
// If name is longer than the create_names[i] that it matches the next
// character must be not lower case (Copyright vs CopyFoo vs Copy_Foo).
if (name.length() > pos + length) {
return !absl::ascii_islower(name[pos + length]);
} else {
return true;
}
}
}
return false;
}
std::string BaseFileName(const FileDescriptor* file) {

@ -92,6 +92,10 @@ bool PROTOC_EXPORT IsRetainedName(const std::string& name);
// handling under ARC.
bool PROTOC_EXPORT IsInitName(const std::string& name);
// Returns true if the name requires a cf_returns_not_retained attribute applied
// to it.
bool PROTOC_EXPORT IsCreateName(const std::string& name);
// Gets the objc_class_prefix or the prefix made from the proto package.
std::string PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file);

@ -369,6 +369,90 @@ TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) {
}
}
TEST(ObjCHelper, IsRetainedName) {
EXPECT_TRUE(IsRetainedName("new"));
EXPECT_TRUE(IsRetainedName("alloc"));
EXPECT_TRUE(IsRetainedName("copy"));
EXPECT_TRUE(IsRetainedName("mutableCopy"));
EXPECT_TRUE(IsRetainedName("newFoo"));
EXPECT_TRUE(IsRetainedName("allocFoo"));
EXPECT_TRUE(IsRetainedName("copyFoo"));
EXPECT_TRUE(IsRetainedName("mutableCopyFoo"));
EXPECT_TRUE(IsRetainedName("new_foo"));
EXPECT_TRUE(IsRetainedName("alloc_foo"));
EXPECT_TRUE(IsRetainedName("copy_foo"));
EXPECT_TRUE(IsRetainedName("mutableCopy_foo"));
EXPECT_FALSE(IsRetainedName(""));
EXPECT_FALSE(IsRetainedName("ne"));
EXPECT_FALSE(IsRetainedName("all"));
EXPECT_FALSE(IsRetainedName("co"));
EXPECT_FALSE(IsRetainedName("mutable"));
EXPECT_FALSE(IsRetainedName("New"));
EXPECT_FALSE(IsRetainedName("Alloc"));
EXPECT_FALSE(IsRetainedName("Copy"));
EXPECT_FALSE(IsRetainedName("MutableCopy"));
EXPECT_FALSE(IsRetainedName("newer"));
EXPECT_FALSE(IsRetainedName("alloced"));
EXPECT_FALSE(IsRetainedName("copying"));
EXPECT_FALSE(IsRetainedName("mutableCopying"));
EXPECT_FALSE(IsRetainedName("init"));
EXPECT_FALSE(IsRetainedName("Create"));
EXPECT_FALSE(IsRetainedName("Copy"));
}
TEST(ObjCHelper, IsInitName) {
EXPECT_TRUE(IsInitName("init"));
EXPECT_TRUE(IsInitName("initFoo"));
EXPECT_TRUE(IsInitName("init_foo"));
EXPECT_FALSE(IsInitName(""));
EXPECT_FALSE(IsInitName("in"));
EXPECT_FALSE(IsInitName("Init"));
EXPECT_FALSE(IsInitName("inIt"));
EXPECT_FALSE(IsInitName("initial"));
EXPECT_FALSE(IsInitName("initiAl"));
EXPECT_FALSE(IsInitName("fooInit"));
EXPECT_FALSE(IsInitName("foo_init"));
EXPECT_FALSE(IsInitName("new"));
EXPECT_FALSE(IsInitName("alloc"));
EXPECT_FALSE(IsInitName("copy"));
EXPECT_FALSE(IsInitName("mutableCopy"));
EXPECT_FALSE(IsInitName("Create"));
EXPECT_FALSE(IsInitName("Copy"));
}
TEST(ObjCHelper, IsCreateName) {
EXPECT_TRUE(IsCreateName("Create"));
EXPECT_TRUE(IsCreateName("Copy"));
EXPECT_TRUE(IsCreateName("CreateFoo"));
EXPECT_TRUE(IsCreateName("CopyFoo"));
EXPECT_TRUE(IsCreateName("Create_foo"));
EXPECT_TRUE(IsCreateName("Copy_foo"));
EXPECT_TRUE(IsCreateName("ReCreate"));
EXPECT_TRUE(IsCreateName("ReCopy"));
EXPECT_TRUE(IsCreateName("FOOCreate"));
EXPECT_TRUE(IsCreateName("FOOCopy"));
EXPECT_TRUE(IsCreateName("CreateWithCopy"));
EXPECT_FALSE(IsCreateName(""));
EXPECT_FALSE(IsCreateName("Crea"));
EXPECT_FALSE(IsCreateName("Co"));
EXPECT_FALSE(IsCreateName("create"));
EXPECT_FALSE(IsCreateName("recreate"));
EXPECT_FALSE(IsCreateName("recopy"));
EXPECT_FALSE(IsCreateName("ReCreated"));
EXPECT_FALSE(IsCreateName("ReCopying"));
EXPECT_FALSE(IsCreateName("init"));
EXPECT_FALSE(IsCreateName("new"));
EXPECT_FALSE(IsCreateName("alloc"));
EXPECT_FALSE(IsCreateName("copy"));
EXPECT_TRUE(IsCreateName("mutableCopy"));
}
// TODO(thomasvl): Should probably add some unittests for all the special cases
// of name mangling (class name, field name, enum names). Rather than doing
// this with an ObjC test in the objectivec directory, we should be able to

Loading…
Cancel
Save