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">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.0</TargetFrameworks>
<RootNamespace>Capnp</RootNamespace>
<LangVersion>8.0</LangVersion>
<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>A capability interface (<seealso cref="Rpc.InvalidCapabilityInterfaceException"/> for further explanation)</description></item>
/// <item><description><see cref="String"/></description></item>
/// <item><description><see cref="IReadOnlyList{Boolean}"/></description></item>
/// <item><description><see cref="IReadOnlyList{SByte}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Byte}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Int16}"/></description></item>
/// <item><description><see cref="IReadOnlyList{UInt16}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Int32}"/></description></item>
/// <item><description><see cref="IReadOnlyList{UInt32}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Int64}"/></description></item>
/// <item><description><see cref="IReadOnlyList{UInt64}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Single}"/></description></item>
/// <item><description><see cref="IReadOnlyList{Double}"/></description></item>
/// <item><description><see cref="IReadOnlyList{T}"/> whereby T is one of the things listed here.</description></item>
/// <item><description><code>IReadOnlyList{Boolean}</code></description></item>
/// <item><description><code>IReadOnlyList{SByte}"</code></description></item>
/// <item><description><code>IReadOnlyList{Byte}"</code></description></item>
/// <item><description><code>IReadOnlyList{Int16}"</code></description></item>
/// <item><description><code>IReadOnlyList{UInt16}"</code></description></item>
/// <item><description><code>IReadOnlyList{Int32}"</code></description></item>
/// <item><description><code>IReadOnlyList{UInt32}"</code></description></item>
/// <item><description><code>IReadOnlyList{Int64}"</code></description></item>
/// <item><description><code>IReadOnlyList{UInt64}"</code></description></item>
/// <item><description><code>IReadOnlyList{Single}"</code></description></item>
/// <item><description><code>IReadOnlyList{Double}"</code></description></item>
/// <item><description><code>IReadOnlyList{T}</code> whereby T is one of the things listed here.</description></item>
/// </list>
/// </typeparam>
/// <param name="state"></param>
/// <returns></returns>
/// <param name="state">deserializer state to construct from</param>
/// <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)
where T: class
{

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Capnp
{
@ -572,6 +573,7 @@ namespace Capnp
/// <exception cref="IndexOutOfRangeException">negative index</exception>
/// <exception cref="DeserializationException">state does not represent a struct, invalid pointer,
/// non-list-of-bytes pointer, traversal limit exceeded</exception>
[return: NotNullIfNotNull("defaultText")]
public string? ReadText(int index, string? defaultText = null)
{
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>
/// </list>
/// </param>
public void SetObject(object obj)
public void SetObject(object? 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>
/// <exception cref="InvalidOperationException">The list was already initialized</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)
{

View File

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Capnp
{
@ -10,7 +11,7 @@ namespace Capnp
/// <typeparam name="T">Capability interface</typeparam>
public class ListOfCapsSerializer<T> :
SerializerState,
IReadOnlyList<T>
IReadOnlyList<T?>
where T : class
{
/// <summary>
@ -31,6 +32,7 @@ namespace Capnp
/// <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="IndexOutOfRangeException"><paramref name="index"/> is out of range.</exception>
[AllowNull]
public T this[int index]
{
get => (Rpc.CapabilityReflection.CreateProxy<T>(DecodeCapPointer(index)) as T)!;
@ -42,10 +44,7 @@ namespace Capnp
if (index < 0 || index >= RawData.Length)
throw new IndexOutOfRangeException("index out of range");
uint id = ProvideCapability(value);
WirePointer ptr = default;
ptr.SetCapability(id);
RawData[index] = id;
RawData[index] = ProvideCapability(value);
}
}
@ -66,7 +65,7 @@ namespace Capnp
/// <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="ArgumentOutOfRangeException">More than 2^29-1 items.</exception>
public void Init(IReadOnlyList<T> caps)
public void Init(IReadOnlyList<T?>? caps)
{
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>
/// <exception cref="InvalidOperationException">The list was already initialized</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)
{

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>
/// <exception cref="InvalidOperationException">The list was already initialized</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)
{

View File

@ -72,7 +72,7 @@ namespace Capnp
/// <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="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)
{

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>
/// <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>
public void Init(IReadOnlyList<string> items)
public void Init(IReadOnlyList<string?>? items)
{
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>
/// </list></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);
}

View File

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

View File

@ -22,7 +22,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
var whichEnum = EnumDeclaration(_names.UnionDiscriminatorEnum.ToString())
.AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>()));
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>(Nullability.NonNullable)));
var discFields = def.Fields.Where(f => f.DiscValue.HasValue);
@ -52,7 +52,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
var decl = EnumDeclaration(def.Name)
.WithAttributeLists(MakeTypeIdAttributeLists(def.Id))
.AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>()));
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>(Nullability.NonNullable)));
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)
{
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)
{
@ -75,7 +75,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
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)
.AddModifiers(Public).AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
@ -111,7 +112,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
MemberDeclarationSyntax MakeUnionContentField()
{
return FieldDeclaration(
VariableDeclaration(_names.Type<object>())
VariableDeclaration(_names.Type<object>(Nullability.NullableRef))
.WithVariables(
SingletonSeparatedList<VariableDeclaratorSyntax>(
VariableDeclarator(_names.UnionContentField.Identifier))))
@ -163,7 +164,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.Enum:
return MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.NotRelevant),
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.NotRelevant, Nullability.NonNullable),
IdentifierName(value.GetEnumerant().Literal));
case TypeTag.F32:
@ -262,7 +263,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
value.Decode();
return ObjectCreationExpression(
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.DomainClass))
_names.MakeTypeSyntax(value.Type, scope, TypeUsage.DomainClass, Nullability.NonNullable))
.WithArgumentList(ArgumentList())
.WithInitializer(
InitializerExpression(
@ -282,7 +283,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
value.Decode();
return ArrayCreationExpression(ArrayType(
_names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClassNullable))
_names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef))
.WithRankSpecifiers(
SingletonList<ArrayRankSpecifierSyntax>(
ArrayRankSpecifier(
@ -344,7 +345,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.Enum:
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)));
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)
{
var writerProp = MemberAccessExpression(
@ -519,7 +525,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
writerProp,
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.GetCodeIdentifier(field).IdentifierName,
_names.SuppressNullableWarning(_names.GetCodeIdentifier(field).IdentifierName),
IdentifierName(nameof(Nullable<int>.Value)))));
}
else
@ -538,10 +544,11 @@ namespace CapnpC.CSharp.Generator.CodeGen
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
MemberAccessExpression(
ConditionalSuppressNullableWarning(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.WriterParameter.IdentifierName,
_names.GetCodeIdentifier(field).IdentifierName),
field.DiscValue.HasValue),
IdentifierName(nameof(Capnp.DynamicSerializerState.SetObject))))
.AddArgumentListArguments(
Argument(_names.GetCodeIdentifier(field).IdentifierName)));
@ -568,7 +575,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
return ExpressionStatement(
MakeComplexSerializeParticle(
field.Type,
writerProp,
field.DiscValue.HasValue ? _names.SuppressNullableWarning(writerProp) : writerProp,
_names.GetCodeIdentifier(field).IdentifierName));
case TypeTag.Void:
@ -599,20 +606,20 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExpressionSyntax MakeInnerStructListConversion(ExpressionSyntax context, TypeSyntax elementType)
{
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(Parameter(Identifier("_")),
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)),
GenericName(nameof(Capnp.CapnpSerializable.Create))
.AddTypeArgumentListArguments(MakeNonNullableType(elementType))))
.AddArgumentListArguments(Argument(IdentifierName("_"))))));
return ConditionalAccessExpression(
context,
InvocationExpression(
MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(Parameter(Identifier("_")),
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)),
GenericName(nameof(Capnp.CapnpSerializable.Create))
.AddTypeArgumentListArguments(MakeNonNullableType(elementType))))
.AddArgumentListArguments(Argument(IdentifierName("_")))))));
}
ExpressionSyntax MakeStructListConversion(ExpressionSyntax context, TypeSyntax elementType, int rank)
@ -624,28 +631,28 @@ namespace CapnpC.CSharp.Generator.CodeGen
string lambdaVarName = $"_{rank}";
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(
Parameter(Identifier(lambdaVarName)),
MakeStructListConversion(IdentifierName(lambdaVarName), elementType, rank - 1))));
return ConditionalAccessExpression(
context,
InvocationExpression(
MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(
Parameter(Identifier(lambdaVarName)),
MakeStructListConversion(IdentifierName(lambdaVarName), elementType, rank - 1)))));
}
ExpressionSyntax MakeAnyListConversion(ExpressionSyntax context)
{
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(
Parameter(Identifier("_")),
CastExpression(_names.Type<object>(), IdentifierName("_")))));
return ConditionalAccessExpression(
context,
InvocationExpression(
MemberBindingExpression(
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList))))
.AddArgumentListArguments(Argument(
SimpleLambdaExpression(
Parameter(Identifier("_")),
CastExpression(_names.Type<object>(Nullability.NonNullable), IdentifierName("_"))))));
}
ExpressionSyntax MakeDeserializeMethodRightHandSide(Field field)
@ -665,7 +672,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
MakeNonNullableType(_names.MakeTypeSyntax(
field.Type,
field.DeclaringType,
TypeUsage.DomainClass)))))
TypeUsage.DomainClass,
Nullability.NonNullable)))))
.AddArgumentListArguments(Argument(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderParameter.IdentifierName,
@ -684,7 +692,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderParameter.IdentifierName,
_names.GetCodeIdentifier(field).IdentifierName),
_names.MakeTypeSyntax(elementType, field.DeclaringType, TypeUsage.DomainClassNullable),
_names.MakeTypeSyntax(elementType, field.DeclaringType, TypeUsage.DomainClass, Nullability.NullableRef),
rank);
case TypeTag.ListPointer:
@ -716,18 +724,6 @@ namespace CapnpC.CSharp.Generator.CodeGen
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));
}
@ -849,7 +845,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable))))
.AddParameterListParameters(
Parameter(_names.AnonymousParameter.Identifier)
.WithType(_names.Type<Capnp.SerializerState>(true)))
.WithType(_names.Type<Capnp.SerializerState>(Nullability.NonNullable)))
.AddBodyStatements(
ExpressionStatement(
InvocationExpression(_names.SerializeMethod.IdentifierName)
@ -933,7 +929,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ExplicitInterfaceSpecifier(IdentifierName(nameof(Capnp.ICapnpSerializable))))
.AddParameterListParameters(
Parameter(_names.AnonymousParameter.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()))
.WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))
.AddBodyStatements(stmts.ToArray());
}
@ -944,7 +940,10 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (def.UnionInfo != null)
{
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);
}

View File

@ -22,11 +22,17 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
NotRelevant,
DomainClass,
DomainClassNullable,
Reader,
Writer
}
enum Nullability
{
NonNullable,
NullableRefAndValue,
NullableRef
}
class GenNames
{
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)
{
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)
@ -289,82 +295,82 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.AnyPointer:
case TypeTag.StructPointer:
case TypeTag.ListPointer:
return Type<Capnp.ListOfPointersSerializer<Capnp.DynamicSerializerState>>(true);
return Type<Capnp.ListOfPointersSerializer<Capnp.DynamicSerializerState>>(Nullability.NonNullable);
case TypeTag.CapabilityPointer:
return Type<Capnp.ListOfCapsSerializer<Capnp.Rpc.BareProxy>>(true);
return Type<Capnp.ListOfCapsSerializer<Capnp.Rpc.BareProxy>>(Nullability.NonNullable);
case TypeTag.Data:
return Type<Capnp.ListOfPointersSerializer<
Capnp.ListOfPrimitivesSerializer<byte>>>(true);
Capnp.ListOfPrimitivesSerializer<byte>>>(Nullability.NonNullable);
case TypeTag.Enum:
return GenericName("ListOfPrimitivesSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer));
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Group:
case TypeTag.Struct:
return GenericName("ListOfStructsSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer));
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Interface:
return GenericName("ListOfCapsSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer));
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.List:
return GenericName("ListOfPointersSerializer")
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer));
.AddTypeArgumentListArguments(MakeTypeSyntax(elementType, scope, TypeUsage.Writer, Nullability.NonNullable));
case TypeTag.Text:
return Type<Capnp.ListOfTextSerializer>(true);
return Type<Capnp.ListOfTextSerializer>(Nullability.NonNullable);
case TypeTag.Void:
return Type<Capnp.ListOfEmptySerializer>(true);
return Type<Capnp.ListOfEmptySerializer>(Nullability.NonNullable);
case TypeTag.Bool:
return Type<Capnp.ListOfBitsSerializer>(true);
return Type<Capnp.ListOfBitsSerializer>(Nullability.NonNullable);
case TypeTag.F32:
return Type<Capnp.ListOfPrimitivesSerializer<float>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<float>>(Nullability.NonNullable);
case TypeTag.F64:
return Type<Capnp.ListOfPrimitivesSerializer<double>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<double>>(Nullability.NonNullable);
case TypeTag.S8:
return Type<Capnp.ListOfPrimitivesSerializer<sbyte>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<sbyte>>(Nullability.NonNullable);
case TypeTag.U8:
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(Nullability.NonNullable);
case TypeTag.S16:
return Type<Capnp.ListOfPrimitivesSerializer<short>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<short>>(Nullability.NonNullable);
case TypeTag.U16:
case TypeTag.AnyEnum:
return Type<Capnp.ListOfPrimitivesSerializer<ushort>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<ushort>>(Nullability.NonNullable);
case TypeTag.S32:
return Type<Capnp.ListOfPrimitivesSerializer<int>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<int>>(Nullability.NonNullable);
case TypeTag.U32:
return Type<Capnp.ListOfPrimitivesSerializer<uint>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<uint>>(Nullability.NonNullable);
case TypeTag.S64:
return Type<Capnp.ListOfPrimitivesSerializer<long>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<long>>(Nullability.NonNullable);
case TypeTag.U64:
return Type<Capnp.ListOfPrimitivesSerializer<ulong>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<ulong>>(Nullability.NonNullable);
default:
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);
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)
{
case TypeTag.AnyEnum:
return MaybeNullableValueType(Type<ushort>(), usage);
return Type<ushort>(nullability);
case TypeTag.CapabilityPointer:
if (type.Parameter != null)
{
return nonNullable ? GetQName(type, scope) :
MakeNullableType(GetQName(type, scope));
}
return MaybeNullableRefType(GetQName(type, scope), nullability);
else
{
return Type<Capnp.Rpc.BareProxy>(nonNullable);
}
return Type<Capnp.Rpc.BareProxy>(nullability);
case TypeTag.AnyPointer:
case TypeTag.StructPointer:
switch (usage)
{
case TypeUsage.Reader:
return Type<Capnp.DeserializerState>();
return Type<Capnp.DeserializerState>(Nullability.NonNullable);
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.DomainClassNullable:
if (type.Parameter != null)
{
return nonNullable ?
GetQName(type, scope) :
MakeNullableType(GetQName(type, scope));
}
else
{
return Type<object>(nonNullable);
}
return MakeNullableRefType(GetQName(type, scope));
default:
throw new NotImplementedException();
}
case TypeTag.Bool:
return MaybeNullableValueType(Type<bool>(), usage);
return Type<bool>(nullability);
case TypeTag.Data:
switch (usage)
{
case TypeUsage.Reader:
case TypeUsage.DomainClass:
case TypeUsage.DomainClassNullable:
return Type<IReadOnlyList<byte>>(nonNullable);
return Type<IReadOnlyList<byte>>(nullability);
case TypeUsage.Writer:
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(true);
return Type<Capnp.ListOfPrimitivesSerializer<byte>>(nullability);
default:
throw new NotImplementedException();
}
case TypeTag.Enum:
return MaybeNullableValueType(GetQName(type, scope), usage);
return MaybeNullableValueType(GetQName(type, scope), nullability);
case TypeTag.Interface:
return GetQName(type, scope);
return MaybeNullableRefType(GetQName(type, scope), nullability);
case TypeTag.Struct:
case TypeTag.Group:
@ -453,39 +460,38 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeUsage.Reader:
return QualifiedName(GetQName(type, scope), ReaderStruct.IdentifierName);
case TypeUsage.DomainClass:
case TypeUsage.DomainClass when nullability == Nullability.NonNullable:
return GetQName(type, scope);
case TypeUsage.DomainClassNullable:
return MakeNullableType(GetQName(type, scope));
case TypeUsage.DomainClass:
return MakeNullableRefType(GetQName(type, scope));
default:
throw new NotImplementedException();
}
case TypeTag.F32:
return MaybeNullableValueType(Type<float>(), usage);
return Type<float>(nullability);
case TypeTag.F64:
return MaybeNullableValueType(Type<double>(), usage);
return Type<double>(nullability);
case TypeTag.List when type.ElementType.Tag == TypeTag.Void && usage != TypeUsage.Writer:
return MaybeNullableValueType(Type<int>(), usage);
return Type<int>(nullability);
case TypeTag.List:
switch (usage)
{
case TypeUsage.Writer:
return MakeListSerializerSyntax(type.ElementType, scope);
return MaybeNullableRefType(MakeListSerializerSyntax(type.ElementType, scope), nullability);
case TypeUsage.Reader:
return GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader));
return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader, Nullability.NonNullable)), nullability);
case TypeUsage.DomainClass:
case TypeUsage.DomainClassNullable:
return GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, usage));
return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef)), nullability);
default:
throw new NotImplementedException();
@ -495,47 +501,49 @@ namespace CapnpC.CSharp.Generator.CodeGen
switch (usage)
{
case TypeUsage.Writer:
return Type<Capnp.SerializerState>();
return Type<Capnp.SerializerState>(Nullability.NonNullable);
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:
return Type<IReadOnlyList<object>>(false);
case TypeUsage.DomainClassNullable:
return Type<IReadOnlyList<object>>(true);
return MakeNullableRefType(GenericName(Identifier("IReadOnlyList"))
.AddTypeArgumentListArguments(Type<object>(Nullability.NullableRef)));
default:
throw new NotImplementedException();
}
case TypeTag.S16:
return MaybeNullableValueType(Type<short>(), usage);
return Type<short>(nullability);
case TypeTag.S32:
return MaybeNullableValueType(Type<int>(), usage);
return Type<int>(nullability);
case TypeTag.S64:
return MaybeNullableValueType(Type<long>(), usage);
return Type<long>(nullability);
case TypeTag.S8:
return MaybeNullableValueType(Type<sbyte>(), usage);
return Type<sbyte>(nullability);
case TypeTag.Text:
return Type<string>(nonNullable);
return Type<string>(nullability);
case TypeTag.U16:
return MaybeNullableValueType(Type<ushort>(), usage);
return Type<ushort>(nullability);
case TypeTag.U32:
return MaybeNullableValueType(Type<uint>(), usage);
return Type<uint>(nullability);
case TypeTag.U64:
return MaybeNullableValueType(Type<ulong>(), usage);
return Type<ulong>(nullability);
case TypeTag.U8:
return MaybeNullableValueType(Type<byte>(), usage);
return Type<byte>(nullability);
case TypeTag.Void:
return PredefinedType(Token(SyntaxKind.VoidKeyword));
@ -648,7 +656,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
MakePipeliningSupportExtensionMethodName(path)));
}
public TypeSyntax MakeNullableType(TypeSyntax type)
public TypeSyntax MakeNullableRefType(TypeSyntax type)
{
return NullableEnable ?
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>()) :
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:
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:
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:
return GenericName(nameof(Task)).AddTypeArgumentListArguments(
TupleType(SeparatedList(
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)
{
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
{
foreach (var arg in method.Params)
{
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(
_names.GetGenericTypeParameter(name).IdentifierName)
.AddConstraints(_names.MakeNullableClassConstraint());
.AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint));
}
}
@ -124,7 +128,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
ifaceDecl = ifaceDecl.AddBaseListTypes(
SimpleBaseType(_names.MakeTypeSyntax(
superClass, type,
TypeUsage.NotRelevant)));
TypeUsage.DomainClass,
Nullability.NonNullable)));
}
}
@ -226,9 +231,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
StatementSyntax MakeProxyCreateResult(Method method)
{
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(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)),
@ -237,6 +242,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments(
Argument(_names.DeserializerLocal.IdentifierName));
if (_names.NullableEnable)
{
createDomain = PostfixUnaryExpression(
SyntaxKind.SuppressNullableWarningExpression,
createDomain);
}
return LocalDeclarationStatement(
VariableDeclaration(
IdentifierName("var"))
@ -262,7 +274,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
yield return TypeParameterConstraintClause(
_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)
.AddModifiers(Public)
.AddBaseListTypes(
SimpleBaseType(_names.Type<Capnp.Rpc.Proxy>(true)),
SimpleBaseType(_names.Type<Capnp.Rpc.Proxy>(Nullability.NonNullable)),
SimpleBaseType(_names.MakeGenericTypeName(type, NameUsage.Interface)));
if (type.GenericParameters.Count > 0)
@ -311,7 +323,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax(
method.ParamsStruct,
method.ParamsStruct.Definition,
TypeUsage.Writer))))))))))));
TypeUsage.Writer, Nullability.NonNullable))))))))))));
if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct)
{
@ -328,7 +340,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax(
method.ParamsStruct,
method.ParamsStruct.Definition,
TypeUsage.DomainClass))
TypeUsage.DomainClass,
Nullability.NonNullable))
.WithArgumentList(
ArgumentList())
.WithInitializer(
@ -340,13 +353,12 @@ namespace CapnpC.CSharp.Generator.CodeGen
}
bodyStmts.Add(ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.AnonymousParameter.IdentifierName,
_names.SerializeMethod.IdentifierName))
.AddArgumentListArguments(
Argument(_names.ParamsLocal.IdentifierName))));
ConditionalAccessExpression(
_names.AnonymousParameter.IdentifierName,
InvocationExpression(
MemberBindingExpression(_names.SerializeMethod.IdentifierName))
.AddArgumentListArguments(
Argument(_names.ParamsLocal.IdentifierName)))));
var call = InvocationExpression(IdentifierName(nameof(Capnp.Rpc.BareProxy.Call)))
.AddArgumentListArguments(
@ -361,7 +373,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SyntaxKind.SimpleMemberAccessExpression,
_names.ParamsLocal.IdentifierName,
GenericName(nameof(Capnp.SerializerState.Rewrap))
.AddTypeArgumentListArguments(_names.Type<Capnp.DynamicSerializerState>())))
.AddTypeArgumentListArguments(_names.Type<Capnp.DynamicSerializerState>(Nullability.NonNullable))))
.AddArgumentListArguments()),
Argument(
LiteralExpression(SyntaxKind.FalseLiteralExpression)),
@ -446,7 +458,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
GenericName(_names.GetCodeIdentifier(method).ToString())
.AddTypeArgumentListArguments(
Enumerable.Repeat(
_names.Type<Capnp.AnyPointer>(),
_names.Type<Capnp.AnyPointer>(Nullability.NonNullable),
method.GenericParameters.Count).ToArray()));
}
else
@ -502,7 +514,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax(
method.ResultStruct,
method.ResultStruct.Definition,
TypeUsage.Writer)))))))))));
TypeUsage.Writer, Nullability.NonNullable)))))))))));
}
@ -523,7 +535,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
_names.MakeTypeSyntax(
method.ResultStruct,
method.ResultStruct.Definition,
TypeUsage.DomainClass))
TypeUsage.DomainClass,
Nullability.NonNullable))
.WithInitializer(
InitializerExpression(SyntaxKind.ObjectInitializerExpression)
.AddExpressions(
@ -575,9 +588,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
if (method.Params.Count > 0)
{
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(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nameof(Capnp.CapnpSerializable)),
@ -586,6 +599,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments(
Argument(_names.DeserializerLocal.IdentifierName));
if (_names.NullableEnable)
{
createDomain = PostfixUnaryExpression(
SyntaxKind.SuppressNullableWarningExpression,
createDomain);
}
if (method.ParamsStruct.Definition.SpecialName == SpecialName.MethodParamsStruct)
{
yield return LocalDeclarationStatement(
@ -662,13 +682,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
foreach (var method in def.Methods)
{
var methodDecl = MethodDeclaration(
_names.Type<Task<Capnp.Rpc.AnswerOrCounterquestion>>(),
_names.Type<Task<Capnp.Rpc.AnswerOrCounterquestion>>(Nullability.NonNullable),
_names.GetCodeIdentifier(method).Identifier)
.AddParameterListParameters(
Parameter(_names.DeserializerLocal.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()),
.WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)),
Parameter(_names.CancellationTokenParameter.Identifier)
.WithType(_names.Type<CancellationToken>()))
.WithType(_names.Type<CancellationToken>(Nullability.NonNullable)))
.AddBodyStatements(
MakeSkeletonMethodBody(method).ToArray());
@ -709,7 +729,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments(
MakeSkeletonSetMethodTableArguments(type).ToArray()))),
// 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)
.WithExpressionBody(
ArrowExpressionClause(
@ -790,7 +810,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
var accessPath = _names.MakeMemberAccessPathFieldName(method, path);
var methodName = _names.MakePipeliningSupportExtensionMethodName(path);
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())))
{

View File

@ -57,7 +57,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ParameterList(
SingletonSeparatedList<ParameterSyntax>(
Parameter(_names.ReaderContextField.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()))))
.WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithExpressionBody(
ArrowExpressionClause(
ObjectCreationExpression(_names.ReaderStruct.IdentifierName)
@ -78,7 +78,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
SingletonSeparatedList(
Parameter(_names.ContextParameter.Identifier)
.WithType(
_names.Type<Capnp.DeserializerState>()))))
_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithExpressionBody(
ArrowExpressionClause(
ObjectCreationExpression(_names.ReaderStruct.IdentifierName)
@ -90,7 +90,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
yield return FieldDeclaration(
VariableDeclaration(
_names.Type<Capnp.DeserializerState>())
_names.Type<Capnp.DeserializerState>(Nullability.NonNullable))
.AddVariables(_names.ReaderContextField.VariableDeclarator))
.AddModifiers(Readonly);
@ -100,7 +100,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
ParameterList(
SingletonSeparatedList(
Parameter(_names.ContextParameter.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()))))
.WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithBody(
Block(
SingletonList<StatementSyntax>(
@ -122,7 +122,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
yield return FieldDeclaration(
VariableDeclaration(
_names.Type<Capnp.DeserializerState>())
_names.Type<Capnp.DeserializerState>(Nullability.NonNullable))
.AddVariables(_names.ReaderContextField.VariableDeclarator))
.AddModifiers(Readonly);
@ -131,7 +131,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.WithParameterList(
ParameterList(
SingletonSeparatedList(Parameter(_names.GroupReaderContextArg.Identifier)
.WithType(_names.Type<Capnp.DeserializerState>()))))
.WithType(_names.Type<Capnp.DeserializerState>(Nullability.NonNullable)))))
.WithBody(
Block(
SingletonList<StatementSyntax>(
@ -173,57 +173,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
}
static Func<ExpressionSyntax, ExpressionSyntax> MakeCastFunc(TypeSyntax type) =>
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))
);
}
static Func<ExpressionSyntax, ExpressionSyntax> MakeCastFunc(TypeSyntax type) => x => CastExpression(type, x);
PropertyDeclarationSyntax MakeReadProperty(TypeSyntax type, string name, SimpleNameSyntax readName,
object indexOrBitOffset, ExpressionSyntax secondArg,
@ -261,13 +211,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadPrimitiveProperty<T>(Field field, string readName)
{
return MakeReadProperty(_names.Type<T>(), _names.GetCodeIdentifier(field).ToString(), readName, field.BitOffset.Value,
ValueOf(field.DefaultValue.ScalarValue), null, field.DiscValue.HasValue);
return MakeReadProperty(
_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)
{
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,
_names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.SerializerExtensions.ReadDataUShort), field.BitOffset.Value,
@ -278,9 +234,16 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeReadTextProperty(Field field)
{
return MakeReadProperty(_names.Type<string>(), _names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.DeserializerState.ReadText), (int)field.Offset,
ValueOf(field.DefaultValue.ScalarValue), null, field.DiscValue.HasValue);
bool cantBeNull = !field.DiscValue.HasValue && field.DefaultValue.ScalarValue != null;
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)
@ -293,7 +256,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
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);
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);
}
void MakeReadListPropertyImpl(Model.Type elementType, TypeDefinition scope, ExpressionSyntax context, int depth,
out TypeSyntax listType, out ExpressionSyntax impl)
ExpressionSyntax MakeReadListPropertyImpl(Model.Type elementType, TypeDefinition scope, ExpressionSyntax context, int depth)
{
var elementTypeSyntax = _names.MakeTypeSyntax(elementType, scope, TypeUsage.Reader);
listType = GenericName("IReadOnlyList").AddTypeArgumentListArguments(elementTypeSyntax);
var elementTypeSyntax = _names.MakeTypeSyntax(elementType, scope, TypeUsage.Reader, Nullability.NonNullable);
if (elementType.Tag == TypeTag.Interface ||
elementType.Tag == TypeTag.CapabilityPointer)
{
if (depth == 0)
{
impl = InvocationExpression(MemberAccessExpression(
return InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.ReaderContextField.IdentifierName,
GenericName(nameof(Capnp.DeserializerState.ReadCapList))
@ -336,15 +297,13 @@ namespace CapnpC.CSharp.Generator.CodeGen
}
else
{
impl = InvocationExpression(
return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context,
GenericName(nameof(Capnp.DeserializerState.RequireCapList))
.AddTypeArgumentListArguments(elementTypeSyntax)
));
}
return;
}
if (depth == 0)
@ -374,56 +333,44 @@ namespace CapnpC.CSharp.Generator.CodeGen
case TypeTag.List:
{
MakeReadListPropertyImpl(
var innerImpl = MakeReadListPropertyImpl(
elementType.ElementType,
scope,
lambdaArg,
depth + 1,
out var innerListType,
out var innerImpl);
depth + 1);
listType = GenericName("IReadOnlyList").AddTypeArgumentListArguments(innerListType);
impl = InvocationExpression(
return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ListDeserializer.Cast))))
.AddArgumentListArguments(
Argument(SimpleLambdaExpression(lambdaParam, innerImpl)));
return;
}
case TypeTag.ListPointer:
{
listType = _names.Type<IReadOnlyList<object>>();
context = InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.DeserializerState.RequireList))
)).AddArgumentListArguments(Argument(lambdaArg));
impl = InvocationExpression(
return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ReadOnlyListExtensions.LazyListSelect))))
.AddArgumentListArguments(
Argument(SimpleLambdaExpression(lambdaParam, context)));
return;
}
case TypeTag.Struct:
{
impl = InvocationExpression(
return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ListDeserializer.Cast))))
.AddArgumentListArguments(
Argument(MakeReaderCreator(elementTypeSyntax)));
return;
}
case TypeTag.Enum:
@ -432,32 +379,26 @@ namespace CapnpC.CSharp.Generator.CodeGen
lambdaParam,
CastExpression(elementTypeSyntax, lambdaArg));
impl = InvocationExpression(
return InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ListDeserializer.CastEnums))))
.AddArgumentListArguments(
Argument(cons));
return;
}
case TypeTag.AnyPointer:
case TypeTag.StructPointer:
{
listType = _names.Type<IReadOnlyList<Capnp.DeserializerState>>();
impl = context;
return;
return context;
}
case TypeTag.Void:
{
listType = _names.Type<int>();
impl = MemberAccessExpression(
return MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(nameof(Capnp.ListDeserializer.Count)));
return;
}
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");
}
impl = InvocationExpression(MemberAccessExpression(
return InvocationExpression(MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
context,
IdentifierName(castFuncName)));
@ -527,13 +468,18 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
var elementType = field.Type.ElementType;
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);
}
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(),
nameof(Capnp.DeserializerState.ReadList),
@ -542,18 +488,19 @@ namespace CapnpC.CSharp.Generator.CodeGen
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))
.AddTypeArgumentListArguments(type);
.AddTypeArgumentListArguments(nonNullableType);
return MakeReadProperty(type, _names.GetCodeIdentifier(field).ToString(),
return MakeReadProperty(nullableType, _names.GetCodeIdentifier(field).ToString(),
readName,
(int)field.Offset, null, null, field.DiscValue.HasValue);
}
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(),
nameof(Capnp.DeserializerState.ReadCap),
@ -573,7 +520,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
IdentifierName(nameof(Capnp.ListDeserializer.CastByte))));
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);
}

View File

@ -115,12 +115,21 @@ namespace CapnpC.CSharp.Generator.CodeGen
.AddArgumentListArguments(
Argument(ValueOf(index)));
ExpressionSyntax MakeLinkSyntax(object index) =>
InvocationExpression(
ExpressionSyntax MakeLinkSyntax(object index, bool suppressNullableWarning)
{
ExpressionSyntax value = IdentifierName("value");
if (suppressNullableWarning)
{
value = _names.SuppressNullableWarning(value);
}
return InvocationExpression(
IdentifierName(SerializerStateWorder.LinkName))
.AddArgumentListArguments(
Argument(ValueOf(index)),
Argument(IdentifierName("value")));
Argument(value));
}
ExpressionSyntax MakeLinkObjectSyntax(object index) =>
InvocationExpression(
@ -129,22 +138,46 @@ namespace CapnpC.CSharp.Generator.CodeGen
Argument(ValueOf(index)),
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)
{
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(
TypeSyntax type, string name, object index,
bool cast, bool cond)
PropertyDeclarationSyntax MakePointerAsStructProperty(TypeSyntax type, string name, object index, bool cast, bool cond)
{
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(
@ -195,7 +228,10 @@ namespace CapnpC.CSharp.Generator.CodeGen
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,
nameof(Capnp.SerializerExtensions.WriteData),
field.BitOffset.Value,
@ -207,7 +243,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
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(),
readName,
nameof(Capnp.SerializerExtensions.WriteData),
@ -220,7 +258,9 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeTextProperty(Field field)
{
return MakeProperty(_names.Type<string>(), null,
return MakeProperty(
_names.Type<string>(Nullability.NullableRef),
null,
_names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.SerializerState.ReadText),
nameof(Capnp.SerializerState.WriteText),
@ -233,7 +273,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
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(),
(int)field.Offset, false, field.DiscValue.HasValue);
@ -241,7 +281,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
PropertyDeclarationSyntax MakeGroupProperty(Field field)
{
var type = QualifiedName(
TypeSyntax type = QualifiedName(
_names.MakeTypeName(field.Type.Definition).IdentifierName,
_names.WriterStruct.IdentifierName);
@ -249,12 +289,17 @@ namespace CapnpC.CSharp.Generator.CodeGen
GenericName(nameof(Capnp.SerializerState.Rewrap))
.AddTypeArgumentListArguments(type));
if (field.DiscValue.HasValue)
{
type = _names.MakeNullableRefType(type);
}
return MakeWriterProperty(type, _names.GetCodeIdentifier(field).ToString(), getter, null, false, field.DiscValue.HasValue);
}
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(),
(int)field.Offset, false, field.DiscValue.HasValue);
@ -269,20 +314,21 @@ namespace CapnpC.CSharp.Generator.CodeGen
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;
string name = _names.GetCodeIdentifier(field).ToString();
ExpressionSyntax getter = MakeReadCapSyntax(type, index);
ExpressionSyntax getter = MakeReadCapSyntax(nonNullableType, 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)
{
return MakeProperty(
_names.UnionDiscriminatorEnum.IdentifierName,
_names.Type<ushort>(),
_names.Type<ushort>(Nullability.NonNullable),
_names.UnionDiscriminatorProp.ToString(),
nameof(Capnp.SerializerExtensions.ReadDataUShort),
nameof(Capnp.SerializerExtensions.WriteData),

View File

@ -9,13 +9,24 @@ namespace MsBuildGenerationTest
// 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.
void use(object x)
{
}
var vatId = new Capnp.Rpc.Twoparty.VatId();
use(vatId);
var msg = new Capnp.Rpc.Message();
use(msg);
var node = new Capnp.Schema.Node();
use(node);
var x = Capnproto_test.Capnp.Test.TestEnum.garply;
use(x);
var imp = new CapnpGen.TestImport();
use(imp);
var imp2 = new CapnpGen.TestImport2();
use(imp2);
var book = new CapnpGen.AddressBook();
use(book);
}
}
}

View File

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