예제 #1
0
        public void Execute(GeneratorExecutionContext context)
        {
            // retrieve the populated receiver
            if (context.SyntaxReceiver is not SyntaxReceiver receiver)
            {
                return;
            }

            var compilation = (CSharpCompilation)context.Compilation;
            // TODO: Get baseType programmatically
            var baseType = compilation.GetTypeByMetadataName("Entities.Entity");

            SourceText sourceText;

            using var stringWriter = new StringWriter();
            using var itw          = new IndentedTextWriter(stringWriter, "    ");

            var candidateClasses = receiver.CandidateClasses
                                   .Where(classDeclarationSyntax =>
            {
                var semanticClassModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
                var classSymbol        = semanticClassModel.GetDeclaredSymbol(classDeclarationSyntax);
                return(classSymbol.IsDerivedFrom(baseType));
            })
                                   .OrderBy(classDeclarationSyntax => classDeclarationSyntax, classDeclarationSyntaxComparer)
                                   .ToList();

            itw.WriteLine("using System;");
            itw.WriteLine();

            // TODO: Get Namespace from compilation
            using (itw.StartScope("namespace Entities"))
            {
                foreach (var candidateClass in candidateClasses)
                {
                    using (itw.StartScope($"partial class {candidateClass.Identifier.ValueText}"))
                    {
                        using (itw.StartScope($"public override {candidateClass.Identifier.ValueText} Update({candidateClass.Identifier.ValueText} other)"))
                        {
                            using (itw.StartScope($"if (other is null)"))
                            {
                                itw.WriteLine("return this;");
                            }

                            foreach (var classMemberDeclarationSyntax in candidateClass.Members)
                            {
                                var propertyDeclarationSyntax = classMemberDeclarationSyntax as PropertyDeclarationSyntax;

                                var propertySemanticModel = compilation.GetSemanticModel(classMemberDeclarationSyntax.SyntaxTree);
                                var propertySymbol        = propertySemanticModel.GetDeclaredSymbol(propertyDeclarationSyntax);

                                if (propertySymbol.IsReadOnly)
                                {
                                    continue;
                                }

                                ITypeSymbol propertyTypeSymbol  = propertySymbol.Type;
                                var         isDerivedFromEntity = propertyTypeSymbol.IsDerivedFrom(baseType);

                                //var isSimpleType = GeneratorHelpers.IsSimpleType(typeSymbol);

                                if (isDerivedFromEntity)
                                {
                                    // The member is another type derived from entity, so we can call the update method on it.
                                    itw.WriteTernaryAssignment(
                                        $"this.{propertyDeclarationSyntax.Identifier}",
                                        $"this.{propertyDeclarationSyntax.Identifier} is null",
                                        $"other.{propertyDeclarationSyntax.Identifier}",
                                        $"this.{propertyDeclarationSyntax.Identifier}.Update(other.{propertyDeclarationSyntax.Identifier})");
                                }
                                //else if (!isSimpleType)
                                //{
                                //    // The member is complex type not derived from entity, so we try to set its properties
                                //    var typeSymbolName = compilation.GetTypeByMetadataName(typeSymbol.ToString());
                                //    var members = typeSymbolName.GetMembers().OfType<IPropertySymbol>();
                                //}
                                else
                                {
                                    // The type is a simple type - we test for equality and overwrite, if necessary
                                    using (itw.StartScope($"if (this.{propertyDeclarationSyntax.Identifier} != other.{propertyDeclarationSyntax.Identifier})"))
                                    {
                                        itw.WriteLine($"this.{propertyDeclarationSyntax.Identifier} = other.{propertyDeclarationSyntax.Identifier};");
                                    }
                                }
                            }

                            itw.WriteLine("return this;");
                        }
                    }
                }
            }

            itw.Flush();
            stringWriter.Flush();

            sourceText = SourceText.From(stringWriter.ToString(), Encoding.UTF8);

            // Adds the generated source code to the compilation
            context.AddSource("Generated.cs", sourceText);
        }