[ObjC] Improve handing of the WKT ObjC Category additions.

Include a comment in the generated header about there being helpers
in GPBWellKnowTypes.h

Generate some extra code for the WKTs that have categories to help
ensure the categories get linked so developers don't have to use
-ObjC in some cases.

PiperOrigin-RevId: 589179237
pull/14987/head
Thomas Van Lenten 1 year ago committed by Copybara-Service
parent cca8a7cc23
commit b146d14e31
  1. 3
      objectivec/GPBAny.pbobjc.h
  2. 8
      objectivec/GPBAny.pbobjc.m
  3. 3
      objectivec/GPBDuration.pbobjc.h
  4. 8
      objectivec/GPBDuration.pbobjc.m
  5. 3
      objectivec/GPBTimestamp.pbobjc.h
  6. 8
      objectivec/GPBTimestamp.pbobjc.m
  7. 36
      src/google/protobuf/compiler/objectivec/file.cc
  8. 28
      src/google/protobuf/compiler/objectivec/helpers.cc
  9. 5
      src/google/protobuf/compiler/objectivec/helpers.h
  10. 12
      src/google/protobuf/compiler/objectivec/message.cc

@ -168,6 +168,9 @@ GPB_FINAL @interface GPBAny : GPBMessage
/** Must be a valid serialized protocol buffer of the above specified type. */
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

@ -3,6 +3,7 @@
// source: google/protobuf/any.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBAny.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBAnyRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* any_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBAny
@implementation GPBAny

@ -123,6 +123,9 @@ GPB_FINAL @interface GPBDuration : GPBMessage
**/
@property(nonatomic, readwrite) int32_t nanos;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

@ -3,6 +3,7 @@
// source: google/protobuf/duration.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBDuration.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBDurationRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* duration_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBDuration
@implementation GPBDuration

@ -152,6 +152,9 @@ GPB_FINAL @interface GPBTimestamp : GPBMessage
**/
@property(nonatomic, readwrite) int32_t nanos;
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
@end
NS_ASSUME_NONNULL_END

@ -3,6 +3,7 @@
// source: google/protobuf/timestamp.proto
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBWellKnownTypes.h"
#import "GPBTimestamp.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30007
@ -39,6 +40,13 @@ static GPBFileDescription GPBTimestampRoot_FileDescription = {
.syntax = GPBFileSyntaxProto3
};
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* timestamp_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
#pragma mark - GPBTimestamp
@implementation GPBTimestamp

@ -22,6 +22,8 @@
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/objectivec/enum.h"
#include "google/protobuf/compiler/objectivec/extension.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
@ -139,6 +141,27 @@ void MakeDescriptors(
}
}
void EmitLinkWKTs(absl::string_view name, io::Printer* p) {
absl::string_view::size_type last_slash = name.rfind('/');
std::string basename;
if (last_slash == absl::string_view::npos) {
basename = std::string(name);
} else {
basename = std::string(name.substr(last_slash + 1));
}
p->Emit({{"basename", StripProto(basename)}},
R"objc(
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* $basename$_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
)objc");
p->Emit("\n");
}
void EmitSourceFwdDecls(const absl::btree_set<std::string>& fwd_decls,
io::Printer* p) {
if (fwd_decls.empty()) {
@ -385,6 +408,10 @@ void FileGenerator::GenerateSource(io::Printer* p) const {
EmitRootImplementation(p, deps_with_extensions);
EmitFileDescription(p);
if (is_bundled_proto_ && HasWKTWithObjCCategory(file_)) {
EmitLinkWKTs(file_->name(), p);
}
for (const auto& generator : enum_generators_) {
generator->GenerateSource(p);
}
@ -395,6 +422,8 @@ void FileGenerator::GenerateSource(io::Printer* p) const {
}
void FileGenerator::GenerateGlobalSource(io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
std::vector<const FileDescriptor*> deps_with_extensions =
common_state_->CollectMinimalFileDepsContainingExtensions(file_);
GeneratedFileOptions file_options;
@ -416,6 +445,8 @@ void FileGenerator::GenerateGlobalSource(io::Printer* p) const {
}
void FileGenerator::GenerateSourceForEnums(io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
// Enum implementation uses atomic in the generated code.
GeneratedFileOptions file_options;
file_options.extra_system_headers.push_back("stdatomic.h");
@ -428,6 +459,8 @@ void FileGenerator::GenerateSourceForEnums(io::Printer* p) const {
}
void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
const auto& generator = message_generators_[idx];
absl::btree_set<std::string> fwd_decls;
@ -485,6 +518,9 @@ void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type,
break;
case GeneratedFileType::kSource:
import_writer.AddRuntimeImport("GPBProtocolBuffers_RuntimeSupport.h");
if (is_bundled_proto_ && HasWKTWithObjCCategory(file_)) {
import_writer.AddRuntimeImport("GPBWellKnownTypes.h");
}
import_writer.AddFile(file_, header_extension);
if (HeadersUseForwardDeclarations()) {
if (generation_options_.generate_minimal_imports) {

@ -13,6 +13,7 @@
#include <string>
#include <vector>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
@ -393,6 +394,33 @@ void EmitCommentsString(io::Printer* printer, const SourceLocation& location,
)");
}
bool HasWKTWithObjCCategory(const FileDescriptor* file) {
// We don't check the name prefix or proto package because some files
// (descriptor.proto), aren't shipped generated by the library, so this
// seems to be the safest way to only catch the ones shipped.
const std::string name = file->name();
if (name == "google/protobuf/any.proto" ||
name == "google/protobuf/duration.proto" ||
name == "google/protobuf/timestamp.proto") {
ABSL_DCHECK(IsProtobufLibraryBundledProtoFile(file));
return true;
}
return false;
}
bool IsWKTWithObjCCategory(const Descriptor* descriptor) {
if (!HasWKTWithObjCCategory(descriptor->file())) {
return false;
}
const std::string full_name = descriptor->full_name();
if (full_name == "google.protobuf.Any" ||
full_name == "google.protobuf.Duration" ||
full_name == "google.protobuf.Timestamp") {
return true;
}
return false;
}
} // namespace objectivec
} // namespace compiler
} // namespace protobuf

@ -148,6 +148,11 @@ std::string GetOptionalDeprecatedAttribute(
}
}
// Helpers to identify the WellKnownType files/messages that get an Objective-C
// category within the runtime to add helpers.
bool HasWKTWithObjCCategory(const FileDescriptor* file);
bool IsWKTWithObjCCategory(const Descriptor* descriptor);
} // namespace objectivec
} // namespace compiler
} // namespace protobuf

@ -336,6 +336,17 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const {
}
field_generators_.get(field).GeneratePropertyDeclaration(printer);
}
}},
{"wkt_extra",
[&] {
if (!IsWKTWithObjCCategory(descriptor_)) {
return;
}
printer->Emit(R"objc(
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
)objc");
printer->Emit("\n");
}}},
R"objc(
#pragma mark - $classname$
@ -347,6 +358,7 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const {
GPB_FINAL @interface $classname$ : GPBMessage
$message_properties$
$wkt_extra$
@end
)objc");
printer->Emit("\n");

Loading…
Cancel
Save