private static GenerateCodeContext CreateGenerateCodeContext()

in Blog-SourceGenerator/MvvmGenerator/AutoImplementNotifyPropertyChangedGenerator.cs [53:132]


        private static GenerateCodeContext CreateGenerateCodeContext(GeneratorExecutionContext context, IEnumerable<ClassDeclarationSyntax> classes)
        {
            var options = (context.Compilation as CSharpCompilation)?.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
            var compilation = context
                .Compilation
                .AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(AutoNotifyCode, Encoding.UTF8), options));

            var autoNotifyAttributeSymbol = compilation.GetTypeByMetadataName(Consts.AutoNotifyAttributeFullName) ?? throw new InvalidOperationException();
            var inpcSymbol = compilation.GetTypeByMetadataName(typeof(INotifyPropertyChanged).FullName)?? throw new InvalidOperationException();
            return new GenerateCodeContext(classes.Select(x => processClass(x)));

            Clazz processClass(ClassDeclarationSyntax c)
            {
                var model = compilation.GetSemanticModel(c.SyntaxTree);
                if (model.GetDeclaredSymbol(c) is not ITypeSymbol typeSymbol)
                {
                    throw new InvalidOperationException();
                }

                var isAlreadyImplementedINPC = typeSymbol.Interfaces.Contains(inpcSymbol);
                return new Clazz(
                    typeSymbol.ContainingNamespace.ToDisplayString(),
                    typeSymbol.Name,
                    processFields(c.Members.OfType<FieldDeclarationSyntax>(), c.Members.OfType<PropertyDeclarationSyntax>()));
            }

            IEnumerable<Property> processFields(IEnumerable<FieldDeclarationSyntax> fields, IEnumerable<PropertyDeclarationSyntax> properties)
            {
                var candidateFields = fields
                    .Select(field => (field, model: compilation.GetSemanticModel(field.SyntaxTree)))
                    .SelectMany(x => x.field.Declaration.Variables.Select(variable => x.model.GetDeclaredSymbol(variable) as IFieldSymbol))
                    .Where(x => x.GetAttributes().Any(y => y.AttributeClass?.Equals(autoNotifyAttributeSymbol, SymbolEqualityComparer.Default) ?? false));
                var candidateProperties = properties
                    .Select(property => (property, model: compilation.GetSemanticModel(property.SyntaxTree)))
                    .Select(x => (x.property, propertySymbol: x.model.GetDeclaredSymbol(x.property) ?? throw new InvalidOperationException()))
                    .Where(x => x.propertySymbol.GetAttributes().Any(y => y.AttributeClass?.Equals(autoNotifyAttributeSymbol, SymbolEqualityComparer.Default) ?? false))
                    .ToArray();

                var result = candidateFields.Select(x => new Property(x.Type.ToString(), x.Name, getPropertyName(x), true))
                    .Where(x => !string.IsNullOrEmpty(x.Name))
                    .ToList();

                if (candidateProperties.Any())
                {
                    var propMap = result.ToDictionary(x => x.Name);
                    var dependParis = candidateProperties
                        .SelectMany(x => 
                            x.property
                                .DescendantNodes(y => !y.IsKind(SyntaxKind.IdentifierName))
                                .OfType<IdentifierNameSyntax>()
                                .Select(y => (propertyName: x.property.Identifier.Text, dependPropertyName: y.Identifier.Text)))
                        .Where(x => propMap.ContainsKey(x.dependPropertyName));
                    foreach (var pair in dependParis)
                    {
                        propMap[pair.dependPropertyName].RelatedProperties.Add(pair.propertyName);
                    }

                    result.AddRange(dependParis
                        .Select(x => x.propertyName)
                        .Distinct()
                        .Select(x => new Property("", "", x, false)));
                }

                return result;
            }

            string getPropertyName(IFieldSymbol f)
            {
                var attrData = f.GetAttributes().Single(x => x.AttributeClass?.Equals(autoNotifyAttributeSymbol, SymbolEqualityComparer.Default) ?? false);
                var overridenNameOpt = attrData.ConstructorArguments.FirstOrDefault().Value as string;
                return (f.Name.TrimStart('_'), overridenNameOpt) switch
                {
                    (_, string y) when !string.IsNullOrEmpty(y) => y,
                    ({ Length: 0 }, _) => "",
                    ({ Length: 1 } y, _) => y.ToUpper(),
                    (string y, _) => $"{y.Substring(0, 1).ToUpper()}{y.Substring(1)}",
                    _ => "",
                };
            }
        }