nullability works, but not yet configurable

This commit is contained in:
Christian Köllner 2020-01-22 22:21:11 +01:00
parent 4da57f9a28
commit affde90304
21 changed files with 524 additions and 333 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.0</TargetFrameworks> <TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.0</TargetFrameworks>
<RootNamespace>Capnp</RootNamespace> <RootNamespace>Capnp</RootNamespace>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
<Nullable>Enable</Nullable> <Nullable>Enable</Nullable>

View File

@ -148,22 +148,24 @@ namespace Capnp
/// <item><description>Type implementing <see cref="ICapnpSerializable"/>. The type must must have a public parameterless constructor.</description></item> /// <item><description>Type implementing <see cref="ICapnpSerializable"/>. The type must must have a public parameterless constructor.</description></item>
/// <item><description>A capability interface (<seealso cref="Rpc.InvalidCapabilityInterfaceException"/> for further explanation)</description></item> /// <item><description>A capability interface (<seealso cref="Rpc.InvalidCapabilityInterfaceException"/> for further explanation)</description></item>
/// <item><description><see cref="String"/></description></item> /// <item><description><see cref="String"/></description></item>
/// <item><description><see cref="IReadOnlyList{Boolean}"/></description></item> /// <item><description><code>IReadOnlyList{Boolean}</code></description></item>
/// <item><description><see cref="IReadOnlyList{SByte}"/></description></item> /// <item><description><code>IReadOnlyList{SByte}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Byte}"/></description></item> /// <item><description><code>IReadOnlyList{Byte}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Int16}"/></description></item> /// <item><description><code>IReadOnlyList{Int16}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{UInt16}"/></description></item> /// <item><description><code>IReadOnlyList{UInt16}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Int32}"/></description></item> /// <item><description><code>IReadOnlyList{Int32}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{UInt32}"/></description></item> /// <item><description><code>IReadOnlyList{UInt32}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Int64}"/></description></item> /// <item><description><code>IReadOnlyList{Int64}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{UInt64}"/></description></item> /// <item><description><code>IReadOnlyList{UInt64}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Single}"/></description></item> /// <item><description><code>IReadOnlyList{Single}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{Double}"/></description></item> /// <item><description><code>IReadOnlyList{Double}"</code></description></item>
/// <item><description><see cref="IReadOnlyList{T}"/> whereby T is one of the things listed here.</description></item> /// <item><description><code>IReadOnlyList{T}</code> whereby T is one of the things listed here.</description></item>
/// </list> /// </list>
/// </typeparam> /// </typeparam>
/// <param name="state"></param> /// <param name="state">deserializer state to construct from</param>
/// <returns></returns> /// <returns>The domain object instance. Nullability note: The returned reference will be null if (and only if) <typeparamref name="T"/> is a capability interface and
/// <paramref name="state"/> represents the nil object (obtained from a null pointer). For all other types, when the state is nil,
/// the method still constructs a valid but "empty" object instance (such as domain object without any properties set, empty string, empty list etc.)</returns>
public static T? Create<T>(DeserializerState state) public static T? Create<T>(DeserializerState state)
where T: class where T: class
{ {

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Capnp namespace Capnp
{ {
@ -572,6 +573,7 @@ namespace Capnp
/// <exception cref="IndexOutOfRangeException">negative index</exception> /// <exception cref="IndexOutOfRangeException">negative index</exception>
/// <exception cref="DeserializationException">state does not represent a struct, invalid pointer, /// <exception cref="DeserializationException">state does not represent a struct, invalid pointer,
/// non-list-of-bytes pointer, traversal limit exceeded</exception> /// non-list-of-bytes pointer, traversal limit exceeded</exception>
[return: NotNullIfNotNull("defaultText")]
public string? ReadText(int index, string? defaultText = null) public string? ReadText(int index, string? defaultText = null)
{ {
return StructReadPointer(index).RequireList().CastText() ?? defaultText; return StructReadPointer(index).RequireList().CastText() ?? defaultText;

View File

@ -144,7 +144,7 @@ namespace Capnp
/// <item><description>A <code><![CDATA[IReadOnlyList<object>]]></code> whereby each list item is one of the things listed here.</description></item> /// <item><description>A <code><![CDATA[IReadOnlyList<object>]]></code> whereby each list item is one of the things listed here.</description></item>
/// </list> /// </list>
/// </param> /// </param>
public void SetObject(object obj) public void SetObject(object? obj)
{ {
switch (obj) switch (obj)
{ {

View File

@ -73,7 +73,7 @@ namespace Capnp
/// <param name="items">List content. Can be null in which case the list is simply not initialized.</param> /// <param name="items">List content. Can be null in which case the list is simply not initialized.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init(IReadOnlyList<bool> items) public void Init(IReadOnlyList<bool>? items)
{ {
if (items == null) if (items == null)
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Capnp namespace Capnp
{ {
@ -10,7 +11,7 @@ namespace Capnp
/// <typeparam name="T">Capability interface</typeparam> /// <typeparam name="T">Capability interface</typeparam>
public class ListOfCapsSerializer<T> : public class ListOfCapsSerializer<T> :
SerializerState, SerializerState,
IReadOnlyList<T> IReadOnlyList<T?>
where T : class where T : class
{ {
/// <summary> /// <summary>
@ -31,6 +32,7 @@ namespace Capnp
/// <returns>Proxy object of capability at given element index</returns> /// <returns>Proxy object of capability at given element index</returns>
/// <exception cref="InvalidOperationException">List was not initialized, or attempting to overwrite an already set element.</exception> /// <exception cref="InvalidOperationException">List was not initialized, or attempting to overwrite an already set element.</exception>
/// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is out of range.</exception> /// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is out of range.</exception>
[AllowNull]
public T this[int index] public T this[int index]
{ {
get => (Rpc.CapabilityReflection.CreateProxy<T>(DecodeCapPointer(index)) as T)!; get => (Rpc.CapabilityReflection.CreateProxy<T>(DecodeCapPointer(index)) as T)!;
@ -42,10 +44,7 @@ namespace Capnp
if (index < 0 || index >= RawData.Length) if (index < 0 || index >= RawData.Length)
throw new IndexOutOfRangeException("index out of range"); throw new IndexOutOfRangeException("index out of range");
uint id = ProvideCapability(value); RawData[index] = ProvideCapability(value);
WirePointer ptr = default;
ptr.SetCapability(id);
RawData[index] = id;
} }
} }
@ -66,7 +65,7 @@ namespace Capnp
/// <param name="caps">List content. Can be null in which case the list is simply not initialized.</param> /// <param name="caps">List content. Can be null in which case the list is simply not initialized.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init(IReadOnlyList<T> caps) public void Init(IReadOnlyList<T?>? caps)
{ {
if (caps == null) if (caps == null)
{ {

View File

@ -92,7 +92,7 @@ namespace Capnp
/// <param name="init">Serialization action to transfer a particular item into the serializer state.</param> /// <param name="init">Serialization action to transfer a particular item into the serializer state.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init<T>(IReadOnlyList<T> items, Action<TS, T> init) public void Init<T>(IReadOnlyList<T>? items, Action<TS, T> init)
{ {
if (items == null) if (items == null)
{ {

View File

@ -69,7 +69,7 @@ namespace Capnp
/// <param name="items">List content. Can be null in which case the list is simply not initialized.</param> /// <param name="items">List content. Can be null in which case the list is simply not initialized.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init(IReadOnlyList<T> items) public void Init(IReadOnlyList<T>? items)
{ {
if (items == null) if (items == null)
{ {

View File

@ -72,7 +72,7 @@ namespace Capnp
/// <param name="init">Serialization action to transfer a particular item into the serializer state.</param> /// <param name="init">Serialization action to transfer a particular item into the serializer state.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init<T>(IReadOnlyList<T> items, Action<TS, T> init) public void Init<T>(IReadOnlyList<T>? items, Action<TS, T> init)
{ {
if (items == null) if (items == null)
{ {

View File

@ -88,7 +88,7 @@ namespace Capnp
/// <param name="items">List content. Can be null in which case the list is simply not initialized.</param> /// <param name="items">List content. Can be null in which case the list is simply not initialized.</param>
/// <exception cref="InvalidOperationException">The list was already initialized</exception> /// <exception cref="InvalidOperationException">The list was already initialized</exception>
/// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items, or the UTF-8 encoding of an individual string requires more than 2^29-2 bytes.</exception> /// <exception cref="ArgumentOutOfRangeException">More than 2^29-1 items, or the UTF-8 encoding of an individual string requires more than 2^29-2 bytes.</exception>
public void Init(IReadOnlyList<string> items) public void Init(IReadOnlyList<string?>? items)
{ {
if (items == null) if (items == null)
{ {

View File

@ -0,0 +1,140 @@
#pragma warning disable MA0048 // File name must match type name
#define INTERNAL_NULLABLE_ATTRIBUTES
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48
// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class AllowNullAttribute : Attribute
{ }
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DisallowNullAttribute : Attribute
{ }
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullAttribute : Attribute
{ }
/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullAttribute : Attribute
{ }
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullIfNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
}
/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnAttribute : Attribute
{ }
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnIfAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}
}
#endif

View File

@ -882,7 +882,7 @@ namespace Capnp
/// <item><description>Object at given position was already set.</description></item> /// <item><description>Object at given position was already set.</description></item>
/// </list></exception> /// </list></exception>
/// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is out of bounds.</exception> /// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is out of bounds.</exception>
public void WriteText(int index, string text, string defaultText) public void WriteText(int index, string? text, string defaultText)
{ {
BuildPointer(index).WriteText(text ?? defaultText); BuildPointer(index).WriteText(text ?? defaultText);
} }

View File

@ -61,7 +61,7 @@
{ {
var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier) var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier)
.AddModifiers(Public) .AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<Capnp.ICapnpSerializable>(true))); .AddBaseListTypes(SimpleBaseType(_names.Type<Capnp.ICapnpSerializable>(Nullability.NonNullable)));
if (def.GenericParameters.Count > 0) if (def.GenericParameters.Count > 0)
{ {
@ -184,6 +184,8 @@
internal string Transform(GenFile file) internal string Transform(GenFile file)
{ {
_names.NullableEnable = file.NullableEnable;
NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace; NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace;
var ns = NamespaceDeclaration(topNamespace); var ns = NamespaceDeclaration(topNamespace);
@ -204,7 +206,15 @@
UsingDirective(ParseName("Capnp")), UsingDirective(ParseName("Capnp")),
UsingDirective(ParseName("Capnp.Rpc")), UsingDirective(ParseName("Capnp.Rpc")),
UsingDirective(ParseName("System")), UsingDirective(ParseName("System")),
UsingDirective(ParseName("System.Collections.Generic")), UsingDirective(ParseName("System.Collections.Generic")));
if (_names.NullableEnable)
{
cu = cu.AddUsings(
UsingDirective(ParseName("System.Diagnostics.CodeAnalysis")));
}
cu = cu.AddUsings(
UsingDirective(ParseName("System.Threading")), UsingDirective(ParseName("System.Threading")),
UsingDirective(ParseName("System.Threading.Tasks"))); UsingDirective(ParseName("System.Threading.Tasks")));

View File

@ -22,7 +22,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
var whichEnum = EnumDeclaration(_names.UnionDiscriminatorEnum.ToString()) var whichEnum = EnumDeclaration(_names.UnionDiscriminatorEnum.ToString())
.AddModifiers(Public) .AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>())); .AddBaseListTypes(SimpleBaseType(_names.Type<ushort>(Nullability.NonNullable)));
var discFields = def.Fields.Where(f => f.DiscValue.HasValue); var discFields = def.Fields.Where(f => f.DiscValue.HasValue);
@ -52,7 +52,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
var decl = EnumDeclaration(def.Name) var decl = EnumDeclaration(def.Name)
.WithAttributeLists(MakeTypeIdAttributeLists(def.Id)) .WithAttributeLists(MakeTypeIdAttributeLists(def.Id))
.AddModifiers(Public) .AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>())); .AddBaseListTypes(SimpleBaseType(_names.Type<ushort>(Nullability.NonNullable)));
foreach (var enumerant in def.Enumerants.OrderBy(e => e.CodeOrder)) foreach (var enumerant in def.Enumerants.OrderBy(e => e.CodeOrder))
{ {

View File

@ -20,7 +20,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
MemberDeclarationSyntax MakeUnionField(Field field) MemberDeclarationSyntax MakeUnionField(Field field)
{ {
var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClassNullable); var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClass, Nullability.NullableRefAndValue);
switch (field.Type.Tag) switch (field.Type.Tag)
{ {
@ -75,7 +75,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
return null; return null;
} }
var prop = PropertyDeclaration(_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClassNullable), var prop = PropertyDeclaration(
_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClass, Nullability.NullableRef),
_names.GetCodeIdentifier(field).Identifier) _names.GetCodeIdentifier(field).Identifier)
.AddModifiers(Public).AddAccessorListAccessors( .AddModifiers(Public).AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
@ -111,7 +112,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
MemberDeclarationSyntax MakeUnionContentField() MemberDeclarationSyntax MakeUnionContentField()
{ {
return FieldDeclaration( return FieldDeclaration(
VariableDeclaration(_names.Type<object>()) VariableDeclaration(_names.Type<object>(Nullability.NullableRef))
.WithVariables( .WithVariables(
SingletonSeparatedList<VariableDeclaratorSyntax>( SingletonSeparatedList<VariableDeclaratorSyntax>(
VariableDeclarator(_names.UnionContentField.Identifier)))) VariableDeclarator(_names.UnionContentField.Identifier))))
@ -163,7 +164,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.Enum: case TypeTag.Enum:
return MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, return MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.NotRelevant), _names.MakeTypeSyntax(value.Type, scope, TypeUsage.NotRelevant, Nullability.NonNullable),
IdentifierName(value.GetEnumerant().Literal)); IdentifierName(value.GetEnumerant().Literal));
case TypeTag.F32: case TypeTag.F32:
@ -262,7 +263,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
value.Decode(); value.Decode();
return ObjectCreationExpression( return ObjectCreationExpression(
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.DomainClass)) _names.MakeTypeSyntax(value.Type, scope, TypeUsage.DomainClass, Nullability.NonNullable))
.WithArgumentList(ArgumentList()) .WithArgumentList(ArgumentList())
.WithInitializer( .WithInitializer(
InitializerExpression( InitializerExpression(
@ -282,7 +283,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
value.Decode(); value.Decode();
return ArrayCreationExpression(ArrayType( return ArrayCreationExpression(ArrayType(
_names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClassNullable)) _names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef))
.WithRankSpecifiers( .WithRankSpecifiers(
SingletonList<ArrayRankSpecifierSyntax>( SingletonList<ArrayRankSpecifierSyntax>(
ArrayRankSpecifier( ArrayRankSpecifier(
@ -344,7 +345,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.Enum: case TypeTag.Enum:
return CastExpression( return CastExpression(
_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.NotRelevant), _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.NotRelevant, Nullability.NonNullable),
LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0))); LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)));
case TypeTag.F32: case TypeTag.F32:
@ -488,6 +489,11 @@ namespace CapnpC.CSharp.Generator.CodeGen
} }
} }
ExpressionSyntax ConditionalSuppressNullableWarning(ExpressionSyntax expression, bool suppress)
{
return suppress ? _names.SuppressNullableWarning(expression) : expression;
}
StatementSyntax MakeSerializeMethodFieldAssignment(Field field) StatementSyntax MakeSerializeMethodFieldAssignment(Field field)
{ {
var writerProp = MemberAccessExpression( var writerProp = MemberAccessExpression(
@ -519,7 +525,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
writerProp, writerProp,
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.GetCodeIdentifier(field).IdentifierName, _names.SuppressNullableWarning(_names.GetCodeIdentifier(field).IdentifierName),
IdentifierName(nameof(Nullable<int>.Value))))); IdentifierName(nameof(Nullable<int>.Value)))));
} }
else else
@ -538,10 +544,11 @@ namespace CapnpC.CSharp.Generator.CodeGen
InvocationExpression( InvocationExpression(
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
MemberAccessExpression( ConditionalSuppressNullableWarning(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.WriterParameter.IdentifierName, _names.WriterParameter.IdentifierName,
_names.GetCodeIdentifier(field).IdentifierName), _names.GetCodeIdentifier(field).IdentifierName),
field.DiscValue.HasValue),
IdentifierName(nameof(Capnp.DynamicSerializerState.SetObject)))) IdentifierName(nameof(Capnp.DynamicSerializerState.SetObject))))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(_names.GetCodeIdentifier(field).IdentifierName))); Argument(_names.GetCodeIdentifier(field).IdentifierName)));
@ -568,7 +575,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
return ExpressionStatement( return ExpressionStatement(
MakeComplexSerializeParticle( MakeComplexSerializeParticle(
field.Type, field.Type,
writerProp, field.DiscValue.HasValue ? _names.SuppressNullableWarning(writerProp) : writerProp,
_names.GetCodeIdentifier(field).IdentifierName)); _names.GetCodeIdentifier(field).IdentifierName));
case TypeTag.Void: case TypeTag.Void:
@ -599,20 +606,20 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExpressionSyntax MakeInnerStructListConversion(ExpressionSyntax context, TypeSyntax elementType) ExpressionSyntax MakeInnerStructListConversion(ExpressionSyntax context, TypeSyntax elementType)
{ {
return InvocationExpression( return ConditionalAccessExpression(
MemberAccessExpression( context,
SyntaxKind.SimpleMemberAccessExpression, InvocationExpression(
context, MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList)))) IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument( .AddArgumentListArguments(Argument(
SimpleLambdaExpression(Parameter(Identifier("_")), SimpleLambdaExpression(Parameter(Identifier("_")),
InvocationExpression( InvocationExpression(
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)), IdentifierName(nameof(Capnp.CapnpSerializable)),
GenericName(nameof(Capnp.CapnpSerializable.Create)) GenericName(nameof(Capnp.CapnpSerializable.Create))
.AddTypeArgumentListArguments(MakeNonNullableType(elementType)))) .AddTypeArgumentListArguments(MakeNonNullableType(elementType))))
.AddArgumentListArguments(Argument(IdentifierName("_")))))); .AddArgumentListArguments(Argument(IdentifierName("_")))))));
} }
ExpressionSyntax MakeStructListConversion(ExpressionSyntax context, TypeSyntax elementType, int rank) ExpressionSyntax MakeStructListConversion(ExpressionSyntax context, TypeSyntax elementType, int rank)
@ -624,28 +631,28 @@ namespace CapnpC.CSharp.Generator.CodeGen
string lambdaVarName = $"_{rank}"; string lambdaVarName = $"_{rank}";
return InvocationExpression( return ConditionalAccessExpression(
MemberAccessExpression( context,
SyntaxKind.SimpleMemberAccessExpression, InvocationExpression(
context, MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList)))) IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument( .AddArgumentListArguments(Argument(
SimpleLambdaExpression( SimpleLambdaExpression(
Parameter(Identifier(lambdaVarName)), Parameter(Identifier(lambdaVarName)),
MakeStructListConversion(IdentifierName(lambdaVarName), elementType, rank - 1)))); MakeStructListConversion(IdentifierName(lambdaVarName), elementType, rank - 1)))));
} }
ExpressionSyntax MakeAnyListConversion(ExpressionSyntax context) ExpressionSyntax MakeAnyListConversion(ExpressionSyntax context)
{ {
return InvocationExpression( return ConditionalAccessExpression(
MemberAccessExpression( context,
SyntaxKind.SimpleMemberAccessExpression, InvocationExpression(
context, MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList)))) IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument( .AddArgumentListArguments(Argument(
SimpleLambdaExpression( SimpleLambdaExpression(
Parameter(Identifier("_")), Parameter(Identifier("_")),
CastExpression(_names.Type<object>(), IdentifierName("_"))))); CastExpression(_names.Type<object>(Nullability.NonNullable), IdentifierName("_"))))));
} }
ExpressionSyntax MakeDeserializeMethodRightHandSide(Field field) ExpressionSyntax MakeDeserializeMethodRightHandSide(Field field)
@ -665,7 +672,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
MakeNonNullableType(_names.MakeTypeSyntax( MakeNonNullableType(_names.MakeTypeSyntax(
field.Type, field.Type,
field.DeclaringType, field.DeclaringType,
TypeUsage.DomainClass))))) TypeUsage.DomainClass,
Nullability.NonNullable)))))
.AddArgumentListArguments(Argument(MemberAccessExpression( .AddArgumentListArguments(Argument(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderParameter.IdentifierName, _names.ReaderParameter.IdentifierName,
@ -684,7 +692,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderParameter.IdentifierName, _names.ReaderParameter.IdentifierName,
_names.GetCodeIdentifier(field).IdentifierName), _names.GetCodeIdentifier(field).IdentifierName),
_names.MakeTypeSyntax(elementType, field.DeclaringType, TypeUsage.DomainClassNullable), _names.MakeTypeSyntax(elementType, field.DeclaringType, TypeUsage.DomainClass, Nullability.NullableRef),
rank); rank);
case TypeTag.ListPointer: case TypeTag.ListPointer:
@ -716,18 +724,6 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (unionField.Type.Tag != TypeTag.Void) if (unionField.Type.Tag != TypeTag.Void)
{ {
ExpressionSyntax right = _names.GetCodeIdentifier(unionField).IdentifierName;
var syntax = _names.MakeTypeSyntax(unionField.Type, unionField.DeclaringType, TypeUsage.DomainClassNullable);
if (syntax is NullableTypeSyntax)
{
right = MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
right,
IdentifierName(nameof(Nullable<int>.Value)));
}
section = section.AddStatements(MakeSerializeMethodFieldAssignment(unionField)); section = section.AddStatements(MakeSerializeMethodFieldAssignment(unionField));
} }
@ -849,7 +845,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable)))) ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable))))
.AddParameterListParameters( .AddParameterListParameters(
Parameter(_names.AnonymousParameter.Identifier) Parameter(_names.AnonymousParameter.Identifier)
.WithType(_names.Type<Capnp.SerializerState>(true))) .WithType(_names.Type<Capnp.SerializerState>(Nullability.NonNullable)))
.AddBodyStatements( .AddBodyStatements(
ExpressionStatement( ExpressionStatement(
InvocationExpression(_names.SerializeMethod.IdentifierName) InvocationExpression(_names.SerializeMethod.IdentifierName)
@ -933,7 +929,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable)))) ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable))))
.AddParameterListParameters( .AddParameterListParameters(
Parameter(_names.AnonymousParameter.Identifier) Parameter(_names.AnonymousParameter.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>())) .WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))
.AddBodyStatements(stmts.ToArray()); .AddBodyStatements(stmts.ToArray());
} }
@ -944,7 +940,10 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (def.UnionInfo != null) if (def.UnionInfo != null)
{ {
yield return MakeUnionDiscriminatorField(); yield return MakeUnionDiscriminatorField();
yield return MakeUnionContentField(); if (def.Fields.Any(f => f.DiscValue.HasValue && f.Type.Tag != TypeTag.Void))
{
yield return MakeUnionContentField();
}
yield return MakeUnionDiscriminatorProperty(def); yield return MakeUnionDiscriminatorProperty(def);
} }

View File

@ -22,11 +22,17 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
NotRelevant, NotRelevant,
DomainClass, DomainClass,
DomainClassNullable,
Reader, Reader,
Writer Writer
} }
enum Nullability
{
NonNullable,
NullableRefAndValue,
NullableRef
}
class GenNames class GenNames
{ {
readonly Dictionary<Field, Name> _fieldNameMap = new Dictionary<Field, Name>(); readonly Dictionary<Field, Name> _fieldNameMap = new Dictionary<Field, Name>();
@ -185,7 +191,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
TypeSyntax ResolveGenericParameter(GenericParameter p, Model.Type boundType, TypeDefinition def) TypeSyntax ResolveGenericParameter(GenericParameter p, Model.Type boundType, TypeDefinition def)
{ {
var type = boundType.ResolveGenericParameter(p); var type = boundType.ResolveGenericParameter(p);
return MakeTypeSyntax(type, def, TypeUsage.DomainClass); return MakeTypeSyntax(type, def, TypeUsage.DomainClass, Nullability.NonNullable);
} }
public SimpleNameSyntax MakeGenericTypeName(TypeDefinition def, Model.Type boundType, NameUsage usage = NameUsage.Default) public SimpleNameSyntax MakeGenericTypeName(TypeDefinition def, Model.Type boundType, NameUsage usage = NameUsage.Default)
@ -289,82 +295,82 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.AnyPointer: case TypeTag.AnyPointer:
case TypeTag.StructPointer: case TypeTag.StructPointer:
case TypeTag.ListPointer: case TypeTag.ListPointer:
return Type<Capnp.ListOfPointersSerializer<Capnp.DynamicSerializerState>>(true); return Type<Capnp.ListOfPointersSerializer<Capnp.DynamicSerializerState>>(Nullability.NonNullable);
case TypeTag.CapabilityPointer: case TypeTag.CapabilityPointer:
return Type<Capnp.ListOfCapsSerializer<Capnp.Rpc.BareProxy>>(true); return Type<Capnp.ListOfCapsSerializer<Capnp.Rpc.BareProxy>>(Nullability.NonNullable);
case TypeTag.Data: case TypeTag.Data:
return Type<Capnp.ListOfPointersSerializer< return Type<Capnp.ListOfPointersSerializer<
Capnp.ListOfPrimitivesSerializer<byte>>>(true); Capnp.ListOfPrimitivesSerializer<byte>>>(Nullability.NonNullable);
case TypeTag.Enum: case TypeTag.Enum:
return GenericName("ListOfPrimitivesSerializer") return GenericName("ListOfPrimitivesSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer)); .AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Group: case TypeTag.Group:
case TypeTag.Struct: case TypeTag.Struct:
return GenericName("ListOfStructsSerializer") return GenericName("ListOfStructsSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer)); .AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Interface: case TypeTag.Interface:
return GenericName("ListOfCapsSerializer") return GenericName("ListOfCapsSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer)); .AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.List: case TypeTag.List:
return GenericName("ListOfPointersSerializer") return GenericName("ListOfPointersSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer)); .AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Text: case TypeTag.Text:
return Type<Capnp.ListOfTextSerializer>(true); return Type<Capnp.ListOfTextSerializer>(Nullability.NonNullable);
case TypeTag.Void: case TypeTag.Void:
return Type<Capnp.ListOfEmptySerializer>(true); return Type<Capnp.ListOfEmptySerializer>(Nullability.NonNullable);
case TypeTag.Bool: case TypeTag.Bool:
return Type<Capnp.ListOfBitsSerializer>(true); return Type<Capnp.ListOfBitsSerializer>(Nullability.NonNullable);
case TypeTag.F32: case TypeTag.F32:
return Type<Capnp.ListOfPrimitivesSerializer<float>>(true); return Type<Capnp.ListOfPrimitivesSerializer<float>>(Nullability.NonNullable);
case TypeTag.F64: case TypeTag.F64:
return Type<Capnp.ListOfPrimitivesSerializer<double>>(true); return Type<Capnp.ListOfPrimitivesSerializer<double>>(Nullability.NonNullable);
case TypeTag.S8: case TypeTag.S8:
return Type<Capnp.ListOfPrimitivesSerializer<sbyte>>(true); return Type<Capnp.ListOfPrimitivesSerializer<sbyte>>(Nullability.NonNullable);
case TypeTag.U8: case TypeTag.U8:
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(true); return Type<Capnp.ListOfPrimitivesSerializer<byte>>(Nullability.NonNullable);
case TypeTag.S16: case TypeTag.S16:
return Type<Capnp.ListOfPrimitivesSerializer<short>>(true); return Type<Capnp.ListOfPrimitivesSerializer<short>>(Nullability.NonNullable);
case TypeTag.U16: case TypeTag.U16:
case TypeTag.AnyEnum: case TypeTag.AnyEnum:
return Type<Capnp.ListOfPrimitivesSerializer<ushort>>(true); return Type<Capnp.ListOfPrimitivesSerializer<ushort>>(Nullability.NonNullable);
case TypeTag.S32: case TypeTag.S32:
return Type<Capnp.ListOfPrimitivesSerializer<int>>(true); return Type<Capnp.ListOfPrimitivesSerializer<int>>(Nullability.NonNullable);
case TypeTag.U32: case TypeTag.U32:
return Type<Capnp.ListOfPrimitivesSerializer<uint>>(true); return Type<Capnp.ListOfPrimitivesSerializer<uint>>(Nullability.NonNullable);
case TypeTag.S64: case TypeTag.S64:
return Type<Capnp.ListOfPrimitivesSerializer<long>>(true); return Type<Capnp.ListOfPrimitivesSerializer<long>>(Nullability.NonNullable);
case TypeTag.U64: case TypeTag.U64:
return Type<Capnp.ListOfPrimitivesSerializer<ulong>>(true); return Type<Capnp.ListOfPrimitivesSerializer<ulong>>(Nullability.NonNullable);
default: default:
throw new NotImplementedException("Unexpected type tag, don't know how to deal with this"); throw new NotImplementedException("Unexpected type tag, don't know how to deal with this");
} }
} }
TypeSyntax MaybeNullableValueType(TypeSyntax typeSyntax, TypeUsage usage) TypeSyntax MaybeNullableValueType(TypeSyntax typeSyntax, Nullability nullability)
{ {
switch (usage) switch (nullability)
{ {
case TypeUsage.DomainClassNullable: case Nullability.NullableRefAndValue:
return NullableType(typeSyntax); return NullableType(typeSyntax);
default: default:
@ -372,76 +378,77 @@ namespace CapnpC.CSharp.Generator.CodeGen
} }
} }
public TypeSyntax MakeTypeSyntax(Model.Type type, TypeDefinition scope, TypeUsage usage) TypeSyntax MaybeNullableRefType(TypeSyntax typeSyntax, Nullability nullability)
{ {
bool nonNullable = usage != TypeUsage.DomainClassNullable; switch (nullability)
{
case Nullability.NullableRef:
case Nullability.NullableRefAndValue:
return NullableType(typeSyntax);
default:
return typeSyntax;
}
}
public TypeSyntax MakeTypeSyntax(Model.Type type, TypeDefinition scope, TypeUsage usage, Nullability nullability)
{
switch (type.Tag) switch (type.Tag)
{ {
case TypeTag.AnyEnum: case TypeTag.AnyEnum:
return MaybeNullableValueType(Type<ushort>(), usage); return Type<ushort>(nullability);
case TypeTag.CapabilityPointer: case TypeTag.CapabilityPointer:
if (type.Parameter != null) if (type.Parameter != null)
{ return MaybeNullableRefType(GetQName(type, scope), nullability);
return nonNullable ? GetQName(type, scope) :
MakeNullableType(GetQName(type, scope));
}
else else
{ return Type<Capnp.Rpc.BareProxy>(nullability);
return Type<Capnp.Rpc.BareProxy>(nonNullable);
}
case TypeTag.AnyPointer: case TypeTag.AnyPointer:
case TypeTag.StructPointer: case TypeTag.StructPointer:
switch (usage) switch (usage)
{ {
case TypeUsage.Reader: case TypeUsage.Reader:
return Type<Capnp.DeserializerState>(); return Type<Capnp.DeserializerState>(Nullability.NonNullable);
case TypeUsage.Writer: case TypeUsage.Writer:
return Type<Capnp.DynamicSerializerState>(); return Type<Capnp.DynamicSerializerState>(Nullability.NullableRef);
case TypeUsage.DomainClass when type.Parameter == null:
return Type<object>(nullability);
case TypeUsage.DomainClass when nullability == Nullability.NonNullable:
return GetQName(type, scope);
case TypeUsage.DomainClass: case TypeUsage.DomainClass:
case TypeUsage.DomainClassNullable: return MakeNullableRefType(GetQName(type, scope));
if (type.Parameter != null)
{
return nonNullable ?
GetQName(type, scope) :
MakeNullableType(GetQName(type, scope));
}
else
{
return Type<object>(nonNullable);
}
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
case TypeTag.Bool: case TypeTag.Bool:
return MaybeNullableValueType(Type<bool>(), usage); return Type<bool>(nullability);
case TypeTag.Data: case TypeTag.Data:
switch (usage) switch (usage)
{ {
case TypeUsage.Reader: case TypeUsage.Reader:
case TypeUsage.DomainClass: case TypeUsage.DomainClass:
case TypeUsage.DomainClassNullable: return Type<IReadOnlyList<byte>>(nullability);
return Type<IReadOnlyList<byte>>(nonNullable);
case TypeUsage.Writer: case TypeUsage.Writer:
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(true); return Type<Capnp.ListOfPrimitivesSerializer<byte>>(nullability);
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
case TypeTag.Enum: case TypeTag.Enum:
return MaybeNullableValueType(GetQName(type, scope), usage); return MaybeNullableValueType(GetQName(type, scope), nullability);
case TypeTag.Interface: case TypeTag.Interface:
return GetQName(type, scope); return MaybeNullableRefType(GetQName(type, scope), nullability);
case TypeTag.Struct: case TypeTag.Struct:
case TypeTag.Group: case TypeTag.Group:
@ -453,39 +460,38 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeUsage.Reader: case TypeUsage.Reader:
return QualifiedName(GetQName(type, scope), ReaderStruct.IdentifierName); return QualifiedName(GetQName(type, scope), ReaderStruct.IdentifierName);
case TypeUsage.DomainClass: case TypeUsage.DomainClass when nullability == Nullability.NonNullable:
return GetQName(type, scope); return GetQName(type, scope);
case TypeUsage.DomainClassNullable: case TypeUsage.DomainClass:
return MakeNullableType(GetQName(type, scope)); return MakeNullableRefType(GetQName(type, scope));
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
case TypeTag.F32: case TypeTag.F32:
return MaybeNullableValueType(Type<float>(), usage); return Type<float>(nullability);
case TypeTag.F64: case TypeTag.F64:
return MaybeNullableValueType(Type<double>(), usage); return Type<double>(nullability);
case TypeTag.List when type.ElementType.Tag == TypeTag.Void && usage != TypeUsage.Writer: case TypeTag.List when type.ElementType.Tag == TypeTag.Void && usage != TypeUsage.Writer:
return MaybeNullableValueType(Type<int>(), usage); return Type<int>(nullability);
case TypeTag.List: case TypeTag.List:
switch (usage) switch (usage)
{ {
case TypeUsage.Writer: case TypeUsage.Writer:
return MakeListSerializerSyntax(type.ElementType, scope); return MaybeNullableRefType(MakeListSerializerSyntax(type.ElementType, scope), nullability);
case TypeUsage.Reader: case TypeUsage.Reader:
return GenericName(Identifier("IReadOnlyList")) return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader)); .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader, Nullability.NonNullable)), nullability);
case TypeUsage.DomainClass: case TypeUsage.DomainClass:
case TypeUsage.DomainClassNullable: return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList"))
return GenericName(Identifier("IReadOnlyList")) .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef)), nullability);
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, usage));
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
@ -495,47 +501,49 @@ namespace CapnpC.CSharp.Generator.CodeGen
switch (usage) switch (usage)
{ {
case TypeUsage.Writer: case TypeUsage.Writer:
return Type<Capnp.SerializerState>(); return Type<Capnp.SerializerState>(Nullability.NonNullable);
case TypeUsage.Reader: case TypeUsage.Reader:
return Type<IReadOnlyList<Capnp.DeserializerState>>(); return Type<IReadOnlyList<Capnp.DeserializerState>>(Nullability.NonNullable);
case TypeUsage.DomainClass when nullability == Nullability.NonNullable:
return GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(Type<object>(Nullability.NullableRef));
case TypeUsage.DomainClass: case TypeUsage.DomainClass:
return Type<IReadOnlyList<object>>(false); return MakeNullableRefType(GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(Type<object>(Nullability.NullableRef)));
case TypeUsage.DomainClassNullable:
return Type<IReadOnlyList<object>>(true);
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
case TypeTag.S16: case TypeTag.S16:
return MaybeNullableValueType(Type<short>(), usage); return Type<short>(nullability);
case TypeTag.S32: case TypeTag.S32:
return MaybeNullableValueType(Type<int>(), usage); return Type<int>(nullability);
case TypeTag.S64: case TypeTag.S64:
return MaybeNullableValueType(Type<long>(), usage); return Type<long>(nullability);
case TypeTag.S8: case TypeTag.S8:
return MaybeNullableValueType(Type<sbyte>(), usage); return Type<sbyte>(nullability);
case TypeTag.Text: case TypeTag.Text:
return Type<string>(nonNullable); return Type<string>(nullability);
case TypeTag.U16: case TypeTag.U16:
return MaybeNullableValueType(Type<ushort>(), usage); return Type<ushort>(nullability);
case TypeTag.U32: case TypeTag.U32:
return MaybeNullableValueType(Type<uint>(), usage); return Type<uint>(nullability);
case TypeTag.U64: case TypeTag.U64:
return MaybeNullableValueType(Type<ulong>(), usage); return Type<ulong>(nullability);
case TypeTag.U8: case TypeTag.U8:
return MaybeNullableValueType(Type<byte>(), usage); return Type<byte>(nullability);
case TypeTag.Void: case TypeTag.Void:
return PredefinedType(Token(SyntaxKind.VoidKeyword)); return PredefinedType(Token(SyntaxKind.VoidKeyword));
@ -648,7 +656,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
MakePipeliningSupportExtensionMethodName(path))); MakePipeliningSupportExtensionMethodName(path)));
} }
public TypeSyntax MakeNullableType(TypeSyntax type) public TypeSyntax MakeNullableRefType(TypeSyntax type)
{ {
return NullableEnable ? return NullableEnable ?
NullableType(type) : NullableType(type) :
@ -656,13 +664,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
} }
public TypeSyntax Type<T>(bool nonNullable = false) public TypeSyntax Type<T>(Nullability nullability)
{ {
return NullableEnable && !typeof(T).IsValueType && !nonNullable ? return (NullableEnable && !typeof(T).IsValueType && nullability != Nullability.NonNullable) ||
( typeof(T).IsValueType && nullability == Nullability.NullableRefAndValue) ?
NullableType(SyntaxHelpers.NonNullableType<T>()) : NullableType(SyntaxHelpers.NonNullableType<T>()) :
SyntaxHelpers.NonNullableType<T>(); SyntaxHelpers.NonNullableType<T>();
} }
public ClassOrStructConstraintSyntax MakeNullableClassConstraint() => ClassOrStructConstraint(SyntaxKind.ClassConstraint); public ExpressionSyntax SuppressNullableWarning(ExpressionSyntax expression)
{
return NullableEnable ?
PostfixUnaryExpression(SyntaxKind.SuppressNullableWarningExpression, expression) :
expression;
}
} }
} }

View File

@ -27,15 +27,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
case 0: case 0:
return IdentifierName(nameof(Task)); return IdentifierName(nameof(Task));
case 1 when method.Results[0].Type.Tag == TypeTag.Struct:
return GenericName(nameof(Task)).AddTypeArgumentListArguments(
_names.MakeTypeSyntax(method.Results[0].Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NonNullable));
case 1: case 1:
return GenericName(nameof(Task)).AddTypeArgumentListArguments( return GenericName(nameof(Task)).AddTypeArgumentListArguments(
_names.MakeTypeSyntax(method.Results[0].Type, method.DeclaringInterface, TypeUsage.DomainClassNullable)); _names.MakeTypeSyntax(method.Results[0].Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NullableRef));
default: default:
return GenericName(nameof(Task)).AddTypeArgumentListArguments( return GenericName(nameof(Task)).AddTypeArgumentListArguments(
TupleType(SeparatedList( TupleType(SeparatedList(
method.Results.Select( method.Results.Select(
f => TupleElement(_names.MakeTypeSyntax(f.Type, method.DeclaringInterface, TypeUsage.DomainClassNullable)))))); f => TupleElement(_names.MakeTypeSyntax(f.Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NullableRef))))));
} }
} }
@ -50,14 +54,14 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (arg0.Name == null) if (arg0.Name == null)
{ {
list.Add(Parameter(_names.AnonymousParameter.Identifier) list.Add(Parameter(_names.AnonymousParameter.Identifier)
.WithType(_names.MakeTypeSyntax(arg0.Type, method.DeclaringInterface, TypeUsage.DomainClassNullable))); .WithType(_names.MakeTypeSyntax(arg0.Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NullableRef)));
} }
else else
{ {
foreach (var arg in method.Params) foreach (var arg in method.Params)
{ {
list.Add(Parameter(Identifier(IdentifierRenamer.ToNonKeyword(arg.Name))) list.Add(Parameter(Identifier(IdentifierRenamer.ToNonKeyword(arg.Name)))
.WithType(_names.MakeTypeSyntax(arg.Type, method.DeclaringInterface, TypeUsage.DomainClassNullable))); .WithType(_names.MakeTypeSyntax(arg.Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NullableRef)));
} }
} }
} }
@ -85,7 +89,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
yield return TypeParameterConstraintClause( yield return TypeParameterConstraintClause(
_names.GetGenericTypeParameter(name).IdentifierName) _names.GetGenericTypeParameter(name).IdentifierName)
.AddConstraints(_names.MakeNullableClassConstraint()); .AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint));
} }
} }
@ -124,7 +128,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
ifaceDecl = ifaceDecl.AddBaseListTypes( ifaceDecl = ifaceDecl.AddBaseListTypes(
SimpleBaseType(_names.MakeTypeSyntax( SimpleBaseType(_names.MakeTypeSyntax(
superClass, type, superClass, type,
TypeUsage.NotRelevant))); TypeUsage.DomainClass,
Nullability.NonNullable)));
} }
} }
@ -226,9 +231,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
StatementSyntax MakeProxyCreateResult(Method method) StatementSyntax MakeProxyCreateResult(Method method)
{ {
var resultType = method.ResultStruct; var resultType = method.ResultStruct;
var domainType = _names.MakeTypeSyntax(resultType, method.DeclaringInterface, TypeUsage.DomainClass); var domainType = _names.MakeTypeSyntax(resultType, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NonNullable);
var createDomain = InvocationExpression( ExpressionSyntax createDomain = InvocationExpression(
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)), IdentifierName(nameof(Capnp.CapnpSerializable)),
@ -237,6 +242,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(_names.DeserializerLocal.IdentifierName)); Argument(_names.DeserializerLocal.IdentifierName));
if (_names.NullableEnable)
{
createDomain = PostfixUnaryExpression(
SyntaxKind.SuppressNullableWarningExpression,
createDomain);
}
return LocalDeclarationStatement( return LocalDeclarationStatement(
VariableDeclaration( VariableDeclaration(
IdentifierName("var")) IdentifierName("var"))
@ -262,7 +274,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
yield return TypeParameterConstraintClause( yield return TypeParameterConstraintClause(
_names.GetGenericTypeParameter(name).IdentifierName) _names.GetGenericTypeParameter(name).IdentifierName)
.AddConstraints(_names.MakeNullableClassConstraint()); .AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint));
} }
} }
@ -271,7 +283,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
var classDecl = ClassDeclaration(_names.MakeTypeName(type, NameUsage.Proxy).Identifier) var classDecl = ClassDeclaration(_names.MakeTypeName(type, NameUsage.Proxy).Identifier)
.AddModifiers(Public) .AddModifiers(Public)
.AddBaseListTypes( .AddBaseListTypes(
SimpleBaseType(_names.Type<Capnp.Rpc.Proxy>(true)), SimpleBaseType(_names.Type<Capnp.Rpc.Proxy>(Nullability.NonNullable)),
SimpleBaseType(_names.MakeGenericTypeName(type, NameUsage.Interface))); SimpleBaseType(_names.MakeGenericTypeName(type, NameUsage.Interface)));
if (type.GenericParameters.Count > 0) if (type.GenericParameters.Count > 0)
@ -311,7 +323,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax( _names.MakeTypeSyntax(
method.ParamsStruct, method.ParamsStruct,
method.ParamsStruct.Definition, method.ParamsStruct.Definition,
TypeUsage.Writer)))))))))))); TypeUsage.Writer, Nullability.NonNullable))))))))))));
if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct) if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct)
{ {
@ -328,7 +340,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax( _names.MakeTypeSyntax(
method.ParamsStruct, method.ParamsStruct,
method.ParamsStruct.Definition, method.ParamsStruct.Definition,
TypeUsage.DomainClass)) TypeUsage.DomainClass,
Nullability.NonNullable))
.WithArgumentList( .WithArgumentList(
ArgumentList()) ArgumentList())
.WithInitializer( .WithInitializer(
@ -340,13 +353,12 @@ namespace CapnpC.CSharp.Generator.CodeGen
} }
bodyStmts.Add(ExpressionStatement( bodyStmts.Add(ExpressionStatement(
InvocationExpression( ConditionalAccessExpression(
MemberAccessExpression( _names.AnonymousParameter.IdentifierName,
SyntaxKind.SimpleMemberAccessExpression, InvocationExpression(
_names.AnonymousParameter.IdentifierName, MemberBindingExpression(_names.SerializeMethod.IdentifierName))
_names.SerializeMethod.IdentifierName)) .AddArgumentListArguments(
.AddArgumentListArguments( Argument(_names.ParamsLocal.IdentifierName)))));
Argument(_names.ParamsLocal.IdentifierName))));
var call = InvocationExpression(IdentifierName(nameof(Capnp.Rpc.BareProxy.Call))) var call = InvocationExpression(IdentifierName(nameof(Capnp.Rpc.BareProxy.Call)))
.AddArgumentListArguments( .AddArgumentListArguments(
@ -361,7 +373,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.ParamsLocal.IdentifierName, _names.ParamsLocal.IdentifierName,
GenericName(nameof(Capnp.SerializerState.Rewrap)) GenericName(nameof(Capnp.SerializerState.Rewrap))
.AddTypeArgumentListArguments(_names.Type<Capnp.DynamicSerializerState>()))) .AddTypeArgumentListArguments(_names.Type<Capnp.DynamicSerializerState>(Nullability.NonNullable))))
.AddArgumentListArguments()), .AddArgumentListArguments()),
Argument( Argument(
LiteralExpression(SyntaxKind.FalseLiteralExpression)), LiteralExpression(SyntaxKind.FalseLiteralExpression)),
@ -446,7 +458,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
GenericName(_names.GetCodeIdentifier(method).ToString()) GenericName(_names.GetCodeIdentifier(method).ToString())
.AddTypeArgumentListArguments( .AddTypeArgumentListArguments(
Enumerable.Repeat( Enumerable.Repeat(
_names.Type<Capnp.AnyPointer>(), _names.Type<Capnp.AnyPointer>(Nullability.NonNullable),
method.GenericParameters.Count).ToArray())); method.GenericParameters.Count).ToArray()));
} }
else else
@ -502,7 +514,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax( _names.MakeTypeSyntax(
method.ResultStruct, method.ResultStruct,
method.ResultStruct.Definition, method.ResultStruct.Definition,
TypeUsage.Writer))))))))))); TypeUsage.Writer, Nullability.NonNullable)))))))))));
} }
@ -523,7 +535,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax( _names.MakeTypeSyntax(
method.ResultStruct, method.ResultStruct,
method.ResultStruct.Definition, method.ResultStruct.Definition,
TypeUsage.DomainClass)) TypeUsage.DomainClass,
Nullability.NonNullable))
.WithInitializer( .WithInitializer(
InitializerExpression(SyntaxKind.ObjectInitializerExpression) InitializerExpression(SyntaxKind.ObjectInitializerExpression)
.AddExpressions( .AddExpressions(
@ -575,9 +588,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (method.Params.Count > 0) if (method.Params.Count > 0)
{ {
var paramsType = method.ParamsStruct; var paramsType = method.ParamsStruct;
var domainType = _names.MakeTypeSyntax(paramsType, method.ParamsStruct.Definition, TypeUsage.DomainClass); var domainType = _names.MakeTypeSyntax(paramsType, method.ParamsStruct.Definition, TypeUsage.DomainClass, Nullability.NonNullable);
var createDomain = InvocationExpression( ExpressionSyntax createDomain = InvocationExpression(
MemberAccessExpression( MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)), IdentifierName(nameof(Capnp.CapnpSerializable)),
@ -586,6 +599,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(_names.DeserializerLocal.IdentifierName)); Argument(_names.DeserializerLocal.IdentifierName));
if (_names.NullableEnable)
{
createDomain = PostfixUnaryExpression(
SyntaxKind.SuppressNullableWarningExpression,
createDomain);
}
if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct) if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct)
{ {
yield return LocalDeclarationStatement( yield return LocalDeclarationStatement(
@ -662,13 +682,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
foreach (var method in def.Methods) foreach (var method in def.Methods)
{ {
var methodDecl = MethodDeclaration( var methodDecl = MethodDeclaration(
_names.Type<Task<Capnp.Rpc.AnswerOrCounterquestion>>(), _names.Type<Task<Capnp.Rpc.AnswerOrCounterquestion>>(Nullability.NonNullable),
_names.GetCodeIdentifier(method).Identifier) _names.GetCodeIdentifier(method).Identifier)
.AddParameterListParameters( .AddParameterListParameters(
Parameter(_names.DeserializerLocal.Identifier) Parameter(_names.DeserializerLocal.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()), .WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)),
Parameter(_names.CancellationTokenParameter.Identifier) Parameter(_names.CancellationTokenParameter.Identifier)
.WithType(_names.Type<CancellationToken>())) .WithType(_names.Type<CancellationToken>(Nullability.NonNullable)))
.AddBodyStatements( .AddBodyStatements(
MakeSkeletonMethodBody(method).ToArray()); MakeSkeletonMethodBody(method).ToArray());
@ -709,7 +729,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments( .AddArgumentListArguments(
MakeSkeletonSetMethodTableArguments(type).ToArray()))), MakeSkeletonSetMethodTableArguments(type).ToArray()))),
// InterfaceId // InterfaceId
PropertyDeclaration(_names.Type<ulong>(), nameof(Capnp.Rpc.Skeleton<object>.InterfaceId)) PropertyDeclaration(_names.Type<ulong>(Nullability.NonNullable), nameof(Capnp.Rpc.Skeleton<object>.InterfaceId))
.AddModifiers(Public, Override) .AddModifiers(Public, Override)
.WithExpressionBody( .WithExpressionBody(
ArrowExpressionClause( ArrowExpressionClause(
@ -790,7 +810,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
var accessPath = _names.MakeMemberAccessPathFieldName(method, path); var accessPath = _names.MakeMemberAccessPathFieldName(method, path);
var methodName = _names.MakePipeliningSupportExtensionMethodName(path); var methodName = _names.MakePipeliningSupportExtensionMethodName(path);
var capType = path[path.Count - 1].Type; var capType = path[path.Count - 1].Type;
var capTypeSyntax = _names.MakeTypeSyntax(capType, null, TypeUsage.DomainClass); var capTypeSyntax = _names.MakeTypeSyntax(capType, null, TypeUsage.DomainClass, Nullability.NonNullable);
if (!_existingExtensionMethods.Add((capTypeSyntax.ToString(), methodName.ToString()))) if (!_existingExtensionMethods.Add((capTypeSyntax.ToString(), methodName.ToString())))
{ {

View File

@ -57,7 +57,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ParameterList( ParameterList(
SingletonSeparatedList<ParameterSyntax>( SingletonSeparatedList<ParameterSyntax>(
Parameter(_names.ReaderContextField.Identifier) Parameter(_names.ReaderContextField.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>())))) .WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithExpressionBody( .WithExpressionBody(
ArrowExpressionClause( ArrowExpressionClause(
ObjectCreationExpression(_names.ReaderStruct.IdentifierName) ObjectCreationExpression(_names.ReaderStruct.IdentifierName)
@ -78,7 +78,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SingletonSeparatedList( SingletonSeparatedList(
Parameter(_names.ContextParameter.Identifier) Parameter(_names.ContextParameter.Identifier)
.WithType( .WithType(
_names.Type<Capnp.DeserializerState>())))) _names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithExpressionBody( .WithExpressionBody(
ArrowExpressionClause( ArrowExpressionClause(
ObjectCreationExpression(_names.ReaderStruct.IdentifierName) ObjectCreationExpression(_names.ReaderStruct.IdentifierName)
@ -90,7 +90,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
yield return FieldDeclaration( yield return FieldDeclaration(
VariableDeclaration( VariableDeclaration(
_names.Type<Capnp.DeserializerState>()) _names.Type<Capnp.DeserializerState>(Nullability.NonNullable))
.AddVariables(_names.ReaderContextField.VariableDeclarator)) .AddVariables(_names.ReaderContextField.VariableDeclarator))
.AddModifiers(Readonly); .AddModifiers(Readonly);
@ -100,7 +100,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ParameterList( ParameterList(
SingletonSeparatedList( SingletonSeparatedList(
Parameter(_names.ContextParameter.Identifier) Parameter(_names.ContextParameter.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>())))) .WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithBody( .WithBody(
Block( Block(
SingletonList<StatementSyntax>( SingletonList<StatementSyntax>(
@ -122,7 +122,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
yield return FieldDeclaration( yield return FieldDeclaration(
VariableDeclaration( VariableDeclaration(
_names.Type<Capnp.DeserializerState>()) _names.Type<Capnp.DeserializerState>(Nullability.NonNullable))
.AddVariables(_names.ReaderContextField.VariableDeclarator)) .AddVariables(_names.ReaderContextField.VariableDeclarator))
.AddModifiers(Readonly); .AddModifiers(Readonly);
@ -131,7 +131,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.WithParameterList( .WithParameterList(
ParameterList( ParameterList(
SingletonSeparatedList(Parameter(_names.GroupReaderContextArg.Identifier) SingletonSeparatedList(Parameter(_names.GroupReaderContextArg.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>())))) .WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithBody( .WithBody(
Block( Block(
SingletonList<StatementSyntax>( SingletonList<StatementSyntax>(
@ -173,57 +173,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
} }
static Func<ExpressionSyntax, ExpressionSyntax> MakeCastFunc(TypeSyntax type) => static Func<ExpressionSyntax, ExpressionSyntax> MakeCastFunc(TypeSyntax type) => x => CastExpression(type, x);
x => CastExpression(type, x);
static Func<ExpressionSyntax, ExpressionSyntax> MakeListCastFunc(string castName, Field field)
{
// Insight: List may have complex default values (e.g. [true, false, false, true] as a
// valid default value for a list of bools. This does not yet fit the author's mindset.
//if (field.DefaultValueIsExplicit)
//{
// return x => InvocationExpression(
// MemberAccessExpression(
// SyntaxKind.SimpleMemberAccessExpression,
// x,
// IdentifierName(castName))
// )
// .AddArgumentListArguments(
// Argument(ValueOf(field.DefaultValue)));
//}
//else
{
return x => InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
x,
IdentifierName(castName))
);
}
}
static Func<ExpressionSyntax, ExpressionSyntax> MakeListCastFuncWithCons(
string castName, ExpressionSyntax cons)
{
return x => InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
x,
IdentifierName(castName))
).AddArgumentListArguments(Argument(cons));
}
static Func<ExpressionSyntax, ExpressionSyntax> MakeGenericListCastFunc(string castName, TypeSyntax genericArgument)
{
return x => InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
x,
GenericName(castName).AddTypeArgumentListArguments(genericArgument))
);
}
PropertyDeclarationSyntax MakeReadProperty(TypeSyntax type, string name, SimpleNameSyntax readName, PropertyDeclarationSyntax MakeReadProperty(TypeSyntax type, string name, SimpleNameSyntax readName,
object indexOrBitOffset, ExpressionSyntax secondArg, object indexOrBitOffset, ExpressionSyntax secondArg,
@ -261,13 +211,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadPrimitiveProperty<T>(Field field, string readName) PropertyDeclarationSyntax MakeReadPrimitiveProperty<T>(Field field, string readName)
{ {
return MakeReadProperty(_names.Type<T>(), _names.GetCodeIdentifier(field).ToString(), readName, field.BitOffset.Value, return MakeReadProperty(
ValueOf(field.DefaultValue.ScalarValue), null, field.DiscValue.HasValue); _names.Type<T>(Nullability.NonNullable),
_names.GetCodeIdentifier(field).ToString(),
readName,
field.BitOffset.Value,
ValueOf(field.DefaultValue.ScalarValue),
null,
field.DiscValue.HasValue);
} }
PropertyDeclarationSyntax MakeReadEnumProperty(Field field) PropertyDeclarationSyntax MakeReadEnumProperty(Field field)
{ {
var typeSyntax = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader); var typeSyntax = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NonNullable);
return MakeReadProperty(typeSyntax, return MakeReadProperty(typeSyntax,
_names.GetCodeIdentifier(field).ToString(), _names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.SerializerExtensions.ReadDataUShort), field.BitOffset.Value, nameof(Capnp.SerializerExtensions.ReadDataUShort), field.BitOffset.Value,
@ -278,9 +234,16 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadTextProperty(Field field) PropertyDeclarationSyntax MakeReadTextProperty(Field field)
{ {
return MakeReadProperty(_names.Type<string>(), _names.GetCodeIdentifier(field).ToString(), bool cantBeNull = !field.DiscValue.HasValue && field.DefaultValue.ScalarValue != null;
nameof(Capnp.DeserializerState.ReadText), (int)field.Offset,
ValueOf(field.DefaultValue.ScalarValue), null, field.DiscValue.HasValue); return MakeReadProperty(
_names.Type<string>(cantBeNull ? Nullability.NonNullable : Nullability.NullableRef),
_names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.DeserializerState.ReadText),
(int)field.Offset,
ValueOf(field.DefaultValue.ScalarValue),
null,
field.DiscValue.HasValue);
} }
MemberAccessExpressionSyntax MakeReaderCreator(TypeSyntax qtype) MemberAccessExpressionSyntax MakeReaderCreator(TypeSyntax qtype)
@ -293,7 +256,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadStructProperty(Field field) PropertyDeclarationSyntax MakeReadStructProperty(Field field)
{ {
var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader); var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NonNullable);
var creator = MakeReaderCreator(qtype); var creator = MakeReaderCreator(qtype);
return MakeReadProperty(qtype, _names.GetCodeIdentifier(field).ToString(), return MakeReadProperty(qtype, _names.GetCodeIdentifier(field).ToString(),
@ -316,18 +279,16 @@ namespace CapnpC.CSharp.Generator.CodeGen
return MakeReaderProperty(type, _names.GetCodeIdentifier(field).ToString(), right, field.DiscValue.HasValue); return MakeReaderProperty(type, _names.GetCodeIdentifier(field).ToString(), right, field.DiscValue.HasValue);
} }
void MakeReadListPropertyImpl(Model.Type elementType, TypeDefinition scope, ExpressionSyntax context, int depth, ExpressionSyntax MakeReadListPropertyImpl(Model.Type elementType, TypeDefinition scope, ExpressionSyntax context, int depth)
out TypeSyntax listType, out ExpressionSyntax impl)
{ {
var elementTypeSyntax = _names.MakeTypeSyntax(elementType, scope, TypeUsage.Reader); var elementTypeSyntax = _names.MakeTypeSyntax(elementType, scope, TypeUsage.Reader, Nullability.NonNullable);
listType = GenericName("IReadOnlyList").AddTypeArgumentListArguments(elementTypeSyntax);
if (elementType.Tag == TypeTag.Interface || if (elementType.Tag == TypeTag.Interface ||
elementType.Tag == TypeTag.CapabilityPointer) elementType.Tag == TypeTag.CapabilityPointer)
{ {
if (depth == 0) if (depth == 0)
{ {
impl = InvocationExpression(MemberAccessExpression( return InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderContextField.IdentifierName, _names.ReaderContextField.IdentifierName,
GenericName(nameof(Capnp.DeserializerState.ReadCapList)) GenericName(nameof(Capnp.DeserializerState.ReadCapList))
@ -336,15 +297,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
} }
else else
{ {
impl = InvocationExpression( return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context, context,
GenericName(nameof(Capnp.DeserializerState.RequireCapList)) GenericName(nameof(Capnp.DeserializerState.RequireCapList))
.AddTypeArgumentListArguments(elementTypeSyntax) .AddTypeArgumentListArguments(elementTypeSyntax)
)); ));
} }
return;
} }
if (depth == 0) if (depth == 0)
@ -374,56 +333,44 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.List: case TypeTag.List:
{ {
MakeReadListPropertyImpl( var innerImpl = MakeReadListPropertyImpl(
elementType.ElementType, elementType.ElementType,
scope, scope,
lambdaArg, lambdaArg,
depth + 1, depth + 1);
out var innerListType,
out var innerImpl);
listType = GenericName("IReadOnlyList").AddTypeArgumentListArguments(innerListType); return InvocationExpression(
impl = InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.ListDeserializer.Cast)))) IdentifierName(nameof(Capnp.ListDeserializer.Cast))))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(SimpleLambdaExpression(lambdaParam, innerImpl))); Argument(SimpleLambdaExpression(lambdaParam, innerImpl)));
return;
} }
case TypeTag.ListPointer: case TypeTag.ListPointer:
{ {
listType = _names.Type<IReadOnlyList<object>>();
context = InvocationExpression(MemberAccessExpression( context = InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.DeserializerState.RequireList)) IdentifierName(nameof(Capnp.DeserializerState.RequireList))
)).AddArgumentListArguments(Argument(lambdaArg)); )).AddArgumentListArguments(Argument(lambdaArg));
impl = InvocationExpression( return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.LazyListSelect)))) IdentifierName(nameof(Capnp.ReadOnlyListExtensions.LazyListSelect))))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(SimpleLambdaExpression(lambdaParam, context))); Argument(SimpleLambdaExpression(lambdaParam, context)));
return;
} }
case TypeTag.Struct: case TypeTag.Struct:
{ {
impl = InvocationExpression( return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.ListDeserializer.Cast)))) IdentifierName(nameof(Capnp.ListDeserializer.Cast))))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(MakeReaderCreator(elementTypeSyntax))); Argument(MakeReaderCreator(elementTypeSyntax)));
return;
} }
case TypeTag.Enum: case TypeTag.Enum:
@ -432,32 +379,26 @@ namespace CapnpC.CSharp.Generator.CodeGen
lambdaParam, lambdaParam,
CastExpression(elementTypeSyntax, lambdaArg)); CastExpression(elementTypeSyntax, lambdaArg));
impl = InvocationExpression( return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.ListDeserializer.CastEnums)))) IdentifierName(nameof(Capnp.ListDeserializer.CastEnums))))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(cons)); Argument(cons));
return;
} }
case TypeTag.AnyPointer: case TypeTag.AnyPointer:
case TypeTag.StructPointer: case TypeTag.StructPointer:
{ {
listType = _names.Type<IReadOnlyList<Capnp.DeserializerState>>(); return context;
impl = context;
return;
} }
case TypeTag.Void: case TypeTag.Void:
{ {
listType = _names.Type<int>(); return MemberAccessExpression(
impl = MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(nameof(Capnp.ListDeserializer.Count))); IdentifierName(nameof(Capnp.ListDeserializer.Count)));
return;
} }
case TypeTag.Data: case TypeTag.Data:
@ -517,7 +458,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
throw new NotImplementedException("Unexpected type tag, don't know how to deal with this"); throw new NotImplementedException("Unexpected type tag, don't know how to deal with this");
} }
impl = InvocationExpression(MemberAccessExpression( return InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleMemberAccessExpression,
context, context,
IdentifierName(castFuncName))); IdentifierName(castFuncName)));
@ -527,13 +468,18 @@ namespace CapnpC.CSharp.Generator.CodeGen
{ {
var elementType = field.Type.ElementType; var elementType = field.Type.ElementType;
var context = ValueOf((int)field.Offset); var context = ValueOf((int)field.Offset);
MakeReadListPropertyImpl(elementType, field.DeclaringType, context, 0, out var listType, out var impl); var impl = MakeReadListPropertyImpl(elementType, field.DeclaringType, context, 0);
var listType = _names.MakeTypeSyntax(
field.Type,
field.DeclaringType,
TypeUsage.Reader,
field.DiscValue.HasValue ? Nullability.NullableRef : Nullability.NonNullable);
return MakeReaderProperty(listType, _names.GetCodeIdentifier(field).ToString(), impl, field.DiscValue.HasValue); return MakeReaderProperty(listType, _names.GetCodeIdentifier(field).ToString(), impl, field.DiscValue.HasValue);
} }
PropertyDeclarationSyntax MakeReadAnyListProperty(Field field) PropertyDeclarationSyntax MakeReadAnyListProperty(Field field)
{ {
var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader); var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NonNullable);
return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(), return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.DeserializerState.ReadList), nameof(Capnp.DeserializerState.ReadList),
@ -542,18 +488,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadCapProperty(Field field) PropertyDeclarationSyntax MakeReadCapProperty(Field field)
{ {
var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader); var nullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NullableRef);
var nonNullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NonNullable);
var readName = GenericName(nameof(Capnp.DeserializerState.ReadCap)) var readName = GenericName(nameof(Capnp.DeserializerState.ReadCap))
.AddTypeArgumentListArguments(type); .AddTypeArgumentListArguments(nonNullableType);
return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(), return MakeReadProperty(nullableType, _names.GetCodeIdentifier(field).ToString(),
readName, readName,
(int)field.Offset, null, null, field.DiscValue.HasValue); (int)field.Offset, null, null, field.DiscValue.HasValue);
} }
PropertyDeclarationSyntax MakeReadAnyCapProperty(Field field) PropertyDeclarationSyntax MakeReadAnyCapProperty(Field field)
{ {
var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader); var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader, Nullability.NonNullable);
return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(), return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.DeserializerState.ReadCap), nameof(Capnp.DeserializerState.ReadCap),
@ -573,7 +520,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
IdentifierName(nameof(Capnp.ListDeserializer.CastByte)))); IdentifierName(nameof(Capnp.ListDeserializer.CastByte))));
return MakeReaderProperty( return MakeReaderProperty(
_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader), _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Reader,
field.DiscValue.HasValue ? Nullability.NullableRefAndValue : Nullability.NonNullable),
_names.GetCodeIdentifier(field).ToString(), impl, field.DiscValue.HasValue); _names.GetCodeIdentifier(field).ToString(), impl, field.DiscValue.HasValue);
} }

View File

@ -115,12 +115,21 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(ValueOf(index))); Argument(ValueOf(index)));
ExpressionSyntax MakeLinkSyntax(object index) => ExpressionSyntax MakeLinkSyntax(object index, bool suppressNullableWarning)
InvocationExpression( {
ExpressionSyntax value = IdentifierName("value");
if (suppressNullableWarning)
{
value = _names.SuppressNullableWarning(value);
}
return InvocationExpression(
IdentifierName(SerializerStateWorder.LinkName)) IdentifierName(SerializerStateWorder.LinkName))
.AddArgumentListArguments( .AddArgumentListArguments(
Argument(ValueOf(index)), Argument(ValueOf(index)),
Argument(IdentifierName("value"))); Argument(value));
}
ExpressionSyntax MakeLinkObjectSyntax(object index) => ExpressionSyntax MakeLinkObjectSyntax(object index) =>
InvocationExpression( InvocationExpression(
@ -129,22 +138,46 @@ namespace CapnpC.CSharp.Generator.CodeGen
Argument(ValueOf(index)), Argument(ValueOf(index)),
Argument(IdentifierName("value"))); Argument(IdentifierName("value")));
PropertyDeclarationSyntax MakeWriterRefTypeProperty(
TypeSyntax type,
string name,
ExpressionSyntax getter,
ExpressionSyntax setter,
bool cast,
bool cond)
{
if (cond)
{
type = _names.MakeNullableRefType(type);
}
var prop = MakeWriterProperty(type, name, getter, setter, cast, cond);
if (cond && _names.NullableEnable)
{
prop = prop.AddAttributeLists(
AttributeList(
SingletonSeparatedList(
Attribute(
IdentifierName("DisallowNull")))));
}
return prop;
}
PropertyDeclarationSyntax MakePointerProperty(TypeSyntax type, string name, object index, bool cast, bool cond) PropertyDeclarationSyntax MakePointerProperty(TypeSyntax type, string name, object index, bool cast, bool cond)
{ {
ExpressionSyntax getter = MakePointerSyntax(type, index); ExpressionSyntax getter = MakePointerSyntax(type, index);
ExpressionSyntax setter = MakeLinkSyntax(index); ExpressionSyntax setter = MakeLinkSyntax(index, cond);
return MakeWriterProperty(type, name, getter, setter, cast, cond); return MakeWriterRefTypeProperty(type, name, getter, setter, cast, cond);
} }
PropertyDeclarationSyntax MakePointerAsStructProperty( PropertyDeclarationSyntax MakePointerAsStructProperty(TypeSyntax type, string name, object index, bool cast, bool cond)
TypeSyntax type, string name, object index,
bool cast, bool cond)
{ {
ExpressionSyntax getter = MakeTypedPointerSyntax(index, type); ExpressionSyntax getter = MakeTypedPointerSyntax(index, type);
ExpressionSyntax setter = MakeLinkSyntax(index); ExpressionSyntax setter = MakeLinkSyntax(index, cond);
return MakeWriterProperty(type, name, getter, setter, cast, cond); return MakeWriterRefTypeProperty(type, name, getter, setter, cast, cond);
} }
PropertyDeclarationSyntax MakeProperty( PropertyDeclarationSyntax MakeProperty(
@ -195,7 +228,10 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakePrimitiveProperty<T>(Field field, string readName) PropertyDeclarationSyntax MakePrimitiveProperty<T>(Field field, string readName)
{ {
return MakeProperty(_names.Type<T>(), null, _names.GetCodeIdentifier(field).ToString(), return MakeProperty(
_names.Type<T>(Nullability.NonNullable),
null,
_names.GetCodeIdentifier(field).ToString(),
readName, readName,
nameof(Capnp.SerializerExtensions.WriteData), nameof(Capnp.SerializerExtensions.WriteData),
field.BitOffset.Value, field.BitOffset.Value,
@ -207,7 +243,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeEnumProperty(Field field, string readName) PropertyDeclarationSyntax MakeEnumProperty(Field field, string readName)
{ {
return MakeProperty(_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.NotRelevant), _names.Type<ushort>(), return MakeProperty(
_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.NotRelevant, Nullability.NonNullable),
_names.Type<ushort>(Nullability.NonNullable),
_names.GetCodeIdentifier(field).ToString(), _names.GetCodeIdentifier(field).ToString(),
readName, readName,
nameof(Capnp.SerializerExtensions.WriteData), nameof(Capnp.SerializerExtensions.WriteData),
@ -220,7 +258,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeTextProperty(Field field) PropertyDeclarationSyntax MakeTextProperty(Field field)
{ {
return MakeProperty(_names.Type<string>(), null, return MakeProperty(
_names.Type<string>(Nullability.NullableRef),
null,
_names.GetCodeIdentifier(field).ToString(), _names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.SerializerState.ReadText), nameof(Capnp.SerializerState.ReadText),
nameof(Capnp.SerializerState.WriteText), nameof(Capnp.SerializerState.WriteText),
@ -233,7 +273,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeStructProperty(Field field) PropertyDeclarationSyntax MakeStructProperty(Field field)
{ {
var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer); var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
return MakePointerAsStructProperty(qtype, _names.GetCodeIdentifier(field).ToString(), return MakePointerAsStructProperty(qtype, _names.GetCodeIdentifier(field).ToString(),
(int)field.Offset, false, field.DiscValue.HasValue); (int)field.Offset, false, field.DiscValue.HasValue);
@ -241,7 +281,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeGroupProperty(Field field) PropertyDeclarationSyntax MakeGroupProperty(Field field)
{ {
var type = QualifiedName( TypeSyntax type = QualifiedName(
_names.MakeTypeName(field.Type.Definition).IdentifierName, _names.MakeTypeName(field.Type.Definition).IdentifierName,
_names.WriterStruct.IdentifierName); _names.WriterStruct.IdentifierName);
@ -249,12 +289,17 @@ namespace CapnpC.CSharp.Generator.CodeGen
GenericName(nameof(Capnp.SerializerState.Rewrap)) GenericName(nameof(Capnp.SerializerState.Rewrap))
.AddTypeArgumentListArguments(type)); .AddTypeArgumentListArguments(type));
if (field.DiscValue.HasValue)
{
type = _names.MakeNullableRefType(type);
}
return MakeWriterProperty(type, _names.GetCodeIdentifier(field).ToString(), getter, null, false, field.DiscValue.HasValue); return MakeWriterProperty(type, _names.GetCodeIdentifier(field).ToString(), getter, null, false, field.DiscValue.HasValue);
} }
PropertyDeclarationSyntax MakeListProperty(Field field) PropertyDeclarationSyntax MakeListProperty(Field field)
{ {
var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer); var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
return MakePointerProperty(qtype, _names.GetCodeIdentifier(field).ToString(), return MakePointerProperty(qtype, _names.GetCodeIdentifier(field).ToString(),
(int)field.Offset, false, field.DiscValue.HasValue); (int)field.Offset, false, field.DiscValue.HasValue);
@ -269,20 +314,21 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeCapProperty(Field field) PropertyDeclarationSyntax MakeCapProperty(Field field)
{ {
var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer); var nonNullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
var nullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NullableRef);
int index = (int)field.Offset; int index = (int)field.Offset;
string name = _names.GetCodeIdentifier(field).ToString(); string name = _names.GetCodeIdentifier(field).ToString();
ExpressionSyntax getter = MakeReadCapSyntax(type, index); ExpressionSyntax getter = MakeReadCapSyntax(nonNullableType, index);
ExpressionSyntax setter = MakeLinkObjectSyntax(index); ExpressionSyntax setter = MakeLinkObjectSyntax(index);
return MakeWriterProperty(type, name, getter, setter, false, field.DiscValue.HasValue); return MakeWriterProperty(nullableType, name, getter, setter, false, field.DiscValue.HasValue);
} }
PropertyDeclarationSyntax MakeWriterUnionSelector(TypeDefinition def) PropertyDeclarationSyntax MakeWriterUnionSelector(TypeDefinition def)
{ {
return MakeProperty( return MakeProperty(
_names.UnionDiscriminatorEnum.IdentifierName, _names.UnionDiscriminatorEnum.IdentifierName,
_names.Type<ushort>(), _names.Type<ushort>(Nullability.NonNullable),
_names.UnionDiscriminatorProp.ToString(), _names.UnionDiscriminatorProp.ToString(),
nameof(Capnp.SerializerExtensions.ReadDataUShort), nameof(Capnp.SerializerExtensions.ReadDataUShort),
nameof(Capnp.SerializerExtensions.WriteData), nameof(Capnp.SerializerExtensions.WriteData),

View File

@ -9,13 +9,24 @@ namespace MsBuildGenerationTest
// Instantiate some generated classes ensures that they are really present. // Instantiate some generated classes ensures that they are really present.
// Note that this code is not supposed to test runtime behavior, we have plenty of other test cases for that purpose. // Note that this code is not supposed to test runtime behavior, we have plenty of other test cases for that purpose.
void use(object x)
{
}
var vatId = new Capnp.Rpc.Twoparty.VatId(); var vatId = new Capnp.Rpc.Twoparty.VatId();
use(vatId);
var msg = new Capnp.Rpc.Message(); var msg = new Capnp.Rpc.Message();
use(msg);
var node = new Capnp.Schema.Node(); var node = new Capnp.Schema.Node();
use(node);
var x = Capnproto_test.Capnp.Test.TestEnum.garply; var x = Capnproto_test.Capnp.Test.TestEnum.garply;
use(x);
var imp = new CapnpGen.TestImport(); var imp = new CapnpGen.TestImport();
use(imp);
var imp2 = new CapnpGen.TestImport2(); var imp2 = new CapnpGen.TestImport2();
use(imp2);
var book = new CapnpGen.AddressBook(); var book = new CapnpGen.AddressBook();
use(book);
} }
} }
} }

View File

@ -110,7 +110,7 @@
# it for free. # it for free.
using Cxx = import "/capnp/c++.capnp"; using Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("capnp::rpc"); $Cxx.namespace("test::rpc");
# ======================================================================================== # ========================================================================================
# The Four Tables # The Four Tables