public List <PropertyTypeNode> Deserialize() { var definitions = new List <PropertyTypeNode>(); if (string.IsNullOrEmpty(Code)) { return(definitions); } var ast = CSharpSyntaxTree.ParseText(Code); var root = (CompilationUnitSyntax)ast.GetRoot(); var references = ReferenceAssemblies.Locations.Select( location => (MetadataReference)MetadataReference.CreateFromFile(location)).ToArray(); var compilation = CSharpCompilation.Create(Path.GetRandomFileName()) .AddReferences(references) .AddSyntaxTrees(ast); var model = compilation.GetSemanticModel(ast); var collector = new SemanticInformationCollector(model); collector.Visit(root); definitions = ExtractPropertyNodesFrom(model, collector); return(definitions); }
private List <PropertyTypeNode> ExtractPropertyNodesFrom( SemanticModel model, SemanticInformationCollector collector) { if (model == null) { throw new Exception("Invalid semantic model for property node introspection (null)."); } var nodes = new List <PropertyTypeNode>(); var typePerFullTypename = new Dictionary <string, PropertyTypeNode>(); // Expect a top -> bottom tree traversal, so it means that the // list contains types declared in order. foreach (var type in collector.ContainerTypes) { var tag = PropertyTypeNode.TypeTag.Class; if (type is StructDeclarationSyntax) { tag = PropertyTypeNode.TypeTag.Struct; } var symbol = model.GetDeclaredSymbol(type); var typePath = new ContainerTypeTreePath { Namespace = NamespaceForType(type) }; var fullTypeNamePath = symbol.ToString().Replace(typePath.Namespace, "").Trim('.').Split('.'); fullTypeNamePath = fullTypeNamePath.Take(fullTypeNamePath.Length - 1).ToArray(); foreach (var pathPart in fullTypeNamePath) { typePath.TypePath.Push(pathPart); } var node = new PropertyTypeNode { Tag = tag, TypePath = typePath, TypeName = symbol.Name, IsAbstractClass = symbol.IsAbstract, OverrideDefaultBaseClass = symbol.AllInterfaces.Any(i => i.Name == typeof(IPropertyContainer).Name) ? string.Empty : symbol.BaseType.Name }; var fieldCollector = new FieldCollector(model); fieldCollector.Visit(type); foreach (var field in fieldCollector.Properties) { var genericProperty = new RoslynProperty(field.Symbol); if (!genericProperty.IsValid) { continue; } // Parse var property = new PropertyTypeNode() { PropertyName = PropertyNameFromFieldName(field.Symbol.Name), Tag = genericProperty.TypeTag, TypeName = genericProperty.TypeID, Of = genericProperty.ListOf, IsReadonly = genericProperty.IsReadonly, IsPublicProperty = field.SyntaxNode.Modifiers.Any(SyntaxKind.PublicKeyword) }; // Extract info about backing fields var initializer = field.SyntaxNode.Declaration.Variables.First().Initializer; if (initializer?.Value is ExpressionSyntax) { /* * // @TODO * var initializerExpression = initializer.Value; * * // @TODO * var symbolNames = model.LookupSymbols(initializerExpression.SpanStart).Select(s => s.Name).ToList(); */ // property.DefaultValue = property.PropertyBackingAccessor = string.Empty; } if (!string.IsNullOrEmpty(property.PropertyName)) { node.Properties.Add(property); } } var containingSymbolFullName = symbol.ContainingSymbol.ToDisplayString(); // symbol.ContainingSymbol.Name if (typePerFullTypename.ContainsKey(containingSymbolFullName)) { // This is a nested node var parent = typePerFullTypename[containingSymbolFullName]; node.TypePath = new ContainerTypeTreePath(parent.TypePath); node.TypePath.TypePath.Push(parent.TypeName); parent.NestedContainers.Add(node); } else { // This is a new node typePerFullTypename[node.FullTypeName] = node; nodes.Add(node); } } return(nodes); }