support several new codegen annotations

minor fixes
improved CC
This commit is contained in:
Christian Köllner 2020-03-26 21:30:30 +01:00
parent 9dbf474334
commit 6af523b261
20 changed files with 2219 additions and 240 deletions

View File

@ -1,5 +1,7 @@
using Capnp.Rpc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace Capnp.Net.Runtime.Tests
{
@ -366,5 +368,402 @@ namespace Capnp.Net.Runtime.Tests
Assert.AreEqual("reason", r.Unimplemented.Resolve.Exception.Reason);
}
}
void ConstructReconstructTest<TD, TW>(Func<TD> construct, Action<TD> verify)
where TD : class, ICapnpSerializable, new()
where TW: SerializerState, new()
{
var obj = construct();
var mb = MessageBuilder.Create();
var root = mb.BuildRoot<TW>();
obj.Serialize(root);
var d = (DeserializerState)root;
var obj2 = new TD();
obj2.Deserialize(d);
verify(obj2);
}
[TestMethod]
public void DcMessageAbort()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Abort = new Rpc.Exception()
{
Reason = "problem"
}
},
msg =>
{
Assert.IsNotNull(msg.Abort);
Assert.IsNull(msg.Accept);
Assert.AreEqual("problem", msg.Abort.Reason);
}
);
}
[TestMethod]
public void DcMessageAccept()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Accept = new Accept()
{
QuestionId = 123u,
Embargo = true
}
},
msg =>
{
Assert.IsNotNull(msg.Accept);
Assert.AreEqual(123u, msg.Accept.QuestionId);
Assert.IsTrue(msg.Accept.Embargo);
}
);
}
[TestMethod]
public void DcMessageUnimplementedJoin()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Unimplemented = new Message()
{
Join = new Join()
{
QuestionId = 456u,
Target = new MessageTarget()
{
ImportedCap = 789u
}
}
}
},
msg =>
{
Assert.IsNotNull(msg.Unimplemented);
Assert.IsNotNull(msg.Unimplemented.Join);
Assert.AreEqual(456u, msg.Unimplemented.Join.QuestionId);
Assert.IsNotNull(msg.Unimplemented.Join.Target);
Assert.AreEqual(789u, msg.Unimplemented.Join.Target.ImportedCap);
}
);
}
[TestMethod]
public void DcMessageCall()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Call = new Call()
{
AllowThirdPartyTailCall = true,
InterfaceId = 0x12345678abcdef,
MethodId = 0x5555,
Params = new Payload()
{
CapTable = new List<CapDescriptor>()
{
new CapDescriptor()
{
ReceiverAnswer = new PromisedAnswer()
{
QuestionId = 42u,
Transform = new List<PromisedAnswer.Op>()
{
new PromisedAnswer.Op()
{
GetPointerField = 3
}
}
},
},
new CapDescriptor()
{
ReceiverHosted = 7u
},
new CapDescriptor()
{
SenderHosted = 8u
},
new CapDescriptor()
{
SenderPromise = 9u
},
new CapDescriptor()
{
ThirdPartyHosted = new ThirdPartyCapDescriptor()
{
VineId = 10u
}
}
}
},
QuestionId = 57u,
SendResultsTo = new Call.sendResultsTo()
{
which = Call.sendResultsTo.WHICH.Caller
},
Target = new MessageTarget()
{
PromisedAnswer = new PromisedAnswer()
{
QuestionId = 12u
}
}
}
},
msg =>
{
Assert.IsNotNull(msg.Call);
Assert.IsTrue(msg.Call.AllowThirdPartyTailCall);
Assert.AreEqual(0x12345678abcdeful, msg.Call.InterfaceId);
Assert.AreEqual(0x5555u, msg.Call.MethodId);
Assert.IsNotNull(msg.Call.Params);
Assert.IsNotNull(msg.Call.Params.CapTable);
Assert.AreEqual(5, msg.Call.Params.CapTable.Count);
Assert.IsNotNull(msg.Call.Params.CapTable[0].ReceiverAnswer);
Assert.AreEqual(42u, msg.Call.Params.CapTable[0].ReceiverAnswer.QuestionId);
Assert.IsNotNull(msg.Call.Params.CapTable[0].ReceiverAnswer.Transform);
Assert.AreEqual(1, msg.Call.Params.CapTable[0].ReceiverAnswer.Transform.Count);
Assert.AreEqual((ushort)3, msg.Call.Params.CapTable[0].ReceiverAnswer.Transform[0].GetPointerField);
Assert.AreEqual(7u, msg.Call.Params.CapTable[1].ReceiverHosted);
Assert.AreEqual(8u, msg.Call.Params.CapTable[2].SenderHosted);
Assert.AreEqual(9u, msg.Call.Params.CapTable[3].SenderPromise);
Assert.IsNotNull(msg.Call.Params.CapTable[4].ThirdPartyHosted);
Assert.AreEqual(10u, msg.Call.Params.CapTable[4].ThirdPartyHosted.VineId);
Assert.AreEqual(57u, msg.Call.QuestionId);
Assert.IsNotNull(msg.Call.SendResultsTo);
Assert.AreEqual(Call.sendResultsTo.WHICH.Caller, msg.Call.SendResultsTo.which);
Assert.IsNotNull(msg.Call.Target);
Assert.IsNotNull(msg.Call.Target.PromisedAnswer);
Assert.AreEqual(12u, msg.Call.Target.PromisedAnswer.QuestionId);
}
);
}
[TestMethod]
public void DcMessageReturnResults()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Return = new Return()
{
AnswerId = 123u,
ReleaseParamCaps = false,
Results = new Payload()
{
CapTable = new List<CapDescriptor>()
}
}
},
msg =>
{
Assert.IsNotNull(msg.Return);
Assert.AreEqual(123u, msg.Return.AnswerId);
Assert.IsFalse(msg.Return.ReleaseParamCaps);
Assert.IsNotNull(msg.Return.Results);
Assert.IsNotNull(msg.Return.Results.CapTable);
Assert.AreEqual(0, msg.Return.Results.CapTable.Count);
}
);
}
[TestMethod]
public void DcMessageReturnException()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Return = new Return()
{
AnswerId = 123u,
ReleaseParamCaps = true,
Exception = new Rpc.Exception()
{
Reason = "bad",
TheType = Rpc.Exception.Type.overloaded
}
}
},
msg =>
{
Assert.IsNotNull(msg.Return);
Assert.AreEqual(123u, msg.Return.AnswerId);
Assert.IsTrue(msg.Return.ReleaseParamCaps);
Assert.IsNotNull(msg.Return.Exception);
Assert.AreEqual("bad", msg.Return.Exception.Reason);
Assert.AreEqual(Rpc.Exception.Type.overloaded, msg.Return.Exception.TheType);
}
);
}
[TestMethod]
public void DcMessageReturnTakeFromOtherQuestion()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Return = new Return()
{
AnswerId = 123u,
ReleaseParamCaps = true,
TakeFromOtherQuestion = 321u
}
},
msg =>
{
Assert.IsNotNull(msg.Return);
Assert.AreEqual(123u, msg.Return.AnswerId);
Assert.IsTrue(msg.Return.ReleaseParamCaps);
Assert.AreEqual(321u, msg.Return.TakeFromOtherQuestion);
}
);
}
[TestMethod]
public void DcMessageFinish()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Finish = new Finish()
{
QuestionId = 321u,
ReleaseResultCaps = true
}
},
msg =>
{
Assert.IsNotNull(msg.Finish);
Assert.AreEqual(321u, msg.Finish.QuestionId);
Assert.IsTrue(msg.Finish.ReleaseResultCaps);
}
);
}
[TestMethod]
public void DcMessageResolve()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Resolve = new Resolve()
{
PromiseId = 555u,
Exception = new Rpc.Exception()
{
Reason = "error",
TheType = Rpc.Exception.Type.failed
}
}
},
msg =>
{
Assert.IsNotNull(msg.Resolve);
Assert.AreEqual(555u, msg.Resolve.PromiseId);
Assert.AreEqual("error", msg.Resolve.Exception.Reason);
Assert.AreEqual(Rpc.Exception.Type.failed, msg.Resolve.Exception.TheType);
}
);
}
[TestMethod]
public void DcMessageRelease()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Release = new Release()
{
Id = 6000u,
ReferenceCount = 6u
}
},
msg =>
{
Assert.IsNotNull(msg.Release);
Assert.AreEqual(6000u, msg.Release.Id);
Assert.AreEqual(6u, msg.Release.ReferenceCount);
}
);
}
[TestMethod]
public void DcMessageBootstrap()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Bootstrap = new Bootstrap()
{
QuestionId = 99u
}
},
msg =>
{
Assert.IsNotNull(msg.Bootstrap);
Assert.AreEqual(99u, msg.Bootstrap.QuestionId);
}
);
}
[TestMethod]
public void DcMessageProvide()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Provide = new Provide()
{
Target = new MessageTarget()
{
ImportedCap = 7u
}
}
},
msg =>
{
Assert.IsNotNull(msg.Provide);
Assert.IsNotNull(msg.Provide.Target);
Assert.AreEqual(7u, msg.Provide.Target.ImportedCap);
}
);
}
[TestMethod]
public void DcMessageDisembargo()
{
ConstructReconstructTest<Message, Message.WRITER>(
() => new Message()
{
Disembargo = new Disembargo()
{
Context = new Disembargo.context()
{
ReceiverLoopback = 900u
},
Target = new MessageTarget()
}
},
msg =>
{
Assert.IsNotNull(msg.Disembargo);
Assert.IsNotNull(msg.Disembargo.Context);
Assert.AreEqual(900u, msg.Disembargo.Context.ReceiverLoopback);
Assert.IsNotNull(msg.Disembargo.Target);
Assert.IsNull(msg.Disembargo.Target.ImportedCap);
Assert.IsNull(msg.Disembargo.Target.PromisedAnswer);
Assert.AreEqual(MessageTarget.WHICH.undefined, msg.Disembargo.Target.which);
}
);
}
}
}

View File

@ -229,7 +229,7 @@ namespace Capnp.Rpc
}
/// <summary>
/// Checkes whether a given type qualifies as cpapbility interface./> on failure.
/// Checks whether a given type qualifies as cpapbility interface.
/// </summary>
/// <param name="interfaceType">type to check</param>
/// <returns>true when <paramref name="interfaceType"/> is a capability interface</returns>

View File

@ -165,7 +165,7 @@ namespace Capnp.Rpc
SetReturned();
}
_tcs.TrySetException(new RpcException(exception.Reason));
_tcs.TrySetException(new RpcException(exception.Reason ?? "unknown reason"));
}
internal void OnException(System.Exception exception)
@ -313,7 +313,7 @@ namespace Capnp.Rpc
}
var msg = (Message.WRITER)inParams!.MsgBuilder!.Root!;
Debug.Assert(msg.Call.Target.which != MessageTarget.WHICH.undefined);
Debug.Assert(msg.Call!.Target.which != MessageTarget.WHICH.undefined);
var call = msg.Call;
call.QuestionId = QuestionId;
call.SendResultsTo.which = IsTailCall ?

View File

@ -101,7 +101,7 @@ namespace Capnp.Rpc
protected override void GetMessageTarget(MessageTarget.WRITER wr)
{
wr.which = MessageTarget.WHICH.PromisedAnswer;
wr.PromisedAnswer.QuestionId = _question.QuestionId;
wr.PromisedAnswer!.QuestionId = _question.QuestionId;
_access.Serialize(wr.PromisedAnswer);
}
@ -178,7 +178,7 @@ namespace Capnp.Rpc
var call = base.SetupMessage(args, interfaceId, methodId);
call.Target.which = MessageTarget.WHICH.PromisedAnswer;
call.Target.PromisedAnswer.QuestionId = _question.QuestionId;
call.Target.PromisedAnswer!.QuestionId = _question.QuestionId;
_access.Serialize(call.Target.PromisedAnswer);
return call;
@ -243,8 +243,8 @@ namespace Capnp.Rpc
if (endpoint == _ep)
{
writer.which = CapDescriptor.WHICH.ReceiverAnswer;
_access.Serialize(writer.ReceiverAnswer);
writer.ReceiverAnswer.QuestionId = _question.QuestionId;
_access.Serialize(writer.ReceiverAnswer!);
writer.ReceiverAnswer!.QuestionId = _question.QuestionId;
}
else if (_question.IsTailCall)
{

View File

@ -29,7 +29,7 @@ namespace Capnp.Rpc
callMsg.which = Message.WHICH.Call;
var call = callMsg.Call;
var call = callMsg.Call!;
call.AllowThirdPartyTailCall = false;
call.InterfaceId = interfaceId;
call.MethodId = methodId;

View File

@ -210,7 +210,7 @@ namespace Capnp.Rpc
var mb = MessageBuilder.Create();
var msg = mb.BuildRoot<Message.WRITER>();
msg.which = Message.WHICH.Abort;
msg.Abort.Reason = reason;
msg.Abort!.Reason = reason;
Tx(mb.Frame);
}
@ -233,18 +233,18 @@ namespace Capnp.Rpc
var mb = MessageBuilder.Create();
var msg = mb.BuildRoot<Message.WRITER>();
msg.which = Message.WHICH.Resolve;
var resolve = msg.Resolve;
var resolve = msg.Resolve!;
try
{
var resolvedCap = resolvedCapGetter();
resolve.which = Resolve.WHICH.Cap;
resolvedCap.Export(this, resolve.Cap);
resolvedCap.Export(this, resolve.Cap!);
}
catch (System.Exception ex)
{
resolve.which = Resolve.WHICH.Exception;
resolve.Exception.Reason = ex.Message;
resolve.Exception!.Reason = ex.Message;
}
resolve.PromiseId = preliminaryId;
@ -364,7 +364,7 @@ namespace Capnp.Rpc
var ans = bootstrap.MsgBuilder!.BuildRoot<Message.WRITER>();
ans.which = Message.WHICH.Return;
var ret = ans.Return;
var ret = ans.Return!;
ret.AnswerId = q;
Task<AnswerOrCounterquestion> bootstrapTask;
@ -374,7 +374,7 @@ namespace Capnp.Rpc
{
ret.which = Return.WHICH.Results;
bootstrap.SetCapability(bootstrap.ProvideCapability(LocalCapability.Create(bootstrapCap)));
ret.Results.Content = bootstrap;
ret.Results!.Content = bootstrap;
bootstrapTask = Task.FromResult<AnswerOrCounterquestion>(bootstrap);
}
@ -383,7 +383,7 @@ namespace Capnp.Rpc
Logger.LogWarning("Peer asked for bootstrap capability, but no bootstrap capability was set.");
ret.which = Return.WHICH.Exception;
ret.Exception.Reason = "No bootstrap capability present";
ret.Exception!.Reason = "No bootstrap capability present";
bootstrapTask = Task.FromException<AnswerOrCounterquestion>(new RpcException(ret.Exception.Reason));
}
@ -403,7 +403,7 @@ namespace Capnp.Rpc
}
if (bootstrapCap != null)
if (ret.Results != null)
{
ExportCapTableAndSend(bootstrap, ret.Results);
}
@ -420,7 +420,7 @@ namespace Capnp.Rpc
{
var rmsg = mb.BuildRoot<Message.WRITER>();
rmsg.which = Message.WHICH.Return;
var ret = rmsg.Return;
var ret = rmsg.Return!;
ret.AnswerId = req.QuestionId;
return ret;
@ -488,7 +488,7 @@ namespace Capnp.Rpc
{
case Call.sendResultsTo.WHICH.Caller:
ret.which = Return.WHICH.Results;
ret.Results.Content = results.Rewrap<DynamicSerializerState>();
ret.Results!.Content = results.Rewrap<DynamicSerializerState>();
ret.ReleaseParamCaps = releaseParamCaps;
ExportCapTableAndSend(results, ret.Results);
pendingAnswer.CapTable = ret.Results.CapTable;
@ -530,7 +530,7 @@ namespace Capnp.Rpc
ReturnCall(ret =>
{
ret.which = Return.WHICH.Exception;
ret.Exception.Reason = exception.Message;
ret.Exception!.Reason = exception.Message;
ret.ReleaseParamCaps = releaseParamCaps;
});
}
@ -824,7 +824,7 @@ namespace Capnp.Rpc
break;
case Resolve.WHICH.Exception:
resolvableCap.Break(resolve.Exception.Reason);
resolvableCap.Break(resolve.Exception.Reason ?? "unknown reason");
break;
default:
@ -844,8 +844,8 @@ namespace Capnp.Rpc
mb.InitCapTable();
var wr = mb.BuildRoot<Message.WRITER>();
wr.which = Message.WHICH.Disembargo;
wr.Disembargo.Context.which = Disembargo.context.WHICH.ReceiverLoopback;
wr.Disembargo.Context.ReceiverLoopback = disembargo.Context.SenderLoopback;
wr.Disembargo!.Context.which = Disembargo.context.WHICH.ReceiverLoopback;
wr.Disembargo!.Context.ReceiverLoopback = disembargo.Context.SenderLoopback;
var reply = wr.Disembargo;
switch (disembargo.Target.which)
@ -871,7 +871,7 @@ namespace Capnp.Rpc
var promisedAnswer = disembargo.Target.PromisedAnswer;
reply.Target.which = MessageTarget.WHICH.PromisedAnswer;
var replyPromisedAnswer = reply.Target.PromisedAnswer;
replyPromisedAnswer.QuestionId = disembargo.Target.PromisedAnswer.QuestionId;
replyPromisedAnswer!.QuestionId = disembargo.Target.PromisedAnswer.QuestionId;
int count = promisedAnswer.Transform.Count;
replyPromisedAnswer.Transform.Init(count);
@ -1162,7 +1162,7 @@ namespace Capnp.Rpc
var req = mb.BuildRoot<Message.WRITER>();
req.which = Message.WHICH.Bootstrap;
var pendingBootstrap = AllocateQuestion(null, null);
req.Bootstrap.QuestionId = pendingBootstrap.QuestionId;
req.Bootstrap!.QuestionId = pendingBootstrap.QuestionId;
Tx(mb.Frame);
@ -1237,7 +1237,7 @@ namespace Capnp.Rpc
mb.InitCapTable();
var reply = mb.BuildRoot<Message.WRITER>();
reply.which = Message.WHICH.Unimplemented;
Reserializing.DeepCopy(msg, reply.Unimplemented.Rewrap<DynamicSerializerState>());
Reserializing.DeepCopy(msg, reply.Unimplemented!.Rewrap<DynamicSerializerState>());
Tx(mb.Frame);
}
@ -1472,8 +1472,8 @@ namespace Capnp.Rpc
var mb = MessageBuilder.Create();
var msg = mb.BuildRoot<Message.WRITER>();
msg.which = Message.WHICH.Finish;
msg.Finish.QuestionId = questionId;
msg.Finish.ReleaseResultCaps = false;
msg.Finish!.QuestionId = questionId;
msg.Finish!.ReleaseResultCaps = false;
try
{
@ -1518,8 +1518,8 @@ namespace Capnp.Rpc
var mb = MessageBuilder.Create();
var msg = mb.BuildRoot<Message.WRITER>();
msg.which = Message.WHICH.Release;
msg.Release.Id = importId;
msg.Release.ReferenceCount = (uint)count;
msg.Release!.Id = importId;
msg.Release!.ReferenceCount = (uint)count;
try
{
@ -1540,7 +1540,7 @@ namespace Capnp.Rpc
mb.InitCapTable();
var msg = mb.BuildRoot<Message.WRITER>();
msg.which = Message.WHICH.Disembargo;
describe(msg.Disembargo.Target);
describe(msg.Disembargo!.Target);
var ctx = msg.Disembargo.Context;
ctx.which = Disembargo.context.WHICH.SenderLoopback;
ctx.SenderLoopback = id;

File diff suppressed because it is too large Load Diff

View File

@ -71,3 +71,4 @@ Examples:
| NullableDisable2.capnp.bin | false | true | success |
| NullableEnable2.capnp.bin | false | false | errors |
| NullableEnable2.capnp.bin | false | true | success |
| rpc-csharp.capnp.bin | true | true | warnings |

View File

@ -647,6 +647,21 @@ this.ValidGeneratorOutput("NullableEnable2.capnp.bin", "false", "false", "errors
{
#line 50
this.ValidGeneratorOutput("NullableEnable2.capnp.bin", "false", "true", "success", ((string[])(null)));
#line hidden
}
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
[Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Valid generator output: Variant 15")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "Variant 15")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:bin", "rpc-csharp.capnp.bin")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablegen", "true")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablesupp", "true")]
[Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:outcome", "warnings")]
public virtual void ValidGeneratorOutput_Variant15()
{
#line 50
this.ValidGeneratorOutput("rpc-csharp.capnp.bin", "true", "true", "warnings", ((string[])(null)));
#line hidden
}
}

View File

@ -241,14 +241,12 @@ namespace CapnpC.CSharp.Generator.Tests
}
}
catch (AssertFailedException)
finally
{
string generated = _result.GeneratedFiles.Single().GeneratedContent;
string path = Path.ChangeExtension(Path.GetTempFileName(), ".capnp.cs");
File.WriteAllText(path, generated);
Console.WriteLine($"Generated code was saved to {path}");
throw;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -62,8 +62,17 @@
IEnumerable<MemberDeclarationSyntax> TransformStruct(TypeDefinition def)
{
var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier)
.AddModifiers(Public)
.AddBaseListTypes(SimpleBaseType(_names.Type<Capnp.ICapnpSerializable>(Nullability.NonNullable)));
.AddModifiers(_names.TypeVisibilityModifier);
if (_names.EmitDomainClassesAndInterfaces)
{
topDecl = topDecl.AddBaseListTypes(SimpleBaseType(_names.Type<Capnp.ICapnpSerializable>(Nullability.NonNullable)));
}
else
{
topDecl = topDecl.AddModifiers(Static);
}
if (def.GenericParameters.Count > 0)
{
@ -80,9 +89,14 @@
topDecl = topDecl.AddMembers(_commonGen.MakeUnionSelectorEnum(def));
}
if (_names.EmitDomainClassesAndInterfaces)
{
topDecl = topDecl.AddMembers(_domClassGen.MakeDomainClassMembers(def));
topDecl = topDecl.AddMembers(_readerGen.MakeReaderStruct(def));
topDecl = topDecl.AddMembers(_writerGen.MakeWriterStruct(def));
}
topDecl = topDecl.AddMembers(
_readerGen.MakeReaderStruct(def),
_writerGen.MakeWriterStruct(def));
foreach (var nestedGroup in def.NestedGroups)
{
@ -99,6 +113,9 @@
IEnumerable<MemberDeclarationSyntax> TransformInterface(TypeDefinition def)
{
if (!_names.EmitDomainClassesAndInterfaces)
yield break;
yield return _interfaceGen.MakeInterface(def);
yield return _interfaceGen.MakeProxy(def);
yield return _interfaceGen.MakeSkeleton(def);
@ -168,7 +185,7 @@
if (classDecl == null)
{
classDecl = ClassDeclaration(_names.MakePipeliningSupportExtensionClassName(file).Identifier)
.AddModifiers(Public, Static, Partial);
.AddModifiers(_names.TypeVisibilityModifier, Static, Partial);
}
classDecl = classDecl.AddMembers(members);
@ -187,6 +204,8 @@
internal string Transform(GenFile file)
{
_names.NullableEnable = file.NullableEnable ?? _options.NullableEnableDefault;
_names.EmitDomainClassesAndInterfaces = file.EmitDomainClassesAndInterfaces;
_names.TypeVisibility = file.TypeVisibility;
NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace;
@ -211,12 +230,15 @@
ns = ns.AddMembers(Transform(def).ToArray());
}
if (_names.EmitDomainClassesAndInterfaces)
{
var psc = TransformForPipeliningSupport(file);
if (psc != null)
{
ns = ns.AddMembers(psc);
}
}
var cu = CompilationUnit().AddUsings(
UsingDirective(ParseName("Capnp")),

View File

@ -51,7 +51,7 @@ namespace CapnpC.CSharp.Generator.CodeGen
{
var decl = EnumDeclaration(_names.GetCodeIdentifier(def))
.WithAttributeLists(MakeTypeIdAttributeLists(def.Id))
.AddModifiers(Public)
.AddModifiers(_names.TypeVisibilityModifier)
.AddBaseListTypes(SimpleBaseType(_names.Type<ushort>(Nullability.NonNullable)));
foreach (var enumerant in def.Enumerants.OrderBy(e => e.CodeOrder))

View File

@ -1,4 +1,5 @@
using CapnpC.CSharp.Generator.Model;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
@ -74,6 +75,8 @@ namespace CapnpC.CSharp.Generator.CodeGen
public string SkeletonClassFormat { get; }
public Name AwaitProxy { get; }
public bool NullableEnable { get; set; }
public bool EmitDomainClassesAndInterfaces { get; set; }
public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; }
public GenNames(GeneratorOptions options)
{
TopNamespace = new Name(options.TopNamespaceName).IdentifierName;
@ -708,5 +711,23 @@ namespace CapnpC.CSharp.Generator.CodeGen
PostfixUnaryExpression(SyntaxKind.SuppressNullableWarningExpression, expression) :
expression;
}
public SyntaxToken TypeVisibilityModifier
{
get
{
switch (TypeVisibility)
{
case SupportedAnnotations.TypeVisibility.Public:
return Token(SyntaxKind.PublicKeyword);
case SupportedAnnotations.TypeVisibility.Internal:
return Token(SyntaxKind.InternalKeyword);
default:
throw new NotImplementedException();
}
}
}
}
}

View File

@ -13,6 +13,8 @@ namespace CapnpC.CSharp.Generator.Model
public string[] Namespace { get; set; }
public bool? NullableEnable { get; set; }
public bool EmitNullableDirective { get; set; }
public bool EmitDomainClassesAndInterfaces { get; set; }
public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; }
public IEnumerable<TypeDefinition> NestedTypes { get => this.GetNestedTypes(); }
public ICollection<IDefinition> NestedDefinitions { get; } = new List<IDefinition>();

View File

@ -94,6 +94,8 @@ namespace CapnpC.CSharp.Generator.Model
file.Name = name;
file.NullableEnable = GetNullableEnable(node);
file.EmitNullableDirective = GetEmitNullableDirective(node) ?? false;
file.EmitDomainClassesAndInterfaces = GetEmitDomainClassesAndInterfaces(node) ?? true;
file.TypeVisibility = GetTypeVisibility(node) ?? TypeVisibility.Public;
return ProcessNodePass1(id, name, state) as GenFile;
}

View File

@ -19,9 +19,17 @@ namespace CapnpC.CSharp.Generator.Model
public const ulong NullableEnable = 0xeb0d831668c6eda1;
public const ulong Name = 0xeb0d831668c6eda2;
public const ulong EmitNullableDirective = 0xeb0d831668c6eda3;
public const ulong EmitDomainClassesAndInterfaces = 0xeb0d831668c6eda4;
public const ulong TypeVisibility = 0xeb0d831668c6eda6;
}
}
public enum TypeVisibility
{
Public = 0,
Internal = 1
}
public static string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode)
{
foreach (var annotation in fileNode.Annotations)
@ -98,5 +106,29 @@ namespace CapnpC.CSharp.Generator.Model
}
return null;
}
public static bool? GetEmitDomainClassesAndInterfaces(Schema.Node.Reader node)
{
foreach (var annotation in node.Annotations)
{
if (annotation.Id == AnnotationIds.Cs.EmitDomainClassesAndInterfaces && annotation.Value.IsBool)
{
return annotation.Value.Bool;
}
}
return null;
}
public static TypeVisibility? GetTypeVisibility(Schema.Node.Reader node)
{
foreach (var annotation in node.Annotations)
{
if (annotation.Id == AnnotationIds.Cs.TypeVisibility && annotation.Value.IsEnum)
{
return (TypeVisibility)annotation.Value.Enum;
}
}
return null;
}
}
}

View File

@ -1,6 +1,11 @@
@0xeb0d831668c6edab;
$namespace("Capnp.Annotations");
enum TypeVisibility @0xeb0d831668c6eda5 {
public @0;
internal @1;
}
annotation namespace @0xeb0d831668c6eda0 (file) : Text;
# C# namespace for code generation
@ -8,7 +13,13 @@ annotation nullableEnable @0xeb0d831668c6eda1 (file) : Bool;
# Whether to generate C# nullable reference types
annotation emitNullableDirective @0xeb0d831668c6eda3 (file) : Bool;
# Whether to surround the generated with with #nullable enable/disable ... #nullable restore
# Whether to surround the generated code with #nullable enable/disable ... #nullable restore
annotation emitDomainClassesAndInterfaces @0xeb0d831668c6eda4 (file) : Bool;
# Whether generate domain classes and interfaces (default is 'true' if annotation is missing)
annotation typeVisibility @0xeb0d831668c6eda6 (file) : TypeVisibility;
# Visibility of generated types
annotation name @0xeb0d831668c6eda2 (field, enumerant, struct, enum, interface, method, param, group, union) : Text;
# C# member name for code generation

View File

@ -4,12 +4,10 @@ $coverageDir = "$rootDir\coverage"
$coverageReportDir = "$rootDir\coverage\report"
$openCover = "$env:LOCALAPPDATA\Apps\OpenCover\OpenCover.Console.exe"
$vsTestConsole = where.exe vstest.console
$coverageOutput = "$coverageDir\coverage.xml"
$runtimeTests = "$rootDir\Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll"
$coverageOutputRuntime = "$coverageDir\cov-Capnp.Net.Runtime.xml"
$generatorTests = "$rootDir\CapnpC.CSharp.Generator.Tests\bin\Release\netcoreapp3.0\CapnpC.CSharp.Generator.Tests.dll"
$coverageOutputGenerator = "$coverageDir\cov-CapnpC.CSharp.Generator.xml"
If(!(test-path $coverageDir))
{
@ -25,14 +23,15 @@ If(!(test-path $coverageReportDir))
-targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`"" `
-filter:"+[Capnp.Net.Runtime]Capnp.*" `
-excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" `
-output:"$coverageOutputRuntime" `
-output:"$coverageOutput" `
-mergebyhash -register:user -oldStyle
& $openCover -target:"$vsTestConsole" `
-targetArgs:"/inIsolation $generatorTests" `
-filter:"+[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.* -[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.Schema.*" `
-excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" `
-output:"$coverageOutputGenerator" `
-output:"$coverageOutput" `
-mergeoutput `
-mergebyhash -register:user -oldStyle
ReportGenerator.exe -reports:"$coverageOutputRuntime;$coverageOutputGenerator" -targetdir:"$coverageReportDir" -reportTypes:"Html;Xml"
ReportGenerator.exe -reports:"$coverageOutput" -targetdir:"$coverageReportDir" -reportTypes:"Html"