public PropertyTypeNode.TypeTag WhenContextAndBuiltinTypes_Resolve_Works(
            string contextTypePath,
            string typeName)
        {
            var builtinTypes = new Dictionary <string, PropertyTypeNode.TypeTag>
            {
                { "my.namespace.roottype/nested/type/roottype", PropertyTypeNode.TypeTag.Enum },
                { "my.namespace.roottype/nested/type", PropertyTypeNode.TypeTag.Class },
                { "my.namespace.roottype/nested", PropertyTypeNode.TypeTag.Struct },
                { "my.namespace.roottype", PropertyTypeNode.TypeTag.Class },
                { "my.namespace.mytype", PropertyTypeNode.TypeTag.Class },
                { "topleveltype", PropertyTypeNode.TypeTag.Enum },
            };

            return(new TypeResolver()
                   .WithBuiltinSymbols(builtinTypes)
                   .Resolve(
                       ContainerTypeTreePath.CreateFromString(contextTypePath),
                       typeName
                       ));
        }
Example #2
0
        public void Create_WithEmptyPath()
        {
            var p = ContainerTypeTreePath.CreateFromString(string.Empty);

            Assert.AreEqual(p.FullPath, string.Empty);
        }
Example #3
0
 public string Create_WithFullPathIsIdempotent(string fullPath)
 {
     return(ContainerTypeTreePath.CreateFromString(fullPath).FullPath);
 }
Example #4
0
        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);
        }