Commit 54176b26 authored by Sydney Acksman's avatar Sydney Acksman Committed by Jie Luo

C# Proto2 feature : Field presence and default values (#4642)

* Compiler changes

* Generated code changes

* Library changes

* Compiler style changes

* Generated style changes

* Fix Windows build errors

* Implement changes from review

* Reintroduce proto2 check

* Compiler changes (required handling review)

* Generated code changes (required handling review)

* Library changes (required handling review

* Field presence rewrite (compiler changes)

* Field presence rewrite (generated code changes)

* Compiler comment

* IFieldAccessor.HasValue library implementation

* Remove Clear methods and default values from proto3 code (Compiler)

* Remove Clear methods and default values from proto3 code (Generated)

* Remove Clear methods and default values from proto3 code (Library)

* Fix distcheck error

* Rewrite default string values to use base64 and convert

* Library changes (IMessage2)

* Compiler changes (IMessage2)

* Generated changes (IMessage2)

* Rebased and regenerated

* Compiler changes (initialized extension)

* Generated changes (initialized extension)

* Library changes (initialized extension)

* Refactor MessageExtensions.IsRequired

* Move string default value creator and bytes default value creator back to seperate methods

* Dead code cleanup

* Fixed segmentation fault
Removed unused header method declarations
parent fb0a74b6
...@@ -179,7 +179,6 @@ csharp_EXTRA_DIST= \ ...@@ -179,7 +179,6 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs \ csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs \
csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs \ csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs \
csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs \ csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs \
csharp/src/Google.Protobuf/Reflection/PartialClasses.cs \
csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs \ csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs \
csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs \ csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs \
csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs \ csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs \
......
...@@ -247,7 +247,7 @@ namespace Google.Protobuf.Examples.AddressBook { ...@@ -247,7 +247,7 @@ namespace Google.Protobuf.Examples.AddressBook {
phones_.Add(other.phones_); phones_.Add(other.phones_);
if (other.lastUpdated_ != null) { if (other.lastUpdated_ != null) {
if (lastUpdated_ == null) { if (lastUpdated_ == null) {
lastUpdated_ = new global::Google.Protobuf.WellKnownTypes.Timestamp(); LastUpdated = new global::Google.Protobuf.WellKnownTypes.Timestamp();
} }
LastUpdated.MergeFrom(other.LastUpdated); LastUpdated.MergeFrom(other.LastUpdated);
} }
...@@ -280,9 +280,9 @@ namespace Google.Protobuf.Examples.AddressBook { ...@@ -280,9 +280,9 @@ namespace Google.Protobuf.Examples.AddressBook {
} }
case 42: { case 42: {
if (lastUpdated_ == null) { if (lastUpdated_ == null) {
lastUpdated_ = new global::Google.Protobuf.WellKnownTypes.Timestamp(); LastUpdated = new global::Google.Protobuf.WellKnownTypes.Timestamp();
} }
input.ReadMessage(lastUpdated_); input.ReadMessage(LastUpdated);
break; break;
} }
} }
...@@ -447,7 +447,7 @@ namespace Google.Protobuf.Examples.AddressBook { ...@@ -447,7 +447,7 @@ namespace Google.Protobuf.Examples.AddressBook {
break; break;
} }
case 16: { case 16: {
type_ = (global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) input.ReadEnum(); Type = (global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) input.ReadEnum();
break; break;
} }
} }
......
...@@ -354,7 +354,7 @@ namespace Conformance { ...@@ -354,7 +354,7 @@ namespace Conformance {
break; break;
} }
case 24: { case 24: {
requestedOutputFormat_ = (global::Conformance.WireFormat) input.ReadEnum(); RequestedOutputFormat = (global::Conformance.WireFormat) input.ReadEnum();
break; break;
} }
case 34: { case 34: {
...@@ -362,7 +362,7 @@ namespace Conformance { ...@@ -362,7 +362,7 @@ namespace Conformance {
break; break;
} }
case 40: { case 40: {
testCategory_ = (global::Conformance.TestCategory) input.ReadEnum(); TestCategory = (global::Conformance.TestCategory) input.ReadEnum();
break; break;
} }
} }
......
...@@ -724,7 +724,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -724,7 +724,7 @@ namespace Google.Protobuf.TestProtos {
} }
if (other.testMap_ != null) { if (other.testMap_ != null) {
if (testMap_ == null) { if (testMap_ == null) {
testMap_ = new global::Google.Protobuf.TestProtos.TestMap(); TestMap = new global::Google.Protobuf.TestProtos.TestMap();
} }
TestMap.MergeFrom(other.TestMap); TestMap.MergeFrom(other.TestMap);
} }
...@@ -741,9 +741,9 @@ namespace Google.Protobuf.TestProtos { ...@@ -741,9 +741,9 @@ namespace Google.Protobuf.TestProtos {
break; break;
case 10: { case 10: {
if (testMap_ == null) { if (testMap_ == null) {
testMap_ = new global::Google.Protobuf.TestProtos.TestMap(); TestMap = new global::Google.Protobuf.TestProtos.TestMap();
} }
input.ReadMessage(testMap_); input.ReadMessage(TestMap);
break; break;
} }
} }
......
...@@ -1879,7 +1879,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -1879,7 +1879,7 @@ namespace UnitTest.Issues.TestProtos {
} }
if (other.bar_ != null) { if (other.bar_ != null) {
if (bar_ == null) { if (bar_ == null) {
bar_ = new global::UnitTest.Issues.TestProtos.ComplexOptionType1(); Bar = new global::UnitTest.Issues.TestProtos.ComplexOptionType1();
} }
Bar.MergeFrom(other.Bar); Bar.MergeFrom(other.Bar);
} }
...@@ -1888,7 +1888,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -1888,7 +1888,7 @@ namespace UnitTest.Issues.TestProtos {
} }
if (other.fred_ != null) { if (other.fred_ != null) {
if (fred_ == null) { if (fred_ == null) {
fred_ = new global::UnitTest.Issues.TestProtos.ComplexOptionType2.Types.ComplexOptionType4(); Fred = new global::UnitTest.Issues.TestProtos.ComplexOptionType2.Types.ComplexOptionType4();
} }
Fred.MergeFrom(other.Fred); Fred.MergeFrom(other.Fred);
} }
...@@ -1906,9 +1906,9 @@ namespace UnitTest.Issues.TestProtos { ...@@ -1906,9 +1906,9 @@ namespace UnitTest.Issues.TestProtos {
break; break;
case 10: { case 10: {
if (bar_ == null) { if (bar_ == null) {
bar_ = new global::UnitTest.Issues.TestProtos.ComplexOptionType1(); Bar = new global::UnitTest.Issues.TestProtos.ComplexOptionType1();
} }
input.ReadMessage(bar_); input.ReadMessage(Bar);
break; break;
} }
case 16: { case 16: {
...@@ -1917,9 +1917,9 @@ namespace UnitTest.Issues.TestProtos { ...@@ -1917,9 +1917,9 @@ namespace UnitTest.Issues.TestProtos {
} }
case 26: { case 26: {
if (fred_ == null) { if (fred_ == null) {
fred_ = new global::UnitTest.Issues.TestProtos.ComplexOptionType2.Types.ComplexOptionType4(); Fred = new global::UnitTest.Issues.TestProtos.ComplexOptionType2.Types.ComplexOptionType4();
} }
input.ReadMessage(fred_); input.ReadMessage(Fred);
break; break;
} }
case 34: { case 34: {
...@@ -2462,7 +2462,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -2462,7 +2462,7 @@ namespace UnitTest.Issues.TestProtos {
} }
if (other.sub_ != null) { if (other.sub_ != null) {
if (sub_ == null) { if (sub_ == null) {
sub_ = new global::UnitTest.Issues.TestProtos.Aggregate(); Sub = new global::UnitTest.Issues.TestProtos.Aggregate();
} }
Sub.MergeFrom(other.Sub); Sub.MergeFrom(other.Sub);
} }
...@@ -2487,9 +2487,9 @@ namespace UnitTest.Issues.TestProtos { ...@@ -2487,9 +2487,9 @@ namespace UnitTest.Issues.TestProtos {
} }
case 26: { case 26: {
if (sub_ == null) { if (sub_ == null) {
sub_ = new global::UnitTest.Issues.TestProtos.Aggregate(); Sub = new global::UnitTest.Issues.TestProtos.Aggregate();
} }
input.ReadMessage(sub_); input.ReadMessage(Sub);
break; break;
} }
} }
......
...@@ -557,7 +557,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -557,7 +557,7 @@ namespace UnitTest.Issues.TestProtos {
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break; break;
case 8: { case 8: {
value_ = (global::UnitTest.Issues.TestProtos.NegativeEnum) input.ReadEnum(); Value = (global::UnitTest.Issues.TestProtos.NegativeEnum) input.ReadEnum();
break; break;
} }
case 18: case 18:
...@@ -881,7 +881,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -881,7 +881,7 @@ namespace UnitTest.Issues.TestProtos {
primitiveArray_.Add(other.primitiveArray_); primitiveArray_.Add(other.primitiveArray_);
if (other.messageValue_ != null) { if (other.messageValue_ != null) {
if (messageValue_ == null) { if (messageValue_ == null) {
messageValue_ = new global::UnitTest.Issues.TestProtos.DeprecatedChild(); MessageValue = new global::UnitTest.Issues.TestProtos.DeprecatedChild();
} }
MessageValue.MergeFrom(other.MessageValue); MessageValue.MergeFrom(other.MessageValue);
} }
...@@ -912,9 +912,9 @@ namespace UnitTest.Issues.TestProtos { ...@@ -912,9 +912,9 @@ namespace UnitTest.Issues.TestProtos {
} }
case 26: { case 26: {
if (messageValue_ == null) { if (messageValue_ == null) {
messageValue_ = new global::UnitTest.Issues.TestProtos.DeprecatedChild(); MessageValue = new global::UnitTest.Issues.TestProtos.DeprecatedChild();
} }
input.ReadMessage(messageValue_); input.ReadMessage(MessageValue);
break; break;
} }
case 34: { case 34: {
...@@ -922,7 +922,7 @@ namespace UnitTest.Issues.TestProtos { ...@@ -922,7 +922,7 @@ namespace UnitTest.Issues.TestProtos {
break; break;
} }
case 40: { case 40: {
enumValue_ = (global::UnitTest.Issues.TestProtos.DeprecatedEnum) input.ReadEnum(); EnumValue = (global::UnitTest.Issues.TestProtos.DeprecatedEnum) input.ReadEnum();
break; break;
} }
case 50: case 50:
......
...@@ -342,6 +342,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -342,6 +342,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "float_field" field.</summary> /// <summary>Field number for the "float_field" field.</summary>
public const int FloatFieldFieldNumber = 11; public const int FloatFieldFieldNumber = 11;
private static readonly pb::FieldCodec<float?> _single_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90); private static readonly pb::FieldCodec<float?> _single_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90);
...@@ -354,6 +355,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -354,6 +355,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "int64_field" field.</summary> /// <summary>Field number for the "int64_field" field.</summary>
public const int Int64FieldFieldNumber = 12; public const int Int64FieldFieldNumber = 12;
private static readonly pb::FieldCodec<long?> _single_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98); private static readonly pb::FieldCodec<long?> _single_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98);
...@@ -366,6 +368,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -366,6 +368,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "uint64_field" field.</summary> /// <summary>Field number for the "uint64_field" field.</summary>
public const int Uint64FieldFieldNumber = 13; public const int Uint64FieldFieldNumber = 13;
private static readonly pb::FieldCodec<ulong?> _single_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106); private static readonly pb::FieldCodec<ulong?> _single_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106);
...@@ -378,6 +381,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -378,6 +381,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "int32_field" field.</summary> /// <summary>Field number for the "int32_field" field.</summary>
public const int Int32FieldFieldNumber = 14; public const int Int32FieldFieldNumber = 14;
private static readonly pb::FieldCodec<int?> _single_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114); private static readonly pb::FieldCodec<int?> _single_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114);
...@@ -390,6 +394,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -390,6 +394,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "uint32_field" field.</summary> /// <summary>Field number for the "uint32_field" field.</summary>
public const int Uint32FieldFieldNumber = 15; public const int Uint32FieldFieldNumber = 15;
private static readonly pb::FieldCodec<uint?> _single_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122); private static readonly pb::FieldCodec<uint?> _single_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122);
...@@ -402,6 +407,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -402,6 +407,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "bool_field" field.</summary> /// <summary>Field number for the "bool_field" field.</summary>
public const int BoolFieldFieldNumber = 16; public const int BoolFieldFieldNumber = 16;
private static readonly pb::FieldCodec<bool?> _single_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130); private static readonly pb::FieldCodec<bool?> _single_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130);
...@@ -414,6 +420,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -414,6 +420,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "string_field" field.</summary> /// <summary>Field number for the "string_field" field.</summary>
public const int StringFieldFieldNumber = 17; public const int StringFieldFieldNumber = 17;
private static readonly pb::FieldCodec<string> _single_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138); private static readonly pb::FieldCodec<string> _single_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138);
...@@ -426,6 +433,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -426,6 +433,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "bytes_field" field.</summary> /// <summary>Field number for the "bytes_field" field.</summary>
public const int BytesFieldFieldNumber = 18; public const int BytesFieldFieldNumber = 18;
private static readonly pb::FieldCodec<pb::ByteString> _single_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146); private static readonly pb::FieldCodec<pb::ByteString> _single_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
...@@ -438,6 +446,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -438,6 +446,7 @@ namespace Google.Protobuf.TestProtos {
} }
} }
/// <summary>Field number for the "value_field" field.</summary> /// <summary>Field number for the "value_field" field.</summary>
public const int ValueFieldFieldNumber = 19; public const int ValueFieldFieldNumber = 19;
private global::Google.Protobuf.WellKnownTypes.Value valueField_; private global::Google.Protobuf.WellKnownTypes.Value valueField_;
...@@ -667,55 +676,55 @@ namespace Google.Protobuf.TestProtos { ...@@ -667,55 +676,55 @@ namespace Google.Protobuf.TestProtos {
} }
if (other.anyField_ != null) { if (other.anyField_ != null) {
if (anyField_ == null) { if (anyField_ == null) {
anyField_ = new global::Google.Protobuf.WellKnownTypes.Any(); AnyField = new global::Google.Protobuf.WellKnownTypes.Any();
} }
AnyField.MergeFrom(other.AnyField); AnyField.MergeFrom(other.AnyField);
} }
if (other.apiField_ != null) { if (other.apiField_ != null) {
if (apiField_ == null) { if (apiField_ == null) {
apiField_ = new global::Google.Protobuf.WellKnownTypes.Api(); ApiField = new global::Google.Protobuf.WellKnownTypes.Api();
} }
ApiField.MergeFrom(other.ApiField); ApiField.MergeFrom(other.ApiField);
} }
if (other.durationField_ != null) { if (other.durationField_ != null) {
if (durationField_ == null) { if (durationField_ == null) {
durationField_ = new global::Google.Protobuf.WellKnownTypes.Duration(); DurationField = new global::Google.Protobuf.WellKnownTypes.Duration();
} }
DurationField.MergeFrom(other.DurationField); DurationField.MergeFrom(other.DurationField);
} }
if (other.emptyField_ != null) { if (other.emptyField_ != null) {
if (emptyField_ == null) { if (emptyField_ == null) {
emptyField_ = new global::Google.Protobuf.WellKnownTypes.Empty(); EmptyField = new global::Google.Protobuf.WellKnownTypes.Empty();
} }
EmptyField.MergeFrom(other.EmptyField); EmptyField.MergeFrom(other.EmptyField);
} }
if (other.fieldMaskField_ != null) { if (other.fieldMaskField_ != null) {
if (fieldMaskField_ == null) { if (fieldMaskField_ == null) {
fieldMaskField_ = new global::Google.Protobuf.WellKnownTypes.FieldMask(); FieldMaskField = new global::Google.Protobuf.WellKnownTypes.FieldMask();
} }
FieldMaskField.MergeFrom(other.FieldMaskField); FieldMaskField.MergeFrom(other.FieldMaskField);
} }
if (other.sourceContextField_ != null) { if (other.sourceContextField_ != null) {
if (sourceContextField_ == null) { if (sourceContextField_ == null) {
sourceContextField_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContextField = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
SourceContextField.MergeFrom(other.SourceContextField); SourceContextField.MergeFrom(other.SourceContextField);
} }
if (other.structField_ != null) { if (other.structField_ != null) {
if (structField_ == null) { if (structField_ == null) {
structField_ = new global::Google.Protobuf.WellKnownTypes.Struct(); StructField = new global::Google.Protobuf.WellKnownTypes.Struct();
} }
StructField.MergeFrom(other.StructField); StructField.MergeFrom(other.StructField);
} }
if (other.timestampField_ != null) { if (other.timestampField_ != null) {
if (timestampField_ == null) { if (timestampField_ == null) {
timestampField_ = new global::Google.Protobuf.WellKnownTypes.Timestamp(); TimestampField = new global::Google.Protobuf.WellKnownTypes.Timestamp();
} }
TimestampField.MergeFrom(other.TimestampField); TimestampField.MergeFrom(other.TimestampField);
} }
if (other.typeField_ != null) { if (other.typeField_ != null) {
if (typeField_ == null) { if (typeField_ == null) {
typeField_ = new global::Google.Protobuf.WellKnownTypes.Type(); TypeField = new global::Google.Protobuf.WellKnownTypes.Type();
} }
TypeField.MergeFrom(other.TypeField); TypeField.MergeFrom(other.TypeField);
} }
...@@ -766,7 +775,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -766,7 +775,7 @@ namespace Google.Protobuf.TestProtos {
} }
if (other.valueField_ != null) { if (other.valueField_ != null) {
if (valueField_ == null) { if (valueField_ == null) {
valueField_ = new global::Google.Protobuf.WellKnownTypes.Value(); ValueField = new global::Google.Protobuf.WellKnownTypes.Value();
} }
ValueField.MergeFrom(other.ValueField); ValueField.MergeFrom(other.ValueField);
} }
...@@ -783,65 +792,65 @@ namespace Google.Protobuf.TestProtos { ...@@ -783,65 +792,65 @@ namespace Google.Protobuf.TestProtos {
break; break;
case 10: { case 10: {
if (anyField_ == null) { if (anyField_ == null) {
anyField_ = new global::Google.Protobuf.WellKnownTypes.Any(); AnyField = new global::Google.Protobuf.WellKnownTypes.Any();
} }
input.ReadMessage(anyField_); input.ReadMessage(AnyField);
break; break;
} }
case 18: { case 18: {
if (apiField_ == null) { if (apiField_ == null) {
apiField_ = new global::Google.Protobuf.WellKnownTypes.Api(); ApiField = new global::Google.Protobuf.WellKnownTypes.Api();
} }
input.ReadMessage(apiField_); input.ReadMessage(ApiField);
break; break;
} }
case 26: { case 26: {
if (durationField_ == null) { if (durationField_ == null) {
durationField_ = new global::Google.Protobuf.WellKnownTypes.Duration(); DurationField = new global::Google.Protobuf.WellKnownTypes.Duration();
} }
input.ReadMessage(durationField_); input.ReadMessage(DurationField);
break; break;
} }
case 34: { case 34: {
if (emptyField_ == null) { if (emptyField_ == null) {
emptyField_ = new global::Google.Protobuf.WellKnownTypes.Empty(); EmptyField = new global::Google.Protobuf.WellKnownTypes.Empty();
} }
input.ReadMessage(emptyField_); input.ReadMessage(EmptyField);
break; break;
} }
case 42: { case 42: {
if (fieldMaskField_ == null) { if (fieldMaskField_ == null) {
fieldMaskField_ = new global::Google.Protobuf.WellKnownTypes.FieldMask(); FieldMaskField = new global::Google.Protobuf.WellKnownTypes.FieldMask();
} }
input.ReadMessage(fieldMaskField_); input.ReadMessage(FieldMaskField);
break; break;
} }
case 50: { case 50: {
if (sourceContextField_ == null) { if (sourceContextField_ == null) {
sourceContextField_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContextField = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
input.ReadMessage(sourceContextField_); input.ReadMessage(SourceContextField);
break; break;
} }
case 58: { case 58: {
if (structField_ == null) { if (structField_ == null) {
structField_ = new global::Google.Protobuf.WellKnownTypes.Struct(); StructField = new global::Google.Protobuf.WellKnownTypes.Struct();
} }
input.ReadMessage(structField_); input.ReadMessage(StructField);
break; break;
} }
case 66: { case 66: {
if (timestampField_ == null) { if (timestampField_ == null) {
timestampField_ = new global::Google.Protobuf.WellKnownTypes.Timestamp(); TimestampField = new global::Google.Protobuf.WellKnownTypes.Timestamp();
} }
input.ReadMessage(timestampField_); input.ReadMessage(TimestampField);
break; break;
} }
case 74: { case 74: {
if (typeField_ == null) { if (typeField_ == null) {
typeField_ = new global::Google.Protobuf.WellKnownTypes.Type(); TypeField = new global::Google.Protobuf.WellKnownTypes.Type();
} }
input.ReadMessage(typeField_); input.ReadMessage(TypeField);
break; break;
} }
case 82: { case 82: {
...@@ -909,9 +918,9 @@ namespace Google.Protobuf.TestProtos { ...@@ -909,9 +918,9 @@ namespace Google.Protobuf.TestProtos {
} }
case 154: { case 154: {
if (valueField_ == null) { if (valueField_ == null) {
valueField_ = new global::Google.Protobuf.WellKnownTypes.Value(); ValueField = new global::Google.Protobuf.WellKnownTypes.Value();
} }
input.ReadMessage(valueField_); input.ReadMessage(ValueField);
break; break;
} }
} }
......
...@@ -125,5 +125,10 @@ namespace Google.Protobuf ...@@ -125,5 +125,10 @@ namespace Google.Protobuf
return new InvalidProtocolBufferException( return new InvalidProtocolBufferException(
"Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1."); "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");
} }
}
internal static InvalidProtocolBufferException MissingFields()
{
return new InvalidProtocolBufferException("Message was missing required fields");
}
}
} }
\ No newline at end of file
...@@ -30,7 +30,10 @@ ...@@ -30,7 +30,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion #endregion
using Google.Protobuf.Reflection;
using System.Collections;
using System.IO; using System.IO;
using System.Linq;
namespace Google.Protobuf namespace Google.Protobuf
{ {
...@@ -140,6 +143,53 @@ namespace Google.Protobuf ...@@ -140,6 +143,53 @@ namespace Google.Protobuf
return ByteString.AttachBytes(message.ToByteArray()); return ByteString.AttachBytes(message.ToByteArray());
} }
/// <summary>
/// Checks if all required fields in a message have values set. For proto3 messages, this returns true
/// </summary>
public static bool IsInitialized(this IMessage message)
{
if (message.Descriptor.File.Proto.Syntax != "proto2")
{
return true;
}
return message.Descriptor
.Fields
.InDeclarationOrder()
.All(f =>
{
if (f.IsMap)
{
var map = (IDictionary)f.Accessor.GetValue(message);
return map.Values.OfType<IMessage>().All(IsInitialized);
}
else if (f.IsRepeated && f.MessageType != null)
{
var enumerable = (IEnumerable)f.Accessor.GetValue(message);
return enumerable.Cast<IMessage>().All(IsInitialized);
}
else if (f.MessageType != null)
{
if (f.Accessor.HasValue(message))
{
return ((IMessage)f.Accessor.GetValue(message)).IsInitialized();
}
else
{
return !f.IsRequired;
}
}
else if (f.IsRequired)
{
return f.Accessor.HasValue(message);
}
else
{
return true;
}
});
}
// Implementations allowing unknown fields to be discarded. // Implementations allowing unknown fields to be discarded.
internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields) internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields)
{ {
......
...@@ -69,6 +69,7 @@ namespace Google.Protobuf ...@@ -69,6 +69,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
message.MergeFrom(data, DiscardUnknownFields); message.MergeFrom(data, DiscardUnknownFields);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -83,6 +84,7 @@ namespace Google.Protobuf ...@@ -83,6 +84,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
message.MergeFrom(data, offset, length, DiscardUnknownFields); message.MergeFrom(data, offset, length, DiscardUnknownFields);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -95,6 +97,7 @@ namespace Google.Protobuf ...@@ -95,6 +97,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
message.MergeFrom(data, DiscardUnknownFields); message.MergeFrom(data, DiscardUnknownFields);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -107,6 +110,7 @@ namespace Google.Protobuf ...@@ -107,6 +110,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
message.MergeFrom(input, DiscardUnknownFields); message.MergeFrom(input, DiscardUnknownFields);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -123,6 +127,7 @@ namespace Google.Protobuf ...@@ -123,6 +127,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
message.MergeDelimitedFrom(input, DiscardUnknownFields); message.MergeDelimitedFrom(input, DiscardUnknownFields);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -135,6 +140,7 @@ namespace Google.Protobuf ...@@ -135,6 +140,7 @@ namespace Google.Protobuf
{ {
IMessage message = factory(); IMessage message = factory();
MergeFrom(message, input); MergeFrom(message, input);
CheckMergedRequiredFields(message);
return message; return message;
} }
...@@ -167,6 +173,12 @@ namespace Google.Protobuf ...@@ -167,6 +173,12 @@ namespace Google.Protobuf
} }
} }
internal static void CheckMergedRequiredFields(IMessage message)
{
if (!message.IsInitialized())
throw new InvalidOperationException("Parsed message does not contain all required fields");
}
/// <summary> /// <summary>
/// Creates a new message parser which optionally discards unknown fields when parsing. /// Creates a new message parser which optionally discards unknown fields when parsing.
/// </summary> /// </summary>
......
#region Copyright notice and license #region Copyright notice and license
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/ // https://developers.google.com/protocol-buffers/
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
// //
// * Redistributions of source code must retain the above copyright // * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above // * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer // copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the // in the documentation and/or other materials provided with the
// distribution. // distribution.
// * Neither the name of Google Inc. nor the names of its // * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from // contributors may be used to endorse or promote products derived from
// this software without specific prior written permission. // this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion #endregion
using System; using System;
namespace Google.Protobuf namespace Google.Protobuf
{ {
/// <summary> /// <summary>
/// Helper methods for throwing exceptions when preconditions are not met. /// Helper methods for throwing exceptions when preconditions are not met.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This class is used internally and by generated code; it is not particularly /// This class is used internally and by generated code; it is not particularly
/// expected to be used from application code, although nothing prevents it /// expected to be used from application code, although nothing prevents it
/// from being used that way. /// from being used that way.
/// </remarks> /// </remarks>
public static class ProtoPreconditions public static class ProtoPreconditions
{ {
/// <summary> /// <summary>
/// Throws an ArgumentNullException if the given value is null, otherwise /// Throws an ArgumentNullException if the given value is null, otherwise
/// return the value to the caller. /// return the value to the caller.
/// </summary> /// </summary>
public static T CheckNotNull<T>(T value, string name) where T : class public static T CheckNotNull<T>(T value, string name) where T : class
{ {
if (value == null) if (value == null)
{ {
throw new ArgumentNullException(name); throw new ArgumentNullException(name);
} }
return value; return value;
} }
/// <summary> /// <summary>
/// Throws an ArgumentNullException if the given value is null, otherwise /// Throws an ArgumentNullException if the given value is null, otherwise
/// return the value to the caller. /// return the value to the caller.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter /// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
/// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
/// with a value type - but it gets in the way if either you want to use it with a nullable /// with a value type - but it gets in the way if either you want to use it with a nullable
/// value type, or you want to use it with an unconstrained type parameter. /// value type, or you want to use it with an unconstrained type parameter.
/// </remarks> /// </remarks>
internal static T CheckNotNullUnconstrained<T>(T value, string name) internal static T CheckNotNullUnconstrained<T>(T value, string name)
{ {
if (value == null) if (value == null)
{ {
throw new ArgumentNullException(name); throw new ArgumentNullException(name);
} }
return value; return value;
} }
} }
} }
\ No newline at end of file
...@@ -57,6 +57,7 @@ namespace Google.Protobuf.Reflection ...@@ -57,6 +57,7 @@ namespace Google.Protobuf.Reflection
return getValueDelegate(message); return getValueDelegate(message);
} }
public abstract bool HasValue(IMessage message);
public abstract void Clear(IMessage message); public abstract void Clear(IMessage message);
public abstract void SetValue(IMessage message, object value); public abstract void SetValue(IMessage message, object value);
} }
......
...@@ -79,8 +79,7 @@ namespace Google.Protobuf.Reflection ...@@ -79,8 +79,7 @@ namespace Google.Protobuf.Reflection
throw new DescriptorValidationException(this, "Field numbers must be positive integers."); throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
} }
ContainingType = parent; ContainingType = parent;
// OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction. if (proto.HasOneofIndex)
if (proto.OneofIndex != -1)
{ {
if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count) if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
{ {
...@@ -184,6 +183,11 @@ namespace Google.Protobuf.Reflection ...@@ -184,6 +183,11 @@ namespace Google.Protobuf.Reflection
/// </summary> /// </summary>
public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated; public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated;
/// <summary>
/// Returns <c>true</c> if this field is a required field; <c>false</c> otherwise.
/// </summary>
public bool IsRequired => Proto.Label == FieldDescriptorProto.Types.Label.Required;
/// <summary> /// <summary>
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise. /// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
/// </summary> /// </summary>
...@@ -192,13 +196,8 @@ namespace Google.Protobuf.Reflection ...@@ -192,13 +196,8 @@ namespace Google.Protobuf.Reflection
/// <summary> /// <summary>
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise. /// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
/// </summary> /// </summary>
public bool IsPacked => public bool IsPacked => File.Proto.Syntax == "proto2" ? Proto.Options?.Packed ?? false : !Proto.Options.HasPacked || Proto.Options.Packed;
// Note the || rather than && here - we're effectively defaulting to packed, because that *is*
// the default in proto3, which is all we support. We may give the wrong result for the protos
// within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
// within the runtime.
Proto.Options == null || Proto.Options.Packed;
/// <summary> /// <summary>
/// Returns the type of the field. /// Returns the type of the field.
/// </summary> /// </summary>
...@@ -247,9 +246,9 @@ namespace Google.Protobuf.Reflection ...@@ -247,9 +246,9 @@ namespace Google.Protobuf.Reflection
{ {
get get
{ {
if (fieldType != FieldType.Message) if (fieldType != FieldType.Message && fieldType != FieldType.Group)
{ {
throw new InvalidOperationException("MessageType is only valid for message fields."); throw new InvalidOperationException("MessageType is only valid for message or group fields.");
} }
return messageType; return messageType;
} }
...@@ -265,12 +264,12 @@ namespace Google.Protobuf.Reflection ...@@ -265,12 +264,12 @@ namespace Google.Protobuf.Reflection
/// </summary> /// </summary>
internal void CrossLink() internal void CrossLink()
{ {
if (Proto.TypeName != "") if (Proto.HasTypeName)
{ {
IDescriptor typeDescriptor = IDescriptor typeDescriptor =
File.DescriptorPool.LookupSymbol(Proto.TypeName, this); File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
if (Proto.Type != 0) if (Proto.HasType)
{ {
// Choose field type based on symbol. // Choose field type based on symbol.
if (typeDescriptor is MessageDescriptor) if (typeDescriptor is MessageDescriptor)
...@@ -287,7 +286,7 @@ namespace Google.Protobuf.Reflection ...@@ -287,7 +286,7 @@ namespace Google.Protobuf.Reflection
} }
} }
if (fieldType == FieldType.Message) if (fieldType == FieldType.Message || fieldType == FieldType.Group)
{ {
if (!(typeDescriptor is MessageDescriptor)) if (!(typeDescriptor is MessageDescriptor))
{ {
...@@ -295,7 +294,7 @@ namespace Google.Protobuf.Reflection ...@@ -295,7 +294,7 @@ namespace Google.Protobuf.Reflection
} }
messageType = (MessageDescriptor) typeDescriptor; messageType = (MessageDescriptor) typeDescriptor;
if (Proto.DefaultValue != "") if (Proto.HasDefaultValue)
{ {
throw new DescriptorValidationException(this, "Messages can't have default values."); throw new DescriptorValidationException(this, "Messages can't have default values.");
} }
...@@ -325,7 +324,7 @@ namespace Google.Protobuf.Reflection ...@@ -325,7 +324,7 @@ namespace Google.Protobuf.Reflection
File.DescriptorPool.AddFieldByNumber(this); File.DescriptorPool.AddFieldByNumber(this);
if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat) if (ContainingType != null && ContainingType.Proto.HasOptions && ContainingType.Proto.Options.MessageSetWireFormat)
{ {
throw new DescriptorValidationException(this, "MessageSet format is not supported."); throw new DescriptorValidationException(this, "MessageSet format is not supported.");
} }
......
...@@ -74,7 +74,7 @@ namespace Google.Protobuf.Reflection ...@@ -74,7 +74,7 @@ namespace Google.Protobuf.Reflection
/// </summary> /// </summary>
String, String,
/// <summary> /// <summary>
/// The field type used for groups (not supported in this implementation). /// The field type used for groups.
/// </summary> /// </summary>
Group, Group,
/// <summary> /// <summary>
......
...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection ...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection
/// </summary> /// </summary>
void Clear(IMessage message); void Clear(IMessage message);
/// <summary>
/// Indicates whether the field in the specified message is set. For proto3 fields, this throws an <see cref="InvalidOperationException"/>
/// </summary>
bool HasValue(IMessage message);
/// <summary> /// <summary>
/// Fetches the field value. For repeated values, this will be an /// Fetches the field value. For repeated values, this will be an
/// <see cref="IList"/> implementation. For map values, this will be an /// <see cref="IList"/> implementation. For map values, this will be an
......
...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection ...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection
list.Clear(); list.Clear();
} }
public override bool HasValue(IMessage message)
{
throw new InvalidOperationException("HasValue is not implemented for map fields");
}
public override void SetValue(IMessage message, object value) public override void SetValue(IMessage message, object value)
{ {
throw new InvalidOperationException("SetValue is not implemented for map fields"); throw new InvalidOperationException("SetValue is not implemented for map fields");
......
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
// This file just contains partial classes for any autogenerated classes that need additional support.
namespace Google.Protobuf.Reflection
{
internal partial class FieldDescriptorProto
{
// We can't tell the difference between "explicitly set to 0" and "not set"
// in proto3, but we need to tell the difference for OneofIndex. descriptor.proto
// is really a proto2 file, but the runtime doesn't know about proto2 semantics...
// We fake it by defaulting to -1.
partial void OnConstruction()
{
OneofIndex = -1;
}
}
internal partial class FieldOptions
{
// We can't tell the difference between "explicitly set to false" and "not set"
// in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.
// This won't work if we ever need to support proto2, but at that point we'll be
// able to remove this hack and use field presence instead.
partial void OnConstruction()
{
Packed = true;
}
}
}
\ No newline at end of file
...@@ -112,6 +112,9 @@ namespace Google.Protobuf.Reflection ...@@ -112,6 +112,9 @@ namespace Google.Protobuf.Reflection
internal static Action<IMessage> CreateActionIMessage(MethodInfo method) => internal static Action<IMessage> CreateActionIMessage(MethodInfo method) =>
GetReflectionHelper(method.DeclaringType, typeof(object)).CreateActionIMessage(method); GetReflectionHelper(method.DeclaringType, typeof(object)).CreateActionIMessage(method);
internal static Func<IMessage, bool> CreateFuncIMessageBool(MethodInfo method) =>
GetReflectionHelper(method.DeclaringType, method.ReturnType).CreateFuncIMessageBool(method);
/// <summary> /// <summary>
/// Creates a reflection helper for the given type arguments. Currently these are created on demand /// Creates a reflection helper for the given type arguments. Currently these are created on demand
/// rather than cached; this will be "busy" when initially loading a message's descriptor, but after that /// rather than cached; this will be "busy" when initially loading a message's descriptor, but after that
...@@ -129,6 +132,7 @@ namespace Google.Protobuf.Reflection ...@@ -129,6 +132,7 @@ namespace Google.Protobuf.Reflection
Action<IMessage> CreateActionIMessage(MethodInfo method); Action<IMessage> CreateActionIMessage(MethodInfo method);
Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method); Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method);
Action<IMessage, object> CreateActionIMessageObject(MethodInfo method); Action<IMessage, object> CreateActionIMessageObject(MethodInfo method);
Func<IMessage, bool> CreateFuncIMessageBool(MethodInfo method);
} }
private class ReflectionHelper<T1, T2> : IReflectionHelper private class ReflectionHelper<T1, T2> : IReflectionHelper
...@@ -170,6 +174,12 @@ namespace Google.Protobuf.Reflection ...@@ -170,6 +174,12 @@ namespace Google.Protobuf.Reflection
var del = (Action<T1, T2>) method.CreateDelegate(typeof(Action<T1, T2>)); var del = (Action<T1, T2>) method.CreateDelegate(typeof(Action<T1, T2>));
return (message, arg) => del((T1) message, (T2) arg); return (message, arg) => del((T1) message, (T2) arg);
} }
public Func<IMessage, bool> CreateFuncIMessageBool(MethodInfo method)
{
var del = (Func<T1, bool>)method.CreateDelegate(typeof(Func<T1, bool>));
return message => del((T1)message);
}
} }
// Runtime compatibility checking code - see ReflectionHelper<T1, T2>.CreateFuncIMessageInt32 for // Runtime compatibility checking code - see ReflectionHelper<T1, T2>.CreateFuncIMessageInt32 for
......
...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection ...@@ -51,6 +51,11 @@ namespace Google.Protobuf.Reflection
list.Clear(); list.Clear();
} }
public override bool HasValue(IMessage message)
{
throw new InvalidOperationException("HasValue is not implemented for repeated fields");
}
public override void SetValue(IMessage message, object value) public override void SetValue(IMessage message, object value)
{ {
throw new InvalidOperationException("SetValue is not implemented for repeated fields"); throw new InvalidOperationException("SetValue is not implemented for repeated fields");
......
...@@ -48,6 +48,7 @@ namespace Google.Protobuf.Reflection ...@@ -48,6 +48,7 @@ namespace Google.Protobuf.Reflection
private readonly Action<IMessage, object> setValueDelegate; private readonly Action<IMessage, object> setValueDelegate;
private readonly Action<IMessage> clearDelegate; private readonly Action<IMessage> clearDelegate;
private readonly Func<IMessage, bool> hasDelegate;
internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor) internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
{ {
...@@ -56,16 +57,25 @@ namespace Google.Protobuf.Reflection ...@@ -56,16 +57,25 @@ namespace Google.Protobuf.Reflection
throw new ArgumentException("Not all required properties/methods available"); throw new ArgumentException("Not all required properties/methods available");
} }
setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod()); setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
if (descriptor.File.Proto.Syntax == "proto2")
{
MethodInfo hasMethod = property.DeclaringType.GetRuntimeProperty("Has" + property.Name).GetMethod;
hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod ?? throw new ArgumentException("Not all required properties/methods are available"));
MethodInfo clearMethod = property.DeclaringType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod ?? throw new ArgumentException("Not all required properties/methods are available"));
}
else
{
hasDelegate = (_) => throw new InvalidOperationException("HasValue is not implemented for proto3 fields"); var clrType = property.PropertyType;
var clrType = property.PropertyType; // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
object defaultValue =
// TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.) descriptor.FieldType == FieldType.Message ? null
object defaultValue = : clrType == typeof(string) ? ""
descriptor.FieldType == FieldType.Message ? null : clrType == typeof(ByteString) ? ByteString.Empty
: clrType == typeof(string) ? "" : Activator.CreateInstance(clrType);
: clrType == typeof(ByteString) ? ByteString.Empty clearDelegate = message => SetValue(message, defaultValue);
: Activator.CreateInstance(clrType); }
clearDelegate = message => SetValue(message, defaultValue);
} }
public override void Clear(IMessage message) public override void Clear(IMessage message)
...@@ -73,6 +83,11 @@ namespace Google.Protobuf.Reflection ...@@ -73,6 +83,11 @@ namespace Google.Protobuf.Reflection
clearDelegate(message); clearDelegate(message);
} }
public override bool HasValue(IMessage message)
{
return hasDelegate(message);
}
public override void SetValue(IMessage message, object value) public override void SetValue(IMessage message, object value)
{ {
setValueDelegate(message, value); setValueDelegate(message, value);
......
...@@ -328,7 +328,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -328,7 +328,7 @@ namespace Google.Protobuf.WellKnownTypes {
} }
if (other.sourceContext_ != null) { if (other.sourceContext_ != null) {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
SourceContext.MergeFrom(other.SourceContext); SourceContext.MergeFrom(other.SourceContext);
} }
...@@ -365,9 +365,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -365,9 +365,9 @@ namespace Google.Protobuf.WellKnownTypes {
} }
case 42: { case 42: {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
input.ReadMessage(sourceContext_); input.ReadMessage(SourceContext);
break; break;
} }
case 50: { case 50: {
...@@ -375,7 +375,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -375,7 +375,7 @@ namespace Google.Protobuf.WellKnownTypes {
break; break;
} }
case 56: { case 56: {
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum(); Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break; break;
} }
} }
...@@ -688,7 +688,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -688,7 +688,7 @@ namespace Google.Protobuf.WellKnownTypes {
break; break;
} }
case 56: { case 56: {
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum(); Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break; break;
} }
} }
......
...@@ -312,7 +312,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -312,7 +312,7 @@ namespace Google.Protobuf.WellKnownTypes {
options_.Add(other.options_); options_.Add(other.options_);
if (other.sourceContext_ != null) { if (other.sourceContext_ != null) {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
SourceContext.MergeFrom(other.SourceContext); SourceContext.MergeFrom(other.SourceContext);
} }
...@@ -348,13 +348,13 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -348,13 +348,13 @@ namespace Google.Protobuf.WellKnownTypes {
} }
case 42: { case 42: {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
input.ReadMessage(sourceContext_); input.ReadMessage(SourceContext);
break; break;
} }
case 48: { case 48: {
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum(); Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break; break;
} }
} }
...@@ -726,11 +726,11 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -726,11 +726,11 @@ namespace Google.Protobuf.WellKnownTypes {
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break; break;
case 8: { case 8: {
kind_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Kind) input.ReadEnum(); Kind = (global::Google.Protobuf.WellKnownTypes.Field.Types.Kind) input.ReadEnum();
break; break;
} }
case 16: { case 16: {
cardinality_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) input.ReadEnum(); Cardinality = (global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) input.ReadEnum();
break; break;
} }
case 24: { case 24: {
...@@ -1084,7 +1084,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1084,7 +1084,7 @@ namespace Google.Protobuf.WellKnownTypes {
options_.Add(other.options_); options_.Add(other.options_);
if (other.sourceContext_ != null) { if (other.sourceContext_ != null) {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
SourceContext.MergeFrom(other.SourceContext); SourceContext.MergeFrom(other.SourceContext);
} }
...@@ -1116,13 +1116,13 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1116,13 +1116,13 @@ namespace Google.Protobuf.WellKnownTypes {
} }
case 34: { case 34: {
if (sourceContext_ == null) { if (sourceContext_ == null) {
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext(); SourceContext = new global::Google.Protobuf.WellKnownTypes.SourceContext();
} }
input.ReadMessage(sourceContext_); input.ReadMessage(SourceContext);
break; break;
} }
case 40: { case 40: {
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum(); Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break; break;
} }
} }
...@@ -1467,7 +1467,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1467,7 +1467,7 @@ namespace Google.Protobuf.WellKnownTypes {
} }
if (other.value_ != null) { if (other.value_ != null) {
if (value_ == null) { if (value_ == null) {
value_ = new global::Google.Protobuf.WellKnownTypes.Any(); Value = new global::Google.Protobuf.WellKnownTypes.Any();
} }
Value.MergeFrom(other.Value); Value.MergeFrom(other.Value);
} }
...@@ -1488,9 +1488,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1488,9 +1488,9 @@ namespace Google.Protobuf.WellKnownTypes {
} }
case 18: { case 18: {
if (value_ == null) { if (value_ == null) {
value_ = new global::Google.Protobuf.WellKnownTypes.Any(); Value = new global::Google.Protobuf.WellKnownTypes.Any();
} }
input.ReadMessage(value_); input.ReadMessage(Value);
break; break;
} }
} }
......
...@@ -61,11 +61,11 @@ namespace Google.Protobuf ...@@ -61,11 +61,11 @@ namespace Google.Protobuf
/// </summary> /// </summary>
LengthDelimited = 2, LengthDelimited = 2,
/// <summary> /// <summary>
/// A "start group" value - not supported by this implementation. /// A "start group" value
/// </summary> /// </summary>
StartGroup = 3, StartGroup = 3,
/// <summary> /// <summary>
/// An "end group" value - not supported by this implementation. /// An "end group" value
/// </summary> /// </summary>
EndGroup = 4, EndGroup = 4,
/// <summary> /// <summary>
......
...@@ -47,8 +47,8 @@ namespace compiler { ...@@ -47,8 +47,8 @@ namespace compiler {
namespace csharp { namespace csharp {
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, const Options *options) int presenceIndex, const Options *options)
: PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) { : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
} }
EnumFieldGenerator::~EnumFieldGenerator() { EnumFieldGenerator::~EnumFieldGenerator() {
...@@ -56,7 +56,7 @@ EnumFieldGenerator::~EnumFieldGenerator() { ...@@ -56,7 +56,7 @@ EnumFieldGenerator::~EnumFieldGenerator() {
void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) { void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(variables_, printer->Print(variables_,
"$name$_ = ($type_name$) input.ReadEnum();\n"); "$property_name$ = ($type_name$) input.ReadEnum();\n");
} }
void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) { void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
...@@ -82,8 +82,8 @@ void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) { ...@@ -82,8 +82,8 @@ void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
} }
EnumOneofFieldGenerator::EnumOneofFieldGenerator( EnumOneofFieldGenerator::EnumOneofFieldGenerator(
const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
: PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) { : PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options) {
} }
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() { EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
......
...@@ -44,7 +44,7 @@ namespace csharp { ...@@ -44,7 +44,7 @@ namespace csharp {
class EnumFieldGenerator : public PrimitiveFieldGenerator { class EnumFieldGenerator : public PrimitiveFieldGenerator {
public: public:
EnumFieldGenerator(const FieldDescriptor* descriptor, EnumFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~EnumFieldGenerator(); ~EnumFieldGenerator();
...@@ -60,7 +60,7 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator { ...@@ -60,7 +60,7 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator {
class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
public: public:
EnumOneofFieldGenerator(const FieldDescriptor* descriptor, EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~EnumOneofFieldGenerator(); ~EnumOneofFieldGenerator();
......
...@@ -57,6 +57,9 @@ void FieldGeneratorBase::SetCommonFieldVariables( ...@@ -57,6 +57,9 @@ void FieldGeneratorBase::SetCommonFieldVariables(
// repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
// never effects the tag size. // never effects the tag size.
int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
tag_size /= 2;
}
uint tag = internal::WireFormat::MakeTag(descriptor_); uint tag = internal::WireFormat::MakeTag(descriptor_);
uint8 tag_array[5]; uint8 tag_array[5];
io::CodedOutputStream::WriteTagToArray(tag, tag_array); io::CodedOutputStream::WriteTagToArray(tag, tag_array);
...@@ -75,34 +78,52 @@ void FieldGeneratorBase::SetCommonFieldVariables( ...@@ -75,34 +78,52 @@ void FieldGeneratorBase::SetCommonFieldVariables(
(*variables)["name"] = name(); (*variables)["name"] = name();
(*variables)["descriptor_name"] = descriptor_->name(); (*variables)["descriptor_name"] = descriptor_->name();
(*variables)["default_value"] = default_value(); (*variables)["default_value"] = default_value();
if (has_default_value()) { (*variables)["capitalized_type_name"] = capitalized_type_name();
(*variables)["number"] = number();
if (has_default_value() && !IsProto2(descriptor_->file())) {
(*variables)["name_def_message"] = (*variables)["name_def_message"] =
(*variables)["name"] + "_ = " + (*variables)["default_value"]; (*variables)["name"] + "_ = " + (*variables)["default_value"];
} else { } else {
(*variables)["name_def_message"] = (*variables)["name"] + "_"; (*variables)["name_def_message"] = (*variables)["name"] + "_";
} }
(*variables)["capitalized_type_name"] = capitalized_type_name(); if (IsProto2(descriptor_->file())) {
(*variables)["number"] = number(); (*variables)["has_property_check"] = "Has" + (*variables)["property_name"];
(*variables)["has_property_check"] = (*variables)["other_has_property_check"] = "other.Has" + (*variables)["property_name"];
(*variables)["property_name"] + " != " + (*variables)["default_value"]; (*variables)["has_not_property_check"] = "!" + (*variables)["has_property_check"];
(*variables)["other_has_property_check"] = "other." + (*variables)["other_has_not_property_check"] = "!" + (*variables)["other_has_property_check"];
(*variables)["property_name"] + " != " + (*variables)["default_value"]; if (presenceIndex_ != -1) {
string hasBitsNumber = SimpleItoa(presenceIndex_ / 32);
string hasBitsMask = SimpleItoa(1 << (presenceIndex_ % 32));
(*variables)["has_field_check"] = "(_hasBits" + hasBitsNumber + " & " + hasBitsMask + ") != 0";
(*variables)["set_has_field"] = "_hasBits" + hasBitsNumber + " |= " + hasBitsMask;
(*variables)["clear_has_field"] = "_hasBits" + hasBitsNumber + " &= ~" + hasBitsMask;
}
} else {
(*variables)["has_property_check"] =
(*variables)["property_name"] + " != " + (*variables)["default_value"];
(*variables)["other_has_property_check"] = "other." +
(*variables)["property_name"] + " != " + (*variables)["default_value"];
}
} }
void FieldGeneratorBase::SetCommonOneofFieldVariables( void FieldGeneratorBase::SetCommonOneofFieldVariables(
std::map<string, string>* variables) { std::map<string, string>* variables) {
(*variables)["oneof_name"] = oneof_name(); (*variables)["oneof_name"] = oneof_name();
(*variables)["has_property_check"] = if (IsProto2(descriptor_->file())) {
oneof_name() + "Case_ == " + oneof_property_name() + (*variables)["has_property_check"] = "Has" + property_name();
"OneofCase." + property_name(); } else {
(*variables)["has_property_check"] =
oneof_name() + "Case_ == " + oneof_property_name() +
"OneofCase." + property_name();
}
(*variables)["oneof_property_name"] = oneof_property_name(); (*variables)["oneof_property_name"] = oneof_property_name();
} }
FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
int fieldOrdinal, const Options* options) int presenceIndex, const Options* options)
: SourceGeneratorBase(descriptor->file(), options), : SourceGeneratorBase(descriptor->file(), options),
descriptor_(descriptor), descriptor_(descriptor),
fieldOrdinal_(fieldOrdinal) { presenceIndex_(presenceIndex) {
SetCommonFieldVariables(&variables_); SetCommonFieldVariables(&variables_);
} }
...@@ -251,36 +272,6 @@ bool FieldGeneratorBase::has_default_value() { ...@@ -251,36 +272,6 @@ bool FieldGeneratorBase::has_default_value() {
} }
} }
bool FieldGeneratorBase::is_nullable_type() {
switch (descriptor_->type()) {
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_BOOL:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
return false;
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
return true;
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return true;
}
}
bool AllPrintableAscii(const std::string& text) { bool AllPrintableAscii(const std::string& text) {
for(int i = 0; i < text.size(); i++) { for(int i = 0; i < text.size(); i++) {
if (text[i] < 0x20 || text[i] > 0x7e) { if (text[i] < 0x20 || text[i] > 0x7e) {
...@@ -290,14 +281,18 @@ bool AllPrintableAscii(const std::string& text) { ...@@ -290,14 +281,18 @@ bool AllPrintableAscii(const std::string& text) {
return true; return true;
} }
std::string FieldGeneratorBase::GetStringDefaultValueInternal() { std::string FieldGeneratorBase::GetStringDefaultValueInternal(const FieldDescriptor* descriptor) {
// No other default values needed for proto3... if (descriptor->default_value_string().empty())
return "\"\""; return "\"\"";
else
return "global::System.Encoding.UTF8.GetString(global::System.Convert.FromBase64String(\" +" + StringToBase64(descriptor->default_value_string()) + " +\"))";
} }
std::string FieldGeneratorBase::GetBytesDefaultValueInternal() { std::string FieldGeneratorBase::GetBytesDefaultValueInternal(const FieldDescriptor* descriptor) {
// No other default values needed for proto3... if (descriptor->default_value_string().empty())
return "pb::ByteString.Empty"; return "pb::ByteString.Empty";
else
return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor->default_value_string()) + "\")";
} }
std::string FieldGeneratorBase::default_value() { std::string FieldGeneratorBase::default_value() {
...@@ -307,9 +302,13 @@ std::string FieldGeneratorBase::default_value() { ...@@ -307,9 +302,13 @@ std::string FieldGeneratorBase::default_value() {
std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) { std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
switch (descriptor->type()) { switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM: case FieldDescriptor::TYPE_ENUM:
// All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to if (IsProto2(descriptor_->file())) {
// any C# enum. This means we don't need to work out what we actually mapped the enum value name to. return GetClassName(descriptor->default_value_enum()->type()) + "." +
return "0"; GetEnumValueName(descriptor->default_value_enum()->type()->name(), descriptor->default_value_enum()->name());
}
else {
return "0";
}
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_GROUP:
if (IsWrapperType(descriptor)) { if (IsWrapperType(descriptor)) {
...@@ -357,9 +356,9 @@ std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) ...@@ -357,9 +356,9 @@ std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor)
return "false"; return "false";
} }
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
return GetStringDefaultValueInternal(); return GetStringDefaultValueInternal(descriptor);
case FieldDescriptor::TYPE_BYTES: case FieldDescriptor::TYPE_BYTES:
return GetBytesDefaultValueInternal(); return GetBytesDefaultValueInternal(descriptor);
case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_UINT32:
return SimpleItoa(descriptor->default_value_uint32()); return SimpleItoa(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_SFIXED32: case FieldDescriptor::TYPE_SFIXED32:
......
...@@ -47,7 +47,7 @@ namespace csharp { ...@@ -47,7 +47,7 @@ namespace csharp {
class FieldGeneratorBase : public SourceGeneratorBase { class FieldGeneratorBase : public SourceGeneratorBase {
public: public:
FieldGeneratorBase(const FieldDescriptor* descriptor, FieldGeneratorBase(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options* options); const Options* options);
~FieldGeneratorBase(); ~FieldGeneratorBase();
...@@ -67,7 +67,7 @@ class FieldGeneratorBase : public SourceGeneratorBase { ...@@ -67,7 +67,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
protected: protected:
const FieldDescriptor* descriptor_; const FieldDescriptor* descriptor_;
const int fieldOrdinal_; const int presenceIndex_;
std::map<string, string> variables_; std::map<string, string> variables_;
void AddDeprecatedFlag(io::Printer* printer); void AddDeprecatedFlag(io::Printer* printer);
...@@ -84,7 +84,6 @@ class FieldGeneratorBase : public SourceGeneratorBase { ...@@ -84,7 +84,6 @@ class FieldGeneratorBase : public SourceGeneratorBase {
std::string type_name(); std::string type_name();
std::string type_name(const FieldDescriptor* descriptor); std::string type_name(const FieldDescriptor* descriptor);
bool has_default_value(); bool has_default_value();
bool is_nullable_type();
std::string default_value(); std::string default_value();
std::string default_value(const FieldDescriptor* descriptor); std::string default_value(const FieldDescriptor* descriptor);
std::string number(); std::string number();
...@@ -92,8 +91,8 @@ class FieldGeneratorBase : public SourceGeneratorBase { ...@@ -92,8 +91,8 @@ class FieldGeneratorBase : public SourceGeneratorBase {
private: private:
void SetCommonFieldVariables(std::map<string, string>* variables); void SetCommonFieldVariables(std::map<string, string>* variables);
std::string GetStringDefaultValueInternal(); std::string GetStringDefaultValueInternal(const FieldDescriptor* descriptor);
std::string GetBytesDefaultValueInternal(); std::string GetBytesDefaultValueInternal(const FieldDescriptor* descriptor);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase);
}; };
......
...@@ -65,11 +65,11 @@ bool Generator::Generate( ...@@ -65,11 +65,11 @@ bool Generator::Generate(
std::vector<std::pair<string, string> > options; std::vector<std::pair<string, string> > options;
ParseGeneratorParameter(parameter, &options); ParseGeneratorParameter(parameter, &options);
// We only support proto3 - but we make an exception for descriptor.proto. // We only support proto3 - but we make an exception for descriptor.proto.
if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) { if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) {
*error = "C# code generation only supports proto3 syntax"; *error = "C# code generation only supports proto3 syntax";
return false; return false;
} }
struct Options cli_options; struct Options cli_options;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <google/protobuf/stubs/hash.h> #include <google/protobuf/stubs/hash.h>
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <sstream>
#include <google/protobuf/compiler/csharp/csharp_helpers.h> #include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h> #include <google/protobuf/compiler/csharp/csharp_names.h>
...@@ -452,55 +453,89 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { ...@@ -452,55 +453,89 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) {
} }
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options* options) { const Options* options) {
switch (descriptor->type()) { switch (descriptor->type()) {
case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
if (descriptor->is_repeated()) { if (descriptor->is_repeated()) {
if (descriptor->is_map()) { if (descriptor->is_map()) {
return new MapFieldGenerator(descriptor, fieldOrdinal, options); return new MapFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options); return new RepeatedMessageFieldGenerator(descriptor, presenceIndex, options);
} }
} else { } else {
if (IsWrapperType(descriptor)) { if (IsWrapperType(descriptor)) {
if (descriptor->containing_oneof()) { if (descriptor->containing_oneof()) {
return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options); return new WrapperOneofFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
return new WrapperFieldGenerator(descriptor, fieldOrdinal, options); return new WrapperFieldGenerator(descriptor, presenceIndex, options);
} }
} else { } else {
if (descriptor->containing_oneof()) { if (descriptor->containing_oneof()) {
return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options); return new MessageOneofFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
return new MessageFieldGenerator(descriptor, fieldOrdinal, options); return new MessageFieldGenerator(descriptor, presenceIndex, options);
} }
} }
} }
case FieldDescriptor::TYPE_ENUM: case FieldDescriptor::TYPE_ENUM:
if (descriptor->is_repeated()) { if (descriptor->is_repeated()) {
return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options); return new RepeatedEnumFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
if (descriptor->containing_oneof()) { if (descriptor->containing_oneof()) {
return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options); return new EnumOneofFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
return new EnumFieldGenerator(descriptor, fieldOrdinal, options); return new EnumFieldGenerator(descriptor, presenceIndex, options);
} }
} }
default: default:
if (descriptor->is_repeated()) { if (descriptor->is_repeated()) {
return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options); return new RepeatedPrimitiveFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
if (descriptor->containing_oneof()) { if (descriptor->containing_oneof()) {
return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options); return new PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options);
} else { } else {
return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options); return new PrimitiveFieldGenerator(descriptor, presenceIndex, options);
} }
} }
} }
} }
bool IsNullable(const FieldDescriptor* descriptor) {
if (descriptor->is_repeated()) {
return true;
}
switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_BOOL:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
return false;
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
return true;
default:
GOOGLE_LOG(FATAL) << "Unknown field type.";
return true;
}
}
} // namespace csharp } // namespace csharp
} // namespace compiler } // namespace compiler
} // namespace protobuf } // namespace protobuf
......
...@@ -107,9 +107,11 @@ std::string StringToBase64(const std::string& input); ...@@ -107,9 +107,11 @@ std::string StringToBase64(const std::string& input);
std::string FileDescriptorToBase64(const FileDescriptor* descriptor); std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options* options); const Options* options);
bool IsNullable(const FieldDescriptor* descriptor);
// Determines whether the given message is a map entry message, // Determines whether the given message is a map entry message,
// i.e. one implicitly created by protoc due to a map<key, value> field. // i.e. one implicitly created by protoc due to a map<key, value> field.
inline bool IsMapEntryMessage(const Descriptor* descriptor) { inline bool IsMapEntryMessage(const Descriptor* descriptor) {
...@@ -144,6 +146,10 @@ inline bool IsWrapperType(const FieldDescriptor* descriptor) { ...@@ -144,6 +146,10 @@ inline bool IsWrapperType(const FieldDescriptor* descriptor) {
descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto"; descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
} }
inline bool IsProto2(const FileDescriptor* descriptor) {
return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
}
} // namespace csharp } // namespace csharp
} // namespace compiler } // namespace compiler
} // namespace protobuf } // namespace protobuf
......
...@@ -48,9 +48,9 @@ namespace compiler { ...@@ -48,9 +48,9 @@ namespace compiler {
namespace csharp { namespace csharp {
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options* options) const Options* options)
: FieldGeneratorBase(descriptor, fieldOrdinal, options) { : FieldGeneratorBase(descriptor, presenceIndex, options) {
} }
MapFieldGenerator::~MapFieldGenerator() { MapFieldGenerator::~MapFieldGenerator() {
......
...@@ -44,7 +44,7 @@ namespace csharp { ...@@ -44,7 +44,7 @@ namespace csharp {
class MapFieldGenerator : public FieldGeneratorBase { class MapFieldGenerator : public FieldGeneratorBase {
public: public:
MapFieldGenerator(const FieldDescriptor* descriptor, MapFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options* options); const Options* options);
~MapFieldGenerator(); ~MapFieldGenerator();
......
...@@ -61,20 +61,27 @@ bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { ...@@ -61,20 +61,27 @@ bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
MessageGenerator::MessageGenerator(const Descriptor* descriptor, MessageGenerator::MessageGenerator(const Descriptor* descriptor,
const Options* options) const Options* options)
: SourceGeneratorBase(descriptor->file(), options), : SourceGeneratorBase(descriptor->file(), options),
descriptor_(descriptor) { descriptor_(descriptor),
has_bit_field_count_(0) {
// sorted field names
for (int i = 0; i < descriptor_->field_count(); i++) {
field_names_.push_back(descriptor_->field(i)->name());
}
std::sort(field_names_.begin(), field_names_.end());
// fields by number // fields by number
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
fields_by_number_.push_back(descriptor_->field(i)); fields_by_number_.push_back(descriptor_->field(i));
} }
std::sort(fields_by_number_.begin(), fields_by_number_.end(), std::sort(fields_by_number_.begin(), fields_by_number_.end(),
CompareFieldNumbers); CompareFieldNumbers);
if (IsProto2(descriptor_->file())) {
int primitiveCount = 0;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (!IsNullable(field)) {
primitiveCount++;
if (has_bit_field_count_ == 0 || (primitiveCount % 32) == 0) {
has_bit_field_count_++;
}
}
}
}
} }
MessageGenerator::~MessageGenerator() { MessageGenerator::~MessageGenerator() {
...@@ -88,10 +95,6 @@ std::string MessageGenerator::full_class_name() { ...@@ -88,10 +95,6 @@ std::string MessageGenerator::full_class_name() {
return GetClassName(descriptor_); return GetClassName(descriptor_);
} }
const std::vector<std::string>& MessageGenerator::field_names() {
return field_names_;
}
const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
return fields_by_number_; return fields_by_number_;
} }
...@@ -123,6 +126,12 @@ void MessageGenerator::Generate(io::Printer* printer) { ...@@ -123,6 +126,12 @@ void MessageGenerator::Generate(io::Printer* printer) {
printer->Print( printer->Print(
"private pb::UnknownFieldSet _unknownFields;\n"); "private pb::UnknownFieldSet _unknownFields;\n");
for (int i = 0; i < has_bit_field_count_; i++) {
// don't use arrays since all arrays are heap allocated, saving allocations
// use ints instead of bytes since bytes lack bitwise operators, saving casts
printer->Print("private int _hasBits$i$;\n", "i", SimpleItoa(i));
}
WriteGeneratedCodeAttributes(printer); WriteGeneratedCodeAttributes(printer);
printer->Print( printer->Print(
...@@ -288,6 +297,9 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) { ...@@ -288,6 +297,9 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
vars, vars,
"public $class_name$($class_name$ other) : this() {\n"); "public $class_name$($class_name$ other) : this() {\n");
printer->Indent(); printer->Indent();
for (int i = 0; i < has_bit_field_count_; i++) {
printer->Print("_hasBits$i$ = other._hasBits$i$;\n", "i", SimpleItoa(i));
}
// Clone non-oneof fields first // Clone non-oneof fields first
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->containing_oneof()) { if (!descriptor_->field(i)->containing_oneof()) {
...@@ -559,19 +571,29 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { ...@@ -559,19 +571,29 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
printer->Print("}\n\n"); // method printer->Print("}\n\n"); // method
} }
int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { // it's a waste of space to track presence for all values, so we only track them if they're not nullable
for (int i = 0; i < field_names().size(); i++) { int MessageGenerator::GetPresenceIndex(const FieldDescriptor* descriptor) {
if (field_names()[i] == descriptor->name()) { if (IsNullable(descriptor) || !IsProto2(descriptor_->file())) {
return i; return -1;
}
int index = 0;
for (int i = 0; i < fields_by_number().size(); i++) {
const FieldDescriptor* field = fields_by_number()[i];
if (field == descriptor) {
return index;
}
if (!IsNullable(field)) {
index++;
} }
} }
GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name(); GOOGLE_LOG(DFATAL)<< "Could not find presence index for field " << descriptor->name();
return -1; return -1;
} }
FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
const FieldDescriptor* descriptor) { const FieldDescriptor* descriptor) {
return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor), this->options()); return CreateFieldGenerator(descriptor, GetPresenceIndex(descriptor), this->options());
} }
} // namespace csharp } // namespace csharp
......
...@@ -57,13 +57,13 @@ class MessageGenerator : public SourceGeneratorBase { ...@@ -57,13 +57,13 @@ class MessageGenerator : public SourceGeneratorBase {
private: private:
const Descriptor* descriptor_; const Descriptor* descriptor_;
std::vector<std::string> field_names_;
std::vector<const FieldDescriptor*> fields_by_number_; std::vector<const FieldDescriptor*> fields_by_number_;
int has_bit_field_count_;
void GenerateMessageSerializationMethods(io::Printer* printer); void GenerateMessageSerializationMethods(io::Printer* printer);
void GenerateMergingMethods(io::Printer* printer); void GenerateMergingMethods(io::Printer* printer);
int GetFieldOrdinal(const FieldDescriptor* descriptor); int GetPresenceIndex(const FieldDescriptor* descriptor);
FieldGeneratorBase* CreateFieldGeneratorInternal( FieldGeneratorBase* CreateFieldGeneratorInternal(
const FieldDescriptor* descriptor); const FieldDescriptor* descriptor);
...@@ -74,9 +74,6 @@ class MessageGenerator : public SourceGeneratorBase { ...@@ -74,9 +74,6 @@ class MessageGenerator : public SourceGeneratorBase {
std::string class_name(); std::string class_name();
std::string full_class_name(); std::string full_class_name();
// field names sorted alphabetically
const std::vector<std::string>& field_names();
// field descriptors sorted by number // field descriptors sorted by number
const std::vector<const FieldDescriptor*>& fields_by_number(); const std::vector<const FieldDescriptor*>& fields_by_number();
......
...@@ -49,11 +49,13 @@ namespace compiler { ...@@ -49,11 +49,13 @@ namespace compiler {
namespace csharp { namespace csharp {
MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options) const Options *options)
: FieldGeneratorBase(descriptor, fieldOrdinal, options) { : FieldGeneratorBase(descriptor, presenceIndex, options) {
variables_["has_property_check"] = name() + "_ != null"; if (!IsProto2(descriptor_->file())) {
variables_["has_not_property_check"] = name() + "_ == null"; variables_["has_property_check"] = name() + "_ != null";
variables_["has_not_property_check"] = name() + "_ == null";
}
} }
MessageFieldGenerator::~MessageFieldGenerator() { MessageFieldGenerator::~MessageFieldGenerator() {
...@@ -74,6 +76,26 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -74,6 +76,26 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
" $name$_ = value;\n" " $name$_ = value;\n"
" }\n" " }\n"
"}\n"); "}\n");
if (IsProto2(descriptor_->file())) {
printer->Print(
variables_,
"/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
AddPublicMemberAttributes(printer);
printer->Print(
variables_,
"$access_level$ bool Has$property_name$ {\n"
" get { return $name$_ != null; }\n"
"}\n");
printer->Print(
variables_,
"/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
AddPublicMemberAttributes(printer);
printer->Print(
variables_,
"$access_level$ void Clear$property_name$() {\n"
" $name$_ = null;\n"
"}\n");
}
} }
void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) { void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
...@@ -81,7 +103,7 @@ void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) { ...@@ -81,7 +103,7 @@ void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
variables_, variables_,
"if (other.$has_property_check$) {\n" "if (other.$has_property_check$) {\n"
" if ($has_not_property_check$) {\n" " if ($has_not_property_check$) {\n"
" $name$_ = new $type_name$();\n" " $property_name$ = new $type_name$();\n"
" }\n" " }\n"
" $property_name$.MergeFrom(other.$property_name$);\n" " $property_name$.MergeFrom(other.$property_name$);\n"
"}\n"); "}\n");
...@@ -91,10 +113,9 @@ void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) { ...@@ -91,10 +113,9 @@ void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print( printer->Print(
variables_, variables_,
"if ($has_not_property_check$) {\n" "if ($has_not_property_check$) {\n"
" $name$_ = new $type_name$();\n" " $property_name$ = new $type_name$();\n"
"}\n" "}\n"
// TODO(jonskeet): Do we really need merging behaviour like this? "input.ReadMessage($property_name$);\n");
"input.ReadMessage($name$_);\n"); // No need to support TYPE_GROUP...
} }
void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) { void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
...@@ -130,7 +151,6 @@ void MessageFieldGenerator::WriteToString(io::Printer* printer) { ...@@ -130,7 +151,6 @@ void MessageFieldGenerator::WriteToString(io::Printer* printer) {
variables_, variables_,
"PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n"); "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
} }
void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_, printer->Print(variables_,
"$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n"); "$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n");
...@@ -147,9 +167,9 @@ void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) { ...@@ -147,9 +167,9 @@ void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
MessageOneofFieldGenerator::MessageOneofFieldGenerator( MessageOneofFieldGenerator::MessageOneofFieldGenerator(
const FieldDescriptor* descriptor, const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options) const Options *options)
: MessageFieldGenerator(descriptor, fieldOrdinal, options) { : MessageFieldGenerator(descriptor, presenceIndex, options) {
SetCommonOneofFieldVariables(&variables_); SetCommonOneofFieldVariables(&variables_);
} }
...@@ -169,6 +189,28 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -169,6 +189,28 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
" $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
" }\n" " }\n"
"}\n"); "}\n");
if (IsProto2(descriptor_->file())) {
printer->Print(
variables_,
"/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
AddPublicMemberAttributes(printer);
printer->Print(
variables_,
"$access_level$ bool Has$property_name$ {\n"
" get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n"
"}\n");
printer->Print(
variables_,
"/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
AddPublicMemberAttributes(printer);
printer->Print(
variables_,
"$access_level$ void Clear$property_name$() {\n"
" if ($has_property_check$) {\n"
" Clear$oneof_property_name$();\n"
" }\n"
"}\n");
}
} }
void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) { void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
...@@ -187,7 +229,7 @@ void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { ...@@ -187,7 +229,7 @@ void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
"if ($has_property_check$) {\n" "if ($has_property_check$) {\n"
" subBuilder.MergeFrom($property_name$);\n" " subBuilder.MergeFrom($property_name$);\n"
"}\n" "}\n"
"input.ReadMessage(subBuilder);\n" // No support of TYPE_GROUP "input.ReadMessage(subBuilder);\n"
"$property_name$ = subBuilder;\n"); "$property_name$ = subBuilder;\n");
} }
......
...@@ -44,7 +44,7 @@ namespace csharp { ...@@ -44,7 +44,7 @@ namespace csharp {
class MessageFieldGenerator : public FieldGeneratorBase { class MessageFieldGenerator : public FieldGeneratorBase {
public: public:
MessageFieldGenerator(const FieldDescriptor* descriptor, MessageFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~MessageFieldGenerator(); ~MessageFieldGenerator();
...@@ -68,7 +68,7 @@ class MessageFieldGenerator : public FieldGeneratorBase { ...@@ -68,7 +68,7 @@ class MessageFieldGenerator : public FieldGeneratorBase {
class MessageOneofFieldGenerator : public MessageFieldGenerator { class MessageOneofFieldGenerator : public MessageFieldGenerator {
public: public:
MessageOneofFieldGenerator(const FieldDescriptor* descriptor, MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~MessageOneofFieldGenerator(); ~MessageOneofFieldGenerator();
......
...@@ -46,7 +46,7 @@ struct Options; ...@@ -46,7 +46,7 @@ struct Options;
class PrimitiveFieldGenerator : public FieldGeneratorBase { class PrimitiveFieldGenerator : public FieldGeneratorBase {
public: public:
PrimitiveFieldGenerator(const FieldDescriptor* descriptor, PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~PrimitiveFieldGenerator(); ~PrimitiveFieldGenerator();
...@@ -72,7 +72,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { ...@@ -72,7 +72,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase {
class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
public: public:
PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal, int presenceIndex,
const Options *options); const Options *options);
~PrimitiveOneofFieldGenerator(); ~PrimitiveOneofFieldGenerator();
......
...@@ -48,8 +48,8 @@ namespace compiler { ...@@ -48,8 +48,8 @@ namespace compiler {
namespace csharp { namespace csharp {
RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
: FieldGeneratorBase(descriptor, fieldOrdinal, options) { : FieldGeneratorBase(descriptor, presenceIndex, options) {
} }
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment