diff --git a/CHANGES.txt b/CHANGES.txt index e6593c72a3..f466e9c55f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,22 +1,29 @@ -Unreleased version +2022-06-27 Unreleased version * Handle reflection for message splitting. * make metadata fields lazy. * Extend visibility of plugin library to upb * Modernize conformance_cpp.cc. * Don't request 64-byte alignment unless the toolchain supports it. +2022-06-27 version 21.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby) + C++ + * ArenaString improvements (fix alignment issue) + + PHP + * API changes for OneOf (#10102) + 2022-05-27 version 21.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby) - + C++ - * cmake: Revert "Fix cmake install targets (#9822)" (#10060) + * cmake: Revert "Fix cmake install targets (#9822)" (#10060) * Remove Abseil dependency from CMake build (#10056) Python * Update python wheel metadata with more information incl. required python version (#10058) * Fix segmentation fault when instantiating field via repeated field assignment (#10066) - + 2022-05-25 version 21.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby) C++ @@ -1110,11 +1117,11 @@ mistakenly tagged at the wrong commit. 2020-02-14 version 3.11.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) - + C# * Fix latest ArgumentException for C# extensions (#7188) * Enforce recursion depth checking for unknown fields (#7210) - + Ruby * Fix wrappers with a zero value (#7195) * Fix JSON serialization of 0/empty-valued wrapper types (#7198) @@ -1127,13 +1134,13 @@ mistakenly tagged at the wrong commit. PHP * Refactored ulong to zend_ulong for php7.4 compatibility (#7147) * Call register_class before getClass from desc to fix segfault (#7077) - + 2019-12-10 version 3.11.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) PHP * Make c extension portable for php 7.4 (#6968) - + 2019-12-02 version 3.11.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) @@ -1209,7 +1216,7 @@ mistakenly tagged at the wrong commit. * Support 32 bit values for ProtoStreamObjectWriter to Struct. * Removed the internal-only header coded_stream_inl.h and the internal-only methods defined there. * Enforced no SWIG wrapping of descriptor_database.h (other headers already had this restriction). - * Implementation of the equivalent of the MOMI parser for serialization. This removes one of the two serialization routines, by making the fast array serialization routine completely general. SerializeToCodedStream can now be implemented in terms of the much much faster array serialization. The array serialization regresses slightly, but when array serialization is not possible this wins big. + * Implementation of the equivalent of the MOMI parser for serialization. This removes one of the two serialization routines, by making the fast array serialization routine completely general. SerializeToCodedStream can now be implemented in terms of the much much faster array serialization. The array serialization regresses slightly, but when array serialization is not possible this wins big. * Do not convert unknown field name to snake case to accurately report error. * Fix a UBSAN warnings. (#6333) * Add podspec for C++ (#6404) @@ -1243,7 +1250,7 @@ mistakenly tagged at the wrong commit. * Change the parameter types of binaryReaderFn in ExtensionFieldBinaryInfo to (number, ?, ?). * Create dates.ts and time_of_days.ts to mirror Java versions. This is a near-identical conversion of c.g.type.util.{Dates,TimeOfDays} respectively. * Migrate moneys to TypeScript. - + PHP * Fix incorrect leap day for Timestamp (#6696) * Initialize well known type values (#6713) @@ -1257,7 +1264,7 @@ mistakenly tagged at the wrong commit. * Optimization for layout_init() (#6547) * Fix for GC of Ruby map frames. (#6533) * Fixed leap year handling by reworking upb_mktime() -> upb_timegm(). (#6695) - + Objective C * Remove OSReadLittle* due to alignment requirements (#6678) * Don't use unions and instead use memcpy for the type swaps. (#6672) diff --git a/Protobuf.podspec b/Protobuf.podspec index 6b2beda07e..85f1dc6fa1 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.21.1' + s.version = '3.21.2' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/csharp/.editorconfig b/csharp/.editorconfig index 5e2afd0bee..a2bf78c331 100644 --- a/csharp/.editorconfig +++ b/csharp/.editorconfig @@ -14,4 +14,7 @@ tab_width = 4 # New line preferences end_of_line = lf insert_final_newline = false -trim_trailing_whitespace = true \ No newline at end of file +trim_trailing_whitespace = true + +[*.cs] +csharp_space_after_cast = true diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index d477bb1396..ea0559770e 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.21.1 + 3.21.2 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/main/LICENSE diff --git a/csharp/README.md b/csharp/README.md index 9aab782da1..df4849956d 100644 --- a/csharp/README.md +++ b/csharp/README.md @@ -23,6 +23,7 @@ The runtime library is built as a portable class library, supporting: - Windows Phone Silverlight 8 - Windows Phone 8.1 - .NET Core +- .NET 5 You should be able to use Protocol Buffers in Visual Studio 2012 and all later versions. This includes all code generated by `protoc`, @@ -31,15 +32,15 @@ which only uses features from C# 3 and earlier. Building ======== -Open the `src/Google.Protobuf.sln` solution in Visual Studio 2017 or +Open the `src/Google.Protobuf.sln` solution in Visual Studio 2022 or later. Although *users* of this project are only expected to have Visual Studio 2012 or later, *developers* of the library are required to -have Visual Studio 2017 or later, as the library uses C# 6 features -in its implementation, as well as the new Visual Studio 2017 csproj -format. These features have no impact when using the compiled code - -they're only relevant when building the `Google.Protobuf` assembly. +have Visual Studio 2022 or later, as the library uses C# 10 features +in its implementation and runs tests under .NET 6. These features +have no impact when using the compiled code - they're only relevant +when building the `Google.Protobuf` assembly. In order to run and debug the AddressBook example in the IDE, you must install the optional component, ".Net Core 1.0 - 1.1 development tools diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj index 0ecdf37abb..a2d501a81a 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj @@ -6,6 +6,7 @@ ../../keys/Google.Protobuf.snk true False + 8.0 diff --git a/csharp/src/AddressBook/AddPerson.cs b/csharp/src/AddressBook/AddPerson.cs index 889d1d060c..eb0ecb3f1a 100644 --- a/csharp/src/AddressBook/AddPerson.cs +++ b/csharp/src/AddressBook/AddPerson.cs @@ -107,10 +107,8 @@ namespace Google.Protobuf.Examples.AddressBook if (File.Exists(args[0])) { - using (Stream file = File.OpenRead(args[0])) - { - addressBook = AddressBook.Parser.ParseFrom(file); - } + using Stream file = File.OpenRead(args[0]); + addressBook = AddressBook.Parser.ParseFrom(file); } else { diff --git a/csharp/src/Directory.Build.props b/csharp/src/Directory.Build.props new file mode 100644 index 0000000000..dd6946202f --- /dev/null +++ b/csharp/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + 10.0 + + + diff --git a/csharp/src/Google.Protobuf.Benchmarks/BenchmarkDatasetConfig.cs b/csharp/src/Google.Protobuf.Benchmarks/BenchmarkDatasetConfig.cs index c0754190b6..b1483778c9 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/BenchmarkDatasetConfig.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/BenchmarkDatasetConfig.cs @@ -72,16 +72,14 @@ namespace Google.Protobuf.Benchmarks private static byte[] LoadData(string resource) { - using (var stream = typeof(GoogleMessageBenchmark).Assembly.GetManifestResourceStream($"Google.Protobuf.Benchmarks.{resource}")) + using var stream = typeof(GoogleMessageBenchmark).Assembly.GetManifestResourceStream($"Google.Protobuf.Benchmarks.{resource}"); + if (stream == null) { - if (stream == null) - { - throw new ArgumentException($"Unable to load embedded resource {resource}"); - } - var copy = new MemoryStream(); - stream.CopyTo(copy); - return copy.ToArray(); + throw new ArgumentException($"Unable to load embedded resource {resource}"); } + var copy = new MemoryStream(); + stream.CopyTo(copy); + return copy.ToArray(); } public override string ToString() => Name; diff --git a/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs index 8e6710b708..b0852345e4 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs @@ -49,10 +49,10 @@ namespace Google.Protobuf.Benchmarks { const int MaxMessages = 100; - SubTest manyWrapperFieldsTest = new SubTest(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages); - SubTest manyPrimitiveFieldsTest = new SubTest(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages); - SubTest repeatedFieldTest = new SubTest(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages); - SubTest emptyMessageTest = new SubTest(new Empty(), Empty.Parser, () => new Empty(), MaxMessages); + private readonly SubTest manyWrapperFieldsTest = new(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages); + private readonly SubTest manyPrimitiveFieldsTest = new(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages); + private readonly SubTest repeatedFieldTest = new(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages); + private readonly SubTest emptyMessageTest = new(new Empty(), Empty.Parser, () => new Empty(), MaxMessages); public IEnumerable MessageCountValues => new[] { 10, 100 }; @@ -204,8 +204,8 @@ namespace Google.Protobuf.Benchmarks private readonly byte[] data; private readonly byte[] multipleMessagesData; - private ReadOnlySequence dataSequence; - private ReadOnlySequence multipleMessagesDataSequence; + private readonly ReadOnlySequence dataSequence; + private readonly ReadOnlySequence multipleMessagesDataSequence; public SubTest(IMessage message, MessageParser parser, Func factory, int maxMessageCount) { diff --git a/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs index 6df1c872c3..64624a460e 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs @@ -418,7 +418,7 @@ namespace Google.Protobuf.Benchmarks private static byte[] CreateBufferWithRandomData(Random random, int valueCount, int encodedSize, int paddingValueCount) { int bufferSize = (valueCount + paddingValueCount) * encodedSize; - byte[] buffer = new byte[bufferSize]; + var buffer = new byte[bufferSize]; random.NextBytes(buffer); return buffer; } diff --git a/csharp/src/Google.Protobuf.Benchmarks/Program.cs b/csharp/src/Google.Protobuf.Benchmarks/Program.cs index 037752f6b7..d597ff77ad 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/Program.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/Program.cs @@ -44,6 +44,4 @@ namespace Google.Protobuf.Benchmarks BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } } - - } diff --git a/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs index 66b6b4a028..bd0f0aca6a 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs +++ b/csharp/src/Google.Protobuf.Benchmarks/WriteRawPrimitivesBenchmark.cs @@ -32,10 +32,7 @@ using BenchmarkDotNet.Attributes; using System; -using System.Buffers.Binary; using System.Collections.Generic; -using System.IO; -using System.Buffers; using System.Text; namespace Google.Protobuf.Benchmarks diff --git a/csharp/src/Google.Protobuf.Conformance/Program.cs b/csharp/src/Google.Protobuf.Conformance/Program.cs index d721ecfcb7..1c2e9ae885 100644 --- a/csharp/src/Google.Protobuf.Conformance/Program.cs +++ b/csharp/src/Google.Protobuf.Conformance/Program.cs @@ -43,7 +43,7 @@ namespace Google.Protobuf.Conformance /// class Program { - private static void Main(string[] args) + private static void Main() { // This way we get the binary streams instead of readers/writers. var input = new BinaryReader(Console.OpenStandardInput()); @@ -100,32 +100,22 @@ namespace Google.Protobuf.Conformance return new ConformanceResponse { Skipped = "CSharp doesn't support skipping unknown fields in json parsing." }; } var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry)); - switch (request.MessageType) + message = request.MessageType switch { - case "protobuf_test_messages.proto3.TestAllTypesProto3": - message = parser.Parse(request.JsonPayload); - break; - case "protobuf_test_messages.proto2.TestAllTypesProto2": - message = parser.Parse(request.JsonPayload); - break; - default: - throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"); - } + "protobuf_test_messages.proto3.TestAllTypesProto3" => parser.Parse(request.JsonPayload), + "protobuf_test_messages.proto2.TestAllTypesProto2" => parser.Parse(request.JsonPayload), + _ => throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"), + }; break; case ConformanceRequest.PayloadOneofCase.ProtobufPayload: - switch (request.MessageType) + message = request.MessageType switch { - case "protobuf_test_messages.proto3.TestAllTypesProto3": - message = ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser.ParseFrom(request.ProtobufPayload); - break; - case "protobuf_test_messages.proto2.TestAllTypesProto2": - message = ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser - .WithExtensionRegistry(proto2ExtensionRegistry) - .ParseFrom(request.ProtobufPayload); - break; - default: - throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"); - } + "protobuf_test_messages.proto3.TestAllTypesProto3" => ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser.ParseFrom(request.ProtobufPayload), + "protobuf_test_messages.proto2.TestAllTypesProto2" => ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser + .WithExtensionRegistry(proto2ExtensionRegistry) + .ParseFrom(request.ProtobufPayload), + _ => throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"), + }; break; case ConformanceRequest.PayloadOneofCase.TextPayload: return new ConformanceResponse { Skipped = "CSharp doesn't support text format" }; diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj index 8d9d64b37e..3d0ba71752 100644 --- a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj +++ b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj @@ -7,7 +7,7 @@ --> net462;netstandard1.1;netstandard2.0 - 3.0 + 10.0 ../../keys/Google.Protobuf.snk true False diff --git a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs index 3810565faa..b7572871d5 100644 --- a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs +++ b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs @@ -70,7 +70,7 @@ namespace Google.Protobuf Assert.IsFalse(b1 != b1); Assert.IsFalse(b1 != b2); Assert.IsTrue(ByteString.Empty == ByteString.Empty); -#pragma warning disable 1718 +#pragma warning restore 1718 Assert.IsTrue(b1 != b3); Assert.IsTrue(b1 != b4); Assert.IsTrue(b1 != null); @@ -276,12 +276,9 @@ namespace Google.Protobuf Span s = stackalloc byte[data.Length]; data.CopyTo(s); - using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) - { - ByteString bs = ByteString.AttachBytes(manager.Memory); - - Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8)); - } + using var manager = new UnmanagedMemoryManager(s); + ByteString bs = ByteString.AttachBytes(manager.Memory); + Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8)); } [Test] @@ -315,12 +312,9 @@ namespace Google.Protobuf Span s = stackalloc byte[data.Length]; data.CopyTo(s); - using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) - { - ByteString bs = ByteString.AttachBytes(manager.Memory); - - Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); - } + using var manager = new UnmanagedMemoryManager(s); + ByteString bs = ByteString.AttachBytes(manager.Memory); + Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); } [Test] diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs index b84a1b7ce6..a48f3b1048 100644 --- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs @@ -563,8 +563,8 @@ namespace Google.Protobuf int groupFieldNumber = Proto2.TestAllTypes.OptionalGroupFieldNumber; // write Proto2.TestAllTypes with "optional_group" set, but use wrong EndGroup closing tag - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); + var ms = new MemoryStream(); + var output = new CodedOutputStream(ms); output.WriteTag(WireFormat.MakeTag(groupFieldNumber, WireFormat.WireType.StartGroup)); output.WriteGroup(new Proto2.TestAllTypes.Types.OptionalGroup { A = 12345 }); // end group with different field number @@ -578,8 +578,8 @@ namespace Google.Protobuf [Test] public void ReadGroup_UnknownFields_WrongEndGroupTag() { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); + var ms = new MemoryStream(); + var output = new CodedOutputStream(ms); output.WriteTag(WireFormat.MakeTag(14, WireFormat.WireType.StartGroup)); // end group with different field number output.WriteTag(WireFormat.MakeTag(15, WireFormat.WireType.EndGroup)); @@ -654,7 +654,7 @@ namespace Google.Protobuf output.Flush(); ms.Position = 0; - CodedInputStream input = new CodedInputStream(ms); + var input = new CodedInputStream(ms); Assert.AreEqual(tag, input.ReadTag()); Assert.Throws(() => input.ReadBytes()); @@ -694,26 +694,24 @@ namespace Google.Protobuf [Test] public void TestSlowPathAvoidance() { - using (var ms = new MemoryStream()) - { - CodedOutputStream output = new CodedOutputStream(ms); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.Flush(); + using var ms = new MemoryStream(); + var output = new CodedOutputStream(ms); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.Flush(); - ms.Position = 0; - CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); + ms.Position = 0; + CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); - uint tag = input.ReadTag(); - Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); + uint tag = input.ReadTag(); + Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); - tag = input.ReadTag(); - Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); - } + tag = input.ReadTag(); + Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); } [Test] @@ -927,13 +925,11 @@ namespace Google.Protobuf { byte[] serializedMessage = GenerateBigSerializedMessage(); // How many of these big messages do we need to take us near our 2GB limit? - int count = Int32.MaxValue / serializedMessage.Length; + int count = int.MaxValue / serializedMessage.Length; // Now make a MemoryStream that will fake a near-2GB stream of messages by returning // our big serialized message 'count' times. - using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) - { - Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream)); - } + using var stream = new RepeatingMemoryStream(serializedMessage, count); + Assert.DoesNotThrow(() => TestAllTypes.Parser.ParseFrom(stream)); } [Test] @@ -941,17 +937,15 @@ namespace Google.Protobuf { byte[] serializedMessage = GenerateBigSerializedMessage(); // How many of these big messages do we need to take us near our 2GB limit? - int count = Int32.MaxValue / serializedMessage.Length; + int count = int.MaxValue / serializedMessage.Length; // Now add one to take us over the 2GB limit count++; // Now make a MemoryStream that will fake a near-2GB stream of messages by returning // our big serialized message 'count' times. - using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) - { - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream), - "Protocol message was too large. May be malicious. " + - "Use CodedInputStream.SetSizeLimit() to increase the size limit."); - } + using var stream = new RepeatingMemoryStream(serializedMessage, count); + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream), + "Protocol message was too large. May be malicious. " + + "Use CodedInputStream.SetSizeLimit() to increase the size limit."); } /// A serialized big message diff --git a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs index 13f83a2c35..31090c44bc 100644 --- a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs @@ -94,14 +94,12 @@ namespace Google.Protobuf if ((value >> 32) == 0) { MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = - new CodedOutputStream(rawOutput, bufferSize); + CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize); output.WriteRawVarint32((uint) value); output.Flush(); Assert.AreEqual(data, rawOutput.ToArray()); - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; + var bufferWriter = new TestArrayBufferWriter { MaxGrowBy = bufferSize }; WriteContext.Initialize(bufferWriter, out WriteContext ctx); ctx.WriteUInt32((uint) value); ctx.Flush(); @@ -115,8 +113,7 @@ namespace Google.Protobuf output.Flush(); Assert.AreEqual(data, rawOutput.ToArray()); - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; + var bufferWriter = new TestArrayBufferWriter { MaxGrowBy = bufferSize }; WriteContext.Initialize(bufferWriter, out WriteContext ctx); ctx.WriteUInt64(value); ctx.Flush(); @@ -190,8 +187,7 @@ namespace Google.Protobuf output.Flush(); Assert.AreEqual(data, rawOutput.ToArray()); - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; + var bufferWriter = new TestArrayBufferWriter { MaxGrowBy = bufferSize }; WriteContext.Initialize(bufferWriter, out WriteContext ctx); ctx.WriteFixed32(value); ctx.Flush(); @@ -228,8 +224,7 @@ namespace Google.Protobuf output.Flush(); Assert.AreEqual(data, rawOutput.ToArray()); - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = blockSize; + var bufferWriter = new TestArrayBufferWriter { MaxGrowBy = blockSize }; WriteContext.Initialize(bufferWriter, out WriteContext ctx); ctx.WriteFixed64(value); ctx.Flush(); @@ -270,8 +265,7 @@ namespace Google.Protobuf output.Flush(); Assert.AreEqual(rawBytes, rawOutput.ToArray()); - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = blockSize; + var bufferWriter = new TestArrayBufferWriter { MaxGrowBy = blockSize }; message.WriteTo(bufferWriter); Assert.AreEqual(rawBytes, bufferWriter.WrittenSpan.ToArray()); } @@ -383,7 +377,9 @@ namespace Google.Protobuf { byte[] content = new byte[110]; for (int i = 0; i < content.Length; i++) + { content[i] = (byte)i; + } byte[] child = new byte[120]; { diff --git a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs index abd19a2d8e..401b70aba8 100644 --- a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs +++ b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs @@ -91,10 +91,12 @@ namespace Google.Protobuf.Collections [Test] public void AddPreservesInsertionOrder() { - var map = new MapField(); - map.Add("a", "v1"); - map.Add("b", "v2"); - map.Add("c", "v3"); + var map = new MapField + { + { "a", "v1" }, + { "b", "v2" }, + { "c", "v3" } + }; map.Remove("b"); map.Add("d", "v4"); CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys); @@ -104,13 +106,17 @@ namespace Google.Protobuf.Collections [Test] public void EqualityIsOrderInsensitive() { - var map1 = new MapField(); - map1.Add("a", "v1"); - map1.Add("b", "v2"); + var map1 = new MapField + { + { "a", "v1" }, + { "b", "v2" } + }; - var map2 = new MapField(); - map2.Add("b", "v2"); - map2.Add("a", "v1"); + var map2 = new MapField + { + { "b", "v2" }, + { "a", "v1" } + }; EqualityTester.AssertEquality(map1, map2); } @@ -118,13 +124,17 @@ namespace Google.Protobuf.Collections [Test] public void EqualityIsKeySensitive() { - var map1 = new MapField(); - map1.Add("first key", "v1"); - map1.Add("second key", "v2"); + var map1 = new MapField + { + { "first key", "v1" }, + { "second key", "v2" } + }; - var map2 = new MapField(); - map2.Add("third key", "v1"); - map2.Add("fourth key", "v2"); + var map2 = new MapField + { + { "third key", "v1" }, + { "fourth key", "v2" } + }; EqualityTester.AssertInequality(map1, map2); } @@ -143,13 +153,17 @@ namespace Google.Protobuf.Collections { // Note: Without some care, it's a little easier than one might // hope to see hash collisions, but only in some environments... - var map1 = new MapField(); - map1.Add("a", "first value"); - map1.Add("b", "second value"); + var map1 = new MapField + { + { "a", "first value" }, + { "b", "second value" } + }; - var map2 = new MapField(); - map2.Add("a", "third value"); - map2.Add("b", "fourth value"); + var map2 = new MapField + { + { "a", "third value" }, + { "b", "fourth value" } + }; EqualityTester.AssertInequality(map1, map2); } @@ -183,8 +197,7 @@ namespace Google.Protobuf.Collections [Test] public void Add_KeyAlreadyExists() { - var map = new MapField(); - map.Add("foo", "bar"); + var map = new MapField { { "foo", "bar" } }; Assert.Throws(() => map.Add("foo", "baz")); } @@ -211,8 +224,7 @@ namespace Google.Protobuf.Collections [Test] public void Remove_Key() { - var map = new MapField(); - map.Add("foo", "bar"); + var map = new MapField { { "foo", "bar" } }; Assert.AreEqual(1, map.Count); Assert.IsFalse(map.Remove("missing")); Assert.AreEqual(1, map.Count); @@ -224,8 +236,7 @@ namespace Google.Protobuf.Collections [Test] public void Remove_Pair() { - var map = new MapField(); - map.Add("foo", "bar"); + var map = new MapField { { "foo", "bar" } }; ICollection> collection = map; Assert.AreEqual(1, map.Count); Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar"))); @@ -240,8 +251,7 @@ namespace Google.Protobuf.Collections [Test] public void CopyTo_Pair() { - var map = new MapField(); - map.Add("foo", "bar"); + var map = new MapField { { "foo", "bar" } }; ICollection> collection = map; KeyValuePair[] array = new KeyValuePair[3]; collection.CopyTo(array, 1); @@ -270,8 +280,7 @@ namespace Google.Protobuf.Collections [Test] public void Indexer_Set() { - var map = new MapField(); - map["x"] = "y"; + var map = new MapField { ["x"] = "y" }; Assert.AreEqual("y", map["x"]); map["x"] = "z"; // This won't throw, unlike Add. Assert.AreEqual("z", map["x"]); @@ -357,12 +366,10 @@ namespace Google.Protobuf.Collections IDictionary dictionary = map; var array = new DictionaryEntry[3]; dictionary.CopyTo(array, 1); - CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) }, - array); + CollectionAssert.AreEqual(new[] { default, new DictionaryEntry("x", "y"), default }, array); var objectArray = new object[3]; dictionary.CopyTo(objectArray, 1); - CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null }, - objectArray); + CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null }, objectArray); } [Test] @@ -580,8 +587,7 @@ namespace Google.Protobuf.Collections }; Assert.AreEqual("x", map[SampleNaNs.Regular]); Assert.AreEqual("y", map[SampleNaNs.SignallingFlipped]); - string ignored; - Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out ignored)); + Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out _)); } [Test] diff --git a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs index ff8f5cc6b1..766b4cb5db 100644 --- a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs +++ b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs @@ -33,7 +33,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; @@ -59,8 +58,7 @@ namespace Google.Protobuf.Collections [Test] public void Add_SingleItem() { - var list = new RepeatedField(); - list.Add("foo"); + var list = new RepeatedField { "foo" }; Assert.AreEqual(1, list.Count); Assert.AreEqual("foo", list[0]); } @@ -68,8 +66,7 @@ namespace Google.Protobuf.Collections [Test] public void Add_Sequence() { - var list = new RepeatedField(); - list.Add(new[] { "foo", "bar" }); + var list = new RepeatedField { new[] { "foo", "bar" } }; Assert.AreEqual(2, list.Count); Assert.AreEqual("foo", list[0]); Assert.AreEqual("bar", list[1]); @@ -293,15 +290,13 @@ namespace Google.Protobuf.Collections public void Enumerator() { var list = new RepeatedField { "first", "second" }; - using (var enumerator = list.GetEnumerator()) - { - Assert.IsTrue(enumerator.MoveNext()); - Assert.AreEqual("first", enumerator.Current); - Assert.IsTrue(enumerator.MoveNext()); - Assert.AreEqual("second", enumerator.Current); - Assert.IsFalse(enumerator.MoveNext()); - Assert.IsFalse(enumerator.MoveNext()); - } + using var enumerator = list.GetEnumerator(); + Assert.IsTrue(enumerator.MoveNext()); + Assert.AreEqual("first", enumerator.Current); + Assert.IsTrue(enumerator.MoveNext()); + Assert.AreEqual("second", enumerator.Current); + Assert.IsFalse(enumerator.MoveNext()); + Assert.IsFalse(enumerator.MoveNext()); } [Test] diff --git a/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs index 1d69fcb2be..040a2f1121 100644 --- a/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs @@ -29,6 +29,7 @@ // (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 + using NUnit.Framework; using System; using System.Collections.Generic; diff --git a/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs index fd041e0171..f291b1eeee 100644 --- a/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs +++ b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs @@ -50,6 +50,5 @@ namespace Google.Protobuf { AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32")); } - } } diff --git a/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs b/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs index b2c24dd201..23237d40b1 100644 --- a/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs +++ b/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs @@ -1,3 +1,35 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 + using System; using System.Collections; using Google.Protobuf.TestProtos.Proto2; @@ -72,7 +104,7 @@ namespace Google.Protobuf message.SetExtension(OptionalStringExtension, "abcd"); var input = new CodedInputStream(message.ToByteArray()); - input.ExtensionRegistry = new ExtensionRegistry() { OptionalStringExtension }; + input.ExtensionRegistry = new ExtensionRegistry { OptionalStringExtension }; input.ReadTag(); // TryMergeFieldFrom expects that a tag was just read and will inspect the LastTag value ExtensionSet extensionSet = null; diff --git a/csharp/src/Google.Protobuf.Test/FieldMaskTreeTest.cs b/csharp/src/Google.Protobuf.Test/FieldMaskTreeTest.cs index c7fbd1373f..4c206e6589 100644 --- a/csharp/src/Google.Protobuf.Test/FieldMaskTreeTest.cs +++ b/csharp/src/Google.Protobuf.Test/FieldMaskTreeTest.cs @@ -30,7 +30,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System.Collections.Generic; using Google.Protobuf.Collections; using Google.Protobuf.TestProtos; using NUnit.Framework; diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs index fa5f927738..9d03656b1b 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs @@ -1,3 +1,35 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 + using Google.Protobuf.TestProtos.Proto2; using Proto2 = Google.Protobuf.TestProtos.Proto2; using NUnit.Framework; @@ -387,11 +419,9 @@ namespace Google.Protobuf var message = new TestAllExtensions(); message.SetExtension(UnittestExtensions.OptionalBoolExtension, true); byte[] bytes = message.ToByteArray(); - using (CodedInputStream input = new CodedInputStream(bytes)) - { - var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input); - Assert.AreEqual(message, parsed); - } + using CodedInputStream input = new CodedInputStream(bytes); + var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input); + Assert.AreEqual(message, parsed); } } } diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs index 41a0b914cb..8387291956 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs @@ -33,10 +33,7 @@ using System; using System.IO; using Google.Protobuf.TestProtos; -using Proto2 = Google.Protobuf.TestProtos.Proto2; using NUnit.Framework; -using System.Collections; -using System.Collections.Generic; using System.Linq; using Google.Protobuf.WellKnownTypes; @@ -658,9 +655,11 @@ namespace Google.Protobuf [Test] public void OneofSerialization_NonDefaultValue() { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 10; + var message = new TestAllTypes + { + OneofString = "this would take a bit of space", + OneofUint32 = 10 + }; var bytes = message.ToByteArray(); Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! @@ -675,9 +674,11 @@ namespace Google.Protobuf [Test] public void OneofSerialization_DefaultValue() { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized + var message = new TestAllTypes + { + OneofString = "this would take a bit of space", + OneofUint32 = 0 // This is the default value for UInt32; normally wouldn't be serialized + }; var bytes = message.ToByteArray(); Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized @@ -746,7 +747,6 @@ namespace Google.Protobuf [Test] public void ExtraEndGroupThrows() { - var message = SampleMessages.CreateFullTestAllTypes(); var stream = new MemoryStream(); var output = new CodedOutputStream(stream); diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 3a77990cf1..714c78cbeb 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -168,8 +168,7 @@ namespace Google.Protobuf [Test] public void WithFormatDefaultValues_DoesNotAffectProto3OptionalFields() { - var message = new TestProto3Optional(); - message.OptionalInt32 = 0; + var message = new TestProto3Optional { OptionalInt32 = 0 }; var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); var json = formatter.Format(message); // The non-optional proto3 fields are formatted, as is the optional-but-specified field. @@ -179,8 +178,7 @@ namespace Google.Protobuf [Test] public void WithFormatDefaultValues_DoesNotAffectProto2Fields() { - var message = new TestProtos.Proto2.ForeignMessage(); - message.C = 0; + var message = new TestProtos.Proto2.ForeignMessage { C = 0 }; var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); var json = formatter.Format(message); // The specified field is formatted, but the non-specified field (d) is not. diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs index eb8996e620..b5d6c0bbe3 100644 --- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs @@ -641,7 +641,7 @@ namespace Google.Protobuf [TestCase("9999-12-31T23:59:59.999999999Z", null)] public void Timestamp_Valid(string jsonValue, string expectedFormatted) { - expectedFormatted = expectedFormatted ?? jsonValue; + expectedFormatted ??= jsonValue; string json = WrapInQuotes(jsonValue); var parsed = Timestamp.Parser.ParseJson(json); Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString()); @@ -758,7 +758,7 @@ namespace Google.Protobuf [TestCase("-315576000000s", null)] public void Duration_Valid(string jsonValue, string expectedFormatted) { - expectedFormatted = expectedFormatted ?? jsonValue; + expectedFormatted ??= jsonValue; string json = WrapInQuotes(jsonValue); var parsed = Duration.Parser.ParseJson(json); Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString()); @@ -1066,25 +1066,26 @@ namespace Google.Protobuf ""mapStringNestedMessage"": null }"; - TestAllTypesProto3 message = new TestAllTypesProto3(); - - message.OptionalInt32 = 1; - message.OptionalInt64 = 1; - message.OptionalUint32 = 1; - message.OptionalUint64 = 1; - message.OptionalSint32 = 1; - message.OptionalSint64 = 1; - message.OptionalFixed32 = 1; - message.OptionalFixed64 = 1; - message.OptionalSfixed32 = 1; - message.OptionalSfixed64 = 1; - message.OptionalFloat = 1; - message.OptionalDouble = 1; - message.OptionalBool = true; - message.OptionalString = "1"; - message.OptionalBytes = ByteString.CopyFrom(new byte[] { 1 }); - message.OptionalNestedEnum = TestAllTypesProto3.Types.NestedEnum.Bar; - message.OptionalNestedMessage = new TestAllTypesProto3.Types.NestedMessage(); + var message = new TestAllTypesProto3 + { + OptionalInt32 = 1, + OptionalInt64 = 1, + OptionalUint32 = 1, + OptionalUint64 = 1, + OptionalSint32 = 1, + OptionalSint64 = 1, + OptionalFixed32 = 1, + OptionalFixed64 = 1, + OptionalSfixed32 = 1, + OptionalSfixed64 = 1, + OptionalFloat = 1, + OptionalDouble = 1, + OptionalBool = true, + OptionalString = "1", + OptionalBytes = ByteString.CopyFrom(new byte[] { 1 }), + OptionalNestedEnum = TestAllTypesProto3.Types.NestedEnum.Bar, + OptionalNestedMessage = new TestAllTypesProto3.Types.NestedMessage() + }; message.RepeatedInt32.Add(1); message.RepeatedInt64.Add(1); message.RepeatedUint32.Add(1); diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs index df43effd4f..06521dd2dc 100644 --- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs @@ -29,6 +29,7 @@ // (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 + using NUnit.Framework; using System; using System.IO; @@ -126,7 +127,7 @@ namespace Google.Protobuf tokenizer.PushBack(token); Assert.AreEqual(0, tokenizer.ObjectDepth); // Read the same token again, and get back to depth 1 - token = tokenizer.Next(); + _ = tokenizer.Next(); Assert.AreEqual(1, tokenizer.ObjectDepth); // Now the same in reverse, with EndObject diff --git a/csharp/src/Google.Protobuf.Test/LegacyGeneratedCodeTest.cs b/csharp/src/Google.Protobuf.Test/LegacyGeneratedCodeTest.cs index 22adcaa95d..01fca3e494 100644 --- a/csharp/src/Google.Protobuf.Test/LegacyGeneratedCodeTest.cs +++ b/csharp/src/Google.Protobuf.Test/LegacyGeneratedCodeTest.cs @@ -29,14 +29,12 @@ // (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 -using Google.Protobuf; -using Google.Protobuf.Reflection; + using System.Buffers; -using pb = global::Google.Protobuf; -using pbr = global::Google.Protobuf.Reflection; +using pb = Google.Protobuf; +using pbr = Google.Protobuf.Reflection; using NUnit.Framework; using System.IO; -using System; using Google.Protobuf.Buffers; namespace Google.Protobuf diff --git a/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs b/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs index 05f1e36f96..f2eb76280f 100644 --- a/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs +++ b/csharp/src/Google.Protobuf.Test/MessageParsingHelpers.cs @@ -136,8 +136,7 @@ namespace Google.Protobuf // test for different IBufferWriter.GetSpan() segment sizes for (int blockSize = 1; blockSize < 256; blockSize *= 2) { - var segmentedBufferWriter = new TestArrayBufferWriter(); - segmentedBufferWriter.MaxGrowBy = blockSize; + var segmentedBufferWriter = new TestArrayBufferWriter { MaxGrowBy = blockSize }; message.WriteTo(segmentedBufferWriter); Assert.AreEqual(bytes, segmentedBufferWriter.WrittenSpan.ToArray()); } diff --git a/csharp/src/Google.Protobuf.Test/Proto3OptionalTest.cs b/csharp/src/Google.Protobuf.Test/Proto3OptionalTest.cs index 46a8c57a78..b5b0b72df0 100644 --- a/csharp/src/Google.Protobuf.Test/Proto3OptionalTest.cs +++ b/csharp/src/Google.Protobuf.Test/Proto3OptionalTest.cs @@ -38,7 +38,7 @@ using UnitTest.Issues.TestProtos; namespace Google.Protobuf.Test { - class Proto3OptionalTest + public class Proto3OptionalTest { [Test] public void OptionalInt32FieldLifecycle() diff --git a/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs b/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs index f0248ac3c3..d4dfd187fb 100644 --- a/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs +++ b/csharp/src/Google.Protobuf.Test/ReadOnlySequenceFactory.cs @@ -33,9 +33,6 @@ using System; using System.Buffers; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Google.Protobuf { @@ -50,7 +47,7 @@ namespace Google.Protobuf if (addEmptySegmentDelimiters) { - segments.Add(new byte[0]); + segments.Add(Array.Empty()); } var currentIndex = 0; @@ -65,7 +62,7 @@ namespace Google.Protobuf if (addEmptySegmentDelimiters) { - segments.Add(new byte[0]); + segments.Add(Array.Empty()); } } diff --git a/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs b/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs index 9dca501523..f3651df397 100644 --- a/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs +++ b/csharp/src/Google.Protobuf.Test/RefStructCompatibilityTest.cs @@ -77,43 +77,42 @@ namespace Google.Protobuf /// /// private void RunOldCsharpCompilerAndCheckSuccess(string args, string workingDirectory) - { - using (var process = new Process()) - { - // Get the path to the old C# 5 compiler from .NET framework. This approach is not 100% reliable, but works on most machines. - // Alternative way of getting the framework path is System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() - // but it only works with the net45 target. - var oldCsharpCompilerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v4.0.30319", "csc.exe"); - process.StartInfo.FileName = oldCsharpCompilerPath; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardError = true; - process.StartInfo.UseShellExecute = false; - process.StartInfo.Arguments = args; - process.StartInfo.WorkingDirectory = workingDirectory; + { + using var process = new Process(); + + // Get the path to the old C# 5 compiler from .NET framework. This approach is not 100% reliable, but works on most machines. + // Alternative way of getting the framework path is System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() + // but it only works with the net45 target. + var oldCsharpCompilerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v4.0.30319", "csc.exe"); + process.StartInfo.FileName = oldCsharpCompilerPath; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.Arguments = args; + process.StartInfo.WorkingDirectory = workingDirectory; - process.OutputDataReceived += (sender, e) => + process.OutputDataReceived += (sender, e) => + { + if (e.Data != null) { - if (e.Data != null) - { - Console.WriteLine(e.Data); - } - }; - process.ErrorDataReceived += (sender, e) => + Console.WriteLine(e.Data); + } + }; + process.ErrorDataReceived += (sender, e) => + { + if (e.Data != null) { - if (e.Data != null) - { - Console.WriteLine(e.Data); - } - }; + Console.WriteLine(e.Data); + } + }; - process.Start(); + process.Start(); - process.BeginErrorReadLine(); - process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); - process.WaitForExit(); - Assert.AreEqual(0, process.ExitCode); - } + process.WaitForExit(); + Assert.AreEqual(0, process.ExitCode); } } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs index 68b9bd3507..589c35ca6c 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs @@ -31,13 +31,10 @@ #endregion using Google.Protobuf.Reflection; -using Google.Protobuf.WellKnownTypes; using NUnit.Framework; using System; -using System.IO; using System.Linq; using UnitTest.Issues.TestProtos; -using static Google.Protobuf.WireFormat; using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types; using static UnitTest.Issues.TestProtos.UnittestCustomOptionsProto3Extensions; using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types; @@ -65,7 +62,7 @@ namespace Google.Protobuf.Test.Reflection } else { - v = default(E); + v = default; return false; } }; diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs index 65c8b8267f..03722d45b3 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs @@ -35,7 +35,6 @@ using NUnit.Framework; using ProtobufUnittest; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using UnitTest.Issues.TestProtos; diff --git a/csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs b/csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs index f3e5af2056..eeb9f899f0 100644 --- a/csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs +++ b/csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs @@ -30,10 +30,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; using System.IO; using Google.Protobuf.TestProtos; -using Proto2 = Google.Protobuf.TestProtos.Proto2; using NUnit.Framework; namespace Google.Protobuf @@ -127,8 +125,7 @@ namespace Google.Protobuf public void TestClone(IMessage message) { var emptyMessage = new TestEmptyMessage(); - var otherEmptyMessage = new TestEmptyMessage(); - otherEmptyMessage = emptyMessage.Clone(); + TestEmptyMessage otherEmptyMessage = emptyMessage.Clone(); Assert.AreEqual(emptyMessage.CalculateSize(), otherEmptyMessage.CalculateSize()); Assert.AreEqual(emptyMessage.ToByteArray(), otherEmptyMessage.ToByteArray()); @@ -169,13 +166,13 @@ namespace Google.Protobuf byte[] data = message.ToByteArray(); int fullSize = message.CalculateSize(); - Action assertEmpty = msg => + void AssertEmpty(IMessage msg) { Assert.AreEqual(0, msg.CalculateSize()); Assert.AreEqual(goldenEmptyMessage, msg); - }; + } - Action assertFull = msg => Assert.AreEqual(fullSize, msg.CalculateSize()); + void AssertFull(IMessage msg) => Assert.AreEqual(fullSize, msg.CalculateSize()); // Test the behavior of the parsers with and without discarding, both generic and non-generic. MessageParser retainingParser1 = TestEmptyMessage.Parser; @@ -184,28 +181,28 @@ namespace Google.Protobuf MessageParser discardingParser2 = retainingParser2.WithDiscardUnknownFields(true); // Test parse from byte[] - MessageParsingHelpers.AssertReadingMessage(retainingParser1, data, m => assertFull(m)); - MessageParsingHelpers.AssertReadingMessage(retainingParser2, data, m => assertFull(m)); - MessageParsingHelpers.AssertReadingMessage(discardingParser1, data, m => assertEmpty(m)); - MessageParsingHelpers.AssertReadingMessage(discardingParser2, data, m => assertEmpty(m)); + MessageParsingHelpers.AssertReadingMessage(retainingParser1, data, m => AssertFull(m)); + MessageParsingHelpers.AssertReadingMessage(retainingParser2, data, m => AssertFull(m)); + MessageParsingHelpers.AssertReadingMessage(discardingParser1, data, m => AssertEmpty(m)); + MessageParsingHelpers.AssertReadingMessage(discardingParser2, data, m => AssertEmpty(m)); // Test parse from byte[] with offset - assertFull(retainingParser1.ParseFrom(data, 0, data.Length)); - assertFull(retainingParser2.ParseFrom(data, 0, data.Length)); - assertEmpty(discardingParser1.ParseFrom(data, 0, data.Length)); - assertEmpty(discardingParser2.ParseFrom(data, 0, data.Length)); + AssertFull(retainingParser1.ParseFrom(data, 0, data.Length)); + AssertFull(retainingParser2.ParseFrom(data, 0, data.Length)); + AssertEmpty(discardingParser1.ParseFrom(data, 0, data.Length)); + AssertEmpty(discardingParser2.ParseFrom(data, 0, data.Length)); // Test parse from CodedInputStream - assertFull(retainingParser1.ParseFrom(new CodedInputStream(data))); - assertFull(retainingParser2.ParseFrom(new CodedInputStream(data))); - assertEmpty(discardingParser1.ParseFrom(new CodedInputStream(data))); - assertEmpty(discardingParser2.ParseFrom(new CodedInputStream(data))); + AssertFull(retainingParser1.ParseFrom(new CodedInputStream(data))); + AssertFull(retainingParser2.ParseFrom(new CodedInputStream(data))); + AssertEmpty(discardingParser1.ParseFrom(new CodedInputStream(data))); + AssertEmpty(discardingParser2.ParseFrom(new CodedInputStream(data))); // Test parse from Stream - assertFull(retainingParser1.ParseFrom(new MemoryStream(data))); - assertFull(retainingParser2.ParseFrom(new MemoryStream(data))); - assertEmpty(discardingParser1.ParseFrom(new MemoryStream(data))); - assertEmpty(discardingParser2.ParseFrom(new MemoryStream(data))); + AssertFull(retainingParser1.ParseFrom(new MemoryStream(data))); + AssertFull(retainingParser2.ParseFrom(new MemoryStream(data))); + AssertEmpty(discardingParser1.ParseFrom(new MemoryStream(data))); + AssertEmpty(discardingParser2.ParseFrom(new MemoryStream(data))); } [Test] diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs index 771f1f41ba..187e06a4e4 100644 --- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs +++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs @@ -126,7 +126,6 @@ namespace Google.Protobuf.WellKnownTypes [TestCase("foobar", "")] public void GetTypeName(string typeUrl, string expectedTypeName) { - var any = new Any { TypeUrl = typeUrl }; Assert.AreEqual(expectedTypeName, Any.GetTypeName(typeUrl)); } diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs index c615616360..b13b6111af 100644 --- a/csharp/src/Google.Protobuf/ByteString.cs +++ b/csharp/src/Google.Protobuf/ByteString.cs @@ -189,7 +189,7 @@ namespace Google.Protobuf /// The stream to copy into a ByteString. /// The cancellation token to use when reading from the stream, if any. /// A ByteString with content read from the given stream. - public static Task FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) + public static Task FromStreamAsync(Stream stream, CancellationToken cancellationToken = default) { ProtoPreconditions.CheckNotNull(stream, nameof(stream)); return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken); @@ -340,7 +340,7 @@ namespace Google.Protobuf { return true; } - if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) + if (lhs is null || rhs is null) { return false; } diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs index 96ae84c3fe..aea546aab8 100644 --- a/csharp/src/Google.Protobuf/CodedInputStream.cs +++ b/csharp/src/Google.Protobuf/CodedInputStream.cs @@ -32,10 +32,7 @@ using Google.Protobuf.Collections; using System; -using System.Collections.Generic; using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security; namespace Google.Protobuf @@ -649,21 +646,6 @@ namespace Google.Protobuf } } - /// - /// Called when buffer is empty to read more bytes from the - /// input. If is true, RefillBuffer() guarantees that - /// either there will be at least one byte in the buffer when it returns - /// or it will throw an exception. If is false, - /// RefillBuffer() returns false if no more bytes were available. - /// - /// - /// - private bool RefillBuffer(bool mustSucceed) - { - var span = new ReadOnlySpan(buffer); - return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed); - } - /// /// Reads a fixed size of bytes from the input. /// diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs index 5b8cca1d02..2a162c680c 100644 --- a/csharp/src/Google.Protobuf/CodedOutputStream.cs +++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs @@ -30,11 +30,9 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using Google.Protobuf.Collections; using System; using System.IO; using System.Security; -using System.Text; namespace Google.Protobuf { diff --git a/csharp/src/Google.Protobuf/Collections/Lists.cs b/csharp/src/Google.Protobuf/Collections/Lists.cs index 860795ceef..90077092f7 100644 --- a/csharp/src/Google.Protobuf/Collections/Lists.cs +++ b/csharp/src/Google.Protobuf/Collections/Lists.cs @@ -31,7 +31,6 @@ #endregion using System.Collections.Generic; -using System.Collections.ObjectModel; namespace Google.Protobuf.Collections { diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs index 0f02d59454..f0124ee12b 100644 --- a/csharp/src/Google.Protobuf/Collections/MapField.cs +++ b/csharp/src/Google.Protobuf/Collections/MapField.cs @@ -31,9 +31,7 @@ #endregion using Google.Protobuf.Compatibility; -using Google.Protobuf.Reflection; using System; -using System.Buffers; using System.Collections; using System.Collections.Generic; using System.IO; @@ -74,9 +72,8 @@ namespace Google.Protobuf.Collections private static readonly EqualityComparer KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) - private readonly Dictionary>> map = - new Dictionary>>(KeyEqualityComparer); - private readonly LinkedList> list = new LinkedList>(); + private readonly Dictionary>> map = new(KeyEqualityComparer); + private readonly LinkedList> list = new(); /// /// Creates a deep clone of this object. @@ -144,8 +141,7 @@ namespace Google.Protobuf.Collections public bool Remove(TKey key) { ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - LinkedListNode> node; - if (map.TryGetValue(key, out node)) + if (map.TryGetValue(key, out LinkedListNode> node)) { map.Remove(key); node.List.Remove(node); @@ -167,15 +163,14 @@ namespace Google.Protobuf.Collections /// true if the map contains an element with the specified key; otherwise, false. public bool TryGetValue(TKey key, out TValue value) { - LinkedListNode> node; - if (map.TryGetValue(key, out node)) + if (map.TryGetValue(key, out LinkedListNode> node)) { value = node.Value.Value; return true; } else { - value = default(TValue); + value = default; return false; } } @@ -192,8 +187,7 @@ namespace Google.Protobuf.Collections get { ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - TValue value; - if (TryGetValue(key, out value)) + if (TryGetValue(key, out TValue value)) { return value; } @@ -207,9 +201,8 @@ namespace Google.Protobuf.Collections { ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); } - LinkedListNode> node; var pair = new KeyValuePair(key, value); - if (map.TryGetValue(key, out node)) + if (map.TryGetValue(key, out LinkedListNode> node)) { node.Value = pair; } @@ -224,12 +217,12 @@ namespace Google.Protobuf.Collections /// /// Gets a collection containing the keys in the map. /// - public ICollection Keys { get { return new MapView(this, pair => pair.Key, ContainsKey); } } + public ICollection Keys => new MapView(this, pair => pair.Key, ContainsKey); /// /// Gets a collection containing the values in the map. /// - public ICollection Values { get { return new MapView(this, pair => pair.Value, ContainsValue); } } + public ICollection Values => new MapView(this, pair => pair.Value, ContainsValue); /// /// Adds the specified entries to the map. The keys and values are not automatically cloned. @@ -250,10 +243,7 @@ namespace Google.Protobuf.Collections /// /// An enumerator that can be used to iterate through the collection. /// - public IEnumerator> GetEnumerator() - { - return list.GetEnumerator(); - } + public IEnumerator> GetEnumerator() => list.GetEnumerator(); /// /// Returns an enumerator that iterates through a collection. @@ -261,19 +251,13 @@ namespace Google.Protobuf.Collections /// /// An object that can be used to iterate through the collection. /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Adds the specified item to the map. /// /// The item to add to the map. - void ICollection>.Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } + void ICollection>.Add(KeyValuePair item) => Add(item.Key, item.Value); /// /// Removes all items from the map. @@ -289,21 +273,16 @@ namespace Google.Protobuf.Collections /// /// The key/value pair to find. /// - bool ICollection>.Contains(KeyValuePair item) - { - TValue value; - return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value); - } + bool ICollection>.Contains(KeyValuePair item) => + TryGetValue(item.Key, out TValue value) && ValueEqualityComparer.Equals(item.Value, value); /// /// Copies the key/value pairs in this map to an array. /// /// The array to copy the entries into. /// The index of the array at which to start copying values. - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) => list.CopyTo(array, arrayIndex); - } /// /// Removes the specified key/value pair from the map. @@ -317,8 +296,7 @@ namespace Google.Protobuf.Collections { throw new ArgumentException("Key is null", nameof(item)); } - LinkedListNode> node; - if (map.TryGetValue(item.Key, out node) && + if (map.TryGetValue(item.Key, out LinkedListNode> node) && EqualityComparer.Default.Equals(item.Value, node.Value.Value)) { map.Remove(item.Key); @@ -334,12 +312,12 @@ namespace Google.Protobuf.Collections /// /// Gets the number of elements contained in the map. /// - public int Count { get { return list.Count; } } + public int Count => list.Count; /// /// Gets a value indicating whether the map is read-only. /// - public bool IsReadOnly { get { return false; } } + public bool IsReadOnly => false; /// /// Determines whether the specified , is equal to this instance. @@ -348,10 +326,7 @@ namespace Google.Protobuf.Collections /// /// true if the specified is equal to this instance; otherwise, false. /// - public override bool Equals(object other) - { - return Equals(other as MapField); - } + public override bool Equals(object other) => Equals(other as MapField); /// /// Returns a hash code for this instance. @@ -396,8 +371,7 @@ namespace Google.Protobuf.Collections var valueComparer = ValueEqualityComparer; foreach (var pair in this) { - TValue value; - if (!other.TryGetValue(pair.Key, out value)) + if (!other.TryGetValue(pair.Key, out TValue value)) { return false; } @@ -529,33 +503,20 @@ namespace Google.Protobuf.Collections } #region IDictionary explicit interface implementation - void IDictionary.Add(object key, object value) - { - Add((TKey)key, (TValue)value); - } - bool IDictionary.Contains(object key) - { - if (!(key is TKey)) - { - return false; - } - return ContainsKey((TKey)key); - } + void IDictionary.Add(object key, object value) => Add((TKey)key, (TValue)value); - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return new DictionaryEnumerator(GetEnumerator()); - } + bool IDictionary.Contains(object key) => key is TKey k && ContainsKey(k); + + IDictionaryEnumerator IDictionary.GetEnumerator() => new DictionaryEnumerator(GetEnumerator()); void IDictionary.Remove(object key) { ProtoPreconditions.CheckNotNull(key, nameof(key)); - if (!(key is TKey)) + if (key is TKey k) { - return; + Remove(k); } - Remove((TKey)key); } void ICollection.CopyTo(Array array, int index) @@ -565,28 +526,27 @@ namespace Google.Protobuf.Collections temp.CopyTo(array, index); } - bool IDictionary.IsFixedSize { get { return false; } } + bool IDictionary.IsFixedSize => false; - ICollection IDictionary.Keys { get { return (ICollection)Keys; } } + ICollection IDictionary.Keys => (ICollection)Keys; - ICollection IDictionary.Values { get { return (ICollection)Values; } } + ICollection IDictionary.Values => (ICollection)Values; - bool ICollection.IsSynchronized { get { return false; } } + bool ICollection.IsSynchronized => false; - object ICollection.SyncRoot { get { return this; } } + object ICollection.SyncRoot => this; object IDictionary.this[object key] { get { ProtoPreconditions.CheckNotNull(key, nameof(key)); - if (!(key is TKey)) + if (key is TKey k) { - return null; + TryGetValue(k, out TValue value); + return value; } - TValue value; - TryGetValue((TKey)key, out value); - return value; + return null; } set @@ -610,20 +570,14 @@ namespace Google.Protobuf.Collections this.enumerator = enumerator; } - public bool MoveNext() - { - return enumerator.MoveNext(); - } + public bool MoveNext() => enumerator.MoveNext(); - public void Reset() - { - enumerator.Reset(); - } + public void Reset() => enumerator.Reset(); - public object Current { get { return Entry; } } - public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } } - public object Key { get { return enumerator.Current.Key; } } - public object Value { get { return enumerator.Current.Value; } } + public object Current => Entry; + public DictionaryEntry Entry => new DictionaryEntry(Key, Value); + public object Key => enumerator.Current.Key; + public object Value => enumerator.Current.Value; } /// @@ -682,28 +636,19 @@ namespace Google.Protobuf.Collections this.containsCheck = containsCheck; } - public int Count { get { return parent.Count; } } + public int Count => parent.Count; - public bool IsReadOnly { get { return true; } } + public bool IsReadOnly => true; - public bool IsSynchronized { get { return false; } } + public bool IsSynchronized => false; - public object SyncRoot { get { return parent; } } + public object SyncRoot => parent; - public void Add(T item) - { - throw new NotSupportedException(); - } + public void Add(T item) => throw new NotSupportedException(); - public void Clear() - { - throw new NotSupportedException(); - } + public void Clear() => throw new NotSupportedException(); - public bool Contains(T item) - { - return containsCheck(item); - } + public bool Contains(T item) => containsCheck(item); public void CopyTo(T[] array, int arrayIndex) { @@ -726,15 +671,9 @@ namespace Google.Protobuf.Collections return parent.list.Select(projection).GetEnumerator(); } - public bool Remove(T item) - { - throw new NotSupportedException(); - } + public bool Remove(T item) => throw new NotSupportedException(); - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void CopyTo(Array array, int index) { diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs index cd6f5eb572..832e166943 100644 --- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs +++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs @@ -35,7 +35,6 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Security; -using System.Threading; namespace Google.Protobuf.Collections { @@ -74,8 +73,7 @@ namespace Google.Protobuf.Collections if (array != EmptyArray) { clone.array = (T[])array.Clone(); - IDeepCloneable[] cloneableArray = clone.array as IDeepCloneable[]; - if (cloneableArray != null) + if (clone.array is IDeepCloneable[] cloneableArray) { for (int i = 0; i < count; i++) { @@ -349,10 +347,7 @@ namespace Google.Protobuf.Collections /// /// The item to find. /// true if this collection contains the given item; false otherwise. - public bool Contains(T item) - { - return IndexOf(item) != -1; - } + public bool Contains(T item) => IndexOf(item) != -1; /// /// Copies this collection to the given array. @@ -378,7 +373,7 @@ namespace Google.Protobuf.Collections } Array.Copy(array, index + 1, array, index, count - index - 1); count--; - array[count] = default(T); + array[count] = default; return true; } @@ -402,8 +397,7 @@ namespace Google.Protobuf.Collections // Optimization 1: If the collection we're adding is already a RepeatedField, // we know the values are valid. - var otherRepeatedField = values as RepeatedField; - if (otherRepeatedField != null) + if (values is RepeatedField otherRepeatedField) { EnsureSize(count + otherRepeatedField.count); Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count); @@ -413,8 +407,7 @@ namespace Google.Protobuf.Collections // Optimization 2: The collection is an ICollection, so we can expand // just once and ask the collection to copy itself into the array. - var collection = values as ICollection; - if (collection != null) + if (values is ICollection collection) { var extraCount = collection.Count; // For reference types and nullable value types, we need to check that there are no nulls @@ -484,21 +477,15 @@ namespace Google.Protobuf.Collections /// /// true if the specified is equal to this instance; otherwise, false. /// - public override bool Equals(object obj) - { - return Equals(obj as RepeatedField); - } - + public override bool Equals(object obj) => Equals(obj as RepeatedField); + /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Returns a hash code for this instance. @@ -523,7 +510,7 @@ namespace Google.Protobuf.Collections /// true if refers to an equal repeated field; false otherwise. public bool Equals(RepeatedField other) { - if (ReferenceEquals(other, null)) + if (other is null) { return false; } @@ -596,7 +583,7 @@ namespace Google.Protobuf.Collections } Array.Copy(array, index + 1, array, index, count - index - 1); count--; - array[count] = default(T); + array[count] = default; } /// @@ -642,10 +629,7 @@ namespace Google.Protobuf.Collections #region Explicit interface implementation for IList and ICollection. bool IList.IsFixedSize => false; - void ICollection.CopyTo(Array array, int index) - { - Array.Copy(this.array, 0, array, index, count); - } + void ICollection.CopyTo(Array array, int index) => Array.Copy(this.array, 0, array, index, count); bool ICollection.IsSynchronized => false; @@ -653,8 +637,8 @@ namespace Google.Protobuf.Collections object IList.this[int index] { - get { return this[index]; } - set { this[index] = (T)value; } + get => this[index]; + set => this[index] = (T)value; } int IList.Add(object value) @@ -663,32 +647,18 @@ namespace Google.Protobuf.Collections return count - 1; } - bool IList.Contains(object value) - { - return (value is T && Contains((T)value)); - } + bool IList.Contains(object value) => (value is T t && Contains(t)); - int IList.IndexOf(object value) - { - if (!(value is T)) - { - return -1; - } - return IndexOf((T)value); - } + int IList.IndexOf(object value) => (value is T t) ? IndexOf(t) : -1; - void IList.Insert(int index, object value) - { - Insert(index, (T) value); - } + void IList.Insert(int index, object value) => Insert(index, (T) value); void IList.Remove(object value) { - if (!(value is T)) + if (value is T t) { - return; + Remove(t); } - Remove((T)value); } #endregion } diff --git a/csharp/src/Google.Protobuf/Extension.cs b/csharp/src/Google.Protobuf/Extension.cs index d10a668452..28072605bd 100644 --- a/csharp/src/Google.Protobuf/Extension.cs +++ b/csharp/src/Google.Protobuf/Extension.cs @@ -77,7 +77,7 @@ namespace Google.Protobuf this.codec = codec; } - internal TValue DefaultValue => codec != null ? codec.DefaultValue : default(TValue); + internal TValue DefaultValue => codec != null ? codec.DefaultValue : default; internal override Type TargetType => typeof(TTarget); diff --git a/csharp/src/Google.Protobuf/ExtensionRegistry.cs b/csharp/src/Google.Protobuf/ExtensionRegistry.cs index e72314b22c..be381f0986 100644 --- a/csharp/src/Google.Protobuf/ExtensionRegistry.cs +++ b/csharp/src/Google.Protobuf/ExtensionRegistry.cs @@ -55,7 +55,7 @@ namespace Google.Protobuf internal static ExtensionComparer Instance = new ExtensionComparer(); } - private IDictionary, Extension> extensions; + private readonly IDictionary, Extension> extensions; /// /// Creates a new empty extension registry diff --git a/csharp/src/Google.Protobuf/ExtensionSet.cs b/csharp/src/Google.Protobuf/ExtensionSet.cs index 306e45e5fc..aa1acbd459 100644 --- a/csharp/src/Google.Protobuf/ExtensionSet.cs +++ b/csharp/src/Google.Protobuf/ExtensionSet.cs @@ -61,8 +61,7 @@ namespace Google.Protobuf /// public static TValue Get(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage { - IExtensionValue value; - if (TryGetValue(ref set, extension, out value)) + if (TryGetValue(ref set, extension, out IExtensionValue value)) { // The stored ExtensionValue can be a different type to what is being requested. // This happens when the same extension proto is compiled in different assemblies. @@ -98,7 +97,7 @@ namespace Google.Protobuf } } } - else + else { return extension.DefaultValue; } @@ -109,8 +108,7 @@ namespace Google.Protobuf /// public static RepeatedField Get(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage { - IExtensionValue value; - if (TryGetValue(ref set, extension, out value)) + if (TryGetValue(ref set, extension, out IExtensionValue value)) { if (value is RepeatedExtensionValue extensionValue) { @@ -132,7 +130,7 @@ namespace Google.Protobuf } } } - else + else { return null; } @@ -193,8 +191,7 @@ namespace Google.Protobuf /// public static bool Has(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage { - IExtensionValue value; - return TryGetValue(ref set, extension, out value); + return TryGetValue(ref set, extension, out IExtensionValue _); } /// @@ -252,20 +249,18 @@ namespace Google.Protobuf /// public static bool TryMergeFieldFrom(ref ExtensionSet set, ref ParseContext ctx) where TTarget : IExtendableMessage { - Extension extension; int lastFieldNumber = WireFormat.GetTagFieldNumber(ctx.LastTag); - IExtensionValue extensionValue; - if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out extensionValue)) + if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out IExtensionValue extensionValue)) { extensionValue.MergeFrom(ref ctx); return true; } - else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out extension)) + else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out Extension extension)) { IExtensionValue value = extension.CreateValue(); value.MergeFrom(ref ctx); - set = (set ?? new ExtensionSet()); + set ??= new ExtensionSet(); set.ValuesByNumber.Add(extension.FieldNumber, value); return true; } @@ -290,8 +285,7 @@ namespace Google.Protobuf } foreach (var pair in second.ValuesByNumber) { - IExtensionValue value; - if (first.ValuesByNumber.TryGetValue(pair.Key, out value)) + if (first.ValuesByNumber.TryGetValue(pair.Key, out IExtensionValue value)) { value.MergeFrom(pair.Value); } @@ -365,8 +359,7 @@ namespace Google.Protobuf } foreach (var pair in ValuesByNumber) { - IExtensionValue secondValue; - if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out secondValue)) + if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out IExtensionValue secondValue)) { return false; } diff --git a/csharp/src/Google.Protobuf/ExtensionValue.cs b/csharp/src/Google.Protobuf/ExtensionValue.cs index 1329b2f4d5..9637f1ba1d 100644 --- a/csharp/src/Google.Protobuf/ExtensionValue.cs +++ b/csharp/src/Google.Protobuf/ExtensionValue.cs @@ -32,7 +32,6 @@ using Google.Protobuf.Collections; using System; -using System.Linq; namespace Google.Protobuf { @@ -50,7 +49,7 @@ namespace Google.Protobuf internal sealed class ExtensionValue : IExtensionValue { private T field; - private FieldCodec codec; + private readonly FieldCodec codec; internal ExtensionValue(FieldCodec codec) { diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs index ee6bd6a0eb..d3b0b71303 100644 --- a/csharp/src/Google.Protobuf/FieldCodec.cs +++ b/csharp/src/Google.Protobuf/FieldCodec.cs @@ -31,7 +31,6 @@ #endregion using Google.Protobuf.Collections; -using Google.Protobuf.Compatibility; using Google.Protobuf.WellKnownTypes; using System; using System.Collections.Generic; @@ -51,150 +50,105 @@ namespace Google.Protobuf /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForString(uint tag) - { - return FieldCodec.ForString(tag, ""); - } + public static FieldCodec ForString(uint tag) => ForString(tag, ""); /// /// Retrieves a codec suitable for a bytes field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForBytes(uint tag) - { - return FieldCodec.ForBytes(tag, ByteString.Empty); - } + public static FieldCodec ForBytes(uint tag) => ForBytes(tag, ByteString.Empty); /// /// Retrieves a codec suitable for a bool field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForBool(uint tag) - { - return FieldCodec.ForBool(tag, false); - } + public static FieldCodec ForBool(uint tag) => ForBool(tag, false); /// /// Retrieves a codec suitable for an int32 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForInt32(uint tag) - { - return FieldCodec.ForInt32(tag, 0); - } + public static FieldCodec ForInt32(uint tag) => ForInt32(tag, 0); /// /// Retrieves a codec suitable for an sint32 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForSInt32(uint tag) - { - return FieldCodec.ForSInt32(tag, 0); - } + public static FieldCodec ForSInt32(uint tag) => ForSInt32(tag, 0); /// /// Retrieves a codec suitable for a fixed32 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForFixed32(uint tag) - { - return FieldCodec.ForFixed32(tag, 0); - } + public static FieldCodec ForFixed32(uint tag) => ForFixed32(tag, 0); /// /// Retrieves a codec suitable for an sfixed32 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForSFixed32(uint tag) - { - return FieldCodec.ForSFixed32(tag, 0); - } + public static FieldCodec ForSFixed32(uint tag) => ForSFixed32(tag, 0); /// /// Retrieves a codec suitable for a uint32 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForUInt32(uint tag) - { - return FieldCodec.ForUInt32(tag, 0); - } + public static FieldCodec ForUInt32(uint tag) => ForUInt32(tag, 0); /// /// Retrieves a codec suitable for an int64 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForInt64(uint tag) - { - return FieldCodec.ForInt64(tag, 0); - } + public static FieldCodec ForInt64(uint tag) => ForInt64(tag, 0); /// /// Retrieves a codec suitable for an sint64 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForSInt64(uint tag) - { - return FieldCodec.ForSInt64(tag, 0); - } + public static FieldCodec ForSInt64(uint tag) => ForSInt64(tag, 0); /// /// Retrieves a codec suitable for a fixed64 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForFixed64(uint tag) - { - return FieldCodec.ForFixed64(tag, 0); - } + public static FieldCodec ForFixed64(uint tag) => ForFixed64(tag, 0); /// /// Retrieves a codec suitable for an sfixed64 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForSFixed64(uint tag) - { - return FieldCodec.ForSFixed64(tag, 0); - } + public static FieldCodec ForSFixed64(uint tag) => ForSFixed64(tag, 0); /// /// Retrieves a codec suitable for a uint64 field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForUInt64(uint tag) - { - return FieldCodec.ForUInt64(tag, 0); - } + public static FieldCodec ForUInt64(uint tag) => ForUInt64(tag, 0); /// /// Retrieves a codec suitable for a float field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForFloat(uint tag) - { - return FieldCodec.ForFloat(tag, 0); - } + public static FieldCodec ForFloat(uint tag) => ForFloat(tag, 0); /// /// Retrieves a codec suitable for a double field with the given tag. /// /// The tag. /// A codec for the given tag. - public static FieldCodec ForDouble(uint tag) - { - return FieldCodec.ForDouble(tag, 0); - } + public static FieldCodec ForDouble(uint tag) => ForDouble(tag, 0); // Enums are tricky. We can probably use expression trees to build these delegates automatically, // but it's easy to generate the code for it. @@ -206,10 +160,8 @@ namespace Google.Protobuf /// A conversion function from to the enum type. /// A conversion function from the enum type to . /// A codec for the given tag. - public static FieldCodec ForEnum(uint tag, Func toInt32, Func fromInt32) - { - return FieldCodec.ForEnum(tag, toInt32, fromInt32, default(T)); - } + public static FieldCodec ForEnum(uint tag, Func toInt32, Func fromInt32) => + ForEnum(tag, toInt32, fromInt32, default); /// /// Retrieves a codec suitable for a string field with the given tag. @@ -565,8 +517,7 @@ namespace Google.Protobuf /// internal static FieldCodec GetCodec() { - object value; - if (!Codecs.TryGetValue(typeof(T), out value)) + if (!Codecs.TryGetValue(typeof(T), out object value)) { throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T)); } @@ -575,8 +526,7 @@ namespace Google.Protobuf internal static ValueReader GetReader() where T : struct { - object value; - if (!Readers.TryGetValue(typeof(T), out value)) + if (!Readers.TryGetValue(typeof(T), out object value)) { throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T)); } diff --git a/csharp/src/Google.Protobuf/FieldMaskTree.cs b/csharp/src/Google.Protobuf/FieldMaskTree.cs index 63eb5f61c8..084374ff5f 100644 --- a/csharp/src/Google.Protobuf/FieldMaskTree.cs +++ b/csharp/src/Google.Protobuf/FieldMaskTree.cs @@ -120,8 +120,7 @@ namespace Google.Protobuf return this; } - Node childNode; - if (!node.Children.TryGetValue(part, out childNode)) + if (!node.Children.TryGetValue(part, out Node childNode)) { createNewBranch = true; childNode = new Node(); diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index d3c18db7d0..5517b0030c 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.21.1 + 3.21.2 7.2 Google Inc. diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs index 6a3dbd6809..333838bb5e 100644 --- a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs +++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs @@ -136,5 +136,5 @@ namespace Google.Protobuf { return new InvalidProtocolBufferException("Message was missing required fields"); } -} + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 16f7c5a4e4..2ef10ee7e9 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -62,7 +62,6 @@ namespace Google.Protobuf internal const string AnyTypeUrlField = "@type"; internal const string AnyDiagnosticValueField = "@value"; internal const string AnyWellKnownTypeValueField = "value"; - private const string TypeUrlPrefix = "type.googleapis.com"; private const string NameValueSeparator = ": "; private const string PropertySeparator = ", "; @@ -202,8 +201,7 @@ namespace Google.Protobuf } if (DiagnosticOnly) { - ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage; - if (customDiagnosticMessage != null) + if (message is ICustomDiagnosticMessage customDiagnosticMessage) { writer.Write(customDiagnosticMessage.ToDiagnosticString()); return; @@ -320,39 +318,20 @@ namespace Google.Protobuf IList list = (IList) value; return list.Count == 0; } - switch (descriptor.FieldType) - { - case FieldType.Bool: - return (bool) value == false; - case FieldType.Bytes: - return (ByteString) value == ByteString.Empty; - case FieldType.String: - return (string) value == ""; - case FieldType.Double: - return (double) value == 0.0; - case FieldType.SInt32: - case FieldType.Int32: - case FieldType.SFixed32: - case FieldType.Enum: - return (int) value == 0; - case FieldType.Fixed32: - case FieldType.UInt32: - return (uint) value == 0; - case FieldType.Fixed64: - case FieldType.UInt64: - return (ulong) value == 0; - case FieldType.SFixed64: - case FieldType.Int64: - case FieldType.SInt64: - return (long) value == 0; - case FieldType.Float: - return (float) value == 0f; - case FieldType.Message: - case FieldType.Group: // Never expect to get this, but... - return value == null; - default: - throw new ArgumentException("Invalid field type"); - } + return descriptor.FieldType switch + { + FieldType.Bool => (bool) value == false, + FieldType.Bytes => (ByteString) value == ByteString.Empty, + FieldType.String => (string) value == "", + FieldType.Double => (double) value == 0.0, + FieldType.SInt32 or FieldType.Int32 or FieldType.SFixed32 or FieldType.Enum => (int) value == 0, + FieldType.Fixed32 or FieldType.UInt32 => (uint) value == 0, + FieldType.Fixed64 or FieldType.UInt64 => (ulong) value == 0, + FieldType.SFixed64 or FieldType.Int64 or FieldType.SInt64 => (long) value == 0, + FieldType.Float => (float) value == 0f, + FieldType.Message or FieldType.Group => value == null, + _ => throw new ArgumentException("Invalid field type"), + }; } /// @@ -369,28 +348,28 @@ namespace Google.Protobuf { WriteNull(writer); } - else if (value is bool) + else if (value is bool b) { - writer.Write((bool)value ? "true" : "false"); + writer.Write(b ? "true" : "false"); } - else if (value is ByteString) + else if (value is ByteString byteString) { // Nothing in Base64 needs escaping writer.Write('"'); - writer.Write(((ByteString)value).ToBase64()); + writer.Write(byteString.ToBase64()); writer.Write('"'); } - else if (value is string) + else if (value is string str) { - WriteString(writer, (string)value); + WriteString(writer, str); } - else if (value is IDictionary) + else if (value is IDictionary dictionary) { - WriteDictionary(writer, (IDictionary)value); + WriteDictionary(writer, dictionary); } - else if (value is IList) + else if (value is IList list) { - WriteList(writer, (IList)value); + WriteList(writer, list); } else if (value is int || value is uint) { @@ -437,9 +416,9 @@ namespace Google.Protobuf writer.Write(text); } } - else if (value is IMessage) + else if (value is IMessage message) { - Format((IMessage)value, writer); + Format(message, writer); } else { @@ -469,9 +448,8 @@ namespace Google.Protobuf // WriteValue will do the right thing.) if (descriptor.IsWrapperType) { - if (value is IMessage) + if (value is IMessage message) { - var message = (IMessage) value; value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message); } WriteValue(writer, value); @@ -679,15 +657,15 @@ namespace Google.Protobuf writer.Write(PropertySeparator); } string keyText; - if (pair.Key is string) + if (pair.Key is string s) { - keyText = (string) pair.Key; + keyText = s; } - else if (pair.Key is bool) + else if (pair.Key is bool b) { - keyText = (bool) pair.Key ? "true" : "false"; + keyText = b ? "true" : "false"; } - else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong) + else if (pair.Key is int || pair.Key is uint || pair.Key is long || pair.Key is ulong) { keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture); } @@ -916,9 +894,8 @@ namespace Google.Protobuf } } - string originalName; // If this returns false, originalName will be null, which is what we want. - nameMapping.TryGetValue(value, out originalName); + nameMapping.TryGetValue(value, out string originalName); return originalName; } diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs index cb5f5a8f21..3575e2529e 100644 --- a/csharp/src/Google.Protobuf/JsonParser.cs +++ b/csharp/src/Google.Protobuf/JsonParser.cs @@ -70,8 +70,7 @@ namespace Google.Protobuf // TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers // and the signatures of various methods. - private static readonly Dictionary> - WellKnownTypeHandlers = new Dictionary> + private static readonly Dictionary> WellKnownTypeHandlers = new() { { Timestamp.Descriptor.FullName, (parser, message, tokenizer) => MergeTimestamp(message, tokenizer.Next()) }, { Duration.Descriptor.FullName, (parser, message, tokenizer) => MergeDuration(message, tokenizer.Next()) }, @@ -156,8 +155,7 @@ namespace Google.Protobuf } if (message.Descriptor.IsWellKnownType) { - Action handler; - if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out handler)) + if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out Action handler)) { handler(this, message, tokenizer); return; @@ -187,8 +185,7 @@ namespace Google.Protobuf throw new InvalidOperationException("Unexpected token type " + token.Type); } string name = token.StringValue; - FieldDescriptor field; - if (jsonFieldMap.TryGetValue(name, out field)) + if (jsonFieldMap.TryGetValue(name, out FieldDescriptor field)) { if (field.ContainingOneof != null) { @@ -303,11 +300,7 @@ namespace Google.Protobuf } object key = ParseMapKey(keyField, token.StringValue); object value = ParseSingleValue(valueField, tokenizer); - if (value == null) - { - throw new InvalidProtocolBufferException("Map values must not be null"); - } - dictionary[key] = value; + dictionary[key] = value ?? throw new InvalidProtocolBufferException("Map values must not be null"); } } @@ -853,7 +846,7 @@ namespace Google.Protobuf if (secondsToAdd < 0 && nanosToAdd > 0) { secondsToAdd++; - nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond; + nanosToAdd -= Duration.NanosecondsPerSecond; } if (secondsToAdd != 0 || nanosToAdd != 0) { @@ -1049,23 +1042,20 @@ namespace Google.Protobuf /// when unknown fields are encountered. /// /// true if unknown fields should be ignored when parsing; false to throw an exception. - public Settings WithIgnoreUnknownFields(bool ignoreUnknownFields) => - new Settings(RecursionLimit, TypeRegistry, ignoreUnknownFields); + public Settings WithIgnoreUnknownFields(bool ignoreUnknownFields) => new(RecursionLimit, TypeRegistry, ignoreUnknownFields); /// /// Creates a new object based on this one, but with the specified recursion limit. /// /// The new recursion limit. - public Settings WithRecursionLimit(int recursionLimit) => - new Settings(recursionLimit, TypeRegistry, IgnoreUnknownFields); + public Settings WithRecursionLimit(int recursionLimit) => new(recursionLimit, TypeRegistry, IgnoreUnknownFields); /// /// Creates a new object based on this one, but with the specified type registry. /// /// The new type registry. Must not be null. public Settings WithTypeRegistry(TypeRegistry typeRegistry) => - new Settings( - RecursionLimit, + new(RecursionLimit, ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry)), IgnoreUnknownFields); } diff --git a/csharp/src/Google.Protobuf/JsonToken.cs b/csharp/src/Google.Protobuf/JsonToken.cs index 6c0138ccb6..c23a25c313 100644 --- a/csharp/src/Google.Protobuf/JsonToken.cs +++ b/csharp/src/Google.Protobuf/JsonToken.cs @@ -36,24 +36,14 @@ namespace Google.Protobuf { internal sealed class JsonToken : IEquatable { - // Tokens with no value can be reused. - private static readonly JsonToken _true = new JsonToken(TokenType.True); - private static readonly JsonToken _false = new JsonToken(TokenType.False); - private static readonly JsonToken _null = new JsonToken(TokenType.Null); - private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject); - private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject); - private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray); - private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray); - private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument); - - internal static JsonToken Null { get { return _null; } } - internal static JsonToken False { get { return _false; } } - internal static JsonToken True { get { return _true; } } - internal static JsonToken StartObject{ get { return startObject; } } - internal static JsonToken EndObject { get { return endObject; } } - internal static JsonToken StartArray { get { return startArray; } } - internal static JsonToken EndArray { get { return endArray; } } - internal static JsonToken EndDocument { get { return endDocument; } } + internal static JsonToken Null { get; } = new JsonToken(TokenType.Null); + internal static JsonToken False { get; } = new JsonToken(TokenType.False); + internal static JsonToken True { get; } = new JsonToken(TokenType.True); + internal static JsonToken StartObject { get; } = new JsonToken(TokenType.StartObject); + internal static JsonToken EndObject { get; } = new JsonToken(TokenType.EndObject); + internal static JsonToken StartArray { get; } = new JsonToken(TokenType.StartArray); + internal static JsonToken EndArray { get; } = new JsonToken(TokenType.EndArray); + internal static JsonToken EndDocument { get; } = new JsonToken(TokenType.EndDocument); internal static JsonToken Name(string name) { @@ -94,9 +84,9 @@ namespace Google.Protobuf private readonly string stringValue; private readonly double numberValue; - internal TokenType Type { get { return type; } } - internal string StringValue { get { return stringValue; } } - internal double NumberValue { get { return numberValue; } } + internal TokenType Type => type; + internal string StringValue => stringValue; + internal double NumberValue => numberValue; private JsonToken(TokenType type, string stringValue = null, double numberValue = 0) { @@ -105,10 +95,7 @@ namespace Google.Protobuf this.numberValue = numberValue; } - public override bool Equals(object obj) - { - return Equals(obj as JsonToken); - } + public override bool Equals(object obj) => Equals(obj as JsonToken); public override int GetHashCode() { @@ -124,38 +111,26 @@ namespace Google.Protobuf public override string ToString() { - switch (type) + return type switch { - case TokenType.Null: - return "null"; - case TokenType.True: - return "true"; - case TokenType.False: - return "false"; - case TokenType.Name: - return "name (" + stringValue + ")"; - case TokenType.StringValue: - return "value (" + stringValue + ")"; - case TokenType.Number: - return "number (" + numberValue + ")"; - case TokenType.StartObject: - return "start-object"; - case TokenType.EndObject: - return "end-object"; - case TokenType.StartArray: - return "start-array"; - case TokenType.EndArray: - return "end-array"; - case TokenType.EndDocument: - return "end-document"; - default: - throw new InvalidOperationException("Token is of unknown type " + type); - } + TokenType.Null => "null", + TokenType.True => "true", + TokenType.False => "false", + TokenType.Name => $"name ({stringValue})", + TokenType.StringValue => $"value ({stringValue})", + TokenType.Number => $"number ({numberValue})", + TokenType.StartObject => "start-object", + TokenType.EndObject => "end-object", + TokenType.StartArray => "start-array", + TokenType.EndArray => "end-array", + TokenType.EndDocument => "end-document", + _ => throw new InvalidOperationException($"Token is of unknown type {type}"), + }; } public bool Equals(JsonToken other) { - if (ReferenceEquals(other, null)) + if (other is null) { return false; } diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs index 13a12c05dd..ed5473433b 100644 --- a/csharp/src/Google.Protobuf/JsonTokenizer.cs +++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs @@ -29,6 +29,7 @@ // (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 + using System; using System.Collections.Generic; using System.Globalization; @@ -362,29 +363,19 @@ namespace Google.Protobuf private char ReadEscapedCharacter() { char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence"); - switch (c) + return c switch { - case 'n': - return '\n'; - case '\\': - return '\\'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'r': - return '\r'; - case 't': - return '\t'; - case '"': - return '"'; - case '/': - return '/'; - case 'u': - return ReadUnicodeEscape(); - default: - throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c)); - } + 'n' => '\n', + '\\' => '\\', + 'b' => '\b', + 'f' => '\f', + 'r' => '\r', + 't' => '\t', + '"' => '"', + '/' => '/', + 'u' => ReadUnicodeEscape(), + _ => throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int)c)), + }; } /// @@ -498,8 +489,7 @@ namespace Google.Protobuf throw reader.CreateException("Invalid numeric literal"); } builder.Append(first); - int digitCount; - char? next = ConsumeDigits(builder, out digitCount); + char? next = ConsumeDigits(builder, out int digitCount); if (first == '0' && digitCount != 0) { throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value."); @@ -510,8 +500,7 @@ namespace Google.Protobuf private char? ReadFrac(StringBuilder builder) { builder.Append('.'); // Already consumed this - int digitCount; - char? next = ConsumeDigits(builder, out digitCount); + char? next = ConsumeDigits(builder, out int digitCount); if (digitCount == 0) { throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits"); @@ -535,8 +524,7 @@ namespace Google.Protobuf { reader.PushBack(next.Value); } - int digitCount; - next = ConsumeDigits(builder, out digitCount); + next = ConsumeDigits(builder, out int digitCount); if (digitCount == 0) { throw reader.CreateException("Invalid numeric literal: exponent without value"); @@ -591,20 +579,13 @@ namespace Google.Protobuf { containerStack.Pop(); var parent = containerStack.Peek(); - switch (parent) + state = parent switch { - case ContainerType.Object: - state = State.ObjectAfterProperty; - break; - case ContainerType.Array: - state = State.ArrayAfterValue; - break; - case ContainerType.Document: - state = State.ExpectedEndOfDocument; - break; - default: - throw new InvalidOperationException("Unexpected container type: " + parent); - } + ContainerType.Object => State.ObjectAfterProperty, + ContainerType.Array => State.ArrayAfterValue, + ContainerType.Document => State.ExpectedEndOfDocument, + _ => throw new InvalidOperationException("Unexpected container type: " + parent), + }; } private enum ContainerType diff --git a/csharp/src/Google.Protobuf/LimitedInputStream.cs b/csharp/src/Google.Protobuf/LimitedInputStream.cs index 50ead9c992..46d5295f05 100644 --- a/csharp/src/Google.Protobuf/LimitedInputStream.cs +++ b/csharp/src/Google.Protobuf/LimitedInputStream.cs @@ -51,34 +51,20 @@ namespace Google.Protobuf bytesLeft = size; } - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; public override void Flush() { } - public override long Length - { - get { throw new NotSupportedException(); } - } + public override long Length => throw new NotSupportedException(); public override long Position { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) @@ -92,19 +78,10 @@ namespace Google.Protobuf return 0; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); } } diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs index c4b3f82343..22d3a2fb80 100644 --- a/csharp/src/Google.Protobuf/MessageExtensions.cs +++ b/csharp/src/Google.Protobuf/MessageExtensions.cs @@ -107,7 +107,7 @@ namespace Google.Protobuf /// The message data as a byte array. public static byte[] ToByteArray(this IMessage message) { - ProtoPreconditions.CheckNotNull(message, "message"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); byte[] result = new byte[message.CalculateSize()]; CodedOutputStream output = new CodedOutputStream(result); message.WriteTo(output); @@ -122,8 +122,8 @@ namespace Google.Protobuf /// The stream to write to. public static void WriteTo(this IMessage message, Stream output) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(output, "output"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(output, nameof(output)); CodedOutputStream codedOutput = new CodedOutputStream(output); message.WriteTo(codedOutput); codedOutput.Flush(); @@ -136,8 +136,8 @@ namespace Google.Protobuf /// The output stream to write to. public static void WriteDelimitedTo(this IMessage message, Stream output) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(output, "output"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(output, nameof(output)); CodedOutputStream codedOutput = new CodedOutputStream(output); codedOutput.WriteLength(message.CalculateSize()); message.WriteTo(codedOutput); @@ -151,7 +151,7 @@ namespace Google.Protobuf /// The message data as a byte string. public static ByteString ToByteString(this IMessage message) { - ProtoPreconditions.CheckNotNull(message, "message"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); return ByteString.AttachBytes(message.ToByteArray()); } @@ -251,30 +251,34 @@ namespace Google.Protobuf // Implementations allowing unknown fields to be discarded. internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields, ExtensionRegistry registry) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(data, "data"); - CodedInputStream input = new CodedInputStream(data); - input.DiscardUnknownFields = discardUnknownFields; - input.ExtensionRegistry = registry; + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(data, nameof(data)); + CodedInputStream input = new CodedInputStream(data) + { + DiscardUnknownFields = discardUnknownFields, + ExtensionRegistry = registry + }; message.MergeFrom(input); input.CheckReadEndOfStreamTag(); } internal static void MergeFrom(this IMessage message, byte[] data, int offset, int length, bool discardUnknownFields, ExtensionRegistry registry) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(data, "data"); - CodedInputStream input = new CodedInputStream(data, offset, length); - input.DiscardUnknownFields = discardUnknownFields; - input.ExtensionRegistry = registry; + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(data, nameof(data)); + CodedInputStream input = new CodedInputStream(data, offset, length) + { + DiscardUnknownFields = discardUnknownFields, + ExtensionRegistry = registry + }; message.MergeFrom(input); input.CheckReadEndOfStreamTag(); } internal static void MergeFrom(this IMessage message, ByteString data, bool discardUnknownFields, ExtensionRegistry registry) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(data, "data"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(data, nameof(data)); CodedInputStream input = data.CreateCodedInput(); input.DiscardUnknownFields = discardUnknownFields; input.ExtensionRegistry = registry; @@ -284,11 +288,13 @@ namespace Google.Protobuf internal static void MergeFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(input, "input"); - CodedInputStream codedInput = new CodedInputStream(input); - codedInput.DiscardUnknownFields = discardUnknownFields; - codedInput.ExtensionRegistry = registry; + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(input, nameof(input)); + CodedInputStream codedInput = new CodedInputStream(input) + { + DiscardUnknownFields = discardUnknownFields, + ExtensionRegistry = registry + }; message.MergeFrom(codedInput); codedInput.CheckReadEndOfStreamTag(); } @@ -315,8 +321,8 @@ namespace Google.Protobuf internal static void MergeDelimitedFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry) { - ProtoPreconditions.CheckNotNull(message, "message"); - ProtoPreconditions.CheckNotNull(input, "input"); + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(input, nameof(input)); int size = (int) CodedInputStream.ReadRawVarint32(input); Stream limitedStream = new LimitedInputStream(input, size); MergeFrom(message, limitedStream, discardUnknownFields, registry); diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs index a10c908916..66907d46fa 100644 --- a/csharp/src/Google.Protobuf/MessageParser.cs +++ b/csharp/src/Google.Protobuf/MessageParser.cs @@ -43,9 +43,8 @@ namespace Google.Protobuf /// public class MessageParser { - private Func factory; - // TODO: When we use a C# 7.1 compiler, make this private protected. - internal bool DiscardUnknownFields { get; } + private readonly Func factory; + private protected bool DiscardUnknownFields { get; } internal ExtensionRegistry Extensions { get; } diff --git a/csharp/src/Google.Protobuf/ObjectIntPair.cs b/csharp/src/Google.Protobuf/ObjectIntPair.cs index b61fc6862f..3270b49b70 100644 --- a/csharp/src/Google.Protobuf/ObjectIntPair.cs +++ b/csharp/src/Google.Protobuf/ObjectIntPair.cs @@ -23,14 +23,7 @@ namespace Google.Protobuf && number == other.number; } - public override bool Equals(object obj) - { - if (obj is ObjectIntPair) - { - return Equals((ObjectIntPair)obj); - } - return false; - } + public override bool Equals(object obj) => obj is ObjectIntPair pair && Equals(pair); public override int GetHashCode() { diff --git a/csharp/src/Google.Protobuf/ParseContext.cs b/csharp/src/Google.Protobuf/ParseContext.cs index 7b278b5a92..85ea56737a 100644 --- a/csharp/src/Google.Protobuf/ParseContext.cs +++ b/csharp/src/Google.Protobuf/ParseContext.cs @@ -32,14 +32,8 @@ using System; using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security; -using System.Text; -using Google.Protobuf.Collections; namespace Google.Protobuf { @@ -53,7 +47,7 @@ namespace Google.Protobuf public ref struct ParseContext { internal const int DefaultRecursionLimit = 100; - internal const int DefaultSizeLimit = Int32.MaxValue; + internal const int DefaultSizeLimit = int.MaxValue; internal ReadOnlySpan buffer; internal ParserInternalState state; @@ -127,14 +121,15 @@ namespace Google.Protobuf /// Returns the last tag read, or 0 if no tags have been read or we've read beyond /// the end of the input. /// - internal uint LastTag { get { return state.lastTag; } } + internal uint LastTag => state.lastTag; /// /// Internal-only property; when set to true, unknown fields will be discarded while parsing. /// - internal bool DiscardUnknownFields { - get { return state.DiscardUnknownFields; } - set { state.DiscardUnknownFields = value; } + internal bool DiscardUnknownFields + { + get => state.DiscardUnknownFields; + set => state.DiscardUnknownFields = value; } /// @@ -142,8 +137,8 @@ namespace Google.Protobuf /// internal ExtensionRegistry ExtensionRegistry { - get { return state.ExtensionRegistry; } - set { state.ExtensionRegistry = value; } + get => state.ExtensionRegistry; + set => state.ExtensionRegistry = value; } /// @@ -156,125 +151,85 @@ namespace Google.Protobuf /// /// The next field tag, or 0 for end of input. (0 is never a valid tag.) [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint ReadTag() - { - return ParsingPrimitives.ParseTag(ref buffer, ref state); - } + public uint ReadTag() => ParsingPrimitives.ParseTag(ref buffer, ref state); /// /// Reads a double field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public double ReadDouble() - { - return ParsingPrimitives.ParseDouble(ref buffer, ref state); - } + public double ReadDouble() => ParsingPrimitives.ParseDouble(ref buffer, ref state); /// /// Reads a float field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float ReadFloat() - { - return ParsingPrimitives.ParseFloat(ref buffer, ref state); - } + public float ReadFloat() => ParsingPrimitives.ParseFloat(ref buffer, ref state); /// /// Reads a uint64 field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ulong ReadUInt64() - { - return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); - } + public ulong ReadUInt64() => ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); /// /// Reads an int64 field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public long ReadInt64() - { - return (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); - } + public long ReadInt64() => (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); /// /// Reads an int32 field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadInt32() - { - return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); - } + public int ReadInt32() => (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); /// /// Reads a fixed64 field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ulong ReadFixed64() - { - return ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); - } + public ulong ReadFixed64() => ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); /// /// Reads a fixed32 field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint ReadFixed32() - { - return ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); - } + public uint ReadFixed32() => ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); /// /// Reads a bool field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ReadBool() - { - return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0; - } + public bool ReadBool() => ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0; + /// /// Reads a string field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string ReadString() - { - return ParsingPrimitives.ReadString(ref buffer, ref state); - } + public string ReadString() => ParsingPrimitives.ReadString(ref buffer, ref state); /// /// Reads an embedded message field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ReadMessage(IMessage message) - { - ParsingPrimitivesMessages.ReadMessage(ref this, message); - } + public void ReadMessage(IMessage message) => ParsingPrimitivesMessages.ReadMessage(ref this, message); /// /// Reads an embedded group field from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ReadGroup(IMessage message) - { - ParsingPrimitivesMessages.ReadGroup(ref this, message); - } + public void ReadGroup(IMessage message) => ParsingPrimitivesMessages.ReadGroup(ref this, message); /// /// Reads a bytes field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ByteString ReadBytes() - { - return ParsingPrimitives.ReadBytes(ref buffer, ref state); - } + public ByteString ReadBytes() => ParsingPrimitives.ReadBytes(ref buffer, ref state); + /// /// Reads a uint32 field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint ReadUInt32() - { - return ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); - } + public uint ReadUInt32() => ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); /// /// Reads an enum field value from the input. @@ -290,37 +245,25 @@ namespace Google.Protobuf /// Reads an sfixed32 field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadSFixed32() - { - return (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); - } + public int ReadSFixed32() => (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); /// /// Reads an sfixed64 field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public long ReadSFixed64() - { - return (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); - } + public long ReadSFixed64() => (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); /// /// Reads an sint32 field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadSInt32() - { - return ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); - } + public int ReadSInt32() => ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); /// /// Reads an sint64 field value from the input. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public long ReadSInt64() - { - return ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state)); - } + public long ReadSInt64() => ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state)); /// /// Reads a length for length-delimited data. @@ -330,10 +273,7 @@ namespace Google.Protobuf /// to make the calling code clearer. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int ReadLength() - { - return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); - } + public int ReadLength() => (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); internal void CopyStateTo(CodedInputStream input) { diff --git a/csharp/src/Google.Protobuf/ParserInternalState.cs b/csharp/src/Google.Protobuf/ParserInternalState.cs index cb4f47143c..af7dd7813f 100644 --- a/csharp/src/Google.Protobuf/ParserInternalState.cs +++ b/csharp/src/Google.Protobuf/ParserInternalState.cs @@ -30,20 +30,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; -using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using Google.Protobuf.Collections; - namespace Google.Protobuf { - // warning: this is a mutable struct, so it needs to be only passed as a ref! internal struct ParserInternalState { diff --git a/csharp/src/Google.Protobuf/ParsingPrimitives.cs b/csharp/src/Google.Protobuf/ParsingPrimitives.cs index e270ed8aa1..4321d269da 100644 --- a/csharp/src/Google.Protobuf/ParsingPrimitives.cs +++ b/csharp/src/Google.Protobuf/ParsingPrimitives.cs @@ -34,13 +34,10 @@ using System; using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; -using System.Text; -using Google.Protobuf.Collections; namespace Google.Protobuf { diff --git a/csharp/src/Google.Protobuf/ParsingPrimitivesMessages.cs b/csharp/src/Google.Protobuf/ParsingPrimitivesMessages.cs index eabaf96d5c..5e1babf82d 100644 --- a/csharp/src/Google.Protobuf/ParsingPrimitivesMessages.cs +++ b/csharp/src/Google.Protobuf/ParsingPrimitivesMessages.cs @@ -33,8 +33,6 @@ using System; using System.Buffers; using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; using System.Security; using Google.Protobuf.Collections; diff --git a/csharp/src/Google.Protobuf/ParsingPrimitivesWrappers.cs b/csharp/src/Google.Protobuf/ParsingPrimitivesWrappers.cs index 629ec32bd8..e874935bdd 100644 --- a/csharp/src/Google.Protobuf/ParsingPrimitivesWrappers.cs +++ b/csharp/src/Google.Protobuf/ParsingPrimitivesWrappers.cs @@ -31,15 +31,7 @@ #endregion using System; -using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security; -using System.Text; -using Google.Protobuf.Collections; namespace Google.Protobuf { diff --git a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs index f6fa1522ba..2c5d2c8346 100644 --- a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs +++ b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs @@ -31,7 +31,6 @@ #endregion using Google.Protobuf.Collections; -using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -226,24 +225,21 @@ namespace Google.Protobuf.Reflection { if (values == null) { - value = default(T); + value = default; return false; } - IExtensionValue extensionValue; - if (values.TryGetValue(field, out extensionValue)) + if (values.TryGetValue(field, out IExtensionValue extensionValue)) { - if (extensionValue is ExtensionValue) + if (extensionValue is ExtensionValue single) { - ExtensionValue single = extensionValue as ExtensionValue; ByteString bytes = single.GetValue().ToByteString(); value = new T(); value.MergeFrom(bytes); return true; } - else if (extensionValue is RepeatedExtensionValue) + else if (extensionValue is RepeatedExtensionValue repeated) { - RepeatedExtensionValue repeated = extensionValue as RepeatedExtensionValue; value = repeated.GetValue() .Select(v => v.ToByteString()) .Aggregate(new T(), (t, b) => @@ -264,22 +260,19 @@ namespace Google.Protobuf.Reflection { if (values == null) { - value = default(T); + value = default; return false; } - IExtensionValue extensionValue; - if (values.TryGetValue(field, out extensionValue)) + if (values.TryGetValue(field, out IExtensionValue extensionValue)) { - if (extensionValue is ExtensionValue) + if (extensionValue is ExtensionValue single) { - ExtensionValue single = extensionValue as ExtensionValue; value = single.GetValue(); return true; } - else if (extensionValue is RepeatedExtensionValue) + else if (extensionValue is RepeatedExtensionValue repeated) { - RepeatedExtensionValue repeated = extensionValue as RepeatedExtensionValue; if (repeated.GetValue().Count != 0) { RepeatedField repeatedField = repeated.GetValue(); @@ -317,7 +310,7 @@ namespace Google.Protobuf.Reflection } } - value = default(T); + value = default; return false; } } diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs index b22048f0a8..3c7fac25e1 100644 --- a/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs +++ b/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs @@ -30,11 +30,9 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Text; using static Google.Protobuf.Reflection.SourceCodeInfo.Types; namespace Google.Protobuf.Reflection diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs index 93f2fa9a4a..5128ad9a6a 100644 --- a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs +++ b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs @@ -51,12 +51,11 @@ namespace Google.Protobuf.Reflection private readonly IDictionary, EnumValueDescriptor> enumValuesByNumber = new Dictionary, EnumValueDescriptor>(); - private readonly HashSet dependencies; + private readonly HashSet dependencies = new HashSet(); internal DescriptorPool(IEnumerable dependencyFiles) { - dependencies = new HashSet(); - foreach (var dependencyFile in dependencyFiles) + foreach (FileDescriptor dependencyFile in dependencyFiles) { dependencies.Add(dependencyFile); ImportPublicDependencies(dependencyFile); @@ -88,10 +87,8 @@ namespace Google.Protobuf.Reflection /// or null if the symbol doesn't exist or has the wrong type internal T FindSymbol(string fullName) where T : class { - IDescriptor result; - descriptorsByName.TryGetValue(fullName, out result); - T descriptor = result as T; - if (descriptor != null) + descriptorsByName.TryGetValue(fullName, out IDescriptor result); + if (result is T descriptor) { return descriptor; } @@ -131,10 +128,9 @@ namespace Google.Protobuf.Reflection name = fullName; } - IDescriptor old; - if (descriptorsByName.TryGetValue(fullName, out old)) + if (descriptorsByName.TryGetValue(fullName, out IDescriptor old)) { - if (!(old is PackageDescriptor)) + if (old is not PackageDescriptor) { throw new DescriptorValidationException(file, "\"" + name + @@ -153,10 +149,9 @@ namespace Google.Protobuf.Reflection internal void AddSymbol(IDescriptor descriptor) { ValidateSymbolName(descriptor); - String fullName = descriptor.FullName; + string fullName = descriptor.FullName; - IDescriptor old; - if (descriptorsByName.TryGetValue(fullName, out old)) + if (descriptorsByName.TryGetValue(fullName, out IDescriptor old)) { int dotPos = fullName.LastIndexOf('.'); string message; @@ -181,8 +176,7 @@ namespace Google.Protobuf.Reflection descriptorsByName[fullName] = descriptor; } - private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$", - FrameworkPortability.CompiledRegexWhereAvailable); + private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$", FrameworkPortability.CompiledRegexWhereAvailable); /// /// Verifies that the descriptor's name is valid (i.e. it contains @@ -191,7 +185,7 @@ namespace Google.Protobuf.Reflection /// private static void ValidateSymbolName(IDescriptor descriptor) { - if (descriptor.Name == "") + if (descriptor.Name.Length == 0) { throw new DescriptorValidationException(descriptor, "Missing name."); } @@ -208,15 +202,13 @@ namespace Google.Protobuf.Reflection /// internal FieldDescriptor FindFieldByNumber(MessageDescriptor messageDescriptor, int number) { - FieldDescriptor ret; - fieldsByNumber.TryGetValue(new ObjectIntPair(messageDescriptor, number), out ret); + fieldsByNumber.TryGetValue(new ObjectIntPair(messageDescriptor, number), out FieldDescriptor ret); return ret; } internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number) { - EnumValueDescriptor ret; - enumValuesByNumber.TryGetValue(new ObjectIntPair(enumDescriptor, number), out ret); + enumValuesByNumber.TryGetValue(new ObjectIntPair(enumDescriptor, number), out EnumValueDescriptor ret); return ret; } @@ -229,8 +221,7 @@ namespace Google.Protobuf.Reflection { // for extensions, we use the extended type, otherwise we use the containing type ObjectIntPair key = new ObjectIntPair(field.Proto.HasExtendee ? field.ExtendeeType : field.ContainingType, field.FieldNumber); - FieldDescriptor old; - if (fieldsByNumber.TryGetValue(key, out old)) + if (fieldsByNumber.TryGetValue(key, out FieldDescriptor old)) { throw new DescriptorValidationException(field, "Field number " + field.FieldNumber + "has already been used in \"" + diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs index 143671dbd4..f48e8e124c 100644 --- a/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs +++ b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs @@ -40,25 +40,16 @@ namespace Google.Protobuf.Reflection /// public sealed class DescriptorValidationException : Exception { - private readonly String name; - private readonly string description; - /// /// The full name of the descriptor where the error occurred. /// - public String ProblemSymbolName - { - get { return name; } - } + public string ProblemSymbolName { get; } /// /// A human-readable description of the error. (The Message property /// is made up of the descriptor's name and this description.) /// - public string Description - { - get { return description; } - } + public string Description { get; } internal DescriptorValidationException(IDescriptor problemDescriptor, string description) : base(problemDescriptor.FullName + ": " + description) @@ -66,15 +57,15 @@ namespace Google.Protobuf.Reflection // Note that problemDescriptor may be partially uninitialized, so we // don't want to expose it directly to the user. So, we only provide // the name and the original proto. - name = problemDescriptor.FullName; - this.description = description; + ProblemSymbolName = problemDescriptor.FullName; + Description = description; } internal DescriptorValidationException(IDescriptor problemDescriptor, string description, Exception cause) : base(problemDescriptor.FullName + ": " + description, cause) { - name = problemDescriptor.FullName; - this.description = description; + ProblemSymbolName = problemDescriptor.FullName; + Description = description; } } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs index 3f2e1c41f5..a14cc1d5b6 100644 --- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs @@ -41,17 +41,12 @@ namespace Google.Protobuf.Reflection /// public sealed class EnumDescriptor : DescriptorBase { - private readonly EnumDescriptorProto proto; - private readonly MessageDescriptor containingType; - private readonly IList values; - private readonly Type clrType; - internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType) : base(file, file.ComputeFullName(parent, proto.Name), index) { - this.proto = proto; - this.clrType = clrType; - containingType = parent; + Proto = proto; + ClrType = clrType; + ContainingType = parent; if (proto.Value.Count == 0) { @@ -60,13 +55,13 @@ namespace Google.Protobuf.Reflection throw new DescriptorValidationException(this, "Enums must contain at least one value."); } - values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value, + Values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value, (value, i) => new EnumValueDescriptor(value, file, this, i)); File.DescriptorPool.AddSymbol(this); } - internal EnumDescriptorProto Proto { get { return proto; } } + internal EnumDescriptorProto Proto { get; } /// /// Returns a clone of the underlying describing this enum. @@ -79,39 +74,29 @@ namespace Google.Protobuf.Reflection /// /// The brief name of the descriptor's target. /// - public override string Name { get { return proto.Name; } } + public override string Name => Proto.Name; - internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) - { - switch (fieldNumber) + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) => + fieldNumber switch { - case EnumDescriptorProto.ValueFieldNumber: - return (IReadOnlyList) Values; - default: - return null; - } - } + EnumDescriptorProto.ValueFieldNumber => (IReadOnlyList)Values, + _ => null, + }; /// /// The CLR type for this enum. For generated code, this will be a CLR enum type. /// - public Type ClrType { get { return clrType; } } + public Type ClrType { get; } /// /// If this is a nested type, get the outer descriptor, otherwise null. /// - public MessageDescriptor ContainingType - { - get { return containingType; } - } + public MessageDescriptor ContainingType { get; } /// /// An unmodifiable list of defined value descriptors for this enum. /// - public IList Values - { - get { return values; } - } + public IList Values { get; } /// /// Finds an enum value by number. If multiple enum values have the diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs index 50b26a46bb..7a0cce04f3 100644 --- a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs @@ -40,20 +40,17 @@ namespace Google.Protobuf.Reflection /// public sealed class EnumValueDescriptor : DescriptorBase { - private readonly EnumDescriptor enumDescriptor; - private readonly EnumValueDescriptorProto proto; - internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file, EnumDescriptor parent, int index) : base(file, parent.FullName + "." + proto.Name, index) { - this.proto = proto; - enumDescriptor = parent; + Proto = proto; + EnumDescriptor = parent; file.DescriptorPool.AddSymbol(this); file.DescriptorPool.AddEnumValueByNumber(this); } - internal EnumValueDescriptorProto Proto { get { return proto; } } + internal EnumValueDescriptorProto Proto { get; } /// /// Returns a clone of the underlying describing this enum value. @@ -66,17 +63,17 @@ namespace Google.Protobuf.Reflection /// /// Returns the name of the enum value described by this object. /// - public override string Name { get { return proto.Name; } } + public override string Name => Proto.Name; /// /// Returns the number associated with this enum value. /// - public int Number { get { return Proto.Number; } } + public int Number => Proto.Number; /// /// Returns the enum descriptor that this value is part of. /// - public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } } + public EnumDescriptor EnumDescriptor { get; } /// /// The (possibly empty) set of custom options for this enum value. diff --git a/csharp/src/Google.Protobuf/Reflection/ExtensionCollection.cs b/csharp/src/Google.Protobuf/Reflection/ExtensionCollection.cs index ca874f9885..1e10060158 100644 --- a/csharp/src/Google.Protobuf/Reflection/ExtensionCollection.cs +++ b/csharp/src/Google.Protobuf/Reflection/ExtensionCollection.cs @@ -107,8 +107,7 @@ namespace Google.Protobuf.Reflection { descriptor.CrossLink(); - IList list; - if (!declarationOrder.TryGetValue(descriptor.ExtendeeType, out list)) + if (!declarationOrder.TryGetValue(descriptor.ExtendeeType, out IList list)) { list = new List(); declarationOrder.Add(descriptor.ExtendeeType, list); diff --git a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs index 85b7d39a83..156025dd5f 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs @@ -42,15 +42,14 @@ namespace Google.Protobuf.Reflection internal abstract class FieldAccessorBase : IFieldAccessor { private readonly Func getValueDelegate; - private readonly FieldDescriptor descriptor; internal FieldAccessorBase(PropertyInfo property, FieldDescriptor descriptor) { - this.descriptor = descriptor; + Descriptor = descriptor; getValueDelegate = ReflectionUtil.CreateFuncIMessageObject(property.GetGetMethod()); } - public FieldDescriptor Descriptor { get { return descriptor; } } + public FieldDescriptor Descriptor { get; } public object GetValue(IMessage message) { diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index 84ad49d276..e4fd7d2371 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -176,47 +176,28 @@ namespace Google.Protobuf.Reflection /// private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Type type) { - switch (type) + return type switch { - case FieldDescriptorProto.Types.Type.Double: - return FieldType.Double; - case FieldDescriptorProto.Types.Type.Float: - return FieldType.Float; - case FieldDescriptorProto.Types.Type.Int64: - return FieldType.Int64; - case FieldDescriptorProto.Types.Type.Uint64: - return FieldType.UInt64; - case FieldDescriptorProto.Types.Type.Int32: - return FieldType.Int32; - case FieldDescriptorProto.Types.Type.Fixed64: - return FieldType.Fixed64; - case FieldDescriptorProto.Types.Type.Fixed32: - return FieldType.Fixed32; - case FieldDescriptorProto.Types.Type.Bool: - return FieldType.Bool; - case FieldDescriptorProto.Types.Type.String: - return FieldType.String; - case FieldDescriptorProto.Types.Type.Group: - return FieldType.Group; - case FieldDescriptorProto.Types.Type.Message: - return FieldType.Message; - case FieldDescriptorProto.Types.Type.Bytes: - return FieldType.Bytes; - case FieldDescriptorProto.Types.Type.Uint32: - return FieldType.UInt32; - case FieldDescriptorProto.Types.Type.Enum: - return FieldType.Enum; - case FieldDescriptorProto.Types.Type.Sfixed32: - return FieldType.SFixed32; - case FieldDescriptorProto.Types.Type.Sfixed64: - return FieldType.SFixed64; - case FieldDescriptorProto.Types.Type.Sint32: - return FieldType.SInt32; - case FieldDescriptorProto.Types.Type.Sint64: - return FieldType.SInt64; - default: - throw new ArgumentException("Invalid type specified"); - } + FieldDescriptorProto.Types.Type.Double => FieldType.Double, + FieldDescriptorProto.Types.Type.Float => FieldType.Float, + FieldDescriptorProto.Types.Type.Int64 => FieldType.Int64, + FieldDescriptorProto.Types.Type.Uint64 => FieldType.UInt64, + FieldDescriptorProto.Types.Type.Int32 => FieldType.Int32, + FieldDescriptorProto.Types.Type.Fixed64 => FieldType.Fixed64, + FieldDescriptorProto.Types.Type.Fixed32 => FieldType.Fixed32, + FieldDescriptorProto.Types.Type.Bool => FieldType.Bool, + FieldDescriptorProto.Types.Type.String => FieldType.String, + FieldDescriptorProto.Types.Type.Group => FieldType.Group, + FieldDescriptorProto.Types.Type.Message => FieldType.Message, + FieldDescriptorProto.Types.Type.Bytes => FieldType.Bytes, + FieldDescriptorProto.Types.Type.Uint32 => FieldType.UInt32, + FieldDescriptorProto.Types.Type.Enum => FieldType.Enum, + FieldDescriptorProto.Types.Type.Sfixed32 => FieldType.SFixed32, + FieldDescriptorProto.Types.Type.Sfixed64 => FieldType.SFixed64, + FieldDescriptorProto.Types.Type.Sint32 => FieldType.SInt32, + FieldDescriptorProto.Types.Type.Sint64 => FieldType.SInt64, + _ => throw new ArgumentException("Invalid type specified"), + }; } /// @@ -391,11 +372,11 @@ namespace Google.Protobuf.Reflection if (fieldType == FieldType.Message || fieldType == FieldType.Group) { - if (!(typeDescriptor is MessageDescriptor)) + if (typeDescriptor is not MessageDescriptor m) { throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type."); } - messageType = (MessageDescriptor) typeDescriptor; + messageType = m; if (Proto.HasDefaultValue) { @@ -404,11 +385,11 @@ namespace Google.Protobuf.Reflection } else if (fieldType == FieldType.Enum) { - if (!(typeDescriptor is EnumDescriptor)) + if (typeDescriptor is not EnumDescriptor e) { throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type."); } - enumType = (EnumDescriptor) typeDescriptor; + enumType = e; } else { diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index d7701da92e..cb711dea00 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -35,7 +35,6 @@ using Google.Protobuf.WellKnownTypes; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Linq; using System.Threading; using static Google.Protobuf.Reflection.SourceCodeInfo.Types; @@ -173,25 +172,18 @@ namespace Google.Protobuf.Reflection return list[index]; } - private IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) - { - switch (fieldNumber) + private IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) => + fieldNumber switch { - case FileDescriptorProto.ServiceFieldNumber: - return (IReadOnlyList) Services; - case FileDescriptorProto.MessageTypeFieldNumber: - return (IReadOnlyList) MessageTypes; - case FileDescriptorProto.EnumTypeFieldNumber: - return (IReadOnlyList) EnumTypes; - default: - return null; - } - } + FileDescriptorProto.ServiceFieldNumber => (IReadOnlyList)Services, + FileDescriptorProto.MessageTypeFieldNumber => (IReadOnlyList)MessageTypes, + FileDescriptorProto.EnumTypeFieldNumber => (IReadOnlyList)EnumTypes, + _ => null, + }; internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor) { - DescriptorDeclaration declaration; - declarations.Value.TryGetValue(descriptor, out declaration); + declarations.Value.TryGetValue(descriptor, out DescriptorDeclaration declaration); return declaration; } @@ -227,8 +219,7 @@ namespace Google.Protobuf.Reflection throw new DescriptorValidationException(@this, "Invalid public dependency index."); } string name = proto.Dependency[index]; - FileDescriptor file; - if (!nameToFileMap.TryGetValue(name, out file)) + if (!nameToFileMap.TryGetValue(name, out FileDescriptor file)) { if (!allowUnknownDependencies) { @@ -332,7 +323,7 @@ namespace Google.Protobuf.Reflection /// The unqualified type name to look for. /// The type of descriptor to look for /// The type's descriptor, or null if not found. - public T FindTypeByName(String name) + public T FindTypeByName(string name) where T : class, IDescriptor { // Don't allow looking up nested types. This will make optimization @@ -507,8 +498,7 @@ namespace Google.Protobuf.Reflection var dependencies = new List(); foreach (var dependencyName in proto.Dependency) { - FileDescriptor dependency; - if (!descriptorsByName.TryGetValue(dependencyName, out dependency)) + if (!descriptorsByName.TryGetValue(dependencyName, out FileDescriptor dependency)) { throw new ArgumentException($"Dependency missing: {dependencyName}"); } @@ -565,7 +555,7 @@ namespace Google.Protobuf.Reflection /// /// The file descriptor for descriptor.proto. /// - public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } } + public static FileDescriptor DescriptorProtoFileDescriptor => DescriptorReflection.Descriptor; /// /// The (possibly empty) set of custom options for this file. diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs index d0a495b851..dbf16c6ef8 100644 --- a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs +++ b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs @@ -29,6 +29,7 @@ // (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 + using System; using System.Diagnostics.CodeAnalysis; @@ -57,7 +58,7 @@ namespace Google.Protobuf.Reflection /// Irrelevant for file descriptors; the CLR type for the message for message descriptors. /// [DynamicallyAccessedMembers(MessageAccessibility)] - public Type ClrType { get; private set; } + public Type ClrType { get; } /// /// Irrelevant for file descriptors; the parser for message descriptors. diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs index 415b7bec83..f2bb61c2cd 100644 --- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs @@ -130,20 +130,14 @@ namespace Google.Protobuf.Reflection /// public override string Name => Proto.Name; - internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) - { - switch (fieldNumber) + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) => + fieldNumber switch { - case DescriptorProto.FieldFieldNumber: - return (IReadOnlyList) fieldsInDeclarationOrder; - case DescriptorProto.NestedTypeFieldNumber: - return (IReadOnlyList) NestedTypes; - case DescriptorProto.EnumTypeFieldNumber: - return (IReadOnlyList) EnumTypes; - default: - return null; - } - } + DescriptorProto.FieldFieldNumber => (IReadOnlyList)fieldsInDeclarationOrder, + DescriptorProto.NestedTypeFieldNumber => (IReadOnlyList)NestedTypes, + DescriptorProto.EnumTypeFieldNumber => (IReadOnlyList)EnumTypes, + _ => null, + }; internal DescriptorProto Proto { get; } @@ -272,7 +266,7 @@ namespace Google.Protobuf.Reflection /// /// The unqualified name of the field (e.g. "foo"). /// The field's descriptor, or null if not found. - public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol(FullName + "." + name); + public FieldDescriptor FindFieldByName(string name) => File.DescriptorPool.FindSymbol(FullName + "." + name); /// /// Finds a field by field number. diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs index f5ecf2ea83..4f0ea4375b 100644 --- a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs @@ -40,35 +40,31 @@ namespace Google.Protobuf.Reflection /// public sealed class MethodDescriptor : DescriptorBase { - private readonly MethodDescriptorProto proto; - private readonly ServiceDescriptor service; - private MessageDescriptor inputType; - private MessageDescriptor outputType; /// /// The service this method belongs to. /// - public ServiceDescriptor Service { get { return service; } } + public ServiceDescriptor Service { get; } /// /// The method's input type. /// - public MessageDescriptor InputType { get { return inputType; } } + public MessageDescriptor InputType { get; private set; } /// /// The method's input type. /// - public MessageDescriptor OutputType { get { return outputType; } } + public MessageDescriptor OutputType { get; private set; } /// /// Indicates if client streams multiple requests. /// - public bool IsClientStreaming { get { return proto.ClientStreaming; } } + public bool IsClientStreaming => Proto.ClientStreaming; /// /// Indicates if server streams multiple responses. /// - public bool IsServerStreaming { get { return proto.ServerStreaming; } } + public bool IsServerStreaming => Proto.ServerStreaming; /// /// The (possibly empty) set of custom options for this method. @@ -91,7 +87,7 @@ namespace Google.Protobuf.Reflection public T GetOption(Extension extension) { var value = Proto.Options.GetExtension(extension); - return value is IDeepCloneable ? (value as IDeepCloneable).Clone() : value; + return value is IDeepCloneable c ? c.Clone() : value; } /// @@ -107,12 +103,12 @@ namespace Google.Protobuf.Reflection ServiceDescriptor parent, int index) : base(file, parent.FullName + "." + proto.Name, index) { - this.proto = proto; - service = parent; + Proto = proto; + Service = parent; file.DescriptorPool.AddSymbol(this); } - internal MethodDescriptorProto Proto { get { return proto; } } + internal MethodDescriptorProto Proto { get; private set; } /// /// Returns a clone of the underlying describing this method. @@ -125,23 +121,23 @@ namespace Google.Protobuf.Reflection /// /// The brief name of the descriptor's target. /// - public override string Name { get { return proto.Name; } } + public override string Name => Proto.Name; internal void CrossLink() { IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this); - if (!(lookup is MessageDescriptor)) + if (lookup is not MessageDescriptor inpoutType) { throw new DescriptorValidationException(this, "\"" + Proto.InputType + "\" is not a message type."); } - inputType = (MessageDescriptor) lookup; + InputType = inpoutType; lookup = File.DescriptorPool.LookupSymbol(Proto.OutputType, this); - if (!(lookup is MessageDescriptor)) + if (lookup is not MessageDescriptor outputType) { throw new DescriptorValidationException(this, "\"" + Proto.OutputType + "\" is not a message type."); } - outputType = (MessageDescriptor) lookup; + OutputType = outputType; } } } diff --git a/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs index 63f5228f3d..880716afb8 100644 --- a/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs +++ b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs @@ -60,6 +60,5 @@ namespace Google.Protobuf.Reflection Name = ProtoPreconditions.CheckNotNull(name, nameof(name)); PreferredAlias = true; } - } } diff --git a/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs index e547d83498..0b6de810de 100644 --- a/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs @@ -39,30 +39,15 @@ namespace Google.Protobuf.Reflection /// internal sealed class PackageDescriptor : IDescriptor { - private readonly string name; - private readonly string fullName; - private readonly FileDescriptor file; - internal PackageDescriptor(string name, string fullName, FileDescriptor file) { - this.file = file; - this.fullName = fullName; - this.name = name; + File = file; + FullName = fullName; + Name = name; } - public string Name - { - get { return name; } - } - - public string FullName - { - get { return fullName; } - } - - public FileDescriptor File - { - get { return file; } - } + public string Name { get; } + public string FullName { get; } + public FileDescriptor File { get; } } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs index 73efcc2566..2a6afdbfce 100644 --- a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs +++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs @@ -221,20 +221,18 @@ namespace Google.Protobuf.Reflection public object GetExtension(IMessage message) { - if (!(message is T1)) + if (message is not T1 extensionMessage) { throw new InvalidCastException("Cannot access extension on message that isn't IExtensionMessage"); } - T1 extensionMessage = (T1)message; - - if (extension is Extension) + if (extension is Extension ext13) { - return extensionMessage.GetExtension(extension as Extension); + return extensionMessage.GetExtension(ext13); } - else if (extension is RepeatedExtension) + else if (extension is RepeatedExtension repeatedExt13) { - return extensionMessage.GetOrInitializeExtension(extension as RepeatedExtension); + return extensionMessage.GetOrInitializeExtension(repeatedExt13); } else { @@ -244,16 +242,14 @@ namespace Google.Protobuf.Reflection public bool HasExtension(IMessage message) { - if (!(message is T1)) + if (message is not T1 extensionMessage) { throw new InvalidCastException("Cannot access extension on message that isn't IExtensionMessage"); } - T1 extensionMessage = (T1)message; - - if (extension is Extension) + if (extension is Extension ext13) { - return extensionMessage.HasExtension(extension as Extension); + return extensionMessage.HasExtension(ext13); } else if (extension is RepeatedExtension) { @@ -267,16 +263,14 @@ namespace Google.Protobuf.Reflection public void SetExtension(IMessage message, object value) { - if (!(message is T1)) + if (message is not T1 extensionMessage) { throw new InvalidCastException("Cannot access extension on message that isn't IExtensionMessage"); } - T1 extensionMessage = (T1)message; - - if (extension is Extension) + if (extension is Extension ext13) { - extensionMessage.SetExtension(extension as Extension, (T3)value); + extensionMessage.SetExtension(ext13, (T3)value); } else if (extension is RepeatedExtension) { @@ -290,20 +284,18 @@ namespace Google.Protobuf.Reflection public void ClearExtension(IMessage message) { - if (!(message is T1)) + if (message is not T1 extensionMessage) { throw new InvalidCastException("Cannot access extension on message that isn't IExtensionMessage"); } - T1 extensionMessage = (T1)message; - - if (extension is Extension) + if (extension is Extension ext13) { - extensionMessage.ClearExtension(extension as Extension); + extensionMessage.ClearExtension(ext13); } - else if (extension is RepeatedExtension) + else if (extension is RepeatedExtension repeatedExt13) { - extensionMessage.GetExtension(extension as RepeatedExtension).Clear(); + extensionMessage.GetExtension(repeatedExt13).Clear(); } else { diff --git a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs index afb4a693fc..2073be332f 100644 --- a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs +++ b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs @@ -60,6 +60,5 @@ namespace Google.Protobuf.Reflection { throw new InvalidOperationException("SetValue is not implemented for repeated fields"); } - } } diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs index 944ea11de1..55d812b4c9 100644 --- a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs @@ -33,7 +33,6 @@ using Google.Protobuf.Collections; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; namespace Google.Protobuf.Reflection { @@ -42,14 +41,11 @@ namespace Google.Protobuf.Reflection /// public sealed class ServiceDescriptor : DescriptorBase { - private readonly ServiceDescriptorProto proto; - private readonly IList methods; - internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index) : base(file, file.ComputeFullName(null, proto.Name), index) { - this.proto = proto; - methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method, + Proto = proto; + Methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method, (method, i) => new MethodDescriptor(method, file, this, i)); file.DescriptorPool.AddSymbol(this); @@ -58,20 +54,16 @@ namespace Google.Protobuf.Reflection /// /// The brief name of the descriptor's target. /// - public override string Name { get { return proto.Name; } } + public override string Name => Proto.Name; - internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) - { - switch (fieldNumber) + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) => + fieldNumber switch { - case ServiceDescriptorProto.MethodFieldNumber: - return (IReadOnlyList) methods; - default: - return null; - } - } + ServiceDescriptorProto.MethodFieldNumber => (IReadOnlyList)Methods, + _ => null, + }; - internal ServiceDescriptorProto Proto { get { return proto; } } + internal ServiceDescriptorProto Proto { get; } /// /// Returns a clone of the underlying describing this service. @@ -84,20 +76,15 @@ namespace Google.Protobuf.Reflection /// /// An unmodifiable list of methods in this service. /// - public IList Methods - { - get { return methods; } - } + public IList Methods { get; } /// /// Finds a method by name. /// /// The unqualified name of the method (e.g. "Foo"). /// The method's descriptor, or null if not found. - public MethodDescriptor FindMethodByName(String name) - { - return File.DescriptorPool.FindSymbol(FullName + "." + name); - } + public MethodDescriptor FindMethodByName(string name) => + File.DescriptorPool.FindSymbol(FullName + "." + name); /// /// The (possibly empty) set of custom options for this service. @@ -134,7 +121,7 @@ namespace Google.Protobuf.Reflection internal void CrossLink() { - foreach (MethodDescriptor method in methods) + foreach (MethodDescriptor method in Methods) { method.CrossLink(); } diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs index ac35e729f7..284effec30 100644 --- a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs +++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs @@ -31,7 +31,6 @@ #endregion using System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using Google.Protobuf.Compatibility; @@ -108,7 +107,7 @@ namespace Google.Protobuf.Reflection // Primitive proto3 fields without the optional keyword, which aren't in oneofs. else { - hasDelegate = message => { throw new InvalidOperationException("Presence is not implemented for this field"); }; + hasDelegate = message => throw new InvalidOperationException("Presence is not implemented for this field"); // While presence isn't supported, clearing still is; it's just setting to a default value. object defaultValue = GetDefaultValue(descriptor); @@ -116,42 +115,21 @@ namespace Google.Protobuf.Reflection } } - private static object GetDefaultValue(FieldDescriptor descriptor) - { - switch (descriptor.FieldType) + private static object GetDefaultValue(FieldDescriptor descriptor) => + descriptor.FieldType switch { - case FieldType.Bool: - return false; - case FieldType.Bytes: - return ByteString.Empty; - case FieldType.String: - return ""; - case FieldType.Double: - return 0.0; - case FieldType.SInt32: - case FieldType.Int32: - case FieldType.SFixed32: - case FieldType.Enum: - return 0; - case FieldType.Fixed32: - case FieldType.UInt32: - return (uint)0; - case FieldType.Fixed64: - case FieldType.UInt64: - return 0UL; - case FieldType.SFixed64: - case FieldType.Int64: - case FieldType.SInt64: - return 0L; - case FieldType.Float: - return 0f; - case FieldType.Message: - case FieldType.Group: // Never expect to get this, but... - return null; - default: - throw new ArgumentException("Invalid field type"); - } - } + FieldType.Bool => false, + FieldType.Bytes => ByteString.Empty, + FieldType.String => "", + FieldType.Double => 0.0, + FieldType.SInt32 or FieldType.Int32 or FieldType.SFixed32 or FieldType.Enum => 0, + FieldType.Fixed32 or FieldType.UInt32 => (uint)0, + FieldType.Fixed64 or FieldType.UInt64 => 0UL, + FieldType.SFixed64 or FieldType.Int64 or FieldType.SInt64 => 0L, + FieldType.Float => 0f, + FieldType.Message or FieldType.Group => null, + _ => throw new ArgumentException("Invalid field type"), + }; public override void Clear(IMessage message) => clearDelegate(message); public override bool HasValue(IMessage message) => hasDelegate(message); diff --git a/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs index e94e3e6c60..222bc7e60e 100644 --- a/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs +++ b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs @@ -29,6 +29,7 @@ // (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 + using System.Collections.Generic; using System.Linq; @@ -60,9 +61,8 @@ namespace Google.Protobuf.Reflection /// if there is no such message descriptor. public MessageDescriptor Find(string fullName) { - MessageDescriptor ret; // Ignore the return value as ret will end up with the right value either way. - fullNameToMessageMap.TryGetValue(fullName, out ret); + fullNameToMessageMap.TryGetValue(fullName, out MessageDescriptor ret); return ret; } diff --git a/csharp/src/Google.Protobuf/UnknownField.cs b/csharp/src/Google.Protobuf/UnknownField.cs index 4793a6419d..abec1082ba 100644 --- a/csharp/src/Google.Protobuf/UnknownField.cs +++ b/csharp/src/Google.Protobuf/UnknownField.cs @@ -30,9 +30,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using Google.Protobuf.Collections; namespace Google.Protobuf @@ -73,13 +71,12 @@ namespace Google.Protobuf { return true; } - UnknownField otherField = other as UnknownField; - return otherField != null - && Lists.Equals(varintList, otherField.varintList) - && Lists.Equals(fixed32List, otherField.fixed32List) - && Lists.Equals(fixed64List, otherField.fixed64List) - && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList) - && Lists.Equals(groupList, otherField.groupList); + return other is UnknownField otherField + && Lists.Equals(varintList, otherField.varintList) + && Lists.Equals(fixed32List, otherField.fixed32List) + && Lists.Equals(fixed64List, otherField.fixed64List) + && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList) + && Lists.Equals(groupList, otherField.groupList); } /// diff --git a/csharp/src/Google.Protobuf/UnknownFieldSet.cs b/csharp/src/Google.Protobuf/UnknownFieldSet.cs index 9888dd1c3d..b97eb5e205 100644 --- a/csharp/src/Google.Protobuf/UnknownFieldSet.cs +++ b/csharp/src/Google.Protobuf/UnknownFieldSet.cs @@ -32,9 +32,7 @@ using System; using System.Collections.Generic; -using System.IO; using System.Security; -using Google.Protobuf.Reflection; namespace Google.Protobuf { @@ -49,14 +47,13 @@ namespace Google.Protobuf /// public sealed partial class UnknownFieldSet { - private readonly IDictionary fields; + private readonly IDictionary fields = new Dictionary(); /// /// Creates a new UnknownFieldSet. /// internal UnknownFieldSet() { - this.fields = new Dictionary(); } /// @@ -125,8 +122,7 @@ namespace Google.Protobuf } foreach (KeyValuePair leftEntry in fields) { - UnknownField rightValue; - if (!otherFields.TryGetValue(leftEntry.Key, out rightValue)) + if (!otherFields.TryGetValue(leftEntry.Key, out UnknownField rightValue)) { return false; } @@ -170,8 +166,7 @@ namespace Google.Protobuf return null; } - UnknownField existing; - if (fields.TryGetValue(number, out existing)) + if (fields.TryGetValue(number, out UnknownField existing)) { return existing; } diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs index cebbcd2fec..04b64abf4f 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs @@ -112,7 +112,7 @@ namespace Google.Protobuf.WellKnownTypes T target = new T(); if (GetTypeName(TypeUrl) != target.Descriptor.FullName) { - result = default(T); // Can't use null as there's no class constraint, but this always *will* be null in real usage. + result = default; // Can't use null as there's no class constraint, but this always *will* be null in real usage. return false; } target.MergeFrom(Value); diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs index 2f5172f1ca..c52147f796 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs @@ -59,8 +59,8 @@ namespace Google.Protobuf.WellKnownTypes /// The difference between the two specified timestamps. public static Duration operator -(Timestamp lhs, Timestamp rhs) { - ProtoPreconditions.CheckNotNull(lhs, "lhs"); - ProtoPreconditions.CheckNotNull(rhs, "rhs"); + ProtoPreconditions.CheckNotNull(lhs, nameof(lhs)); + ProtoPreconditions.CheckNotNull(rhs, nameof(rhs)); checked { return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos); @@ -75,8 +75,8 @@ namespace Google.Protobuf.WellKnownTypes /// The result of adding the duration to the timestamp. public static Timestamp operator +(Timestamp lhs, Duration rhs) { - ProtoPreconditions.CheckNotNull(lhs, "lhs"); - ProtoPreconditions.CheckNotNull(rhs, "rhs"); + ProtoPreconditions.CheckNotNull(lhs, nameof(lhs)); + ProtoPreconditions.CheckNotNull(rhs, nameof(rhs)); checked { return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos); @@ -91,8 +91,8 @@ namespace Google.Protobuf.WellKnownTypes /// The result of subtracting the duration from the timestamp. public static Timestamp operator -(Timestamp lhs, Duration rhs) { - ProtoPreconditions.CheckNotNull(lhs, "lhs"); - ProtoPreconditions.CheckNotNull(rhs, "rhs"); + ProtoPreconditions.CheckNotNull(lhs, nameof(lhs)); + ProtoPreconditions.CheckNotNull(rhs, nameof(rhs)); checked { return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos); @@ -308,7 +308,7 @@ namespace Google.Protobuf.WellKnownTypes /// true if the two timestamps refer to the same nanosecond public static bool operator ==(Timestamp a, Timestamp b) { - return ReferenceEquals(a, b) || (ReferenceEquals(a, null) ? (ReferenceEquals(b, null) ? true : false) : a.Equals(b)); + return ReferenceEquals(a, b) || (a is null ? (b is null) : a.Equals(b)); } /// diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs index d34b560de0..a6846e78d0 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs @@ -41,7 +41,7 @@ namespace Google.Protobuf.WellKnownTypes /// A newly-created Value message with the given value. public static Value ForString(string value) { - ProtoPreconditions.CheckNotNull(value, "value"); + ProtoPreconditions.CheckNotNull(value, nameof(value)); return new Value { StringValue = value }; } @@ -81,7 +81,7 @@ namespace Google.Protobuf.WellKnownTypes /// A newly-created Value message an initial list value. public static Value ForList(params Value[] values) { - ProtoPreconditions.CheckNotNull(values, "values"); + ProtoPreconditions.CheckNotNull(values, nameof(values)); return new Value { ListValue = new ListValue { Values = { values } } }; } @@ -92,7 +92,7 @@ namespace Google.Protobuf.WellKnownTypes /// A newly-created Value message an initial struct value. public static Value ForStruct(Struct value) { - ProtoPreconditions.CheckNotNull(value, "value"); + ProtoPreconditions.CheckNotNull(value, nameof(value)); return new Value { StructValue = value }; } } diff --git a/csharp/src/Google.Protobuf/WriteBufferHelper.cs b/csharp/src/Google.Protobuf/WriteBufferHelper.cs index f2a59bc56f..9230aa6aef 100644 --- a/csharp/src/Google.Protobuf/WriteBufferHelper.cs +++ b/csharp/src/Google.Protobuf/WriteBufferHelper.cs @@ -32,7 +32,6 @@ using System; using System.Buffers; -using System.IO; using System.Runtime.CompilerServices; using System.Security; diff --git a/csharp/src/Google.Protobuf/WriteContext.cs b/csharp/src/Google.Protobuf/WriteContext.cs index e822e1d6da..082c20e221 100644 --- a/csharp/src/Google.Protobuf/WriteContext.cs +++ b/csharp/src/Google.Protobuf/WriteContext.cs @@ -32,14 +32,8 @@ using System; using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security; -using System.Text; -using Google.Protobuf.Collections; namespace Google.Protobuf { @@ -101,166 +95,112 @@ namespace Google.Protobuf /// Writes a double field value, without a tag. /// /// The value to write - public void WriteDouble(double value) - { - WritingPrimitives.WriteDouble(ref buffer, ref state, value); - } + public void WriteDouble(double value) => WritingPrimitives.WriteDouble(ref buffer, ref state, value); /// /// Writes a float field value, without a tag. /// /// The value to write - public void WriteFloat(float value) - { - WritingPrimitives.WriteFloat(ref buffer, ref state, value); - } + public void WriteFloat(float value) => WritingPrimitives.WriteFloat(ref buffer, ref state, value); /// /// Writes a uint64 field value, without a tag. /// /// The value to write - public void WriteUInt64(ulong value) - { - WritingPrimitives.WriteUInt64(ref buffer, ref state, value); - } + public void WriteUInt64(ulong value) => WritingPrimitives.WriteUInt64(ref buffer, ref state, value); /// /// Writes an int64 field value, without a tag. /// /// The value to write - public void WriteInt64(long value) - { - WritingPrimitives.WriteInt64(ref buffer, ref state, value); - } + public void WriteInt64(long value) => WritingPrimitives.WriteInt64(ref buffer, ref state, value); /// /// Writes an int32 field value, without a tag. /// /// The value to write - public void WriteInt32(int value) - { - WritingPrimitives.WriteInt32(ref buffer, ref state, value); - } + public void WriteInt32(int value) => WritingPrimitives.WriteInt32(ref buffer, ref state, value); /// /// Writes a fixed64 field value, without a tag. /// /// The value to write - public void WriteFixed64(ulong value) - { - WritingPrimitives.WriteFixed64(ref buffer, ref state, value); - } + public void WriteFixed64(ulong value) => WritingPrimitives.WriteFixed64(ref buffer, ref state, value); /// /// Writes a fixed32 field value, without a tag. /// /// The value to write - public void WriteFixed32(uint value) - { - WritingPrimitives.WriteFixed32(ref buffer, ref state, value); - } + public void WriteFixed32(uint value) => WritingPrimitives.WriteFixed32(ref buffer, ref state, value); /// /// Writes a bool field value, without a tag. /// /// The value to write - public void WriteBool(bool value) - { - WritingPrimitives.WriteBool(ref buffer, ref state, value); - } + public void WriteBool(bool value) => WritingPrimitives.WriteBool(ref buffer, ref state, value); /// /// Writes a string field value, without a tag. /// The data is length-prefixed. /// /// The value to write - public void WriteString(string value) - { - WritingPrimitives.WriteString(ref buffer, ref state, value); - } + public void WriteString(string value) => WritingPrimitives.WriteString(ref buffer, ref state, value); /// /// Writes a message, without a tag. /// The data is length-prefixed. /// /// The value to write - public void WriteMessage(IMessage value) - { - WritingPrimitivesMessages.WriteMessage(ref this, value); - } + public void WriteMessage(IMessage value) => WritingPrimitivesMessages.WriteMessage(ref this, value); /// /// Writes a group, without a tag, to the stream. /// /// The value to write - public void WriteGroup(IMessage value) - { - WritingPrimitivesMessages.WriteGroup(ref this, value); - } + public void WriteGroup(IMessage value) => WritingPrimitivesMessages.WriteGroup(ref this, value); /// /// Write a byte string, without a tag, to the stream. /// The data is length-prefixed. /// /// The value to write - public void WriteBytes(ByteString value) - { - WritingPrimitives.WriteBytes(ref buffer, ref state, value); - } + public void WriteBytes(ByteString value) => WritingPrimitives.WriteBytes(ref buffer, ref state, value); /// /// Writes a uint32 value, without a tag. /// /// The value to write - public void WriteUInt32(uint value) - { - WritingPrimitives.WriteUInt32(ref buffer, ref state, value); - } + public void WriteUInt32(uint value) => WritingPrimitives.WriteUInt32(ref buffer, ref state, value); /// /// Writes an enum value, without a tag. /// /// The value to write - public void WriteEnum(int value) - { - WritingPrimitives.WriteEnum(ref buffer, ref state, value); - } + public void WriteEnum(int value) => WritingPrimitives.WriteEnum(ref buffer, ref state, value); /// /// Writes an sfixed32 value, without a tag. /// /// The value to write. - public void WriteSFixed32(int value) - { - WritingPrimitives.WriteSFixed32(ref buffer, ref state, value); - } + public void WriteSFixed32(int value) => WritingPrimitives.WriteSFixed32(ref buffer, ref state, value); /// /// Writes an sfixed64 value, without a tag. /// /// The value to write - public void WriteSFixed64(long value) - { - WritingPrimitives.WriteSFixed64(ref buffer, ref state, value); - } + public void WriteSFixed64(long value) => WritingPrimitives.WriteSFixed64(ref buffer, ref state, value); /// /// Writes an sint32 value, without a tag. /// /// The value to write - public void WriteSInt32(int value) - { - WritingPrimitives.WriteSInt32(ref buffer, ref state, value); - } + public void WriteSInt32(int value) => WritingPrimitives.WriteSInt32(ref buffer, ref state, value); /// /// Writes an sint64 value, without a tag. /// /// The value to write - public void WriteSInt64(long value) - { - WritingPrimitives.WriteSInt64(ref buffer, ref state, value); - } + public void WriteSInt64(long value) => WritingPrimitives.WriteSInt64(ref buffer, ref state, value); /// /// Writes a length (in bytes) for length-delimited data. @@ -269,48 +209,33 @@ namespace Google.Protobuf /// This method simply writes a rawint, but exists for clarity in calling code. /// /// Length value, in bytes. - public void WriteLength(int length) - { - WritingPrimitives.WriteLength(ref buffer, ref state, length); - } + public void WriteLength(int length) => WritingPrimitives.WriteLength(ref buffer, ref state, length); /// /// Encodes and writes a tag. /// /// The number of the field to write the tag for /// The wire format type of the tag to write - public void WriteTag(int fieldNumber, WireFormat.WireType type) - { - WritingPrimitives.WriteTag(ref buffer, ref state, fieldNumber, type); - } + public void WriteTag(int fieldNumber, WireFormat.WireType type) => WritingPrimitives.WriteTag(ref buffer, ref state, fieldNumber, type); /// /// Writes an already-encoded tag. /// /// The encoded tag - public void WriteTag(uint tag) - { - WritingPrimitives.WriteTag(ref buffer, ref state, tag); - } + public void WriteTag(uint tag) => WritingPrimitives.WriteTag(ref buffer, ref state, tag); /// /// Writes the given single-byte tag. /// /// The encoded tag - public void WriteRawTag(byte b1) - { - WritingPrimitives.WriteRawTag(ref buffer, ref state, b1); - } + public void WriteRawTag(byte b1) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1); /// /// Writes the given two-byte tag. /// /// The first byte of the encoded tag /// The second byte of the encoded tag - public void WriteRawTag(byte b1, byte b2) - { - WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2); - } + public void WriteRawTag(byte b1, byte b2) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2); /// /// Writes the given three-byte tag. @@ -318,10 +243,7 @@ namespace Google.Protobuf /// The first byte of the encoded tag /// The second byte of the encoded tag /// The third byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3) - { - WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3); - } + public void WriteRawTag(byte b1, byte b2, byte b3) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3); /// /// Writes the given four-byte tag. @@ -330,10 +252,7 @@ namespace Google.Protobuf /// The second byte of the encoded tag /// The third byte of the encoded tag /// The fourth byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) - { - WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4); - } + public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4); /// /// Writes the given five-byte tag. @@ -343,20 +262,11 @@ namespace Google.Protobuf /// The third byte of the encoded tag /// The fourth byte of the encoded tag /// The fifth byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) - { - WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4, b5); - } + public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) => WritingPrimitives.WriteRawTag(ref buffer, ref state, b1, b2, b3, b4, b5); - internal void Flush() - { - WriteBufferHelper.Flush(ref buffer, ref state); - } + internal void Flush() => WriteBufferHelper.Flush(ref buffer, ref state); - internal void CheckNoSpaceLeft() - { - WriteBufferHelper.CheckNoSpaceLeft(ref state); - } + internal void CheckNoSpaceLeft() => WriteBufferHelper.CheckNoSpaceLeft(ref state); internal void CopyStateTo(CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WriterInternalState.cs b/csharp/src/Google.Protobuf/WriterInternalState.cs index a779305bb7..ea4515a51a 100644 --- a/csharp/src/Google.Protobuf/WriterInternalState.cs +++ b/csharp/src/Google.Protobuf/WriterInternalState.cs @@ -30,20 +30,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; -using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using Google.Protobuf.Collections; - namespace Google.Protobuf { - // warning: this is a mutable struct, so it needs to be only passed as a ref! internal struct WriterInternalState { diff --git a/csharp/src/Google.Protobuf/WritingPrimitives.cs b/csharp/src/Google.Protobuf/WritingPrimitives.cs index 8beefc54c5..cfba5c7288 100644 --- a/csharp/src/Google.Protobuf/WritingPrimitives.cs +++ b/csharp/src/Google.Protobuf/WritingPrimitives.cs @@ -32,7 +32,6 @@ using System; using System.Buffers.Binary; -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; #if GOOGLE_PROTOBUF_SIMD diff --git a/csharp/src/Google.Protobuf/WritingPrimitivesMessages.cs b/csharp/src/Google.Protobuf/WritingPrimitivesMessages.cs index cd2d437915..6e70ee2a00 100644 --- a/csharp/src/Google.Protobuf/WritingPrimitivesMessages.cs +++ b/csharp/src/Google.Protobuf/WritingPrimitivesMessages.cs @@ -30,9 +30,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices.ComTypes; using System.Security; namespace Google.Protobuf diff --git a/java/README.md b/java/README.md index 20f4c9be7b..7e71e66716 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.21.1 + 3.21.2 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.21.1 + 3.21.2 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.21.1' + implementation 'com.google.protobuf:protobuf-java:3.21.2' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index 3813b32528..b4c3465e11 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.21.1 + 3.21.2 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index e32d0aa352..845ff8856a 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 3585f3ae7d..3fec5ec459 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index e7958767bf..43debafe50 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 1a5c951ba3..1ad0019847 100644 --- a/java/lite.md +++ b/java/lite.md @@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following: com.google.protobuf protobuf-javalite - 3.21.1 + 3.21.2 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index 8b1590ba82..7c635ec33f 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 5776cfda91..34475a455a 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index afc912b072..53f90ce6dc 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.1 + 3.21.2 protobuf-java-util diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 5ef108509a..bf3d90eb86 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,11 +10,11 @@ protobuf-opensource@google.com yes - 2022-05-27 - + 2022-06-23 + - 3.21.1 - 3.21.1 + 3.21.2 + 3.21.2 stable @@ -1343,5 +1343,20 @@ G A release. + + + 3.21.2 + 3.21.2 + + + stable + stable + + 2022-06-23 + + BSD-3-Clause + + + diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 6488196ff7..c5dac32909 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.21.1" +#define PHP_PROTOBUF_VERSION "3.21.2" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index 81b068cd83..b6c35f38ae 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1,3 +1,3 @@ -PROTOC_VERSION = '21.1' -PROTOBUF_JAVA_VERSION = '3.21.1' -PROTOBUF_PYTHON_VERSION = '4.21.1' +PROTOC_VERSION = '21.2' +PROTOBUF_JAVA_VERSION = '3.21.2' +PROTOBUF_PYTHON_VERSION = '4.21.2' diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index 06af961d8a..bce8121b46 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.21.1 + 3.21.2 pom Protobuf Compiler diff --git a/python/.repo-metadata.json b/python/.repo-metadata.json new file mode 100644 index 0000000000..c8d71a84ec --- /dev/null +++ b/python/.repo-metadata.json @@ -0,0 +1,11 @@ +{ + "name": "protobuf", + "name_pretty": "Protocol Buffers", + "product_documentation": "https://developers.google.com/protocol-buffers ", + "client_documentation": "https://developers.google.com/protocol-buffers/docs/pythontutorial", + "issue_tracker": "https://github.com/protocolbuffers/protobuf/issues", + "release_level": "ga", + "language": "python", + "repo": "protocolbuffers/protobuf ", + "distribution_name": "protobuf" +} diff --git a/python/README.md b/python/README.md index 27f22c82c0..c7f7828e0b 100644 --- a/python/README.md +++ b/python/README.md @@ -33,7 +33,7 @@ Installation 2) If you do not have setuptools installed, note that it will be downloaded and installed automatically as soon as you run `setup.py`. If you would rather install it manually, you may do so by following - the instructions on [this page](https://packaging.python.org/en/latest/installing.html#setup-for-installing-packages). + the instructions on [this page](https://packaging.python.org/en/latest/tutorials/installing-packages/). 3) Build the C++ code, or install a binary distribution of `protoc`. If you install a binary distribution, make sure that it is the same diff --git a/python/docs/google/protobuf.rst b/python/docs/google/protobuf.rst index b26102e110..6c472e190f 100644 --- a/python/docs/google/protobuf.rst +++ b/python/docs/google/protobuf.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/any_pb2.rst b/python/docs/google/protobuf/any_pb2.rst index b6f47ef3fd..9fca2d2ee6 100644 --- a/python/docs/google/protobuf/any_pb2.rst +++ b/python/docs/google/protobuf/any_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/descriptor.rst b/python/docs/google/protobuf/descriptor.rst index 29b07746f4..5a8a264680 100644 --- a/python/docs/google/protobuf/descriptor.rst +++ b/python/docs/google/protobuf/descriptor.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/descriptor_database.rst b/python/docs/google/protobuf/descriptor_database.rst index 1b8b3904d8..660fc41a71 100644 --- a/python/docs/google/protobuf/descriptor_database.rst +++ b/python/docs/google/protobuf/descriptor_database.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/descriptor_pb2.rst b/python/docs/google/protobuf/descriptor_pb2.rst index 94eec35c34..9f20f49551 100644 --- a/python/docs/google/protobuf/descriptor_pb2.rst +++ b/python/docs/google/protobuf/descriptor_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/descriptor_pool.rst b/python/docs/google/protobuf/descriptor_pool.rst index c2ee33e7b3..aa8de30e99 100644 --- a/python/docs/google/protobuf/descriptor_pool.rst +++ b/python/docs/google/protobuf/descriptor_pool.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/duration_pb2.rst b/python/docs/google/protobuf/duration_pb2.rst index 4233e3cb52..9e9a032a3c 100644 --- a/python/docs/google/protobuf/duration_pb2.rst +++ b/python/docs/google/protobuf/duration_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/empty_pb2.rst b/python/docs/google/protobuf/empty_pb2.rst index c386a4c5c9..f117553691 100644 --- a/python/docs/google/protobuf/empty_pb2.rst +++ b/python/docs/google/protobuf/empty_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/field_mask_pb2.rst b/python/docs/google/protobuf/field_mask_pb2.rst index d9d807069e..1c11f46d11 100644 --- a/python/docs/google/protobuf/field_mask_pb2.rst +++ b/python/docs/google/protobuf/field_mask_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/internal/containers.rst b/python/docs/google/protobuf/internal/containers.rst index c3b8e594a7..67009bc9c1 100644 --- a/python/docs/google/protobuf/internal/containers.rst +++ b/python/docs/google/protobuf/internal/containers.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/json_format.rst b/python/docs/google/protobuf/json_format.rst index eb3b0c5399..71023fcd90 100644 --- a/python/docs/google/protobuf/json_format.rst +++ b/python/docs/google/protobuf/json_format.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/message.rst b/python/docs/google/protobuf/message.rst index a20424807c..c33561fd67 100644 --- a/python/docs/google/protobuf/message.rst +++ b/python/docs/google/protobuf/message.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/message_factory.rst b/python/docs/google/protobuf/message_factory.rst index 93183cc03d..19f66239b3 100644 --- a/python/docs/google/protobuf/message_factory.rst +++ b/python/docs/google/protobuf/message_factory.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/proto_builder.rst b/python/docs/google/protobuf/proto_builder.rst index 36243a2fff..718f612b52 100644 --- a/python/docs/google/protobuf/proto_builder.rst +++ b/python/docs/google/protobuf/proto_builder.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/reflection.rst b/python/docs/google/protobuf/reflection.rst index d177fc02f6..c806834553 100644 --- a/python/docs/google/protobuf/reflection.rst +++ b/python/docs/google/protobuf/reflection.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/service.rst b/python/docs/google/protobuf/service.rst index 6d71f81088..ddc427f360 100644 --- a/python/docs/google/protobuf/service.rst +++ b/python/docs/google/protobuf/service.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/service_reflection.rst b/python/docs/google/protobuf/service_reflection.rst index 30f30dd293..f088c170a0 100644 --- a/python/docs/google/protobuf/service_reflection.rst +++ b/python/docs/google/protobuf/service_reflection.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/struct_pb2.rst b/python/docs/google/protobuf/struct_pb2.rst index 9179eede3c..7b2548788f 100644 --- a/python/docs/google/protobuf/struct_pb2.rst +++ b/python/docs/google/protobuf/struct_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/symbol_database.rst b/python/docs/google/protobuf/symbol_database.rst index 6ea73522f5..99a8c10a61 100644 --- a/python/docs/google/protobuf/symbol_database.rst +++ b/python/docs/google/protobuf/symbol_database.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/text_encoding.rst b/python/docs/google/protobuf/text_encoding.rst index a2eb959dc0..5a070e5db0 100644 --- a/python/docs/google/protobuf/text_encoding.rst +++ b/python/docs/google/protobuf/text_encoding.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/text_format.rst b/python/docs/google/protobuf/text_format.rst index 686b8fc002..5c2c346f3c 100644 --- a/python/docs/google/protobuf/text_format.rst +++ b/python/docs/google/protobuf/text_format.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/timestamp_pb2.rst b/python/docs/google/protobuf/timestamp_pb2.rst index 540df8395d..62e4708843 100644 --- a/python/docs/google/protobuf/timestamp_pb2.rst +++ b/python/docs/google/protobuf/timestamp_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/type_pb2.rst b/python/docs/google/protobuf/type_pb2.rst index e9b19d7b85..cbd4150d1d 100644 --- a/python/docs/google/protobuf/type_pb2.rst +++ b/python/docs/google/protobuf/type_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/google/protobuf/unknown_fields.rst b/python/docs/google/protobuf/unknown_fields.rst new file mode 100644 index 0000000000..7ba283d061 --- /dev/null +++ b/python/docs/google/protobuf/unknown_fields.rst @@ -0,0 +1,21 @@ +.. DO NOT EDIT, generated by generate_docs.py. + +.. ifconfig:: build_env == 'readthedocs' + + .. warning:: + + You are reading the documentation for the `latest committed changes + `_ of + the `Protocol Buffers package for Python + `_. + Some features may not yet be released. Read the documentation for the + latest released package at `googleapis.dev + `_. + +google.protobuf.unknown_fields +============================== + +.. automodule:: google.protobuf.unknown_fields + :members: + :inherited-members: + :undoc-members: diff --git a/python/docs/google/protobuf/wrappers_pb2.rst b/python/docs/google/protobuf/wrappers_pb2.rst index 8f29aa7838..64f9cbbfd1 100644 --- a/python/docs/google/protobuf/wrappers_pb2.rst +++ b/python/docs/google/protobuf/wrappers_pb2.rst @@ -5,7 +5,7 @@ .. warning:: You are reading the documentation for the `latest committed changes - `_ of + `_ of the `Protocol Buffers package for Python `_. Some features may not yet be released. Read the documentation for the diff --git a/python/docs/index.rst b/python/docs/index.rst index 5535b398a9..544b18e02d 100644 --- a/python/docs/index.rst +++ b/python/docs/index.rst @@ -52,6 +52,7 @@ Modules and Packages google/protobuf/text_format google/protobuf/timestamp_pb2 google/protobuf/type_pb2 + google/protobuf/unknown_fields google/protobuf/wrappers_pb2 .. END REFTOC. diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py index 7f84a63fea..dccac5e714 100644 --- a/python/google/protobuf/descriptor_pool.py +++ b/python/google/protobuf/descriptor_pool.py @@ -217,7 +217,7 @@ class DescriptorPool(object): file_desc.serialized_pb = serialized_file_desc_proto return file_desc - # Add Descriptor to descriptor pool is dreprecated. Please use Add() + # Add Descriptor to descriptor pool is deprecated. Please use Add() # or AddSerializedFile() to add a FileDescriptorProto instead. @_Deprecated def AddDescriptor(self, desc): @@ -242,7 +242,7 @@ class DescriptorPool(object): self._descriptors[desc.full_name] = desc self._AddFileDescriptor(desc.file) - # Add EnumDescriptor to descriptor pool is dreprecated. Please use Add() + # Add EnumDescriptor to descriptor pool is deprecated. Please use Add() # or AddSerializedFile() to add a FileDescriptorProto instead. @_Deprecated def AddEnumDescriptor(self, enum_desc): @@ -283,7 +283,7 @@ class DescriptorPool(object): self._top_enum_values[full_name] = enum_value self._AddFileDescriptor(enum_desc.file) - # Add ServiceDescriptor to descriptor pool is dreprecated. Please use Add() + # Add ServiceDescriptor to descriptor pool is deprecated. Please use Add() # or AddSerializedFile() to add a FileDescriptorProto instead. @_Deprecated def AddServiceDescriptor(self, service_desc): @@ -304,7 +304,7 @@ class DescriptorPool(object): service_desc.file.name) self._service_descriptors[service_desc.full_name] = service_desc - # Add ExtensionDescriptor to descriptor pool is dreprecated. Please use Add() + # Add ExtensionDescriptor to descriptor pool is deprecated. Please use Add() # or AddSerializedFile() to add a FileDescriptorProto instead. @_Deprecated def AddExtensionDescriptor(self, extension): diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index cecc370dce..e7aa377519 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.21.1" + s.version = "3.21.2" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index b861c39748..f1bdbf1f1f 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.21.1 + 3.21.2 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.21.1 + 3.21.2 org.jruby diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index 3bcf7eb5f0..676cd587e4 100644 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -105,11 +105,11 @@ class GetDeallocator { }; SerialArena::SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats) - : space_allocated_(b->size) { + : space_allocated_(b->size()) { owner_ = owner; - head_ = b; - ptr_ = b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize); - limit_ = b->Pointer(b->size & static_cast(-8)); + set_head(b); + set_ptr(b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize)); + limit_ = b->Pointer(b->size() & static_cast(-8)); arena_stats_ = stats; } @@ -124,12 +124,12 @@ SerialArena* SerialArena::New(Memory mem, void* owner, template SerialArena::Memory SerialArena::Free(Deallocator deallocator) { - Block* b = head_; - Memory mem = {b, b->size}; + Block* b = head(); + Memory mem = {b, b->size()}; while (b->next) { b = b->next; // We must first advance before deleting this block deallocator(mem); - mem = {b, b->size}; + mem = {b, b->size()}; } return mem; } @@ -141,31 +141,49 @@ void* SerialArena::AllocateAlignedFallback(size_t n, return AllocateFromExisting(n); } +PROTOBUF_NOINLINE +void* SerialArena::AllocateAlignedWithCleanupFallback( + size_t n, size_t align, void (*destructor)(void*), + const AllocationPolicy* policy) { + size_t required = AlignUpTo(n, align) + cleanup::Size(destructor); + AllocateNewBlock(required, policy); + return AllocateFromExistingWithCleanupFallback(n, align, destructor); +} + +PROTOBUF_NOINLINE +void SerialArena::AddCleanupFallback(void* elem, void (*destructor)(void*), + const AllocationPolicy* policy) { + AllocateNewBlock(0, policy); + AddCleanupFromExisting(elem, destructor); +} + void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) { // Sync limit to block - head_->start = reinterpret_cast(limit_); + head()->cleanup_nodes = limit_; // Record how much used in this block. - size_t used = ptr_ - head_->Pointer(kBlockHeaderSize); - size_t wasted = head_->size - used; - space_used_ += used; + size_t used = static_cast(ptr() - head()->Pointer(kBlockHeaderSize)); + size_t wasted = head()->size() - used; + space_used_.store(space_used_.load(std::memory_order_relaxed) + used, + std::memory_order_relaxed); // TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a // win. In preliminary testing showed increased memory savings as expected, // but with a CPU regression. The regression might have been an artifact of // the microbenchmark. - auto mem = AllocateMemory(policy, head_->size, n); + auto mem = AllocateMemory(policy, head()->size(), n); // We don't want to emit an expensive RMW instruction that requires // exclusive access to a cacheline. Hence we write it in terms of a // regular add. - auto relaxed = std::memory_order_relaxed; - space_allocated_.store(space_allocated_.load(relaxed) + mem.size, relaxed); + space_allocated_.store( + space_allocated_.load(std::memory_order_relaxed) + mem.size, + std::memory_order_relaxed); ThreadSafeArenaStats::RecordAllocateStats(arena_stats_, /*used=*/used, /*allocated=*/mem.size, wasted); - head_ = new (mem.ptr) Block{head_, mem.size}; - ptr_ = head_->Pointer(kBlockHeaderSize); - limit_ = head_->Pointer(head_->size); + set_head(new (mem.ptr) Block{head(), mem.size}); + ptr_.store(head()->Pointer(kBlockHeaderSize), std::memory_order_relaxed); + limit_ = head()->Pointer(head()->size()); #ifdef ADDRESS_SANITIZER ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_); @@ -173,24 +191,63 @@ void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) { } uint64_t SerialArena::SpaceUsed() const { - uint64_t space_used = ptr_ - head_->Pointer(kBlockHeaderSize); - space_used += space_used_; + // Note: the calculation below technically causes a race with + // AllocateNewBlock when called from another thread (which happens in + // ThreadSafeArena::SpaceUsed). However, worst-case space_used_ will have + // stale data and the calculation will incorrectly assume 100% + // usage of the *current* block. + // TODO(mkruskal) Consider eliminating this race in exchange for a possible + // performance hit on ARM (see cl/455186837). + const uint64_t current_block_size = head()->size(); + uint64_t space_used = std::min( + static_cast( + ptr() - const_cast(head())->Pointer(kBlockHeaderSize)), + current_block_size); + space_used += space_used_.load(std::memory_order_relaxed); // Remove the overhead of the SerialArena itself. space_used -= ThreadSafeArena::kSerialArenaSize; return space_used; } void SerialArena::CleanupList() { - Block* b = head_; - b->start = reinterpret_cast(limit_); + Block* b = head(); + b->cleanup_nodes = limit_; do { - auto* limit = reinterpret_cast( - b->Pointer(b->size & static_cast(-8))); - auto it = b->start; - auto num = limit - it; - if (num > 0) { - for (; it < limit; it++) { - it->cleanup(it->elem); + char* limit = reinterpret_cast( + b->Pointer(b->size() & static_cast(-8))); + char* it = reinterpret_cast(b->cleanup_nodes); + if (it < limit) { + // A prefetch distance of 8 here was chosen arbitrarily. It makes the + // pending nodes fill a cacheline which seemed nice. + constexpr int kPrefetchDist = 8; + cleanup::Tag pending_type[kPrefetchDist]; + char* pending_node[kPrefetchDist]; + + int pos = 0; + for (; pos < kPrefetchDist && it < limit; ++pos) { + pending_type[pos] = cleanup::Type(it); + pending_node[pos] = it; + it += cleanup::Size(pending_type[pos]); + } + + if (pos < kPrefetchDist) { + for (int i = 0; i < pos; ++i) { + cleanup::DestroyNode(pending_type[i], pending_node[i]); + } + } else { + pos = 0; + while (it < limit) { + cleanup::PrefetchNode(it); + cleanup::DestroyNode(pending_type[pos], pending_node[pos]); + pending_type[pos] = cleanup::Type(it); + pending_node[pos] = it; + it += cleanup::Size(pending_type[pos]); + pos = (pos + 1) % kPrefetchDist; + } + for (int i = pos; i < pos + kPrefetchDist; ++i) { + cleanup::DestroyNode(pending_type[i % kPrefetchDist], + pending_node[i % kPrefetchDist]); + } } } b = b->next; @@ -290,12 +347,9 @@ void ThreadSafeArena::InitializeWithPolicy(void* mem, size_t size, #undef GOOGLE_DCHECK_POLICY_FLAGS_ } -void ThreadSafeArena::Init() { -#ifndef NDEBUG - const bool was_message_owned = IsMessageOwned(); -#endif // NDEBUG +uint64_t ThreadSafeArena::GetNextLifeCycleId() { ThreadCache& tc = thread_cache(); - auto id = tc.next_lifecycle_id; + uint64_t id = tc.next_lifecycle_id; // We increment lifecycle_id's by multiples of two so we can use bit 0 as // a tag. constexpr uint64_t kDelta = 2; @@ -308,14 +362,19 @@ void ThreadSafeArena::Init() { id = lifecycle_id_generator_.id.fetch_add(1, relaxed) * kInc; } tc.next_lifecycle_id = id + kDelta; - // Message ownership is stored in tag_and_id_, and is set in the constructor. - // This flag bit must be preserved, even across calls to Reset(). - tag_and_id_ = id | (tag_and_id_ & kMessageOwnedArena); - hint_.store(nullptr, std::memory_order_relaxed); + return id; +} + +void ThreadSafeArena::Init() { + const bool message_owned = IsMessageOwned(); + if (!message_owned) { + // Message-owned arenas bypass thread cache and do not need life cycle ID. + tag_and_id_ = GetNextLifeCycleId(); + } else { + GOOGLE_DCHECK_EQ(tag_and_id_, kMessageOwnedArena); + } threads_.store(nullptr, std::memory_order_relaxed); -#ifndef NDEBUG - GOOGLE_CHECK_EQ(was_message_owned, IsMessageOwned()); -#endif // NDEBUG + GOOGLE_DCHECK_EQ(message_owned, IsMessageOwned()); arena_stats_ = Sample(); } @@ -370,7 +429,6 @@ uint64_t ThreadSafeArena::Reset() { // Discard all blocks except the special block (if present). size_t space_allocated = 0; auto mem = Free(&space_allocated); - arena_stats_.RecordReset(); AllocationPolicy* policy = alloc_policy_.get(); if (policy) { diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index ee4b4db607..b629780822 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -90,15 +90,10 @@ class RepeatedPtrFieldBase; // defined in repeated_ptr_field.h template class GenericTypeHandler; // defined in repeated_field.h -// Templated cleanup methods. -template -void arena_destruct_object(void* object) { - reinterpret_cast(object)->~T(); -} - template struct ObjectDestructor { - constexpr static void (*destructor)(void*) = &arena_destruct_object; + constexpr static void (*destructor)(void*) = + &internal::cleanup::arena_destruct_object; }; template @@ -362,9 +357,12 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final { // sizes of the underlying blocks. uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); } // Returns the total space used by the arena. Similar to SpaceAllocated but - // does not include free space and block overhead. The total space returned - // may not include space used by other threads executing concurrently with - // the call to this method. + // does not include free space and block overhead. This is a best-effort + // estimate and may inaccurately calculate space used by other threads + // executing concurrently with the call to this method. These inaccuracies + // are due to race conditions, and are bounded but unpredictable. Stale data + // can lead to underestimates of the space used, and race conditions can lead + // to overestimates (up to the current block size). uint64_t SpaceUsed() const { return impl_.SpaceUsed(); } // Frees all storage allocated by this arena after calling destructors @@ -389,7 +387,7 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final { template PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) { if (object != NULL) { - impl_.AddCleanup(object, &internal::arena_destruct_object); + impl_.AddCleanup(object, &internal::cleanup::arena_destruct_object); } } diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h index 0bfceb413a..743b62c641 100644 --- a/src/google/protobuf/arena_impl.h +++ b/src/google/protobuf/arena_impl.h @@ -35,12 +35,14 @@ #include #include +#include #include #include #include #include + #ifdef ADDRESS_SANITIZER #include #endif // ADDRESS_SANITIZER @@ -62,12 +64,12 @@ enum { kCacheAlignment = 64 }; enum { kCacheAlignment = alignof(max_align_t) }; // do the best we can #endif -inline constexpr size_t AlignUpTo8(size_t n) { +inline PROTOBUF_ALWAYS_INLINE constexpr size_t AlignUpTo8(size_t n) { // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.) return (n + 7) & static_cast(-8); } -inline constexpr size_t AlignUpTo(size_t n, size_t a) { +inline PROTOBUF_ALWAYS_INLINE constexpr size_t AlignUpTo(size_t n, size_t a) { // We are wasting space by over allocating align - 8 bytes. Compared to a // dedicated function that takes current alignment in consideration. Such a // scheme would only waste (align - 8)/2 bytes on average, but requires a @@ -85,6 +87,124 @@ inline PROTOBUF_ALWAYS_INLINE void* AlignTo(void* p, size_t a) { } } +namespace cleanup { + +template +void arena_destruct_object(void* object) { + reinterpret_cast(object)->~T(); +} + +enum class Tag : uintptr_t { + kDynamic = 0, // {void* elem, void (*destructor)(void*)} + kString = 1, // std::string* | kString +}; + +constexpr bool EnableSpecializedTags() { + return alignof(std::string) >= 8 + ; +} + +// All node types must start with a `uintptr_t` that stores `Tag` in its low +// two bits. +struct DynamicNode { + uintptr_t elem; + void (*destructor)(void*); +}; + +struct StringNode { + uintptr_t elem; +}; + + +inline PROTOBUF_ALWAYS_INLINE void CreateNode(Tag tag, void* pos, + const void* elem, + void (*destructor)(void*)) { + if (EnableSpecializedTags()) { + switch (tag) { + case Tag::kString: { + StringNode n = {reinterpret_cast(elem) | + static_cast(Tag::kString)}; + memcpy(pos, &n, sizeof(n)); + return; + } + default: + break; + } + } + DynamicNode n = {reinterpret_cast(elem), destructor}; + memcpy(pos, &n, sizeof(n)); +} + +inline PROTOBUF_ALWAYS_INLINE void PrefetchNode(const void* elem_address) { +} + +inline PROTOBUF_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) { + if (EnableSpecializedTags()) { + switch (tag) { + case Tag::kString: { + StringNode n; + memcpy(&n, pos, sizeof(n)); + auto* s = reinterpret_cast(n.elem & ~0x7ULL); + // Some compilers don't like fully qualified explicit dtor calls, + // so use an alias to avoid having to type `::`. + using string_type = std::string; + s->~string_type(); + return; + } + default: + break; + } + } + DynamicNode n; + memcpy(&n, pos, sizeof(n)); + n.destructor(reinterpret_cast(n.elem)); +} + +inline PROTOBUF_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) { + if (EnableSpecializedTags()) { + if (destructor == &arena_destruct_object) { + return Tag::kString; + } + } + return Tag::kDynamic; +} + +inline PROTOBUF_ALWAYS_INLINE Tag Type(void* raw) { + if (!EnableSpecializedTags()) return Tag::kDynamic; + + uintptr_t elem; + memcpy(&elem, raw, sizeof(elem)); + switch (static_cast(elem & 0x7ULL)) { + case Tag::kDynamic: + return Tag::kDynamic; + case Tag::kString: + return Tag::kString; + default: + GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL); + return Tag::kDynamic; + } +} + +inline PROTOBUF_ALWAYS_INLINE size_t Size(Tag tag) { + if (!EnableSpecializedTags()) return sizeof(DynamicNode); + + switch (tag) { + case Tag::kDynamic: + return sizeof(DynamicNode); + case Tag::kString: + return sizeof(StringNode); + default: + GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast(tag); + return sizeof(DynamicNode); + } +} + +inline PROTOBUF_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) { + return destructor == nullptr ? 0 : Size(Type(destructor)); +} + +} // namespace cleanup + using LifecycleIdAtomic = uint64_t; // MetricsCollector collects stats for a particular arena. @@ -220,13 +340,6 @@ enum class AllocationClient { kDefault, kArray }; // contains the information on block growth policy and backing memory allocation // used. class PROTOBUF_EXPORT SerialArena { - // Node contains the ptr of the object to be cleaned up and the associated - // cleanup function ptr. - struct CleanupNode { - void* elem; // Pointer to the object to be cleaned up. - void (*cleanup)(void*); // Function pointer to the destructor or deleter. - }; - public: struct Memory { void* ptr; @@ -240,7 +353,7 @@ class PROTOBUF_EXPORT SerialArena { uint64_t SpaceUsed() const; bool HasSpace(size_t n) const { - return n <= static_cast(limit_ - ptr_); + return n <= static_cast(limit_ - ptr()); } // See comments on `cached_blocks_` member for details. @@ -272,7 +385,7 @@ class PROTOBUF_EXPORT SerialArena { template void* AllocateAligned(size_t n, const AllocationPolicy* policy) { GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned. - GOOGLE_DCHECK_GE(limit_, ptr_); + GOOGLE_DCHECK_GE(limit_, ptr()); if (alloc_client == AllocationClient::kArray) { if (void* res = TryAllocateFromCachedBlock(n)) { @@ -289,10 +402,10 @@ class PROTOBUF_EXPORT SerialArena { private: void* AllocateFromExisting(size_t n) { #ifdef ADDRESS_SANITIZER - ASAN_UNPOISON_MEMORY_REGION(ptr_, n); + ASAN_UNPOISON_MEMORY_REGION(ptr(), n); #endif // ADDRESS_SANITIZER - void* ret = ptr_; - ptr_ += n; + void* ret = ptr(); + set_ptr(static_cast(ret) + n); return ret; } @@ -321,7 +434,16 @@ class PROTOBUF_EXPORT SerialArena { std::copy(cached_blocks_, cached_blocks_ + cached_block_length_, new_list); + +#ifdef ADDRESS_SANITIZER + // We need to unpoison this memory before filling it in case it has been + // poisoned by another santizer client. + ASAN_UNPOISON_MEMORY_REGION( + new_list + cached_block_length_, + (new_size - cached_block_length_) * sizeof(CachedBlock*)); +#endif std::fill(new_list + cached_block_length_, new_list + new_size, nullptr); + cached_blocks_ = new_list; // Make the size fit in uint8_t. This is the power of two, so we don't // need anything larger. @@ -344,28 +466,31 @@ class PROTOBUF_EXPORT SerialArena { // Allocate space if the current region provides enough space. bool MaybeAllocateAligned(size_t n, void** out) { GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned. - GOOGLE_DCHECK_GE(limit_, ptr_); + GOOGLE_DCHECK_GE(limit_, ptr()); if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false; *out = AllocateFromExisting(n); return true; } + PROTOBUF_ALWAYS_INLINE void* AllocateAlignedWithCleanup(size_t n, size_t align, void (*destructor)(void*), const AllocationPolicy* policy) { - size_t required = AlignUpTo(n, align) + kCleanupSize; + size_t required = AlignUpTo(n, align) + cleanup::Size(destructor); if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) { - AllocateNewBlock(required, policy); + return AllocateAlignedWithCleanupFallback(n, align, destructor, policy); } return AllocateFromExistingWithCleanupFallback(n, align, destructor); } - void AddCleanup(void* elem, void (*cleanup)(void*), + PROTOBUF_ALWAYS_INLINE + void AddCleanup(void* elem, void (*destructor)(void*), const AllocationPolicy* policy) { - if (PROTOBUF_PREDICT_FALSE(!HasSpace(kCleanupSize))) { - AllocateNewBlock(kCleanupSize, policy); + size_t required = cleanup::Size(destructor); + if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) { + return AddCleanupFallback(elem, destructor, policy); } - AddCleanupFromExisting(elem, cleanup); + AddCleanupFromExisting(elem, destructor); } private: @@ -377,18 +502,22 @@ class PROTOBUF_EXPORT SerialArena { #endif // ADDRESS_SANITIZER void* ret = internal::AlignTo(ptr_, align); ptr_ += n; + GOOGLE_DCHECK_GE(limit_, ptr_); AddCleanupFromExisting(ret, destructor); return ret; } - void AddCleanupFromExisting(void* elem, void (*cleanup)(void*)) { + PROTOBUF_ALWAYS_INLINE + void AddCleanupFromExisting(void* elem, void (*destructor)(void*)) { + cleanup::Tag tag = cleanup::Type(destructor); + size_t n = cleanup::Size(tag); + #ifdef ADDRESS_SANITIZER - ASAN_UNPOISON_MEMORY_REGION(limit_ - kCleanupSize, kCleanupSize); + ASAN_UNPOISON_MEMORY_REGION(limit_ - n, n); #endif // ADDRESS_SANITIZER - limit_ -= kCleanupSize; - auto c = reinterpret_cast(limit_); - c->elem = elem; - c->cleanup = cleanup; + limit_ -= n; + GOOGLE_DCHECK_GE(limit_, ptr_); + cleanup::CreateNode(tag, limit_, elem, destructor); } public: @@ -411,29 +540,45 @@ class PROTOBUF_EXPORT SerialArena { // Blocks are variable length malloc-ed objects. The following structure // describes the common header for all blocks. struct Block { - Block(Block* next, size_t size) : next(next), size(size), start(nullptr) {} + Block(Block* next, size_t size) + : next(next), cleanup_nodes(nullptr), relaxed_size(size) {} char* Pointer(size_t n) { - GOOGLE_DCHECK(n <= size); + GOOGLE_DCHECK(n <= size()); return reinterpret_cast(this) + n; } + size_t size() const { return relaxed_size.load(std::memory_order_relaxed); } + Block* const next; - const size_t size; - CleanupNode* start; + void* cleanup_nodes; + + private: + const std::atomic relaxed_size; // data follows }; void* owner_; // &ThreadCache of this thread; - Block* head_; // Head of linked list of blocks. + std::atomic head_; // Head of linked list of blocks. SerialArena* next_; // Next SerialArena in this linked list. - size_t space_used_ = 0; // Necessary for metrics. + std::atomic space_used_{0}; // Necessary for metrics. std::atomic space_allocated_; // Next pointer to allocate from. Always 8-byte aligned. Points inside // head_ (and head_->pos will always be non-canonical). We keep these // here to reduce indirection. - char* ptr_; + std::atomic ptr_; + + // Helper getters/setters to handle relaxed operations on atomic variables. + Block* head() { return head_.load(std::memory_order_relaxed); } + const Block* head() const { return head_.load(std::memory_order_relaxed); } + void set_head(Block* head) { + return head_.store(head, std::memory_order_relaxed); + } + char* ptr() { return ptr_.load(std::memory_order_relaxed); } + const char* ptr() const { return ptr_.load(std::memory_order_relaxed); } + void set_ptr(char* ptr) { return ptr_.store(ptr, std::memory_order_relaxed); } + // Limiting address up to which memory can be allocated from the head block. char* limit_; // For holding sampling information. The pointer is owned by the @@ -457,11 +602,15 @@ class PROTOBUF_EXPORT SerialArena { // Constructor is private as only New() should be used. inline SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats); void* AllocateAlignedFallback(size_t n, const AllocationPolicy* policy); + void* AllocateAlignedWithCleanupFallback(size_t n, size_t align, + void (*destructor)(void*), + const AllocationPolicy* policy); + void AddCleanupFallback(void* elem, void (*destructor)(void*), + const AllocationPolicy* policy); void AllocateNewBlock(size_t n, const AllocationPolicy* policy); public: static constexpr size_t kBlockHeaderSize = AlignUpTo8(sizeof(Block)); - static constexpr size_t kCleanupSize = AlignUpTo8(sizeof(CleanupNode)); }; // Tag type used to invoke the constructor of message-owned arena. @@ -537,7 +686,7 @@ class PROTOBUF_EXPORT ThreadSafeArena { PROTOBUF_NDEBUG_INLINE bool MaybeAllocateAligned(size_t n, void** out) { SerialArena* arena; if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() && - GetSerialArenaFromThreadCache(&arena))) { + GetSerialArenaFast(&arena))) { return arena->MaybeAllocateAligned(n, out); } return false; @@ -556,6 +705,8 @@ class PROTOBUF_EXPORT ThreadSafeArena { } private: + static uint64_t GetNextLifeCycleId(); + // Unique for each arena. Changes on Reset(). uint64_t tag_and_id_ = 0; // The LSB of tag_and_id_ indicates if the arena is message-owned. @@ -567,7 +718,6 @@ class PROTOBUF_EXPORT ThreadSafeArena { "SerialArena needs to be trivially destructible."); // Pointer to a linked list of SerialArena. std::atomic threads_; - std::atomic hint_; // Fast thread-local block access const AllocationPolicy* AllocPolicy() const { return alloc_policy_.get(); } void InitializeFrom(void* mem, size_t size); @@ -583,36 +733,14 @@ class PROTOBUF_EXPORT ThreadSafeArena { // Delete or Destruct all objects owned by the arena. void CleanupList(); - inline uint64_t LifeCycleId() const { - return tag_and_id_ & ~kMessageOwnedArena; - } - inline void CacheSerialArena(SerialArena* serial) { - thread_cache().last_serial_arena = serial; - thread_cache().last_lifecycle_id_seen = tag_and_id_; - // TODO(haberman): evaluate whether we would gain efficiency by getting rid - // of hint_. It's the only write we do to ThreadSafeArena in the allocation - // path, which will dirty the cache line. - - hint_.store(serial, std::memory_order_release); - } - - PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) { - if (GetSerialArenaFromThreadCache(arena)) return true; - - // Check whether we own the last accessed SerialArena on this arena. This - // fast path optimizes the case where a single thread uses multiple arenas. - ThreadCache* tc = &thread_cache(); - SerialArena* serial = hint_.load(std::memory_order_acquire); - if (PROTOBUF_PREDICT_TRUE(serial != nullptr && serial->owner() == tc)) { - *arena = serial; - return true; + if (!IsMessageOwned()) { + thread_cache().last_serial_arena = serial; + thread_cache().last_lifecycle_id_seen = tag_and_id_; } - return false; } - PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFromThreadCache( - SerialArena** arena) { + PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) { // If this thread already owns a block in this arena then try to use that. // This fast path optimizes the case where multiple threads allocate from // the same arena. diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 017b5f8097..6c88505d8d 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -791,7 +791,7 @@ TEST(ArenaTest, AddAllocatedWithReflection) { } TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) { -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifndef PROTOBUF_FUTURE_REMOVE_CLEARED_API { RepeatedPtrField repeated_field; EXPECT_TRUE(repeated_field.empty()); @@ -802,7 +802,7 @@ TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) { EXPECT_TRUE(repeated_field.empty()); EXPECT_EQ(0, repeated_field.size()); } -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // !PROTOBUF_FUTURE_REMOVE_CLEARED_API { RepeatedPtrField repeated_field; EXPECT_TRUE(repeated_field.empty()); @@ -1530,14 +1530,19 @@ TEST(ArenaTest, SpaceReuseForArraysSizeChecks) { TEST(ArenaTest, SpaceReusePoisonsAndUnpoisonsMemory) { #ifdef ADDRESS_SANITIZER char buf[1024]{}; + constexpr int kSize = 32; { Arena arena(buf, sizeof(buf)); std::vector pointers; for (int i = 0; i < 100; ++i) { - pointers.push_back(Arena::CreateArray(&arena, 16)); + void* p = Arena::CreateArray(&arena, kSize); + // Simulate other ASan client managing shadow memory. + ASAN_POISON_MEMORY_REGION(p, kSize); + ASAN_UNPOISON_MEMORY_REGION(p, kSize - 4); + pointers.push_back(p); } for (void* p : pointers) { - internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, 16); + internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, kSize); // The first one is not poisoned because it becomes the freelist. if (p != pointers[0]) EXPECT_TRUE(__asan_address_is_poisoned(p)); } @@ -1562,91 +1567,6 @@ TEST(ArenaTest, SpaceReusePoisonsAndUnpoisonsMemory) { #endif // ADDRESS_SANITIZER } -namespace { -uint32_t hooks_num_init = 0; -uint32_t hooks_num_allocations = 0; -uint32_t hooks_num_reset = 0; -uint32_t hooks_num_destruct = 0; - -void ClearHookCounts() { - hooks_num_init = 0; - hooks_num_allocations = 0; - hooks_num_reset = 0; - hooks_num_destruct = 0; -} -} // namespace - -// A helper utility class that handles arena callbacks. -class ArenaOptionsTestFriend final : public internal::ArenaMetricsCollector { - public: - static internal::ArenaMetricsCollector* NewWithAllocs() { - return new ArenaOptionsTestFriend(true); - } - - static internal::ArenaMetricsCollector* NewWithoutAllocs() { - return new ArenaOptionsTestFriend(false); - } - - static void Enable(ArenaOptions* options) { - ClearHookCounts(); - options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithAllocs; - } - - static void EnableWithoutAllocs(ArenaOptions* options) { - ClearHookCounts(); - options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithoutAllocs; - } - - explicit ArenaOptionsTestFriend(bool record_allocs) - : ArenaMetricsCollector(record_allocs) { - ++hooks_num_init; - } - void OnDestroy(uint64_t space_allocated) override { - ++hooks_num_destruct; - delete this; - } - void OnReset(uint64_t space_allocated) override { ++hooks_num_reset; } - void OnAlloc(const std::type_info* allocated_type, - uint64_t alloc_size) override { - ++hooks_num_allocations; - } -}; - -// Test the hooks are correctly called. -TEST(ArenaTest, ArenaHooksSanity) { - ArenaOptions options; - ArenaOptionsTestFriend::Enable(&options); - - // Scope for defining the arena - { - Arena arena(options); - EXPECT_EQ(1, hooks_num_init); - EXPECT_EQ(0, hooks_num_allocations); - Arena::Create(&arena); - if (std::is_trivially_destructible::value) { - EXPECT_EQ(1, hooks_num_allocations); - } else { - EXPECT_EQ(2, hooks_num_allocations); - } - arena.Reset(); - arena.Reset(); - EXPECT_EQ(2, hooks_num_reset); - } - EXPECT_EQ(2, hooks_num_reset); - EXPECT_EQ(1, hooks_num_destruct); -} - -// Test that allocation hooks are not called when we don't need them. -TEST(ArenaTest, ArenaHooksWhenAllocationsNotNeeded) { - ArenaOptions options; - ArenaOptionsTestFriend::EnableWithoutAllocs(&options); - - Arena arena(options); - EXPECT_EQ(0, hooks_num_allocations); - Arena::Create(&arena); - EXPECT_EQ(0, hooks_num_allocations); -} - } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/arenaz_sampler.cc b/src/google/protobuf/arenaz_sampler.cc index 965a2de69e..6ad3a36504 100644 --- a/src/google/protobuf/arenaz_sampler.cc +++ b/src/google/protobuf/arenaz_sampler.cc @@ -69,7 +69,6 @@ ThreadSafeArenaStats::~ThreadSafeArenaStats() = default; void ThreadSafeArenaStats::PrepareForSampling(int64_t stride) { num_allocations.store(0, std::memory_order_relaxed); - num_resets.store(0, std::memory_order_relaxed); bytes_used.store(0, std::memory_order_relaxed); bytes_allocated.store(0, std::memory_order_relaxed); bytes_wasted.store(0, std::memory_order_relaxed); @@ -82,21 +81,6 @@ void ThreadSafeArenaStats::PrepareForSampling(int64_t stride) { depth = absl::GetStackTrace(stack, kMaxStackDepth, /* skip_count= */ 0); } -void RecordResetSlow(ThreadSafeArenaStats* info) { - const size_t max_bytes = - info->max_bytes_allocated.load(std::memory_order_relaxed); - const size_t allocated_bytes = - info->bytes_allocated.load(std::memory_order_relaxed); - if (max_bytes < allocated_bytes) { - info->max_bytes_allocated.store(allocated_bytes); - } - info->bytes_used.store(0, std::memory_order_relaxed); - info->bytes_allocated.store(0, std::memory_order_relaxed); - info->bytes_wasted.store(0, std::memory_order_relaxed); - info->num_allocations.store(0, std::memory_order_relaxed); - info->num_resets.fetch_add(1, std::memory_order_relaxed); -} - void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used, size_t allocated, size_t wasted) { info->num_allocations.fetch_add(1, std::memory_order_relaxed); @@ -144,6 +128,10 @@ void SetThreadSafeArenazSampleParameter(int32_t rate) { } } +int32_t ThreadSafeArenazSampleParameter() { + return g_arenaz_sample_parameter.load(std::memory_order_relaxed); +} + void SetThreadSafeArenazMaxSamples(int32_t max) { if (max > 0) { GlobalThreadSafeArenazSampler().SetMaxSamples(max); @@ -171,6 +159,7 @@ ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) { void SetThreadSafeArenazEnabled(bool enabled) {} void SetThreadSafeArenazSampleParameter(int32_t rate) {} +int32_t ThreadSafeArenazSampleParameter() { return 0; } void SetThreadSafeArenazMaxSamples(int32_t max) {} void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {} #endif // defined(PROTOBUF_ARENAZ_SAMPLE) diff --git a/src/google/protobuf/arenaz_sampler.h b/src/google/protobuf/arenaz_sampler.h index 31097ec169..4a04c6a953 100644 --- a/src/google/protobuf/arenaz_sampler.h +++ b/src/google/protobuf/arenaz_sampler.h @@ -45,7 +45,6 @@ namespace internal { #if defined(PROTOBUF_ARENAZ_SAMPLE) struct ThreadSafeArenaStats; -void RecordResetSlow(ThreadSafeArenaStats* info); void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used, size_t allocated, size_t wasted); // Stores information about a sampled thread safe arena. All mutations to this @@ -67,16 +66,15 @@ struct ThreadSafeArenaStats // These fields are mutated by the various Record* APIs and need to be // thread-safe. std::atomic num_allocations; - std::atomic num_resets; std::atomic bytes_used; std::atomic bytes_allocated; std::atomic bytes_wasted; - // Records the largest size an arena ever had. Maintained across resets. + // Records the largest size an arena ever had. std::atomic max_bytes_allocated; // Bit `i` is set to 1 indicates that a thread with `tid % 63 = i` accessed // the underlying arena. We use `% 63` as a rudimentary hash to ensure some // bit mixing for thread-ids; `% 64` would only grab the low bits and might - // create sampling artifacts. Maintained across resets. + // create sampling artifacts. std::atomic thread_ids; // All of the fields below are set by `PrepareForSampling`, they must not @@ -131,11 +129,6 @@ class ThreadSafeArenaStatsHandle { return *this; } - void RecordReset() { - if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return; - RecordResetSlow(info_); - } - ThreadSafeArenaStats* MutableStats() { return info_; } friend void swap(ThreadSafeArenaStatsHandle& lhs, @@ -212,6 +205,9 @@ void SetThreadSafeArenazEnabled(bool enabled); // Sets the rate at which thread safe arena will be sampled. void SetThreadSafeArenazSampleParameter(int32_t rate); +// Returns the rate at which thread safe arena will be sampled. +int32_t ThreadSafeArenazSampleParameter(); + // Sets a soft max for the number of samples that will be kept. void SetThreadSafeArenazMaxSamples(int32_t max); diff --git a/src/google/protobuf/arenaz_sampler_test.cc b/src/google/protobuf/arenaz_sampler_test.cc index 6eae73c1dc..7bac100ee1 100644 --- a/src/google/protobuf/arenaz_sampler_test.cc +++ b/src/google/protobuf/arenaz_sampler_test.cc @@ -86,7 +86,6 @@ TEST(ThreadSafeArenaStatsTest, PrepareForSampling) { info.PrepareForSampling(kTestStride); EXPECT_EQ(info.num_allocations.load(), 0); - EXPECT_EQ(info.num_resets.load(), 0); EXPECT_EQ(info.bytes_used.load(), 0); EXPECT_EQ(info.bytes_allocated.load(), 0); EXPECT_EQ(info.bytes_wasted.load(), 0); @@ -94,7 +93,6 @@ TEST(ThreadSafeArenaStatsTest, PrepareForSampling) { EXPECT_EQ(info.weight, kTestStride); info.num_allocations.store(1, std::memory_order_relaxed); - info.num_resets.store(1, std::memory_order_relaxed); info.bytes_used.store(1, std::memory_order_relaxed); info.bytes_allocated.store(1, std::memory_order_relaxed); info.bytes_wasted.store(1, std::memory_order_relaxed); @@ -102,7 +100,6 @@ TEST(ThreadSafeArenaStatsTest, PrepareForSampling) { info.PrepareForSampling(2 * kTestStride); EXPECT_EQ(info.num_allocations.load(), 0); - EXPECT_EQ(info.num_resets.load(), 0); EXPECT_EQ(info.bytes_used.load(), 0); EXPECT_EQ(info.bytes_allocated.load(), 0); EXPECT_EQ(info.bytes_wasted.load(), 0); @@ -117,7 +114,6 @@ TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) { info.PrepareForSampling(kTestStride); RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0); EXPECT_EQ(info.num_allocations.load(), 1); - EXPECT_EQ(info.num_resets.load(), 0); EXPECT_EQ(info.bytes_used.load(), 100); EXPECT_EQ(info.bytes_allocated.load(), 128); EXPECT_EQ(info.bytes_wasted.load(), 0); @@ -125,26 +121,28 @@ TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) { RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256, /*wasted=*/28); EXPECT_EQ(info.num_allocations.load(), 2); - EXPECT_EQ(info.num_resets.load(), 0); EXPECT_EQ(info.bytes_used.load(), 200); EXPECT_EQ(info.bytes_allocated.load(), 384); EXPECT_EQ(info.bytes_wasted.load(), 28); EXPECT_EQ(info.max_bytes_allocated.load(), 0); } -TEST(ThreadSafeArenaStatsTest, RecordResetSlow) { - ThreadSafeArenaStats info; - constexpr int64_t kTestStride = 584; - MutexLock l(&info.init_mu); - info.PrepareForSampling(kTestStride); - EXPECT_EQ(info.num_resets.load(), 0); - EXPECT_EQ(info.bytes_allocated.load(), 0); - RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0); - EXPECT_EQ(info.num_resets.load(), 0); - EXPECT_EQ(info.bytes_allocated.load(), 128); - RecordResetSlow(&info); - EXPECT_EQ(info.num_resets.load(), 1); - EXPECT_EQ(info.bytes_allocated.load(), 0); +TEST(ThreadSafeArenazSamplerTest, SamplingCorrectness) { + SetThreadSafeArenazEnabled(true); + for (int p = 0; p <= 15; ++p) { + SetThreadSafeArenazSampleParameter(1 << p); + SetThreadSafeArenazGlobalNextSample(1 << p); + const int kTrials = 1000 << p; + std::vector hv; + for (int i = 0; i < kTrials; ++i) { + ThreadSafeArenaStatsHandle h = Sample(); + if (h.MutableStats() != nullptr) hv.push_back(std::move(h)); + } + // Ideally samples << p should be very close to kTrials. But we keep a + // factor of two guard band. + EXPECT_GE(hv.size() << p, kTrials / 2); + EXPECT_LE(hv.size() << p, 2 * kTrials); + } } TEST(ThreadSafeArenazSamplerTest, SmallSampleParameter) { diff --git a/src/google/protobuf/compiler/cpp/map_field.cc b/src/google/protobuf/compiler/cpp/map_field.cc index 3a55ef5352..1810c6496b 100644 --- a/src/google/protobuf/compiler/cpp/map_field.cc +++ b/src/google/protobuf/compiler/cpp/map_field.cc @@ -40,12 +40,6 @@ namespace google { namespace protobuf { namespace compiler { namespace cpp { - -bool IsProto3Field(const FieldDescriptor* field_descriptor) { - const FileDescriptor* file_descriptor = field_descriptor->file(); - return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - void SetMessageVariables(const FieldDescriptor* descriptor, std::map* variables, const Options& options) { diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index db4d209777..68c7d162b4 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -82,8 +82,9 @@ int TagSize(uint32_t field_number) { return 2; } -std::string FieldParseFunctionName( - const TailCallTableInfo::FieldEntryInfo& entry, const Options& options); +void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry, + const Options& options, + TailCallTableInfo::FastFieldInfo& info); bool IsFieldEligibleForFastParsing( const TailCallTableInfo::FieldEntryInfo& entry, const Options& options, @@ -196,18 +197,12 @@ std::vector SplitFastFieldsForSize( // Fill in this field's entry: GOOGLE_CHECK(info.func_name.empty()) << info.func_name; - info.func_name = FieldParseFunctionName(entry, options); info.field = field; info.coded_tag = tag; + PopulateFastFieldEntry(entry, options, info); // If this field does not have presence, then it can set an out-of-bounds // bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32). info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63; - if (IsStringInlined(field, options)) { - GOOGLE_CHECK(!field->is_repeated()); - info.aux_idx = static_cast(entry.inlined_string_idx); - } else { - info.aux_idx = static_cast(entry.aux_idx); - } } return result; } @@ -375,6 +370,8 @@ TailCallTableInfo::TailCallTableInfo( enum_values[0] <= std::numeric_limits::max() && enum_values.size() <= std::numeric_limits::max()) { entry.is_enum_range = true; + entry.enum_range_min = enum_values.front(); + entry.enum_range_max = enum_values.back(); aux_entries.push_back( StrCat(enum_values[0], ", ", enum_values.size())); } else { @@ -1658,10 +1655,12 @@ void ParseFunctionGenerator::GenerateFieldSwitch( namespace { -std::string FieldParseFunctionName( - const TailCallTableInfo::FieldEntryInfo& entry, const Options& options) { +void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry, + const Options& options, + TailCallTableInfo::FastFieldInfo& info) { const FieldDescriptor* field = entry.field; std::string name = "::_pbi::TcParser::Fast"; + uint8_t aux_idx = static_cast(entry.aux_idx); switch (field->type()) { case FieldDescriptor::TYPE_FIXED32: @@ -1695,9 +1694,22 @@ std::string FieldParseFunctionName( } if (field->is_repeated() && field->is_packed()) { GOOGLE_LOG(DFATAL) << "Enum validation not handled: " << field->DebugString(); - return ""; + return; + } + if (entry.is_enum_range) { + name.append("Er"); + if (entry.enum_range_max <= 127) { + if (entry.enum_range_min == 0) { + name.append("0"); + aux_idx = entry.enum_range_max; + } else if (entry.enum_range_min == 1) { + name.append("1"); + aux_idx = entry.enum_range_max; + } + } + } else { + name.append("Ev"); } - name.append(entry.is_enum_range ? "Er" : "Ev"); break; case FieldDescriptor::TYPE_SINT32: @@ -1727,10 +1739,12 @@ std::string FieldParseFunctionName( default: GOOGLE_LOG(DFATAL) << "Mode not handled: " << static_cast(GetUtf8CheckMode(field, options)); - return ""; + return; } if (IsStringInlined(field, options)) { name.append("i"); + GOOGLE_CHECK(!field->is_repeated()); + aux_idx = static_cast(entry.inlined_string_idx); } break; @@ -1743,7 +1757,7 @@ std::string FieldParseFunctionName( default: GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString(); - return ""; + return; } // The field implementation functions are prefixed by cardinality: @@ -1758,7 +1772,8 @@ std::string FieldParseFunctionName( // Append the tag length. Fast parsing only handles 1- or 2-byte tags. name.append(TagSize(field->number()) == 1 ? "1" : "2"); - return name; + info.func_name = std::move(name); + info.aux_idx = aux_idx; } } // namespace diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.h b/src/google/protobuf/compiler/cpp/parse_function_generator.h index 542a15a06a..973d9130a2 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.h +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.h @@ -72,6 +72,8 @@ struct TailCallTableInfo { uint16_t aux_idx; // True for enums entirely covered by the start/length fields of FieldAux: bool is_enum_range; + int32_t enum_range_min; + int32_t enum_range_max; }; std::vector field_entries; std::vector aux_entries; diff --git a/src/google/protobuf/compiler/java/doc_comment.cc b/src/google/protobuf/compiler/java/doc_comment.cc index 066bff6432..d5fadb63cf 100644 --- a/src/google/protobuf/compiler/java/doc_comment.cc +++ b/src/google/protobuf/compiler/java/doc_comment.cc @@ -37,8 +37,10 @@ #include #include +#include #include #include +#include namespace google { namespace protobuf { @@ -103,26 +105,63 @@ std::string EscapeJavadoc(const std::string& input) { return result; } +static std::string EscapeKdoc(const std::string& input) { + std::string result; + result.reserve(input.size() * 2); + + char prev = 'a'; + + for (char c : input) { + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + default: + result.push_back(c); + break; + } + + prev = c; + } + + return result; +} + static void WriteDocCommentBodyForLocation(io::Printer* printer, - const SourceLocation& location) { + const SourceLocation& location, + const bool kdoc) { std::string comments = location.leading_comments.empty() ? location.trailing_comments : location.leading_comments; if (!comments.empty()) { - // TODO(kenton): Ideally we should parse the comment text as Markdown and - // write it back as HTML, but this requires a Markdown parser. For now - // we just use
 to get fixed-width text formatting.
-
-    // If the comment itself contains block comment start or end markers,
-    // HTML-escape them so that they don't accidentally close the doc comment.
-    comments = EscapeJavadoc(comments);
+    if (!kdoc) {
+      comments = EscapeJavadoc(comments);
+    }
 
     std::vector lines = Split(comments, "\n");
     while (!lines.empty() && lines.back().empty()) {
       lines.pop_back();
     }
 
-    printer->Print(" * 
\n");
+    if (kdoc) {
+      printer->Print(" * ```\n");
+    } else {
+      printer->Print(" * 
\n");
+    }
+
     for (int i = 0; i < lines.size(); i++) {
       // Most lines should start with a space.  Watch out for lines that start
       // with a /, since putting that right after the leading asterisk will
@@ -133,18 +172,23 @@ static void WriteDocCommentBodyForLocation(io::Printer* printer,
         printer->Print(" *$line$\n", "line", lines[i]);
       }
     }
-    printer->Print(
-        " * 
\n" - " *\n"); + + if (kdoc) { + printer->Print(" * ```\n"); + } else { + printer->Print(" *
\n"); + } + printer->Print(" *\n"); } } template static void WriteDocCommentBody(io::Printer* printer, - const DescriptorType* descriptor) { + const DescriptorType* descriptor, + const bool kdoc) { SourceLocation location; if (descriptor->GetSourceLocation(&location)) { - WriteDocCommentBodyForLocation(printer, location); + WriteDocCommentBodyForLocation(printer, location, kdoc); } } @@ -164,16 +208,36 @@ static std::string FirstLineOf(const std::string& value) { return result; } -void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { +static void WriteDebugString(io::Printer* printer, const FieldDescriptor* field, + const bool kdoc) { + if (kdoc) { + printer->Print(" * `$def$`\n", "def", + EscapeKdoc(FirstLineOf(field->DebugString()))); + } else { + printer->Print(" * $def$\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + } +} + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message, + const bool kdoc) { printer->Print("/**\n"); - WriteDocCommentBody(printer, message); - printer->Print( - " * Protobuf type {@code $fullname$}\n" - " */\n", - "fullname", EscapeJavadoc(message->full_name())); + WriteDocCommentBody(printer, message, kdoc); + if (kdoc) { + printer->Print( + " * Protobuf type `$fullname$`\n" + " */\n", + "fullname", EscapeKdoc(message->full_name())); + } else { + printer->Print( + " * Protobuf type {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(message->full_name())); + } } -void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field, + const bool kdoc) { // We start the comment with the main body based on the comments from the // .proto file (if present). We then continue with the field declaration, // e.g.: @@ -181,9 +245,14 @@ void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { // And then we end with the javadoc tags if applicable. // If the field is a group, the debug string might end with {. printer->Print("/**\n"); - WriteDocCommentBody(printer, field); - printer->Print(" * $def$\n", "def", - EscapeJavadoc(FirstLineOf(field->DebugString()))); + WriteDocCommentBody(printer, field, kdoc); + if (kdoc) { + printer->Print(" * `$def$`\n", "def", + EscapeKdoc(FirstLineOf(field->DebugString()))); + } else { + printer->Print(" * $def$\n", "def", + EscapeJavadoc(FirstLineOf(field->DebugString()))); + } printer->Print(" */\n"); } @@ -214,12 +283,11 @@ void WriteDeprecatedJavadoc(io::Printer* printer, const FieldDescriptor* field, void WriteFieldAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder) { + const bool builder, const bool kdoc) { printer->Print("/**\n"); - WriteDocCommentBody(printer, field); - printer->Print(" * $def$\n", "def", - EscapeJavadoc(FirstLineOf(field->DebugString()))); - WriteDeprecatedJavadoc(printer, field, type); + WriteDocCommentBody(printer, field, kdoc); + WriteDebugString(printer, field, kdoc); + if (!kdoc) WriteDeprecatedJavadoc(printer, field, type); switch (type) { case HAZZER: printer->Print(" * @return Whether the $name$ field is set.\n", "name", @@ -273,12 +341,12 @@ void WriteFieldAccessorDocComment(io::Printer* printer, void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder) { + const bool builder, + const bool kdoc) { printer->Print("/**\n"); - WriteDocCommentBody(printer, field); - printer->Print(" * $def$\n", "def", - EscapeJavadoc(FirstLineOf(field->DebugString()))); - WriteDeprecatedJavadoc(printer, field, type); + WriteDocCommentBody(printer, field, kdoc); + WriteDebugString(printer, field, kdoc); + if (!kdoc) WriteDeprecatedJavadoc(printer, field, type); switch (type) { case HAZZER: // Should never happen @@ -343,12 +411,12 @@ void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder) { + const bool builder, + const bool kdoc) { printer->Print("/**\n"); - WriteDocCommentBody(printer, field); - printer->Print(" * $def$\n", "def", - EscapeJavadoc(FirstLineOf(field->DebugString()))); - WriteDeprecatedJavadoc(printer, field, type); + WriteDocCommentBody(printer, field, kdoc); + WriteDebugString(printer, field, kdoc); + if (!kdoc) WriteDeprecatedJavadoc(printer, field, type); switch (type) { case HAZZER: // Should never happen @@ -399,19 +467,28 @@ void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, // Enum -void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_, + const bool kdoc) { printer->Print("/**\n"); - WriteDocCommentBody(printer, enum_); - printer->Print( - " * Protobuf enum {@code $fullname$}\n" - " */\n", - "fullname", EscapeJavadoc(enum_->full_name())); + WriteDocCommentBody(printer, enum_, kdoc); + if (kdoc) { + printer->Print( + " * Protobuf enum `$fullname$`\n" + " */\n", + "fullname", EscapeKdoc(enum_->full_name())); + } else { + printer->Print( + " * Protobuf enum {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(enum_->full_name())); + } } void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) { printer->Print("/**\n"); - WriteDocCommentBody(printer, value); + WriteDocCommentBody(printer, value, /* kdoc */ false); + printer->Print( " * $def$\n" " */\n", @@ -421,7 +498,7 @@ void WriteEnumValueDocComment(io::Printer* printer, void WriteServiceDocComment(io::Printer* printer, const ServiceDescriptor* service) { printer->Print("/**\n"); - WriteDocCommentBody(printer, service); + WriteDocCommentBody(printer, service, /* kdoc */ false); printer->Print( " * Protobuf service {@code $fullname$}\n" " */\n", @@ -431,7 +508,7 @@ void WriteServiceDocComment(io::Printer* printer, void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) { printer->Print("/**\n"); - WriteDocCommentBody(printer, method); + WriteDocCommentBody(printer, method, /* kdoc */ false); printer->Print( " * $def$\n" " */\n", diff --git a/src/google/protobuf/compiler/java/doc_comment.h b/src/google/protobuf/compiler/java/doc_comment.h index 7f687781fb..03672bf52d 100644 --- a/src/google/protobuf/compiler/java/doc_comment.h +++ b/src/google/protobuf/compiler/java/doc_comment.h @@ -67,21 +67,27 @@ enum FieldAccessorType { LIST_MULTI_ADDER }; -void WriteMessageDocComment(io::Printer* printer, const Descriptor* message); -void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field); +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message, + const bool kdoc = false); +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field, + const bool kdoc = false); void WriteFieldAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder = false); + const bool builder = false, + const bool kdoc = false); void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder = false); + const bool builder = false, + const bool kdoc = false); void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, const FieldDescriptor* field, const FieldAccessorType type, - const bool builder = false); -void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_); + const bool builder = false, + const bool kdoc = false); +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_, + const bool kdoc = false); void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value); void WriteServiceDocComment(io::Printer* printer, diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc index 4a93addbe1..c1cb11e51e 100644 --- a/src/google/protobuf/compiler/java/enum_field.cc +++ b/src/google/protobuf/compiler/java/enum_field.cc @@ -271,7 +271,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers( void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -282,14 +282,15 @@ void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -1072,7 +1073,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -1083,7 +1084,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -1094,7 +1095,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -1106,7 +1107,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -1117,7 +1118,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1130,7 +1131,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1142,7 +1143,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc index 6fe683fe0b..bd69f844dd 100644 --- a/src/google/protobuf/compiler/java/enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/enum_field_lite.cc @@ -286,7 +286,7 @@ void ImmutableEnumFieldLiteGenerator::GenerateBuilderMembers( void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -297,14 +297,15 @@ void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -830,7 +831,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -841,7 +842,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -852,7 +853,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -864,7 +865,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -875,7 +876,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -888,7 +889,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -900,7 +901,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/map_field.cc b/src/google/protobuf/compiler/java/map_field.cc index ce0766129c..c430b69939 100644 --- a/src/google/protobuf/compiler/java/map_field.cc +++ b/src/google/protobuf/compiler/java/map_field.cc @@ -706,7 +706,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "$kt_deprecation$ val $kt_name$: " @@ -718,7 +718,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n" " )\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@JvmName(\"put$kt_capitalized_name$\")\n" @@ -728,7 +728,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -740,7 +740,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " put(key, value)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -751,7 +751,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -763,7 +763,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" diff --git a/src/google/protobuf/compiler/java/map_field_lite.cc b/src/google/protobuf/compiler/java/map_field_lite.cc index 7e5f829ba4..7657829c86 100644 --- a/src/google/protobuf/compiler/java/map_field_lite.cc +++ b/src/google/protobuf/compiler/java/map_field_lite.cc @@ -849,7 +849,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "$kt_deprecation$ val $kt_name$: " @@ -861,7 +861,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n" " )\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@JvmName(\"put$kt_capitalized_name$\")\n" @@ -871,7 +871,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -883,7 +883,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " put(key, value)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -894,7 +894,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -906,7 +906,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n" " }\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" diff --git a/src/google/protobuf/compiler/java/message.cc b/src/google/protobuf/compiler/java/message.cc index 5adacef3ad..44c85723ac 100644 --- a/src/google/protobuf/compiler/java/message.cc +++ b/src/google/protobuf/compiler/java/message.cc @@ -1451,6 +1451,7 @@ void ImmutableMessageGenerator::GenerateKotlinMembers( "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), "message", name_resolver_->GetClassName(descriptor_, true)); + WriteMessageDocComment(printer, descriptor_, /* kdoc */ true); printer->Print("object $name$Kt {\n", "name", descriptor_->name()); printer->Indent(); GenerateKotlinDsl(printer); diff --git a/src/google/protobuf/compiler/java/message_field.cc b/src/google/protobuf/compiler/java/message_field.cc index f3833e978c..85fb5d4a14 100644 --- a/src/google/protobuf/compiler/java/message_field.cc +++ b/src/google/protobuf/compiler/java/message_field.cc @@ -419,7 +419,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMembers( void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -430,13 +430,14 @@ void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -1422,7 +1423,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -1433,7 +1434,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -1444,7 +1445,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -1456,7 +1457,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -1467,7 +1468,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1480,7 +1481,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1492,7 +1493,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/message_field_lite.cc b/src/google/protobuf/compiler/java/message_field_lite.cc index eb37ca682c..627aaeef37 100644 --- a/src/google/protobuf/compiler/java/message_field_lite.cc +++ b/src/google/protobuf/compiler/java/message_field_lite.cc @@ -288,7 +288,7 @@ void ImmutableMessageFieldLiteGenerator::GenerateBuilderMembers( void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -299,13 +299,14 @@ void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -809,7 +810,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -820,7 +821,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -831,7 +832,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -843,7 +844,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -854,7 +855,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -867,7 +868,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -879,7 +880,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/message_lite.cc b/src/google/protobuf/compiler/java/message_lite.cc index a42ae3f301..5ad41a061a 100644 --- a/src/google/protobuf/compiler/java/message_lite.cc +++ b/src/google/protobuf/compiler/java/message_lite.cc @@ -792,6 +792,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinMembers( "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), "message", name_resolver_->GetClassName(descriptor_, true)); + WriteMessageDocComment(printer, descriptor_, /* kdoc */ true); printer->Print("object $name$Kt {\n", "name", descriptor_->name()); printer->Indent(); GenerateKotlinDsl(printer); diff --git a/src/google/protobuf/compiler/java/primitive_field.cc b/src/google/protobuf/compiler/java/primitive_field.cc index 9ec99f953b..69de34bc10 100644 --- a/src/google/protobuf/compiler/java/primitive_field.cc +++ b/src/google/protobuf/compiler/java/primitive_field.cc @@ -318,7 +318,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers( void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -329,14 +329,15 @@ void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -852,7 +853,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -863,7 +864,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -874,7 +875,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -886,7 +887,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -897,7 +898,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -910,7 +911,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -922,7 +923,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.cc b/src/google/protobuf/compiler/java/primitive_field_lite.cc index e323feff2a..daf6566f62 100644 --- a/src/google/protobuf/compiler/java/primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/primitive_field_lite.cc @@ -334,14 +334,15 @@ void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -685,7 +686,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( " )\n"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -696,7 +697,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -708,7 +709,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" @@ -719,7 +720,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -732,7 +733,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -744,7 +745,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/string_field.cc b/src/google/protobuf/compiler/java/string_field.cc index 3228da6d4a..d3162a4dc7 100644 --- a/src/google/protobuf/compiler/java/string_field.cc +++ b/src/google/protobuf/compiler/java/string_field.cc @@ -377,7 +377,7 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers( void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: kotlin.String\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -388,14 +388,15 @@ void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -967,7 +968,8 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( " : com.google.protobuf.kotlin.DslProxy()\n"); // property for List - WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER, + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" @@ -979,7 +981,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( // List.add(String) WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -991,7 +993,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( // List += String WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -1004,7 +1006,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( // List.addAll(Iterable) WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1017,7 +1019,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( // List += Iterable WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1031,7 +1033,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( // List[Int] = String WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -1043,7 +1045,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/compiler/java/string_field_lite.cc b/src/google/protobuf/compiler/java/string_field_lite.cc index 8e5b230b8b..b8861977b1 100644 --- a/src/google/protobuf/compiler/java/string_field_lite.cc +++ b/src/google/protobuf/compiler/java/string_field_lite.cc @@ -311,7 +311,7 @@ void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers( void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); + WriteFieldDocComment(printer, descriptor_, /* kdoc */ true); printer->Print(variables_, "$kt_deprecation$var $kt_name$: kotlin.String\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" @@ -322,14 +322,15 @@ void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( " }\n"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); if (HasHazzer(descriptor_)) { - WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); + WriteFieldAccessorDocComment(printer, descriptor_, HAZZER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" @@ -752,7 +753,8 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( " : com.google.protobuf.kotlin.DslProxy()\n"); // property for List - WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); + WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER, + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "$kt_deprecation$ val $kt_name$: " @@ -766,7 +768,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( // List.add(String) WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" @@ -778,7 +780,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( // List += String WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" @@ -791,7 +793,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( // List.addAll(Iterable) WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -804,7 +806,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( // List += Iterable WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -818,7 +820,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( // List[Int] = String WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print( variables_, "@kotlin.jvm.JvmSynthetic\n" @@ -830,7 +832,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( "}"); WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, - /* builder */ false); + /* builder */ false, /* kdoc */ true); printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 1ea1250f8b..e016e4d831 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -356,6 +356,15 @@ class PROTOBUF_EXPORT TcParser final { static const char* FastEvR1(PROTOBUF_TC_PARAM_DECL); static const char* FastEvR2(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr0S1(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr0S2(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr0R1(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr0R2(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr1S1(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr1S2(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr1R1(PROTOBUF_TC_PARAM_DECL); + static const char* FastEr1R2(PROTOBUF_TC_PARAM_DECL); + // Functions referenced by generated fast tables (string types): // B: bytes S: string U: UTF-8 string // (empty): ArenaStringPtr i: InlinedString @@ -449,6 +458,9 @@ class PROTOBUF_EXPORT TcParser final { private: friend class GeneratedTcTableLiteTest; + static void* MaybeGetSplitBase(MessageLite* msg, const bool is_split, + const TcParseTableBase* table, + google::protobuf::internal::ParseContext* ctx); template static inline const char* SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL); @@ -526,8 +538,12 @@ class PROTOBUF_EXPORT TcParser final { // Implementations for fast enum field parsing functions: template static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL); + template + static inline const char* SingularEnumSmallRange(PROTOBUF_TC_PARAM_DECL); template static inline const char* RepeatedEnum(PROTOBUF_TC_PARAM_DECL); + template + static inline const char* RepeatedEnumSmallRange(PROTOBUF_TC_PARAM_DECL); // Implementations for fast string field parsing functions: enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 }; diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc index 8e4036974e..77ce7311e9 100644 --- a/src/google/protobuf/generated_message_tctable_lite.cc +++ b/src/google/protobuf/generated_message_tctable_lite.cc @@ -66,26 +66,25 @@ const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) { // Core fast parsing implementation: ////////////////////////////////////////////////////////////////////////////// -class TcParser::ScopedArenaSwap final { - public: - ScopedArenaSwap(MessageLite* msg, ParseContext* ctx) - : ctx_(ctx), saved_(ctx->data().arena) { - ctx_->data().arena = msg->GetArenaForAllocation(); - } - ScopedArenaSwap(const ScopedArenaSwap&) = delete; - ~ScopedArenaSwap() { ctx_->data().arena = saved_; } - - private: - ParseContext* const ctx_; - Arena* const saved_; -}; - PROTOBUF_NOINLINE const char* TcParser::ParseLoop( MessageLite* msg, const char* ptr, ParseContext* ctx, const TcParseTableBase* table) { - ScopedArenaSwap saved(msg, ctx); + // Note: TagDispatch uses a dispatch table at "&table->fast_entries". + // For fast dispatch, we'd like to have a pointer to that, but if we use + // that expression, there's no easy way to get back to "table", which we also + // need during dispatch. It turns out that "table + 1" points exactly to + // fast_entries, so we just increment table by 1 here, to get the register + // holding the value we want. + table += 1; while (!ctx->Done(&ptr)) { - ptr = TagDispatch(msg, ptr, ctx, table, 0, {}); +#if defined(__GNUC__) + // Note: this asm prevents the compiler (clang, specifically) from + // believing (thanks to CSE) that it needs to dedicate a registeer both + // to "table" and "&table->fast_entries". + // TODO(b/64614992): remove this asm + asm("" : "+r"(table)); +#endif + ptr = TagDispatch(msg, ptr, ctx, table - 1, 0, {}); if (ptr == nullptr) break; if (ctx->LastTag() != 1) break; // Ended on terminating tag } @@ -388,7 +387,7 @@ inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl( if (aux_is_table) { const auto* inner_table = table->field_aux(data.aux_idx())->table; if (field == nullptr) { - field = inner_table->default_instance->New(ctx->data().arena); + field = inner_table->default_instance->New(msg->GetArenaForAllocation()); } if (group_coding) { return ctx->ParseGroup(field, ptr, FastDecodeTag(saved_tag), @@ -399,7 +398,7 @@ inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl( if (field == nullptr) { const MessageLite* default_instance = table->field_aux(data.aux_idx())->message_default(); - field = default_instance->New(ctx->data().arena); + field = default_instance->New(msg->GetArenaForAllocation()); } if (group_coding) { return ctx->ParseGroup(field, ptr, FastDecodeTag(saved_tag)); @@ -850,7 +849,13 @@ PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint( const ::google::protobuf::internal::TcParseTableBase* table; uint64_t hasbits; }; - volatile Spill spill = {data.data, msg, table, hasbits}; + Spill spill = {data.data, msg, table, hasbits}; +#if defined(__GNUC__) + // This empty asm block convinces the compiler that the contents of spill may + // have changed, and thus can't be cached in registers. It's similar to, but + // more optimal then, the effect of declaring it "volatile". + asm("" : "+m"(spill)); +#endif uint64_t tmp; PROTOBUF_ASSUME(static_cast(*ptr) < 0); @@ -1167,6 +1172,91 @@ const char* TcParser::FastEvR2(PROTOBUF_TC_PARAM_DECL) { PROTOBUF_TC_PARAM_PASS); } +template +PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnumSmallRange( + PROTOBUF_TC_PARAM_DECL) { + if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { + PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); + } + + uint8_t v = ptr[sizeof(TagType)]; + if (PROTOBUF_PREDICT_FALSE(min > v || v > data.aux_idx())) { + PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); + } + + RefAt(msg, data.offset()) = v; + ptr += sizeof(TagType) + 1; + hasbits |= (uint64_t{1} << data.hasbit_idx()); + PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr0S1(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return SingularEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr0S2(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return SingularEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr1S1(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return SingularEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr1S2(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return SingularEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + + +template +PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedEnumSmallRange( + PROTOBUF_TC_PARAM_DECL) { + if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { + InvertPacked(data); + if (data.coded_tag() == 0) { + // Packed parsing is handled by generated fallback. + PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS); + } else { + PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); + } + } + auto& field = RefAt>(msg, data.offset()); + auto expected_tag = UnalignedLoad(ptr); + const uint8_t max = data.aux_idx(); + do { + uint8_t v = ptr[sizeof(TagType)]; + if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) { + PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); + } + field.Add(static_cast(v)); + ptr += sizeof(TagType) + 1; + if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) break; + } while (UnalignedLoad(ptr) == expected_tag); + + PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr0R1(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} +const char* TcParser::FastEr0R2(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + +const char* TcParser::FastEr1R1(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} +const char* TcParser::FastEr1R2(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange( + PROTOBUF_TC_PARAM_PASS); +} + ////////////////////////////////////////////////////////////////////////////// // String/bytes fields ////////////////////////////////////////////////////////////////////////////// @@ -1206,7 +1296,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString( ptr += sizeof(TagType); hasbits |= (uint64_t{1} << data.hasbit_idx()); auto& field = RefAt(msg, data.offset()); - auto arena = ctx->data().arena; + auto arena = msg->GetArenaForAllocation(); if (arena) { ptr = ctx->ReadArenaString(ptr, &field, arena); } else { @@ -1395,7 +1485,7 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table, case field_layout::kRepGroup: case field_layout::kRepIWeak: { auto& field = RefAt(msg, current_entry->offset); - if (!ctx->data().arena) { + if (!msg->GetArenaForAllocation()) { delete field; } break; @@ -1421,10 +1511,11 @@ uint32_t GetSplitOffset(const TcParseTableBase* table) { uint32_t GetSizeofSplit(const TcParseTableBase* table) { return table->field_aux(kSplitSizeIdx)->offset; } +} // namespace -void* MaybeGetSplitBase(MessageLite* msg, const bool is_split, - const TcParseTableBase* table, - ::google::protobuf::internal::ParseContext* ctx) { +void* TcParser::MaybeGetSplitBase(MessageLite* msg, const bool is_split, + const TcParseTableBase* table, + ::google::protobuf::internal::ParseContext* ctx) { void* out = msg; if (is_split) { const uint32_t split_offset = GetSplitOffset(table); @@ -1434,7 +1525,7 @@ void* MaybeGetSplitBase(MessageLite* msg, const bool is_split, if (split == default_split) { // Allocate split instance when needed. uint32_t size = GetSizeofSplit(table); - Arena* arena = ctx->data().arena; + Arena* arena = msg->GetArenaForAllocation(); split = (arena == nullptr) ? ::operator new(size) : arena->AllocateAligned(size); memcpy(split, default_split, size); @@ -1443,7 +1534,6 @@ void* MaybeGetSplitBase(MessageLite* msg, const bool is_split, } return out; } -} // namespace template const char* TcParser::MpFixed(PROTOBUF_TC_PARAM_DECL) { @@ -1792,12 +1882,12 @@ const char* TcParser::MpString(PROTOBUF_TC_PARAM_DECL) { } bool is_valid = false; - Arena* arena = ctx->data().arena; void* const base = MaybeGetSplitBase(msg, is_split, table, ctx); switch (rep) { case field_layout::kRepAString: { auto& field = RefAt(base, entry.offset); if (need_init) field.InitDefault(); + Arena* arena = msg->GetArenaForAllocation(); if (arena) { ptr = ctx->ReadArenaString(ptr, &field, arena); } else { @@ -1912,7 +2002,7 @@ const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) { if ((type_card & field_layout::kTvMask) == field_layout::kTvTable) { auto* inner_table = table->field_aux(&entry)->table; if (need_init || field == nullptr) { - field = inner_table->default_instance->New(ctx->data().arena); + field = inner_table->default_instance->New(msg->GetArenaForAllocation()); } if (is_group) { return ctx->ParseGroup(field, ptr, decoded_tag, inner_table); @@ -1920,8 +2010,8 @@ const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) { return ctx->ParseMessage(field, ptr, inner_table); } else { if (need_init || field == nullptr) { - field = - table->field_aux(&entry)->message_default()->New(ctx->data().arena); + field = table->field_aux(&entry)->message_default()->New( + msg->GetArenaForAllocation()); } if (is_group) { return ctx->ParseGroup(field, ptr, decoded_tag); diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 3e044f742f..724a6220f0 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -406,6 +406,15 @@ PROTOBUF_NOINLINE GenericTypeHandler::GetOwningArena(Message* value) { return value->GetOwningArena(); } + +template void InternalMetadata::DoClear(); +template void InternalMetadata::DoMergeFrom( + const UnknownFieldSet& other); +template void InternalMetadata::DoSwap(UnknownFieldSet* other); +template Arena* InternalMetadata::DeleteOutOfLineHelper(); +template UnknownFieldSet* +InternalMetadata::mutable_unknown_fields_slow(); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index d098c81d79..7042a13342 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -1040,6 +1040,7 @@ class PROTOBUF_EXPORT Reflection final { return schema_.IsSplit(field); } + friend class FastReflectionBase; friend class FastReflectionMessageMutator; friend bool internal::IsDescendant(Message& root, const Message& message); diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc index 7526ead779..44e3b3151c 100644 --- a/src/google/protobuf/message_unittest.inc +++ b/src/google/protobuf/message_unittest.inc @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include #ifndef _MSC_VER @@ -285,6 +287,32 @@ TEST(MESSAGE_TEST_NAME, MergeFromUninitialized) { EXPECT_TRUE(TestUtil::EqualsToSerialized(q, p.SerializePartialAsString())); } +TEST(MESSAGE_TEST_NAME, UninitializedAndTooDeep) { + UNITTEST::TestRequiredForeign original; + original.mutable_optional_message()->set_a(1); + original.mutable_optional_lazy_message() + ->mutable_child() + ->mutable_payload() + ->set_optional_int64(0); + + std::string data; + ASSERT_TRUE(original.SerializePartialToString(&data)); + + UNITTEST::TestRequiredForeign pass; + ASSERT_TRUE(pass.ParsePartialFromString(data)); + ASSERT_FALSE(pass.IsInitialized()); + + io::ArrayInputStream array_stream(data.data(), data.size()); + io::CodedInputStream input_stream(&array_stream); + input_stream.SetRecursionLimit(2); + + UNITTEST::TestRequiredForeign fail; + EXPECT_FALSE(fail.ParsePartialFromCodedStream(&input_stream)); + + UNITTEST::TestRequiredForeign fail_uninitialized; + EXPECT_FALSE(fail_uninitialized.ParseFromString(data)); +} + TEST(MESSAGE_TEST_NAME, ExplicitLazyExceedRecursionLimit) { UNITTEST::NestedTestAllTypes original, parsed; // Build proto with recursion depth of 3. @@ -1146,5 +1174,94 @@ TEST(MESSAGE_TEST_NAME, PreservesFloatingPointNegative0) { std::signbit(out_message.optional_double())); } +std::string EncodeEnumValue(int number, int value, int non_canonical_bytes) { + uint8_t buf[100]; + uint8_t* p = buf; + + p = internal::WireFormatLite::WriteEnumToArray(number, value, p); + // varint can have a max of 10 bytes. + while (non_canonical_bytes-- > 0 && p - buf < 10) { + // Add a dummy byte at the end. + p[-1] |= 0x80; + p[0] = 0; + ++p; + } + + return std::string(buf, p); +} + +std::string EncodeOtherField() { + UNITTEST::EnumParseTester obj; + obj.set_other_field(1); + return obj.SerializeAsString(); +} + +TEST(MESSAGE_TEST_NAME, TestEnumParsers) { + UNITTEST::EnumParseTester obj; + + const auto other_field = EncodeOtherField(); + + constexpr int kInvalidValue = 0x900913; + auto* ref = obj.GetReflection(); + auto* descriptor = obj.descriptor(); + for (bool use_tail_field : {false, true}) { + SCOPED_TRACE(use_tail_field); + for (int non_canonical_bytes = 0; non_canonical_bytes < 5; + ++non_canonical_bytes) { + SCOPED_TRACE(non_canonical_bytes); + for (int i = 0; i < descriptor->field_count(); ++i) { + const auto* field = descriptor->field(i); + if (field->name() == "other_field") continue; + SCOPED_TRACE(field->full_name()); + const auto* enum_desc = field->enum_type(); + for (int e = 0; e < enum_desc->value_count(); ++e) { + const auto* value_desc = enum_desc->value(e); + if (value_desc->number() < 0 && non_canonical_bytes > 0) { + // Negative numbers only have a canonical representation. + continue; + } + SCOPED_TRACE(value_desc->number()); + GOOGLE_CHECK_NE(value_desc->number(), kInvalidValue) + << "Invalid value is a real label."; + auto encoded = EncodeEnumValue(field->number(), value_desc->number(), + non_canonical_bytes); + if (use_tail_field) { + encoded += other_field; + } + + EXPECT_TRUE(obj.ParseFromString(encoded)); + if (field->is_repeated()) { + ASSERT_EQ(ref->FieldSize(obj, field), 1); + EXPECT_EQ(ref->GetRepeatedEnumValue(obj, field, 0), + value_desc->number()); + } else { + EXPECT_TRUE(ref->HasField(obj, field)); + EXPECT_EQ(ref->GetEnumValue(obj, field), value_desc->number()); + } + auto& unknown = ref->GetUnknownFields(obj); + ASSERT_EQ(unknown.field_count(), 0); + } + + SCOPED_TRACE("Invalid value"); + // Try an invalid value, which should go to the unknown fields. + EXPECT_TRUE(obj.ParseFromString(EncodeEnumValue( + field->number(), kInvalidValue, non_canonical_bytes))); + if (field->is_repeated()) { + ASSERT_EQ(ref->FieldSize(obj, field), 0); + } else { + EXPECT_FALSE(ref->HasField(obj, field)); + EXPECT_EQ(ref->GetEnumValue(obj, field), + enum_desc->value(0)->number()); + } + auto& unknown = ref->GetUnknownFields(obj); + ASSERT_EQ(unknown.field_count(), 1); + EXPECT_EQ(unknown.field(0).number(), field->number()); + EXPECT_EQ(unknown.field(0).type(), unknown.field(0).TYPE_VARINT); + EXPECT_EQ(unknown.field(0).varint(), kInvalidValue); + } + } + } +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/metadata_lite.h b/src/google/protobuf/metadata_lite.h index 11faba69fc..af840e5065 100644 --- a/src/google/protobuf/metadata_lite.h +++ b/src/google/protobuf/metadata_lite.h @@ -45,6 +45,9 @@ namespace google { namespace protobuf { + +class UnknownFieldSet; + namespace internal { // This is the representation for messages that support arena allocation. It @@ -273,6 +276,19 @@ PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom( template <> PROTOBUF_EXPORT void InternalMetadata::DoSwap(std::string* other); +// Instantiated once in message.cc (where the definition of UnknownFieldSet is +// known) to prevent much duplication across translation units of a large build. +extern template PROTOBUF_EXPORT void +InternalMetadata::DoClear(); +extern template PROTOBUF_EXPORT void +InternalMetadata::DoMergeFrom(const UnknownFieldSet& other); +extern template PROTOBUF_EXPORT void +InternalMetadata::DoSwap(UnknownFieldSet* other); +extern template PROTOBUF_EXPORT Arena* +InternalMetadata::DeleteOutOfLineHelper(); +extern template PROTOBUF_EXPORT UnknownFieldSet* +InternalMetadata::mutable_unknown_fields_slow(); + // This helper RAII class is needed to efficiently parse unknown fields. We // should only call mutable_unknown_fields if there are actual unknown fields. // The obvious thing to just use a stack string and swap it at the end of diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h index 96ee320951..a7baf4d333 100644 --- a/src/google/protobuf/parse_context.h +++ b/src/google/protobuf/parse_context.h @@ -387,7 +387,6 @@ class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream { struct Data { const DescriptorPool* pool = nullptr; MessageFactory* factory = nullptr; - Arena* arena = nullptr; }; template diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index ba71a9fb45..e8791c2227 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -176,9 +176,22 @@ // user code can be updated before upgrading versions of protobuf. // PROTOBUF_FUTURE_FINAL is used on classes that are historically not marked as // final, but that may be marked final in future (breaking) releases. -// #define PROTOBUF_FUTURE_BREAKING_CHANGES 1 -// #define PROTOBUF_FUTURE_FINAL final + +#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES +// Used on classes that are historically not marked as final. +// Owner: kfm@ +#define PROTOBUF_FUTURE_FINAL final + +// Used to remove the RTTI checks for `DefaultFieldComparator`. +// Owner: kfm@ +#define PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR 1 + +// Used to remove the manipulation of cleared elements in RepeatedPtrField. +// Owner: mkruskal@ +#define PROTOBUF_FUTURE_REMOVE_CLEARED_API 1 +#else #define PROTOBUF_FUTURE_FINAL +#endif #ifdef PROTOBUF_VERSION #error PROTOBUF_VERSION was previously defined diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc index 4473bdafa4..2c43d2cf6a 100644 --- a/src/google/protobuf/port_undef.inc +++ b/src/google/protobuf/port_undef.inc @@ -109,8 +109,12 @@ #ifdef PROTOBUF_FUTURE_BREAKING_CHANGES #undef PROTOBUF_FUTURE_BREAKING_CHANGES +#undef PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR +#undef PROTOBUF_FUTURE_REMOVE_CLEARED_API #endif +#undef PROTOBUF_FUTURE_FINAL + // Restore macro that may have been #undef'd in port_def.inc. #ifdef _WIN32 #pragma pop_macro("CREATE_NEW") diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index d8a82bf09e..c5211470bc 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -1258,7 +1258,7 @@ TEST(RepeatedPtrField, ClearedElements) { field.Clear(); EXPECT_EQ(field.ClearedCount(), 2); -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifndef PROTOBUF_FUTURE_REMOVE_CLEARED_API EXPECT_EQ(field.ReleaseCleared(), original); // Take ownership again. EXPECT_EQ(field.ClearedCount(), 1); EXPECT_NE(field.Add(), original); @@ -1270,7 +1270,7 @@ TEST(RepeatedPtrField, ClearedElements) { EXPECT_EQ(field.ClearedCount(), 1); EXPECT_EQ(field.Add(), original); EXPECT_EQ(field.ClearedCount(), 0); -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // !PROTOBUF_FUTURE_REMOVE_CLEARED_API } // Test all code paths in AddAllocated(). diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index c0822e083b..2fca2d6206 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -1092,7 +1092,7 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { // Gets the number of cleared objects that are currently being kept // around for reuse. int ClearedCount() const; -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifndef PROTOBUF_FUTURE_REMOVE_CLEARED_API // Adds an element to the pool of cleared objects, passing ownership to // the RepeatedPtrField. The element must be cleared prior to calling // this method. @@ -1107,7 +1107,7 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { // This method cannot be called when the repeated field is on an arena; doing // so will trigger a GOOGLE_DCHECK-failure. PROTOBUF_NODISCARD Element* ReleaseCleared(); -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // !PROTOBUF_FUTURE_REMOVE_CLEARED_API // Removes the element referenced by position. // @@ -1514,7 +1514,7 @@ inline int RepeatedPtrField::ClearedCount() const { return RepeatedPtrFieldBase::ClearedCount(); } -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifndef PROTOBUF_FUTURE_REMOVE_CLEARED_API template inline void RepeatedPtrField::AddCleared(Element* value) { return RepeatedPtrFieldBase::AddCleared(value); @@ -1524,7 +1524,7 @@ template inline Element* RepeatedPtrField::ReleaseCleared() { return RepeatedPtrFieldBase::ReleaseCleared(); } -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // !PROTOBUF_FUTURE_REMOVE_CLEARED_API template inline void RepeatedPtrField::Reserve(int new_size) { diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index f1b0bd04ba..4d08b44432 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -459,6 +459,9 @@ message TestRequiredForeign { optional TestRequired optional_message = 1; repeated TestRequired repeated_message = 2; optional int32 dummy = 3; + + // Missing required fields must not affect verification of child messages. + optional NestedTestAllTypes optional_lazy_message = 4 [lazy = true]; } message TestRequiredMessage { @@ -1416,3 +1419,105 @@ message TestVerifyBigFieldNumberUint32 { } +// This message contains different kind of enums to exercise the different +// parsers in table-driven. +message EnumParseTester { + enum SeqSmall0 { + SEQ_SMALL_0_DEFAULT = 0; + SEQ_SMALL_0_1 = 1; + SEQ_SMALL_0_2 = 2; + }; + optional SeqSmall0 optional_seq_small_0_lowfield = 1; + optional SeqSmall0 optional_seq_small_0_midfield = 1001; + optional SeqSmall0 optional_seq_small_0_hifield = 1000001; + repeated SeqSmall0 repeated_seq_small_0_lowfield = 2; + repeated SeqSmall0 repeated_seq_small_0_midfield = 1002; + repeated SeqSmall0 repeated_seq_small_0_hifield = 1000002; + repeated SeqSmall0 packed_seq_small_0_lowfield = 3 [packed = true]; + repeated SeqSmall0 packed_seq_small_0_midfield = 1003 [packed = true]; + repeated SeqSmall0 packed_seq_small_0_hifield = 1000003 [packed = true]; + + enum SeqSmall1 { + SEQ_SMALL_1_DEFAULT = 1; + SEQ_SMALL_1_2 = 2; + SEQ_SMALL_1_3 = 3; + }; + optional SeqSmall1 optional_seq_small_1_lowfield = 4; + optional SeqSmall1 optional_seq_small_1_midfield = 1004; + optional SeqSmall1 optional_seq_small_1_hifield = 1000004; + repeated SeqSmall1 repeated_seq_small_1_lowfield = 5; + repeated SeqSmall1 repeated_seq_small_1_midfield = 1005; + repeated SeqSmall1 repeated_seq_small_1_hifield = 1000005; + repeated SeqSmall1 packed_seq_small_1_lowfield = 6 [packed = true]; + repeated SeqSmall1 packed_seq_small_1_midfield = 1006 [packed = true]; + repeated SeqSmall1 packed_seq_small_1_hifield = 1000006 [packed = true]; + + enum SeqLarge { + SEQ_LARGE_DEFAULT = -1; + SEQ_LARGE_0 = 0; + SEQ_LARGE_1 = 1; + SEQ_LARGE_2 = 2; + SEQ_LARGE_3 = 3; + SEQ_LARGE_4 = 4; + SEQ_LARGE_5 = 5; + SEQ_LARGE_6 = 6; + SEQ_LARGE_7 = 7; + SEQ_LARGE_8 = 8; + SEQ_LARGE_9 = 9; + SEQ_LARGE_10 = 10; + SEQ_LARGE_11 = 11; + SEQ_LARGE_12 = 12; + SEQ_LARGE_13 = 13; + SEQ_LARGE_14 = 14; + SEQ_LARGE_15 = 15; + SEQ_LARGE_16 = 16; + SEQ_LARGE_17 = 17; + SEQ_LARGE_18 = 18; + SEQ_LARGE_19 = 19; + SEQ_LARGE_20 = 20; + SEQ_LARGE_21 = 21; + SEQ_LARGE_22 = 22; + SEQ_LARGE_23 = 23; + SEQ_LARGE_24 = 24; + SEQ_LARGE_25 = 25; + SEQ_LARGE_26 = 26; + SEQ_LARGE_27 = 27; + SEQ_LARGE_28 = 28; + SEQ_LARGE_29 = 29; + SEQ_LARGE_30 = 30; + SEQ_LARGE_31 = 31; + SEQ_LARGE_32 = 32; + SEQ_LARGE_33 = 33; + }; + optional SeqLarge optional_seq_large_lowfield = 7; + optional SeqLarge optional_seq_large_midfield = 1007; + optional SeqLarge optional_seq_large_hifield = 1000007; + repeated SeqLarge repeated_seq_large_lowfield = 8; + repeated SeqLarge repeated_seq_large_midfield = 1008; + repeated SeqLarge repeated_seq_large_hifield = 1000008; + repeated SeqLarge packed_seq_large_lowfield = 9 [packed = true]; + repeated SeqLarge packed_seq_large_midfield = 1009 [packed = true]; + repeated SeqLarge packed_seq_large_hifield = 1000009 [packed = true]; + + enum Arbitrary { + ARBITRARY_DEFAULT = -123123; + ARBITRARY_1 = -123; + ARBITRARY_2 = 213; + ARBITRARY_3 = 213213; + ARBITRARY_MIN = -2147483648; + ARBITRARY_MAX = 2147483647; + }; + optional Arbitrary optional_arbitrary_lowfield = 10; + optional Arbitrary optional_arbitrary_midfield = 1010; + optional Arbitrary optional_arbitrary_hifield = 1000010; + repeated Arbitrary repeated_arbitrary_lowfield = 11; + repeated Arbitrary repeated_arbitrary_midfield = 1011; + repeated Arbitrary repeated_arbitrary_hifield = 1000011; + repeated Arbitrary packed_arbitrary_lowfield = 12 [packed = true]; + repeated Arbitrary packed_arbitrary_midfield = 1012 [packed = true]; + repeated Arbitrary packed_arbitrary_hifield = 1000012 [packed = true]; + + // An arbitrary field we can append to to break the runs of repeated fields. + optional int32 other_field = 99; +}; + diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h index 5706da357a..4e8ab50ff5 100644 --- a/src/google/protobuf/util/field_comparator.h +++ b/src/google/protobuf/util/field_comparator.h @@ -262,13 +262,8 @@ class PROTOBUF_EXPORT SimpleFieldComparator : public FieldComparator { }; // Default field comparison: use the basic implementation of FieldComparator. -#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES -class PROTOBUF_EXPORT DefaultFieldComparator final - : public SimpleFieldComparator -#else // PROTOBUF_FUTURE_BREAKING_CHANGES -class PROTOBUF_EXPORT DefaultFieldComparator : public SimpleFieldComparator -#endif // PROTOBUF_FUTURE_BREAKING_CHANGES -{ +class PROTOBUF_EXPORT DefaultFieldComparator PROTOBUF_FUTURE_FINAL + : public SimpleFieldComparator { public: ComparisonResult Compare(const Message& message_1, const Message& message_2, const FieldDescriptor* field, int index_1, diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 10494e55a7..d4e1b1eb9f 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -32,9 +32,12 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -43,7 +46,7 @@ #include #include #include -#include +#include #include #include #include @@ -59,12 +62,12 @@ namespace google { namespace protobuf { namespace util { namespace { - using ::proto3::TestAny; using ::proto3::TestEnumValue; using ::proto3::TestMap; using ::proto3::TestMessage; using ::proto3::TestOneof; +using ::proto3::TestWrapper; using ::proto_util_converter::testing::MapIn; // TODO(b/234474291): Use the gtest versions once that's available in OSS. @@ -288,7 +291,7 @@ TEST(JsonUtilTest, ParseMessage) { { "int32Value": 1234567891, "int64Value": 5302428716536692736, - "floatValue": 3.4028235e+38, + "floatValue": 3.40282002e+38, "repeatedInt32Value": [1, 2], "messageValue": { "value": 2048 @@ -303,7 +306,7 @@ TEST(JsonUtilTest, ParseMessage) { EXPECT_EQ(m.int32_value(), 1234567891); EXPECT_EQ(m.int64_value(), 5302428716536692736); - EXPECT_EQ(m.float_value(), 3.402823466e+38f); + EXPECT_EQ(m.float_value(), 3.40282002e+38f); ASSERT_EQ(m.repeated_int32_value_size(), 2); EXPECT_EQ(m.repeated_int32_value(0), 1); EXPECT_EQ(m.repeated_int32_value(1), 2); @@ -436,7 +439,8 @@ TEST(JsonUtilTest, TestParsingAny) { EXPECT_THAT( ToJson(m), IsOkAndHolds( - R"json({"value":{"@type":"type.googleapis.com/proto3.TestMessage","int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}})json")); + R"({"value":{"@type":"type.googleapis.com/proto3.TestMessage",)" + R"("int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}})")); } TEST(JsonUtilTest, TestParsingAnyMiddleAtType) { @@ -513,7 +517,32 @@ TEST(JsonUtilTest, TestParsingNestedAnys) { EXPECT_THAT( ToJson(m), IsOkAndHolds( - R"json({"value":{"@type":"type.googleapis.com/google.protobuf.Any","value":{"@type":"type.googleapis.com/proto3.TestMessage","int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}}})json")); + R"({"value":{"@type":"type.googleapis.com/google.protobuf.Any",)" + R"("value":{"@type":"type.googleapis.com/proto3.TestMessage",)" + R"("int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}}})")); +} + +TEST(JsonUtilTest, ParseWrappers) { + StringPiece input = R"json( + { + "boolValue": true, + "int32Value": 42, + "stringValue": "ieieo", + } + )json"; + + TestWrapper m; + auto proto_buffer = FromJson(input, &m); + ASSERT_OK(proto_buffer); + + EXPECT_TRUE(m.bool_value().value()); + EXPECT_EQ(m.int32_value().value(), 42); + EXPECT_EQ(m.string_value().value(), "ieieo"); + + EXPECT_THAT( + ToJson(m), + IsOkAndHolds( + R"({"boolValue":true,"int32Value":42,"stringValue":"ieieo"})")); } TEST(JsonUtilTest, TestParsingUnknownAnyFields) { @@ -632,24 +661,200 @@ TEST(JsonUtilTest, TestParsingEnumIgnoreCase) { ASSERT_EQ(m.enum_value(), proto3::BAR); } -TEST(JsonUtilTest, TestWrongJsonInput) { - StringPiece json = "{\"unknown_field\":\"some_value\"}"; - io::ArrayInputStream input_stream(json.data(), json.size()); - char proto_buffer[10000]; +class TypeResolverTest : public testing::Test { + protected: + util::StatusOr Proto2Json(StringPiece proto, + StringPiece type, + const JsonPrintOptions& options = {}) { + io::ArrayInputStream in(proto.data(), proto.size()); + + std::string result; + io::StringOutputStream out(&result); + + RETURN_IF_ERROR(BinaryToJsonStream( + resolver_.get(), StrCat("type.googleapis.com/", type), &in, + &out)); + return result; + } + + util::StatusOr Json2Proto(StringPiece json, + StringPiece type, + const JsonParseOptions& options = {}) { + io::ArrayInputStream in(json.data(), json.size()); + + std::string result; + io::StringOutputStream out(&result); + + RETURN_IF_ERROR(JsonToBinaryStream( + resolver_.get(), StrCat("type.googleapis.com/", type), &in, + &out)); + + return result; + } + + std::unique_ptr resolver_{NewTypeResolverForDescriptorPool( + "type.googleapis.com", DescriptorPool::generated_pool())}; +}; + +TEST_F(TypeResolverTest, ParseFromResolver) { + StringPiece json = R"json( + { + "boolValue": true, + "int32Value": 1234567891, + "int64Value": -5302428716536692736, + "uint32Value": 42, + "uint64Value": 530242871653669, + "floatValue": 3.4e+38, + "doubleValue": -55.5, + "stringValue": "foo bar baz", + "enumValue": "BAR", + "messageValue": { + "value": 2048 + }, + + "repeatedBoolValue": [true], + "repeatedInt32Value": [0, -42], + "repeatedUint64Value": [1, 2], + "repeatedDoubleValue": [1.5, -2.1], + "repeatedStringValue": ["foo", "bar ", ""], + "repeatedEnumValue": [1, "FOO"], + "repeatedMessageValue": [ + {"value": 40}, + {"value": 96} + ] + } + )json"; + + auto proto_buffer = Json2Proto(json, "proto3.TestMessage"); + ASSERT_OK(proto_buffer); + + // Some random message but good enough to verify that the parsing wrapper + // functions are working properly. + TestMessage m; + ASSERT_TRUE(m.ParseFromString(*proto_buffer)); + + EXPECT_TRUE(m.bool_value()); + EXPECT_EQ(m.int32_value(), 1234567891); + EXPECT_EQ(m.int64_value(), -5302428716536692736); + EXPECT_EQ(m.uint32_value(), 42); + EXPECT_EQ(m.uint64_value(), 530242871653669); + EXPECT_EQ(m.float_value(), 3.4e+38f); + EXPECT_EQ(m.double_value(), -55.5); + EXPECT_EQ(m.string_value(), "foo bar baz"); + EXPECT_EQ(m.enum_value(), proto3::EnumType::BAR); + EXPECT_EQ(m.message_value().value(), 2048); + + ASSERT_EQ(m.repeated_bool_value_size(), 1); + EXPECT_TRUE(m.repeated_bool_value(0)); + + ASSERT_EQ(m.repeated_int32_value_size(), 2); + EXPECT_EQ(m.repeated_int32_value(0), 0); + EXPECT_EQ(m.repeated_int32_value(1), -42); + + ASSERT_EQ(m.repeated_uint64_value_size(), 2); + EXPECT_EQ(m.repeated_uint64_value(0), 1); + EXPECT_EQ(m.repeated_uint64_value(1), 2); + + ASSERT_EQ(m.repeated_double_value_size(), 2); + EXPECT_EQ(m.repeated_double_value(0), 1.5); + EXPECT_EQ(m.repeated_double_value(1), -2.1); + + ASSERT_EQ(m.repeated_string_value_size(), 3); + EXPECT_EQ(m.repeated_string_value(0), "foo"); + EXPECT_EQ(m.repeated_string_value(1), "bar "); + EXPECT_EQ(m.repeated_string_value(2), ""); + + ASSERT_EQ(m.repeated_enum_value_size(), 2); + EXPECT_EQ(m.repeated_enum_value(0), proto3::EnumType::BAR); + EXPECT_EQ(m.repeated_enum_value(1), proto3::EnumType::FOO); + + ASSERT_EQ(m.repeated_message_value_size(), 2); + EXPECT_EQ(m.repeated_message_value(0).value(), 40); + EXPECT_EQ(m.repeated_message_value(1).value(), 96); + + StringPiece compacted_json = + R"({"boolValue":true,"int32Value":1234567891,"int64Value":"-5302428716536692736",)" + R"("uint32Value":42,"uint64Value":"530242871653669","floatValue":3.4e+38,)" + R"("doubleValue":-55.5,"stringValue":"foo bar baz","enumValue":"BAR",)" + R"("messageValue":{"value":2048},"repeatedBoolValue":[true],"repeatedInt32Value":[0,-42])" + R"(,"repeatedUint64Value":["1","2"],"repeatedDoubleValue":[1.5,-2.1],)" + R"("repeatedStringValue":["foo","bar ",""],"repeatedEnumValue":["BAR","FOO"],)" + R"("repeatedMessageValue":[{"value":40},{"value":96}]})"; + + EXPECT_THAT(Proto2Json(*proto_buffer, "proto3.TestMessage"), + IsOkAndHolds(compacted_json)); + + // Proto3 messages always used packed, so this will make sure to exercise + // packed decoding. + std::string proto_buffer2; + m.SerializeToString(&proto_buffer2); + + EXPECT_THAT(Proto2Json(proto_buffer2, "proto3.TestMessage"), + IsOkAndHolds(compacted_json)); +} + +TEST_F(TypeResolverTest, ParseAnyFromResolver) { + StringPiece input = R"json( + { + "value": { + "@type": "type.googleapis.com/proto3.TestMessage", + "int32_value": 5, + "string_value": "expected_value", + "message_value": {"value": 1} + } + } + )json"; + + auto proto_buffer = Json2Proto(input, "proto3.TestAny"); + ASSERT_OK(proto_buffer); + + TestAny m; + ASSERT_TRUE(m.ParseFromString(*proto_buffer)); + + TestMessage t; + EXPECT_TRUE(m.value().UnpackTo(&t)); + EXPECT_EQ(t.int32_value(), 5); + EXPECT_EQ(t.string_value(), "expected_value"); + EXPECT_EQ(t.message_value().value(), 1); + + EXPECT_THAT( + Proto2Json(*proto_buffer, "proto3.TestAny"), + IsOkAndHolds( + R"({"value":{"@type":"type.googleapis.com/proto3.TestMessage",)" + R"("int32Value":5,"stringValue":"expected_value","messageValue":{"value":1}}})")); +} + +TEST_F(TypeResolverTest, ParseWrappers) { + StringPiece input = R"json( + { + "boolValue": true, + "int32Value": 42, + "stringValue": "ieieo", + } + )json"; - io::ArrayOutputStream output_stream(proto_buffer, sizeof(proto_buffer)); - std::string message_type = "type.googleapis.com/proto3.TestMessage"; + auto proto_buffer = Json2Proto(input, "proto3.TestWrapper"); + ASSERT_OK(proto_buffer); - auto* resolver = NewTypeResolverForDescriptorPool( - "type.googleapis.com", DescriptorPool::generated_pool()); + TestWrapper m; + ASSERT_TRUE(m.ParseFromString(*proto_buffer)); + EXPECT_TRUE(m.bool_value().value()); + EXPECT_EQ(m.int32_value().value(), 42); + EXPECT_EQ(m.string_value().value(), "ieieo"); EXPECT_THAT( - JsonToBinaryStream(resolver, message_type, &input_stream, &output_stream), - StatusIs(util::StatusCode::kInvalidArgument)); - delete resolver; + Proto2Json(*proto_buffer, "proto3.TestWrapper"), + IsOkAndHolds( + R"({"boolValue":true,"int32Value":42,"stringValue":"ieieo"})")); +} + +TEST_F(TypeResolverTest, TestWrongJsonInput) { + EXPECT_THAT(Json2Proto(R"json({"unknown_field": "some_value"})json", + "proto3.TestMessage"), + StatusIs(util::StatusCode::kInvalidArgument)); } -TEST(JsonUtilTest, HtmlEscape) { +TEST(JsonUtilTest, DISABLED_HtmlEscape) { TestMessage m; m.set_string_value(""); JsonPrintOptions options; diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 30560ed5f4..35e4ed02bf 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -337,14 +337,14 @@ void MessageDifferencer::set_field_comparator(FieldComparator* comparator) { field_comparator_.base = comparator; } -#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifdef PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR void MessageDifferencer::set_field_comparator( DefaultFieldComparator* comparator) { GOOGLE_CHECK(comparator) << "Field comparator can't be NULL."; field_comparator_kind_ = kFCDefault; field_comparator_.default_impl = comparator; } -#endif // PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR void MessageDifferencer::set_message_field_comparison( MessageFieldComparison comparison) { diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index f63cd54185..4df31524ba 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -524,9 +524,9 @@ class PROTOBUF_EXPORT MessageDifferencer { // Note that this method must be called before Compare for the comparator to // be used. void set_field_comparator(FieldComparator* comparator); -#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES +#ifdef PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR void set_field_comparator(DefaultFieldComparator* comparator); -#endif // PROTOBUF_FUTURE_BREAKING_CHANGES +#endif // PROTOBUF_FUTURE_REMOVE_DEFAULT_FIELD_COMPARATOR // DEPRECATED. Pass a DefaultFieldComparator instance instead. // Sets the fraction and margin for the float comparison of a given field.