Merge pull request #9182 from JamesNK/jamesnk/trimming-take3

[C#] Fix trim warnings
This commit is contained in:
Jan Tattermusch 2021-11-30 11:57:56 +01:00 committed by GitHub
commit b79ac0e6e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 660 additions and 49 deletions

View File

@ -182,10 +182,14 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs \
csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs \
csharp/src/Google.Protobuf/Collections/RepeatedField.cs \
csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMembersAttribute.cs \
csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMemberTypes.cs \
csharp/src/Google.Protobuf/Compatibility/MethodInfoExtensions.cs \
csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs \
csharp/src/Google.Protobuf/Compatibility/RequiresUnreferencedCodeAttribute.cs \
csharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs \
csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs \
csharp/src/Google.Protobuf/Compatibility/UnconditionalSuppressMessageAttribute.cs \
csharp/src/Google.Protobuf/Extension.cs \
csharp/src/Google.Protobuf/ExtensionRegistry.cs \
csharp/src/Google.Protobuf/ExtensionSet.cs \

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!--
This TestProtos project is kept separate from the original test project for many reasons.
@ -15,7 +15,7 @@
<!-- Needed for the net45 build to work on Unix. See https://github.com/dotnet/designs/pull/33 -->
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="All" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>

View File

@ -21,7 +21,7 @@
<!-- Needed for the net45 build to work on Unix. See https://github.com/dotnet/designs/pull/33 -->
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="All" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>

View File

@ -35,6 +35,7 @@ using Google.Protobuf.TestProtos;
using Google.Protobuf.WellKnownTypes;
using NUnit.Framework;
using ProtobufTestMessages.Proto2;
using ProtobufTestMessages.Proto3;
using System;
using UnitTest.Issues.TestProtos;
@ -918,10 +919,10 @@ namespace Google.Protobuf
}
[Test]
[TestCase("\"FOREIGN_BAR\"", ForeignEnum.ForeignBar)]
[TestCase("5", ForeignEnum.ForeignBar)]
[TestCase("100", (ForeignEnum)100)]
public void EnumValid(string value, ForeignEnum expectedValue)
[TestCase("\"FOREIGN_BAR\"", TestProtos.ForeignEnum.ForeignBar)]
[TestCase("5", TestProtos.ForeignEnum.ForeignBar)]
[TestCase("100", (TestProtos.ForeignEnum)100)]
public void EnumValid(string value, TestProtos.ForeignEnum expectedValue)
{
string json = "{ \"singleForeignEnum\": " + value + " }";
var parsed = TestAllTypes.Parser.ParseJson(json);
@ -1021,5 +1022,128 @@ namespace Google.Protobuf
{
return '"' + text + '"';
}
[Test]
public void ParseAllNullValues()
{
string json = @"{
""optionalInt32"": null,
""optionalInt64"": null,
""optionalUint32"": null,
""optionalUint64"": null,
""optionalSint32"": null,
""optionalSint64"": null,
""optionalFixed32"": null,
""optionalFixed64"": null,
""optionalSfixed32"": null,
""optionalSfixed64"": null,
""optionalFloat"": null,
""optionalDouble"": null,
""optionalBool"": null,
""optionalString"": null,
""optionalBytes"": null,
""optionalNestedEnum"": null,
""optionalNestedMessage"": null,
""repeatedInt32"": null,
""repeatedInt64"": null,
""repeatedUint32"": null,
""repeatedUint64"": null,
""repeatedSint32"": null,
""repeatedSint64"": null,
""repeatedFixed32"": null,
""repeatedFixed64"": null,
""repeatedSfixed32"": null,
""repeatedSfixed64"": null,
""repeatedFloat"": null,
""repeatedDouble"": null,
""repeatedBool"": null,
""repeatedString"": null,
""repeatedBytes"": null,
""repeatedNestedEnum"": null,
""repeatedNestedMessage"": null,
""mapInt32Int32"": null,
""mapBoolBool"": null,
""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();
message.RepeatedInt32.Add(1);
message.RepeatedInt64.Add(1);
message.RepeatedUint32.Add(1);
message.RepeatedUint64.Add(1);
message.RepeatedSint32.Add(1);
message.RepeatedSint64.Add(1);
message.RepeatedFixed32.Add(1);
message.RepeatedFixed64.Add(1);
message.RepeatedSfixed32.Add(1);
message.RepeatedSfixed64.Add(1);
message.RepeatedFloat.Add(1);
message.RepeatedDouble.Add(1);
message.RepeatedBool.Add(true);
message.RepeatedString.Add("1");
message.RepeatedBytes.Add(ByteString.CopyFrom(new byte[] { 1 }));
message.RepeatedNestedEnum.Add(TestAllTypesProto3.Types.NestedEnum.Bar);
message.RepeatedNestedMessage.Add(new TestAllTypesProto3.Types.NestedMessage());
message.MapInt32Int32.Add(1, 1);
message.MapBoolBool.Add(true, true);
message.MapStringNestedMessage.Add(" ", new TestAllTypesProto3.Types.NestedMessage());
JsonParser.Default.Merge(message, json);
Assert.AreEqual(0, message.OptionalInt32);
Assert.AreEqual(0, message.OptionalInt64);
Assert.AreEqual(0, message.OptionalUint32);
Assert.AreEqual(0, message.OptionalUint64);
Assert.AreEqual(0, message.OptionalSint32);
Assert.AreEqual(0, message.OptionalSint64);
Assert.AreEqual(0, message.OptionalFixed32);
Assert.AreEqual(0, message.OptionalFixed64);
Assert.AreEqual(0, message.OptionalSfixed32);
Assert.AreEqual(0, message.OptionalSfixed64);
Assert.AreEqual(0, message.OptionalFloat);
Assert.AreEqual(0, message.OptionalDouble);
Assert.AreEqual(false, message.OptionalBool);
Assert.AreEqual("", message.OptionalString);
Assert.AreEqual(ByteString.Empty, message.OptionalBytes);
Assert.AreEqual(TestAllTypesProto3.Types.NestedEnum.Foo, message.OptionalNestedEnum);
Assert.AreEqual(null, message.OptionalNestedMessage);
Assert.AreEqual(0, message.RepeatedInt32.Count);
Assert.AreEqual(0, message.RepeatedInt64.Count);
Assert.AreEqual(0, message.RepeatedUint32.Count);
Assert.AreEqual(0, message.RepeatedUint64.Count);
Assert.AreEqual(0, message.RepeatedSint32.Count);
Assert.AreEqual(0, message.RepeatedSint64.Count);
Assert.AreEqual(0, message.RepeatedFixed32.Count);
Assert.AreEqual(0, message.RepeatedFixed64.Count);
Assert.AreEqual(0, message.RepeatedSfixed32.Count);
Assert.AreEqual(0, message.RepeatedFloat.Count);
Assert.AreEqual(0, message.RepeatedDouble.Count);
Assert.AreEqual(0, message.RepeatedBool.Count);
Assert.AreEqual(0, message.RepeatedString.Count);
Assert.AreEqual(0, message.RepeatedBytes.Count);
Assert.AreEqual(0, message.RepeatedNestedEnum.Count);
Assert.AreEqual(0, message.RepeatedNestedMessage.Count);
Assert.AreEqual(0, message.MapInt32Int32.Count);
Assert.AreEqual(0, message.MapBoolBool.Count);
Assert.AreEqual(0, message.MapStringNestedMessage.Count);
}
}
}

View File

@ -0,0 +1,127 @@
#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
#if !NET5_0_OR_GREATER
// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Specifies the types of members that are dynamically accessed.
///
/// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a
/// bitwise combination of its member values.
/// </summary>
[Flags]
internal enum DynamicallyAccessedMemberTypes
{
/// <summary>
/// Specifies no members.
/// </summary>
None = 0,
/// <summary>
/// Specifies the default, parameterless public constructor.
/// </summary>
PublicParameterlessConstructor = 0x0001,
/// <summary>
/// Specifies all public constructors.
/// </summary>
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
/// <summary>
/// Specifies all non-public constructors.
/// </summary>
NonPublicConstructors = 0x0004,
/// <summary>
/// Specifies all public methods.
/// </summary>
PublicMethods = 0x0008,
/// <summary>
/// Specifies all non-public methods.
/// </summary>
NonPublicMethods = 0x0010,
/// <summary>
/// Specifies all public fields.
/// </summary>
PublicFields = 0x0020,
/// <summary>
/// Specifies all non-public fields.
/// </summary>
NonPublicFields = 0x0040,
/// <summary>
/// Specifies all public nested types.
/// </summary>
PublicNestedTypes = 0x0080,
/// <summary>
/// Specifies all non-public nested types.
/// </summary>
NonPublicNestedTypes = 0x0100,
/// <summary>
/// Specifies all public properties.
/// </summary>
PublicProperties = 0x0200,
/// <summary>
/// Specifies all non-public properties.
/// </summary>
NonPublicProperties = 0x0400,
/// <summary>
/// Specifies all public events.
/// </summary>
PublicEvents = 0x0800,
/// <summary>
/// Specifies all non-public events.
/// </summary>
NonPublicEvents = 0x1000,
/// <summary>
/// Specifies all interfaces implemented by the type.
/// </summary>
Interfaces = 0x2000,
/// <summary>
/// Specifies all members.
/// </summary>
All = ~None
}
}
#endif

View File

@ -0,0 +1,83 @@
#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
#if !NET5_0_OR_GREATER
// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Indicates that certain members on a specified <see cref="Type"/> are accessed dynamically,
/// for example through <see cref="System.Reflection"/>.
/// </summary>
/// <remarks>
/// This allows tools to understand which members are being accessed during the execution
/// of a program.
///
/// This attribute is valid on members whose type is <see cref="Type"/> or <see cref="string"/>.
///
/// When this attribute is applied to a location of type <see cref="string"/>, the assumption is
/// that the string represents a fully qualified type name.
///
/// When this attribute is applied to a class, interface, or struct, the members specified
/// can be accessed dynamically on <see cref="Type"/> instances returned from calling
/// <see cref="object.GetType"/> on instances of that class, interface, or struct.
///
/// If the attribute is applied to a method it's treated as a special case and it implies
/// the attribute should be applied to the "this" parameter of the method. As such the attribute
/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
/// will use it there).
/// </remarks>
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
Inherited = false)]
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
/// with the specified member types.
/// </summary>
/// <param name="memberTypes">The types of members dynamically accessed.</param>
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
{
MemberTypes = memberTypes;
}
/// <summary>
/// Gets the <see cref="DynamicallyAccessedMemberTypes"/> which specifies the type
/// of members dynamically accessed.
/// </summary>
public DynamicallyAccessedMemberTypes MemberTypes { get; }
}
}
#endif

View File

@ -0,0 +1,72 @@
#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
#if !NET5_0_OR_GREATER
// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Indicates that the specified method requires dynamic access to code that is not referenced
/// statically, for example through <see cref="System.Reflection"/>.
/// </summary>
/// <remarks>
/// This allows tools to understand which methods are unsafe to call when removing unreferenced
/// code from an application.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
internal sealed class RequiresUnreferencedCodeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="RequiresUnreferencedCodeAttribute"/> class
/// with the specified message.
/// </summary>
/// <param name="message">
/// A message that contains information about the usage of unreferenced code.
/// </param>
public RequiresUnreferencedCodeAttribute(string message)
{
Message = message;
}
/// <summary>
/// Gets a message that contains information about the usage of unreferenced code.
/// </summary>
public string Message { get; }
/// <summary>
/// Gets or sets an optional URL that contains more information about the method,
/// why it requires unreferenced code, and what options a consumer has to deal with it.
/// </summary>
public string Url { get; set; }
}
}
#endif

View File

@ -31,6 +31,7 @@
#endregion
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
#if !NET35
@ -59,7 +60,11 @@ namespace Google.Protobuf.Compatibility
/// including inherited properties or null if there is no such public property.
/// Here, "public property" means a property where either the getter, or the setter, or both, is public.
/// </summary>
internal static PropertyInfo GetProperty(this Type target, string name)
[UnconditionalSuppressMessage("Trimming", "IL2072",
Justification = "The BaseType of the target will have all properties because of the annotation.")]
internal static PropertyInfo GetProperty(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
this Type target, string name)
{
// GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
while (target != null)
@ -86,7 +91,11 @@ namespace Google.Protobuf.Compatibility
/// class Child : Base declares public void Foo(long)).
/// </remarks>
/// <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
internal static MethodInfo GetMethod(this Type target, string name)
[UnconditionalSuppressMessage("Trimming", "IL2072",
Justification = "The BaseType of the target will have all properties because of the annotation.")]
internal static MethodInfo GetMethod(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
this Type target, string name)
{
// GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
while (target != null)

View File

@ -0,0 +1,117 @@
#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
#if !NET5_0_OR_GREATER
// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a
/// single code artifact.
/// </summary>
/// <remarks>
/// <see cref="UnconditionalSuppressMessageAttribute"/> is different than
/// <see cref="SuppressMessageAttribute"/> in that it doesn't have a
/// <see cref="ConditionalAttribute"/>. So it is always preserved in the compiled assembly.
/// </remarks>
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class UnconditionalSuppressMessageAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="UnconditionalSuppressMessageAttribute"/>
/// class, specifying the category of the tool and the identifier for an analysis rule.
/// </summary>
/// <param name="category">The category for the attribute.</param>
/// <param name="checkId">The identifier of the analysis rule the attribute applies to.</param>
public UnconditionalSuppressMessageAttribute(string category, string checkId)
{
Category = category;
CheckId = checkId;
}
/// <summary>
/// Gets the category identifying the classification of the attribute.
/// </summary>
/// <remarks>
/// The <see cref="Category"/> property describes the tool or tool analysis category
/// for which a message suppression attribute applies.
/// </remarks>
public string Category { get; }
/// <summary>
/// Gets the identifier of the analysis tool rule to be suppressed.
/// </summary>
/// <remarks>
/// Concatenated together, the <see cref="Category"/> and <see cref="CheckId"/>
/// properties form a unique check identifier.
/// </remarks>
public string CheckId { get; }
/// <summary>
/// Gets or sets the scope of the code that is relevant for the attribute.
/// </summary>
/// <remarks>
/// The Scope property is an optional argument that specifies the metadata scope for which
/// the attribute is relevant.
/// </remarks>
public string Scope { get; set; }
/// <summary>
/// Gets or sets a fully qualified path that represents the target of the attribute.
/// </summary>
/// <remarks>
/// The <see cref="Target"/> property is an optional argument identifying the analysis target
/// of the attribute. An example value is "System.IO.Stream.ctor():System.Void".
/// Because it is fully qualified, it can be long, particularly for targets such as parameters.
/// The analysis tool user interface should be capable of automatically formatting the parameter.
/// </remarks>
public string Target { get; set; }
/// <summary>
/// Gets or sets an optional argument expanding on exclusion criteria.
/// </summary>
/// <remarks>
/// The <see cref="MessageId "/> property is an optional argument that specifies additional
/// exclusion where the literal metadata target is not sufficiently precise. For example,
/// the <see cref="UnconditionalSuppressMessageAttribute"/> cannot be applied within a method,
/// and it may be desirable to suppress a violation against a statement in the method that will
/// give a rule violation, but not against all statements in the method.
/// </remarks>
public string MessageId { get; set; }
/// <summary>
/// Gets or sets the justification for suppressing the code analysis message.
/// </summary>
public string Justification { get; set; }
}
}
#endif

View File

@ -22,6 +22,7 @@
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Include PDB in the built .nupkg -->
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">

View File

@ -40,6 +40,7 @@ using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
namespace Google.Protobuf
{
@ -879,6 +880,8 @@ namespace Google.Protobuf
private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
= new Dictionary<System.Type, Dictionary<object, string>>();
[UnconditionalSuppressMessage("Trimming", "IL2072",
Justification = "The field for the value must still be present. It will be returned by reflection, will be in this collection, and its name can be resolved.")]
internal static string GetOriginalName(object value)
{
var enumType = value.GetType();
@ -898,21 +901,13 @@ namespace Google.Protobuf
return originalName;
}
#if NET35
// TODO: Consider adding functionality to TypeExtensions to avoid this difference.
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.Where(f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
.FirstOrDefault() as OriginalNameAttribute)
?.PreferredAlias ?? true)
.ToDictionary(f => f.GetValue(null),
f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
.FirstOrDefault() as OriginalNameAttribute)
// If the attribute hasn't been applied, fall back to the name of the field.
?.Name ?? f.Name);
#else
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
enumType.GetTypeInfo().DeclaredFields
private static Dictionary<object, string> GetNameMapping(
[DynamicallyAccessedMembers(
DynamicallyAccessedMemberTypes.PublicFields |
DynamicallyAccessedMemberTypes.NonPublicFields)]
System.Type enumType)
{
return enumType.GetTypeInfo().DeclaredFields
.Where(f => f.IsStatic)
.Where(f => f.GetCustomAttributes<OriginalNameAttribute>()
.FirstOrDefault()?.PreferredAlias ?? true)
@ -921,7 +916,7 @@ namespace Google.Protobuf
.FirstOrDefault()
// If the attribute hasn't been applied, fall back to the name of the field.
?.Name ?? f.Name);
#endif
}
}
}
}

View File

@ -34,6 +34,7 @@ using Google.Protobuf.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@ -63,6 +64,8 @@ namespace Google.Protobuf.Reflection
/// </remarks>
public sealed class CustomOptions
{
private const string UnreferencedCodeMessage = "CustomOptions is incompatible with trimming.";
private static readonly object[] EmptyParameters = new object[0];
private readonly IDictionary<int, IExtensionValue> values;
@ -77,6 +80,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetBool(int field, out bool value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -85,6 +89,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -93,6 +98,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -102,6 +108,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetFixed32(int field, out uint value) => TryGetUInt32(field, out value);
/// <summary>
@ -111,6 +118,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetFixed64(int field, out ulong value) => TryGetUInt64(field, out value);
/// <summary>
@ -120,6 +128,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetSFixed32(int field, out int value) => TryGetInt32(field, out value);
/// <summary>
@ -129,6 +138,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetSFixed64(int field, out long value) => TryGetInt64(field, out value);
/// <summary>
@ -138,6 +148,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetSInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -147,6 +158,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetSInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -155,6 +167,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetUInt32(int field, out uint value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -163,6 +176,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetUInt64(int field, out ulong value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -171,6 +185,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetFloat(int field, out float value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -179,6 +194,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetDouble(int field, out double value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -187,6 +203,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetString(int field, out string value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -195,6 +212,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetBytes(int field, out ByteString value) => TryGetPrimitiveValue(field, out value);
/// <summary>
@ -203,6 +221,7 @@ namespace Google.Protobuf.Reflection
/// <param name="field">The field to fetch the value for.</param>
/// <param name="value">The output variable to populate.</param>
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
public bool TryGetMessage<T>(int field, out T value) where T : class, IMessage, new()
{
if (values == null)
@ -240,6 +259,7 @@ namespace Google.Protobuf.Reflection
return false;
}
[RequiresUnreferencedCode(UnreferencedCodeMessage)]
private bool TryGetPrimitiveValue<T>(int field, out T value)
{
if (values == null)

View File

@ -452,7 +452,7 @@ namespace Google.Protobuf.Reflection
}
return IsMap ? new MapFieldAccessor(property, this)
: IsRepeated ? new RepeatedFieldAccessor(property, this)
: (IFieldAccessor) new SingleFieldAccessor(property, this);
: (IFieldAccessor) new SingleFieldAccessor(ContainingType.ClrType, property, this);
}
}
}

View File

@ -30,6 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Diagnostics.CodeAnalysis;
namespace Google.Protobuf.Reflection
{
@ -43,10 +44,19 @@ namespace Google.Protobuf.Reflection
private static readonly string[] EmptyNames = new string[0];
private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
private static readonly Extension[] EmptyExtensions = new Extension[0];
internal const DynamicallyAccessedMemberTypes MessageAccessibility =
// Creating types
DynamicallyAccessedMemberTypes.PublicConstructors |
// Getting and setting properties
DynamicallyAccessedMemberTypes.PublicProperties |
DynamicallyAccessedMemberTypes.NonPublicProperties |
// Calling presence methods
DynamicallyAccessedMemberTypes.PublicMethods;
/// <summary>
/// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
/// </summary>
[DynamicallyAccessedMembers(MessageAccessibility)]
public Type ClrType { get; private set; }
/// <summary>
@ -88,7 +98,11 @@ namespace Google.Protobuf.Reflection
/// Each array parameter may be null, to indicate a lack of values.
/// The parameter order is designed to make it feasible to format the generated code readably.
/// </summary>
public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, Extension[] extensions, GeneratedClrTypeInfo[] nestedTypes)
public GeneratedClrTypeInfo(
// Preserve all public members on message types when trimming is enabled.
// This ensures that members used by reflection, e.g. JSON serialization, are preserved.
[DynamicallyAccessedMembers(MessageAccessibility)]
Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, Extension[] extensions, GeneratedClrTypeInfo[] nestedTypes)
{
NestedTypes = nestedTypes ?? EmptyCodeInfo;
NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
@ -104,7 +118,11 @@ namespace Google.Protobuf.Reflection
/// Each array parameter may be null, to indicate a lack of values.
/// The parameter order is designed to make it feasible to format the generated code readably.
/// </summary>
public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
public GeneratedClrTypeInfo(
// Preserve all public members on message types when trimming is enabled.
// This ensures that members used by reflection, e.g. JSON serialization, are preserved.
[DynamicallyAccessedMembers(MessageAccessibility)]
Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
: this(clrType, parser, propertyNames, oneofNames, nestedEnums, null, nestedTypes)
{
}

View File

@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
#if NET35
@ -182,6 +183,7 @@ namespace Google.Protobuf.Reflection
/// a wrapper type, and handle the result appropriately.
/// </para>
/// </remarks>
[DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]
public Type ClrType { get; }
/// <summary>

View File

@ -32,6 +32,7 @@
using Google.Protobuf.Compatibility;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace Google.Protobuf.Reflection
@ -115,13 +116,15 @@ namespace Google.Protobuf.Reflection
internal static Func<IMessage, bool> CreateFuncIMessageBool(MethodInfo method) =>
GetReflectionHelper(method.DeclaringType, method.ReturnType).CreateFuncIMessageBool(method);
internal static Func<IMessage, bool> CreateIsInitializedCaller(Type msg) =>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
internal static Func<IMessage, bool> CreateIsInitializedCaller([DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]Type msg) =>
((IExtensionSetReflector)Activator.CreateInstance(typeof(ExtensionSetReflector<>).MakeGenericType(msg))).CreateIsInitializedCaller();
/// <summary>
/// Creates a delegate which will execute the given method after casting the first argument to
/// the type that declares the method, and the second argument to the first parameter type of the method.
/// </summary>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
internal static IExtensionReflectionHelper CreateExtensionHelper(Extension extension) =>
(IExtensionReflectionHelper)Activator.CreateInstance(typeof(ExtensionReflectionHelper<,>).MakeGenericType(extension.TargetType, extension.GetType().GenericTypeArguments[1]), extension);
@ -131,6 +134,7 @@ namespace Google.Protobuf.Reflection
/// they can be garbage collected. We could cache them by type if that proves to be important, but creating
/// an object is pretty cheap.
/// </summary>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
private static IReflectionHelper GetReflectionHelper(Type t1, Type t2) =>
(IReflectionHelper) Activator.CreateInstance(typeof(ReflectionHelper<,>).MakeGenericType(t1, t2));
@ -308,16 +312,14 @@ namespace Google.Protobuf.Reflection
}
}
private class ExtensionSetReflector<T1> : IExtensionSetReflector where T1 : IExtendableMessage<T1>
private class ExtensionSetReflector<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
T1> : IExtensionSetReflector where T1 : IExtendableMessage<T1>
{
public Func<IMessage, bool> CreateIsInitializedCaller()
{
var prop = typeof(T1).GetTypeInfo().GetDeclaredProperty("_Extensions");
#if NET35
var getFunc = (Func<T1, ExtensionSet<T1>>)prop.GetGetMethod(true).CreateDelegate(typeof(Func<T1, ExtensionSet<T1>>));
#else
var getFunc = (Func<T1, ExtensionSet<T1>>)prop.GetMethod.CreateDelegate(typeof(Func<T1, ExtensionSet<T1>>));
#endif
var initializedFunc = (Func<ExtensionSet<T1>, bool>)
typeof(ExtensionSet<T1>)
.GetTypeInfo()

View File

@ -31,6 +31,8 @@
#endregion
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Google.Protobuf.Compatibility;
@ -50,7 +52,9 @@ namespace Google.Protobuf.Reflection
private readonly Action<IMessage> clearDelegate;
private readonly Func<IMessage, bool> hasDelegate;
internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
internal SingleFieldAccessor(
[DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]
Type messageType, PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
{
if (!property.CanWrite)
{
@ -87,13 +91,13 @@ namespace Google.Protobuf.Reflection
// Primitive fields always support presence in proto2, and support presence in proto3 for optional fields.
else if (descriptor.File.Syntax == Syntax.Proto2 || descriptor.Proto.Proto3Optional)
{
MethodInfo hasMethod = property.DeclaringType.GetRuntimeProperty("Has" + property.Name).GetMethod;
MethodInfo hasMethod = messageType.GetRuntimeProperty("Has" + property.Name).GetMethod;
if (hasMethod == null)
{
throw new ArgumentException("Not all required properties/methods are available");
}
hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod);
MethodInfo clearMethod = property.DeclaringType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
MethodInfo clearMethod = messageType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
if (clearMethod == null)
{
throw new ArgumentException("Not all required properties/methods are available");
@ -107,16 +111,48 @@ namespace Google.Protobuf.Reflection
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.
var clrType = property.PropertyType;
object defaultValue =
clrType == typeof(string) ? ""
: clrType == typeof(ByteString) ? ByteString.Empty
: Activator.CreateInstance(clrType);
object defaultValue = GetDefaultValue(descriptor);
clearDelegate = message => SetValue(message, defaultValue);
}
}
private static object GetDefaultValue(FieldDescriptor descriptor)
{
switch (descriptor.FieldType)
{
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");
}
}
public override void Clear(IMessage message) => clearDelegate(message);
public override bool HasValue(IMessage message) => hasDelegate(message);
public override void SetValue(IMessage message, object value) => setValueDelegate(message, value);

View File

@ -33,6 +33,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Google.Protobuf.Reflection;
@ -115,7 +116,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Parses from a string to a FieldMask and validates all field paths.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static FieldMask FromString<T>(string value) where T : IMessage
public static FieldMask FromString<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(string value) where T : IMessage
{
return FromStringEnumerable<T>(new List<string>(value.Split(FIELD_PATH_SEPARATOR)));
}
@ -124,7 +125,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Constructs a FieldMask for a list of field paths in a certain type.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static FieldMask FromStringEnumerable<T>(IEnumerable<string> paths) where T : IMessage
public static FieldMask FromStringEnumerable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(IEnumerable<string> paths) where T : IMessage
{
var mask = new FieldMask();
foreach (var path in paths)
@ -151,7 +152,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Constructs a FieldMask from the passed field numbers.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static FieldMask FromFieldNumbers<T>(params int[] fieldNumbers) where T : IMessage
public static FieldMask FromFieldNumbers<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(params int[] fieldNumbers) where T : IMessage
{
return FromFieldNumbers<T>((IEnumerable<int>)fieldNumbers);
}
@ -160,7 +161,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Constructs a FieldMask from the passed field numbers.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static FieldMask FromFieldNumbers<T>(IEnumerable<int> fieldNumbers) where T : IMessage
public static FieldMask FromFieldNumbers<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(IEnumerable<int> fieldNumbers) where T : IMessage
{
var descriptor = Activator.CreateInstance<T>().Descriptor;
@ -208,7 +209,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Checks whether paths in a given fields mask are valid.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static bool IsValid<T>(FieldMask fieldMask) where T : IMessage
public static bool IsValid<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(FieldMask fieldMask) where T : IMessage
{
var descriptor = Activator.CreateInstance<T>().Descriptor;
@ -235,7 +236,7 @@ namespace Google.Protobuf.WellKnownTypes
/// Checks whether a given field path is valid.
/// </summary>
/// <typeparam name="T">The type to validate the field paths against.</typeparam>
public static bool IsValid<T>(string path) where T : IMessage
public static bool IsValid<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(string path) where T : IMessage
{
var descriptor = Activator.CreateInstance<T>().Descriptor;