Don't generate Has/Clear members for proto2 message fields.

This is a breaking change in terms of proto2 code generation: users who were previously using these members will have to change to null checks for message fields.
After toying with removing Has/Clear for proto2 oneof fields, I've left them alone in this commit, for consistency with other languages. The inconsistency between proto2 and proto3 won't come up here, because proto3 oneof fields can never be explicitly optional.

Fixes #7395.
pull/7455/head
Jon Skeet 5 years ago committed by Jon Skeet
parent 02f182e829
commit 9d74aafbe1
  1. 33
      src/google/protobuf/compiler/csharp/csharp_helpers.h

@ -159,24 +159,23 @@ inline bool IsProto2(const FileDescriptor* descriptor) {
} }
inline bool SupportsPresenceApi(const FieldDescriptor* descriptor) { inline bool SupportsPresenceApi(const FieldDescriptor* descriptor) {
// We don't use descriptor->is_singular_with_presence() as C# has slightly // Unlike most languages, we don't generate Has/Clear members for message
// different behavior to other languages. // types, because they can always be set to null in C#. They're not really
// needed for oneof fields in proto2 either, as everything can be done via
if (IsProto2(descriptor->file())) { // oneof case, but we follow the convention from other languages. Proto3
// We generate Has/Clear for oneof fields in C#, as well as for messages. // oneof fields never have Has/Clear members - but will also never have
// It's possible that we shouldn't, but stopping doing so would be a // the explicit optional keyword either.
// breaking change for proto2. Fortunately the decision is moot for //
// onoeof in proto3: you can't use "optional" inside a oneof. // None of the built-in helpers (descriptor->has_presence() etc) describe
// Proto2: every singular field has presence. (Even fields in oneofs.) // quite the behavior we want, so the rules are explicit below.
return !descriptor->is_repeated();
} else { if (descriptor->is_repeated() ||
// Proto3: only for explictly-optional fields that aren't messages. descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
// (Repeated fields can never be explicitly optional, so we don't need return false;
// to check for that.) Currently we can't get at proto3_optional directly,
// but we can use has_optional_keyword() as a surrogate check.
return descriptor->has_optional_keyword() &&
descriptor->type() != FieldDescriptor::TYPE_MESSAGE;
} }
// has_optional_keyword() has more complex rules for proto2, but that
// doesn't matter given the first part of this condition.
return IsProto2(descriptor->file()) || descriptor->has_optional_keyword();
} }
inline bool RequiresPresenceBit(const FieldDescriptor* descriptor) { inline bool RequiresPresenceBit(const FieldDescriptor* descriptor) {

Loading…
Cancel
Save