/************************************************************************* * ModernUO * * Copyright (C) 2019-2021 - ModernUO Development Team * * Email: hi@modernuo.com * * File: SyntaxReceiver.cs * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using SourceGeneration; namespace SerializationGenerator { public class SerializerSyntaxReceiver : ISyntaxContextReceiver { #pragma warning disable RS1024 public Dictionary)> ClassAndFields { get; } = new(SymbolEqualityComparer.Default); #pragma warning restore RS1024 public ImmutableArray SerializableList => ClassAndFields.Keys.ToImmutableArray(); public void OnVisitSyntaxNode(SyntaxNode node, SemanticModel semanticModel) { var compilation = semanticModel.Compilation; if (node is ClassDeclarationSyntax { AttributeLists: { Count: > 0 } } classDeclarationSyntax) { if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol) { return; } if (classSymbol.WillBeSerializable(compilation, out var attrData)) { if (ClassAndFields.TryGetValue(classSymbol, out var value)) { var (_, fieldsList) = value; ClassAndFields[classSymbol] = (attrData, fieldsList); } else { ClassAndFields.Add(classSymbol, (attrData, new List())); } } return; } if (node is FieldDeclarationSyntax { AttributeLists: { Count: > 0 } } fieldDeclarationSyntax) { foreach (var variable in fieldDeclarationSyntax.Declaration.Variables) { if (semanticModel.GetDeclaredSymbol(variable) is IFieldSymbol fieldSymbol) { AddFieldOrProperty(fieldSymbol, compilation); } } } else if (node is PropertyDeclarationSyntax { AttributeLists: { Count: > 0 } } propertyDeclarationSyntax) { if (semanticModel.GetDeclaredSymbol(propertyDeclarationSyntax) is IPropertySymbol propertySymbol) { AddFieldOrProperty(propertySymbol, compilation); } } } public void OnVisitSyntaxNode(GeneratorSyntaxContext context) => OnVisitSyntaxNode(context.Node, context.SemanticModel); private void AddFieldOrProperty(ISymbol symbol, Compilation compilation) { var serializableFieldAttr = compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTRIBUTE); if (symbol.GetAttribute(serializableFieldAttr) == null) { return; } var classSymbol = symbol.ContainingType; if (ClassAndFields.TryGetValue(classSymbol, out var value)) { var (_, fieldsList) = value; fieldsList.Add(symbol); return; } if (classSymbol.WillBeSerializable(compilation, out var attrData)) { ClassAndFields.Add(classSymbol, (attrData, new List { symbol })); } } } }