public static string GenerateContractEventHandlerMethod(CsField sourceField, CsEvent targetEvent, NamespaceManager manager = null) { if (sourceField == null) { return(null); } if (!sourceField.IsLoaded) { return(null); } if (targetEvent == null) { return(null); } if (!targetEvent.IsLoaded) { return(null); } SourceFormatter formatter = new SourceFormatter(); formatter.AppendCodeLine(0, "/// <summary>"); formatter.AppendCodeLine(0, $"/// Handles the raised event {targetEvent.Name}"); formatter.AppendCodeLine(0, "/// </summary>"); formatter.AppendCodeLine(0, $"protected void {GenerateContractEventHandlerMethodName(sourceField,targetEvent)}{targetEvent.EventHandlerDelegate.Parameters.CSharpFormatParametersSignature(manager,false)}"); formatter.AppendCodeLine(0, "{"); formatter.AppendCodeLine(0); formatter.AppendCodeLine(1, "//TODO: Add Event handler logic"); formatter.AppendCodeLine(0); formatter.AppendCodeLine(0, "}"); formatter.AppendCodeLine(0); return(formatter.ReturnSource()); }
private static AccessorDeclarationSyntax GenerateSetter(CsField csElement, PropertyValueSetTransform valueTransformation) { ExpressionSyntax valueExpression = IdentifierName("value"); var storage = MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(csElement.IntermediateMarshalName) ); return(AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, storage, valueTransformation != null ? valueTransformation(storage, valueExpression) : valueExpression ) ) ) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); }
private MethodDeclarationSyntax GenerateMarshalTo(CsStruct csStruct) { IEnumerable <StatementSyntax> FieldMarshallers(CsField field) { if ((field.Relations?.Count ?? 0) == 0) { yield return(generators.Marshalling.GetMarshaller(field).GenerateManagedToNative(field, false)); yield break; } foreach (var relation in field.Relations) { var marshaller = generators.Marshalling.GetRelationMarshaller(relation); CsField publicElement = null; if (relation is LengthRelation related) { var relatedMarshallableName = related.Identifier; publicElement = csStruct.Fields.First(fld => fld.CppElementName == relatedMarshallableName); } yield return(marshaller.GenerateManagedToNative(publicElement, field)); } } return(GenerateMarshalMethod( "__MarshalTo", Block( csStruct.Fields.SelectMany(FieldMarshallers) .Where(statement => statement != null) ) )); }
protected override StatementSyntax GenerateNativeToManaged(CsField csField, bool singleStackFrame) => ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(csField.Name), GetMarshalStorageLocation(csField) ) );
/// <summary> /// Generates the name of the contract release method name for the target field. /// </summary> /// <param name="sourceField">field to generate the release name for.</param> /// <returns></returns> public static string GenerateContractReleaseMethodName(CsField sourceField) { if (sourceField == null) { return(null); } return($"{sourceField.Name.ConvertToProperCase(new[] {'_'})}_ContractRelease"); }
public StatementSyntax GenerateManagedToNative(CsMarshalBase csElement, bool singleStackFrame) { const ArrayCopyDirection direction = ArrayCopyDirection.ManagedToNative; return(csElement switch { CsParameter { IsLocalManagedReference : true } parameter => GenerateCopyBlock(parameter, direction), CsField field => GenerateCopyMemory(field, direction), _ => null });
private static AccessorDeclarationSyntax GenerateGetter(CsField csElement, PropertyValueGetTransform valueTransformation) { ExpressionSyntax valueExpression = ParseName(csElement.IntermediateMarshalName); return(AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( valueTransformation != null ? valueTransformation(GeneratorHelpers.WrapInParentheses(valueExpression)) : valueExpression ) ) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); }
protected override StatementSyntax GenerateManagedToNative(CsField csField, bool singleStackFrame) => ExpressionStatement( AssignmentExpression( SyntaxKind.OrAssignmentExpression, GetMarshalStorageLocation(csField), GeneratorHelpers.CastExpression( ParseTypeName(csField.MarshalType.QualifiedName), BinaryExpression( SyntaxKind.BitwiseAndExpression, IdentifierName(csField.IntermediateMarshalName), LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(csField.BitMask << csField.BitOffset) ) ) ) ) );
private PropertyDeclarationSyntax GenerateProperty(CsField csElement, TypeSyntax propertyType, PropertyValueGetTransform getterTransform, PropertyValueSetTransform setterTransform) => AddDocumentationTrivia( PropertyDeclaration(propertyType, csElement.Name) .WithAccessorList( AccessorList( List( new[] { GenerateGetter(csElement, getterTransform), GenerateSetter(csElement, setterTransform) } ) ) ) .WithModifiers(csElement.VisibilityTokenList), csElement );
/// <summary> /// Generates a method that releases to a target interface contract for the target field. /// </summary> /// <param name="sourceField">The field for which events to subscribe to.</param> /// <param name="contract">The contract to subscribe to.</param> /// <returns>Full source code for the subscribe method.</returns> public static string GenerateContractReleaseMethod(CsField sourceField, CsInterface contract) { if (sourceField == null) { return(null); } if (!sourceField.IsLoaded) { return(null); } if (contract == null) { return(null); } if (!contract.IsLoaded) { return(null); } SourceFormatter formatter = new SourceFormatter(); formatter.AppendCodeLine(0, "/// <summary>"); formatter.AppendCodeLine(0, $"/// Releases the events from the interface contract of {contract.Namespace}.{contract.Name} for the field {sourceField.Name}"); formatter.AppendCodeLine(0, "/// </summary>"); formatter.AppendCodeLine(0, $"private void {GenerateContractReleaseMethodName(sourceField)}()"); formatter.AppendCodeLine(0, "{"); formatter.AppendCodeLine(0); formatter.AppendCodeLine(1, $"if({sourceField.Name} == null) return;"); formatter.AppendCodeLine(0); foreach (var contractEvent in contract.Events) { if (!contractEvent.IsLoaded) { continue; } formatter.AppendCodeLine(1, $"{sourceField.Name}.{contractEvent.Name} -= {sourceField.Name.ConvertToProperCase(new []{'_'})}_{contractEvent.Name}_EventHandler;"); } formatter.AppendCodeLine(0); formatter.AppendCodeLine(0, "}"); formatter.AppendCodeLine(0); return(formatter.ReturnSource()); }
/// <summary> /// Generates the syntax definition of field in c# syntax. The default definition with all options turned off will return the filed signature and constants if defined and the default values. /// </summary> /// <example> /// With Keywords [Security] [Keywords] [FieldType] [Name]; /// With Keywords and a constant [Security] [Keywords] [FieldType] [Name] = [Constant Value]; /// Without Keywords [Security] [FieldType] [Name]; /// Without Keywords and a constant [Security] [FieldType] [Name] = [Constant Value]; /// </example> /// <param name="source">The source <see cref="CsField"/> model to generate.</param> /// <param name="manager">Namespace manager used to format type names.This is an optional parameter.</param> /// <param name="includeKeywords">Optional parameter that will include all keywords assigned to the field from the source model. This is true by default.</param> /// <param name="fieldSecurity">Optional parameter to set the target security for the field.</param> /// <returns>Fully formatted field definition or null if the field data could not be generated.</returns> public static string CSharpFormatFieldDeclaration(this CsField source, NamespaceManager manager = null, bool includeKeywords = true, CsSecurity fieldSecurity = CsSecurity.Unknown) { if (source == null) { return(null); } StringBuilder fieldFormatting = new StringBuilder(); CsSecurity security = fieldSecurity == CsSecurity.Unknown ? source.Security : fieldSecurity; fieldFormatting.Append($"{security.CSharpFormatKeyword()} "); if (includeKeywords) { if (source.IsStatic) { fieldFormatting.Append($"{Keywords.Static} "); } if (source.IsReadOnly) { fieldFormatting.Append($"{Keywords.Readonly} "); } } if (source.IsConstant) { fieldFormatting.Append($"{Keywords.Constant} "); } fieldFormatting.Append($"{source.DataType.CSharpFormatTypeName(manager)} "); fieldFormatting.Append($"{source.Name}"); if (source.IsConstant) { fieldFormatting.Append($" = {source.DataType.CSharpFormatValueSyntax(source.ConstantValue)}"); } fieldFormatting.Append(";"); return(fieldFormatting.ToString()); }
public static string GenerateContractEventHandlerMethodName(CsField sourceField, CsEvent targetEvent) { if (sourceField == null) { return(null); } if (!sourceField.IsLoaded) { return(null); } if (targetEvent == null) { return(null); } if (!targetEvent.IsLoaded) { return(null); } return($"{sourceField.Name.ConvertToProperCase(new[] {'_'})}_{targetEvent.Name}_EventHandler"); }
/// <summary> /// Generates the source code for a standard field definition. /// </summary> /// <param name="memberData">Event data to be loaded.</param> /// <param name="manager">The namespace manager to use for namespace management with type declarations.</param> /// <param name="fieldSecurity">Parameter to set the target security for the field.</param> /// <param name="includeKeywords">Optional parameter that will include all keywords assigned to the field from the source model. This is true by default.</param> /// <param name="implementConstant">Determines if the filed is implemented as constant is should be returned as a constant, default is true.</param> /// <param name="requireStaticKeyword">Adds the static keyword to the signature, default is false.</param> /// <param name="requireReadOnlyKeyword">Adds the readonly keyword to the signature, default is false.</param> /// <param name="requireConstant">Implements the field as a constant, default is false.</param> /// <param name="requireConstantValue">The value to set the constant to if required.</param> /// <returns>The fully formatted event source code or null if the member could not be implemented.</returns> public static string GenerateStandardFieldSourceCode(CsField memberData, NamespaceManager manager, CsSecurity fieldSecurity, bool includeKeywords = true, bool implementConstant = true, bool requireStaticKeyword = false, bool requireReadOnlyKeyword = false, bool requireConstant = false, string requireConstantValue = null) { //Bounds checking to make sure all data that is needed is provided. If any required data is missing will return null. if (memberData == null) { return(null); } if (!memberData.IsLoaded) { return(null); } if (manager == null) { return(null); } //C# helper used to format output syntax. var formatter = new CodeFactory.SourceFormatter(); //Using the formatter helper to generate a default event signature. string fieldSyntax = memberData.CSharpFormatFieldDeclaration(manager, includeKeywords, fieldSecurity, implementConstant, requireStaticKeyword, requireReadOnlyKeyword, requireConstant, requireConstantValue); //If the property syntax was not created return. if (string.IsNullOrEmpty(fieldSyntax)) { return(null); } //If the member has document then will build the documentation. if (memberData.HasDocumentation) { //Using a documentation helper that will generate an enumerator that will output all XML documentation for the member. foreach (var documentation in memberData.CSharpFormatXmlDocumentationEnumerator()) { //Appending each xml document line to the being of the member definition. formatter.AppendCodeLine(0, documentation); } } //The member has attributes assigned to it, append the attributes. if (memberData.HasAttributes) { //Using a documentation helper that will generate an enumerator that will output each attribute definition. foreach (var attributeSyntax in memberData.Attributes.CSharpFormatAttributeDeclarationEnumerator(manager)) { //Appending each attribute definition before the member definition. formatter.AppendCodeLine(0, attributeSyntax); } } //Adding the event declaration formatter.AppendCodeBlock(0, fieldSyntax); //Adding a extra line feed at the end of the declaration. formatter.AppendCodeLine(0); //The source formatter returning the final results. return(formatter.ReturnSource()); }
protected override bool CanMarshal(CsField csField) => true;
private IEnumerable <MemberDeclarationSyntax> GenerateMarshalStructField(CsStruct csStruct, CsField field) { var fieldDecl = FieldDeclaration( VariableDeclaration( ParseTypeName(field.MarshalType.QualifiedName))) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); if (csStruct.ExplicitLayout) { fieldDecl = fieldDecl.WithAttributeLists(SingletonList( AttributeList( SingletonSeparatedList(Attribute( ParseName("System.Runtime.InteropServices.FieldOffset"), AttributeArgumentList( SingletonSeparatedList(AttributeArgument( LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(field.Offset)))))))) )); } if (field.IsArray) { yield return(fieldDecl.WithDeclaration(fieldDecl.Declaration.AddVariables( VariableDeclarator(field.Name) ))); for (int i = 1; i < field.ArrayDimensionValue; i++) { var declaration = fieldDecl.WithDeclaration(fieldDecl.Declaration.AddVariables(VariableDeclarator($"__{field.Name}{i}"))); if (csStruct.ExplicitLayout) { var offset = field.Offset + (field.Size / field.ArrayDimensionValue) * i; declaration = declaration.WithAttributeLists(SingletonList( AttributeList( SingletonSeparatedList(Attribute( ParseName("System.Runtime.InteropServices.FieldOffset"), AttributeArgumentList( SingletonSeparatedList(AttributeArgument( LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(offset)))))))) )); } yield return(declaration); } } else if (field.PublicType is CsStruct fieldType && fieldType.HasMarshalType) { yield return(fieldDecl.WithDeclaration(VariableDeclaration( ParseTypeName($"{field.MarshalType.QualifiedName}.__Native"), SingletonSeparatedList( VariableDeclarator(field.Name))))); }
private async Task <CsSource> UpdateSubscriptionAsync(CsField subscriptionField, CsClass sourceClass, VsCSharpSource source) { SourceFormatter formatter = new SourceFormatter(); string injectSourceCode = null; var contract = subscriptionField.DataType.GetInterfaceModel(); if (contract == null) { return(null); } CsSource sourceCode = source.SourceCode; try { CsClass currentClass = sourceClass; var events = contract.Events; var subscribePath = ContractHelper.GetSubscribeFilePath(currentClass); if (!subscribePath.hasFile) { var manager = sourceCode.LoadNamespaceManager(sourceClass.Namespace); var parent = await source.GetParentAsync(); if (parent == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } VsDocument generatedDocument = null; string partialClassSource = CSharpSourceGenerationCommon.GeneratePartialClass(currentClass, manager); if (parent.ModelType == VisualStudioModelType.ProjectFolder) { var parentFolder = parent as VsProjectFolder; if (parentFolder == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } generatedDocument = await parentFolder.AddDocumentAsync(Path.GetFileName(subscribePath.filePath), partialClassSource); } else { var parentProject = parent as VsProject; if (parentProject == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } generatedDocument = await parentProject.AddDocumentAsync(subscribePath.filePath, partialClassSource); } sourceCode = await generatedDocument.GetCSharpSourceModelAsync(); sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } } else { var parent = await source.GetParentAsync(); VsCSharpSource sourceDocument = null; if (parent.ModelType == VisualStudioModelType.ProjectFolder) { var parentFolder = parent as VsProjectFolder; if (parentFolder == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } var children = await parentFolder.GetChildrenAsync(false, true); sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource) .Cast <VsCSharpSource>() .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath); } else { var parentProject = parent as VsProject; if (parentProject == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } var children = await parentProject.GetChildrenAsync(false, true); sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource) .Cast <VsCSharpSource>() .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath);; } if (sourceDocument == null) { throw new CodeFactoryException("Could load the contract document."); } sourceCode = sourceDocument.SourceCode; sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } } var namespaceManager = sourceCode.LoadNamespaceManager(currentClass.Namespace); foreach (var contractEvent in contract.Events) { var eventHandlerName = CSharpSourceGenerationWPF.GenerateContractEventHandlerMethodName(subscriptionField, contractEvent); if (eventHandlerName == null) { throw new CodeFactoryException($"Could not create the source code for a contract event handler."); } if (currentClass.Methods.Any(m => m.Name == eventHandlerName)) { continue; } var eventHandlerSource = CSharpSourceGenerationWPF.GenerateContractEventHandlerMethod(subscriptionField, contractEvent, namespaceManager); if (eventHandlerSource == null) { throw new CodeFactoryException($"Could not create the source code for the event handler {eventHandlerName}"); } sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, eventHandlerSource)); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } } var subscriptionName = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethodName(subscriptionField); var subscriptionMethod = currentClass.Methods.FirstOrDefault(m => m.Name == subscriptionName); if (subscriptionMethod != null) { sourceCode = await subscriptionMethod.DeleteAsync(); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } } var subscriptionSource = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethod(subscriptionField, contract); if (subscriptionSource == null) { throw new CodeFactoryException("Cannot generate the subscription contract source code."); } sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, subscriptionSource)); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } var releaseName = CSharpSourceGenerationWPF.GenerateContractReleaseMethodName(subscriptionField); var releaseMethod = currentClass.Methods.FirstOrDefault(m => m.Name == releaseName); if (releaseMethod != null) { sourceCode = await releaseMethod.DeleteAsync(); currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass; if (currentClass == null) { throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription"); } } var releaseSource = CSharpSourceGenerationWPF.GenerateContractReleaseMethod(subscriptionField, contract); if (releaseSource == null) { throw new CodeFactoryException("Cannot generate the release contract source code."); } sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, releaseSource)); } catch (CodeFactoryException) { throw; } catch (Exception unhandledException) { throw new CodeFactoryException("The following unhandledException occured", unhandledException); } return(sourceCode); }
protected abstract StatementSyntax GenerateNativeToManaged(CsField csField, bool singleStackFrame);
protected abstract bool CanMarshal(CsField csField);
/// <summary> /// Generates the syntax definition of field in c# syntax. The default definition with all options turned off will return the filed signature and constants if defined and the default values. /// </summary> /// <example> /// With Keywords [Security] [Keywords] [FieldType] [Name]; /// With Keywords and a constant [Security] [Keywords] [FieldType] [Name] = [Constant Value]; /// Without Keywords [Security] [FieldType] [Name]; /// Without Keywords and a constant [Security] [FieldType] [Name] = [Constant Value]; /// </example> /// <param name="source">The source <see cref="CsField"/> model to generate.</param> /// <param name="manager">Namespace manager used to format type names.This is an optional parameter.</param> /// <param name="includeKeywords">Optional parameter that will include all keywords assigned to the field from the source model. This is true by default.</param> /// <param name="fieldSecurity">Optional parameter to set the target security for the field.</param> /// <param name="implementConstant">Determines if the filed is implemented as constant is should be returned as a constant, default is true.</param> /// <param name="requireStaticKeyword">Adds the static keyword to the signature, default is false.</param> /// <param name="requireReadOnlyKeyword">Adds the readonly keyword to the signature, default is false.</param> /// <param name="requireConstant">Implements the field as a constant, default is false.</param> /// <param name="requireConstantValue">The value to set the constant to if required.</param> /// <returns>Fully formatted field definition or null if the field data could not be generated.</returns> public static string CSharpFormatFieldDeclaration(this CsField source, NamespaceManager manager = null, bool includeKeywords = true, CsSecurity fieldSecurity = CsSecurity.Unknown, bool implementConstant = true, bool requireStaticKeyword = false, bool requireReadOnlyKeyword = false, bool requireConstant = false, string requireConstantValue = null) { if (source == null) { return(null); } StringBuilder fieldFormatting = new StringBuilder(); CsSecurity security = fieldSecurity == CsSecurity.Unknown ? source.Security : fieldSecurity; fieldFormatting.Append($"{security.CSharpFormatKeyword()} "); string constantValue = null; bool staticKeyword = false; bool readOnlyKeyword = false; bool constantKeyword = false; if (includeKeywords) { if (source.IsStatic) { staticKeyword = true; } if (source.IsReadOnly) { readOnlyKeyword = true; } } if (source.IsConstant & implementConstant) { constantKeyword = true; constantValue = source.ConstantValue; } if (!staticKeyword) { staticKeyword = requireStaticKeyword; } if (!readOnlyKeyword) { readOnlyKeyword = requireReadOnlyKeyword; } if (!constantKeyword) { constantKeyword = requireConstant; } if (constantKeyword & string.IsNullOrEmpty(constantValue)) { constantValue = requireConstantValue; } if (staticKeyword) { fieldFormatting.Append($"{Keywords.Static} "); } if (readOnlyKeyword) { fieldFormatting.Append($"{Keywords.Readonly} "); } if (constantKeyword) { fieldFormatting.Append($"{Keywords.Constant} "); } fieldFormatting.Append($"{source.DataType.CSharpFormatTypeName(manager)} "); fieldFormatting.Append($"{source.Name}"); if (constantKeyword) { fieldFormatting.Append($" = {source.DataType.CSharpFormatValueSyntax(constantValue)}"); } fieldFormatting.Append(";"); return(fieldFormatting.ToString()); }
protected override bool CanMarshal(CsField csField) => csField.IsBitField;