private MemberDeclarationSyntax CreateToDerivedTypeMethod(MetaType derivedType) { var derivedTypeName = GetFullyQualifiedSymbolName(derivedType.TypeSymbol); var thatLocal = SyntaxFactory.IdentifierName("that"); var body = new List <StatementSyntax>(); // var that = this as DerivedType; body.Add(SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( varType, SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(thatLocal.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.BinaryExpression( SyntaxKind.AsExpression, SyntaxFactory.ThisExpression(), derivedTypeName))))))); // this.GetType() var thisDotGetType = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName("GetType")), SyntaxFactory.ArgumentList()); // {0}.Equals(typeof(derivedType)) var thisTypeIsEquivalentToDerivedType = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, thisDotGetType, SyntaxFactory.IdentifierName(nameof(Type.Equals))), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument( SyntaxFactory.TypeOfExpression(derivedTypeName))))); var ifEquivalentTypeBlock = new List <StatementSyntax>(); var fieldsBeyond = derivedType.GetFieldsBeyond(this.generator.applyToMetaType); if (fieldsBeyond.Any()) { Func <MetaField, ExpressionSyntax> isUnchanged = v => SyntaxFactory.ParenthesizedExpression( v.IsRequired ? // ({0} == that.{1}) SyntaxFactory.BinaryExpression( SyntaxKind.EqualsExpression, v.NameAsField, SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, thatLocal, v.NameAsProperty)) : // (!{0}.IsDefined || {0}.Value == that.{1}) SyntaxFactory.BinaryExpression( SyntaxKind.LogicalOrExpression, SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, Syntax.OptionalIsDefined(v.NameAsField)), SyntaxFactory.BinaryExpression( SyntaxKind.EqualsExpression, Syntax.OptionalValue(v.NameAsField), SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, thatLocal, v.NameAsProperty)))); var noChangesExpression = fieldsBeyond.Select(isUnchanged).ChainBinaryExpressions(SyntaxKind.LogicalAndExpression); ifEquivalentTypeBlock.Add(SyntaxFactory.IfStatement( noChangesExpression, SyntaxFactory.ReturnStatement(thatLocal))); } else { ifEquivalentTypeBlock.Add(SyntaxFactory.ReturnStatement(thatLocal)); } // if (that != null && this.GetType().IsEquivalentTo(typeof(derivedType))) { ... } body.Add(SyntaxFactory.IfStatement( SyntaxFactory.BinaryExpression( SyntaxKind.LogicalAndExpression, SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, thatLocal, SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)), thisTypeIsEquivalentToDerivedType), SyntaxFactory.Block(ifEquivalentTypeBlock))); // return DerivedType.CreateWithIdentity(...) body.Add(SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, derivedTypeName, CreateWithIdentityMethodName), this.generator.CreateArgumentList(this.generator.applyToMetaType.AllFields, asOptional: OptionalStyle.WhenNotRequired) .AddArguments(RequiredIdentityArgumentFromProperty) .AddArguments(this.generator.CreateArgumentList(fieldsBeyond, ArgSource.Argument).Arguments.ToArray())))); return(SyntaxFactory.MethodDeclaration( derivedTypeName, GetToTypeMethodName(derivedType.TypeSymbol.Name).Identifier) .AddModifiers( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.VirtualKeyword)) .WithParameterList(this.generator.CreateParameterList(fieldsBeyond, ParameterStyle.OptionalOrRequired)) .WithBody(SyntaxFactory.Block(body))); }
private MemberDeclarationSyntax CreateCreateWithIdentityMethod() { ExpressionSyntax returnExpression = DefaultInstanceFieldName; if (this.generator.applyToMetaType.LocalFields.Any()) { returnExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, returnExpression, WithFactoryMethodName), this.generator.CreateArgumentList(this.generator.applyToMetaType.AllFields, ArgSource.OptionalArgumentOrTemplate, OptionalStyle.Always) .AddArguments(OptionalIdentityArgument)); } var method = SyntaxFactory.MethodDeclaration( this.generator.applyToTypeName, CreateWithIdentityMethodName.Identifier) .AddModifiers( SyntaxFactory.Token(SyntaxKind.InternalKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)) .WithParameterList( this.generator.CreateParameterList( this.generator.applyToMetaType.AllFields, ParameterStyle.OptionalOrRequired) .AddParameters(OptionalIdentityParameter)) .WithBody(SyntaxFactory.Block( SyntaxFactory.IfStatement( SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, Syntax.OptionalIsDefined(IdentityParameterName)), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentityParameterName, SyntaxFactory.InvocationExpression(NewIdentityMethodName, SyntaxFactory.ArgumentList())))), SyntaxFactory.ReturnStatement(returnExpression))); // BUG: the condition should be if there are local fields on *any* ancestor // from the closest non-abstract ancestor (exclusive) to this type (inclusive). if (!this.generator.applyToMetaType.LocalFields.Any() && this.generator.applyToMetaType.Ancestors.Any(a => !a.TypeSymbol.IsAbstract)) { method = Syntax.AddNewKeyword(method); } return(method); }
private void ImplementSortedChildrenInterface() { this.baseTypes.Add(SyntaxFactory.SimpleBaseType(Syntax.GetTypeSyntax(typeof(IRecursiveParentWithSortedChildren)))); // int IRecursiveParentWithSortedChildren.Compare(IRecursiveType first, IRecursiveType second) var firstParameterName = SyntaxFactory.IdentifierName("first"); var secondParameterName = SyntaxFactory.IdentifierName("second"); this.innerMembers.Add(SyntaxFactory.MethodDeclaration( SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), nameof(IRecursiveParentWithSortedChildren.Compare)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(SyntaxFactory.IdentifierName(nameof(IRecursiveParentWithSortedChildren)))) .AddParameterListParameters( SyntaxFactory.Parameter(firstParameterName.Identifier).WithType(Syntax.GetTypeSyntax(typeof(IRecursiveType))), SyntaxFactory.Parameter(secondParameterName.Identifier).WithType(Syntax.GetTypeSyntax(typeof(IRecursiveType)))) .WithBody(SyntaxFactory.Block( // return this.Children.KeyComparer.Compare((<#= templateType.RecursiveType.TypeName #>)first, (<#= templateType.RecursiveType.TypeName #>)second); SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, Syntax.ThisDot(SyntaxFactory.IdentifierName(this.generator.applyToMetaType.RecursiveField.Name.ToPascalCase())), SyntaxFactory.IdentifierName(nameof(ImmutableSortedSet <int> .KeyComparer))), SyntaxFactory.IdentifierName(nameof(IComparer <int> .Compare))), SyntaxFactory.ArgumentList(Syntax.JoinSyntaxNodes(SyntaxKind.CommaToken, SyntaxFactory.Argument(SyntaxFactory.CastExpression(this.generator.applyToMetaType.RecursiveType.TypeSyntax, firstParameterName)), SyntaxFactory.Argument(SyntaxFactory.CastExpression(this.generator.applyToMetaType.RecursiveType.TypeSyntax, secondParameterName))))))))); }
private void ImplementOrderedChildrenInterface() { // We only need to declare this interface if the children are not sorted, // since sorted children merit a derived interface making this redundant. if (!this.generator.applyToMetaType.ChildrenAreSorted) { this.baseTypes.Add(SyntaxFactory.SimpleBaseType(Syntax.GetTypeSyntax(typeof(IRecursiveParentWithOrderedChildren)))); } // int IRecursiveParentWithOrderedChildren.IndexOf(IRecursiveType value) var valueParameterName = SyntaxFactory.IdentifierName("value"); this.innerMembers.Add(SyntaxFactory.MethodDeclaration( SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), nameof(IRecursiveParentWithOrderedChildren.IndexOf)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(SyntaxFactory.IdentifierName(nameof(IRecursiveParentWithOrderedChildren)))) .AddParameterListParameters(SyntaxFactory.Parameter(valueParameterName.Identifier).WithType(Syntax.GetTypeSyntax(typeof(IRecursiveType)))) .WithBody(SyntaxFactory.Block( // return this.Children.IndexOf((<#= templateType.RecursiveType.TypeName #>)value); SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, Syntax.ThisDot(SyntaxFactory.IdentifierName(this.generator.applyToMetaType.RecursiveField.Name.ToPascalCase())), SyntaxFactory.IdentifierName(nameof(IList <int> .IndexOf))), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.CastExpression( this.generator.applyToMetaType.RecursiveType.TypeSyntax, valueParameterName))))))))); }
private void ImplementRecursiveParentInterface() { var irecursiveParentOfT = CreateIRecursiveParentOfTSyntax(GetFullyQualifiedSymbolName(this.generator.applyToMetaType.RecursiveType.TypeSymbol)); this.baseTypes.Add(SyntaxFactory.SimpleBaseType(irecursiveParentOfT)); // return this.Children; var returnThisDotChildren = SyntaxFactory.ReturnStatement(Syntax.ThisDot(SyntaxFactory.IdentifierName(this.generator.applyToMetaType.RecursiveField.Name.ToPascalCase()))); // System.Collections.Generic.IEnumerable<IRecursiveType> IRecursiveParent.Children this.innerMembers.Add( SyntaxFactory.PropertyDeclaration( Syntax.GetTypeSyntax(typeof(IEnumerable <IRecursiveType>)), nameof(IRecursiveParent.Children)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(Syntax.GetTypeSyntax(typeof(IRecursiveParent)))) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(returnThisDotChildren)))); // public ParentedRecursiveType<TRecursiveParent, TRecursiveType> GetParentedNode(uint identity) this.innerMembers.Add( SyntaxFactory.MethodDeclaration( SyntaxFactory.GenericName(nameof(ParentedRecursiveType <IRecursiveParent <IRecursiveType>, IRecursiveType>)).AddTypeArgumentListArguments( this.applyTo.RecursiveParent.TypeSyntax, this.applyTo.RecursiveType.TypeSyntax), nameof(IRecursiveParent.GetParentedNode)) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) //.WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(Syntax.GetTypeSyntax(typeof(IRecursiveParent)))) .AddParameterListParameters(RequiredIdentityParameter) .WithBody(SyntaxFactory.Block( // return this.GetParentedNode<TRecursiveParent, TRecursiveType>(identity); SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( Syntax.ThisDot(SyntaxFactory.GenericName(nameof(RecursiveTypeExtensions.GetParentedNode)).AddTypeArgumentListArguments( this.applyTo.RecursiveParent.TypeSyntax, this.applyTo.RecursiveType.TypeSyntax))) .AddArgumentListArguments(SyntaxFactory.Argument(IdentityParameterName)))))); // ParentedRecursiveType<IRecursiveParent<IRecursiveType>, IRecursiveType> IRecursiveParent.GetParentedNode(<#= templateType.RequiredIdentityField.TypeName #> identity) { var parentedVar = SyntaxFactory.IdentifierName("parented"); var returnType = Syntax.GetTypeSyntax(typeof(ParentedRecursiveTypeNonGeneric)); this.innerMembers.Add( SyntaxFactory.MethodDeclaration( returnType, nameof(IRecursiveParent.GetParentedNode)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(Syntax.GetTypeSyntax(typeof(IRecursiveParent)))) .AddParameterListParameters(RequiredIdentityParameter) .WithBody(SyntaxFactory.Block( // var parented = this.GetParentedNode(identity); SyntaxFactory.LocalDeclarationStatement(SyntaxFactory.VariableDeclaration(varType).AddVariables( SyntaxFactory.VariableDeclarator(parentedVar.Identifier).WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression(Syntax.ThisDot(SyntaxFactory.IdentifierName(nameof(RecursiveTypeExtensions.GetParentedNode)))) .AddArgumentListArguments(SyntaxFactory.Argument(IdentityParameterName)))))), // return new ParentedRecursiveType<IRecursiveParent<IRecursiveType>, IRecursiveType>(parented.Value, parented.Parent); SyntaxFactory.ReturnStatement(SyntaxFactory.ObjectCreationExpression(returnType).AddArgumentListArguments( SyntaxFactory.Argument(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, parentedVar, SyntaxFactory.IdentifierName(nameof(ParentedRecursiveTypeNonGeneric.Value)))), SyntaxFactory.Argument(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, parentedVar, SyntaxFactory.IdentifierName(nameof(ParentedRecursiveTypeNonGeneric.Parent))))))))); ////System.Collections.Generic.IEnumerable<<#= templateType.RecursiveType.TypeName #>> IRecursiveParent<<#= templateType.RecursiveType.TypeName #>>.Children { //// get { return this.Children; } ////} this.innerMembers.Add( SyntaxFactory.PropertyDeclaration( Syntax.IEnumerableOf(this.generator.applyToMetaType.RecursiveType.TypeSyntax), nameof(IRecursiveParent <IRecursiveType> .Children)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(irecursiveParentOfT)) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(returnThisDotChildren)))); }
protected override void GenerateCore() { this.baseTypes.Add(SyntaxFactory.SimpleBaseType(Syntax.GetTypeSyntax(typeof(IRecursiveType)))); ////<#= templateType.RequiredIdentityField.TypeName #> IRecursiveType.Identity { //// get { return this.Identity; } ////} this.innerMembers.Add(SyntaxFactory.PropertyDeclaration( IdentityFieldTypeSyntax, nameof(IRecursiveType.Identity)) .WithExplicitInterfaceSpecifier( SyntaxFactory.ExplicitInterfaceSpecifier(Syntax.GetTypeSyntax(typeof(IRecursiveType)))) .AddAccessorListAccessors( SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(SyntaxFactory.ReturnStatement(Syntax.ThisDot(IdentityPropertyName)))))); }
protected override void GenerateCore() { var valueParameterName = SyntaxFactory.IdentifierName("value"); foreach (var field in this.generator.applyToMetaType.LocalFields) { var withPropertyMethod = SyntaxFactory.MethodDeclaration( GetFullyQualifiedSymbolName(this.generator.applyToSymbol), WithPropertyMethodPrefix + field.Name.ToPascalCase()) .WithAdditionalAnnotations() .AddModifiers( SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( SyntaxFactory.Parameter(valueParameterName.Identifier) .WithType(GetFullyQualifiedSymbolName(field.Type))) .WithBody(SyntaxFactory.Block( SyntaxFactory.IfStatement( SyntaxFactory.BinaryExpression( SyntaxKind.EqualsExpression, valueParameterName, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), field.NameAsField)), SyntaxFactory.Block( SyntaxFactory.ReturnStatement(SyntaxFactory.ThisExpression()))), SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), WithMethodName), SyntaxFactory.ArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.NameColon(field.Name), NoneToken, Syntax.OptionalFor(valueParameterName)))))))); this.innerMembers.Add(withPropertyMethod); } foreach (var field in this.generator.applyToMetaType.InheritedFields) { string withMethodName = WithPropertyMethodPrefix + field.Name.ToPascalCase(); var withPropertyMethod = SyntaxFactory.MethodDeclaration( GetFullyQualifiedSymbolName(this.generator.applyToSymbol), withMethodName) .AddModifiers( SyntaxFactory.Token(SyntaxKind.NewKeyword), SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( SyntaxFactory.Parameter(valueParameterName.Identifier) .WithType(GetFullyQualifiedSymbolName(field.Type))) .WithBody(SyntaxFactory.Block( SyntaxFactory.ReturnStatement( SyntaxFactory.CastExpression( GetFullyQualifiedSymbolName(this.generator.applyToSymbol), SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.BaseExpression(), SyntaxFactory.IdentifierName(withMethodName)), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(valueParameterName)))))))); this.innerMembers.Add(withPropertyMethod); } }