private static string GetTypeDisplayString(INamedTypeSymbol symbol)
        {
            if (symbol.SpecialType != SpecialType.None)
            {
                var specialType = symbol.SpecialType;
                var name = Enum.GetName(typeof(SpecialType), symbol.SpecialType).Replace("_", ".");
                return name;
            }

            if (symbol.IsGenericType)
            {
                symbol = symbol.ConstructUnboundGenericType();
            }

            if (symbol.IsUnboundGenericType)
            {
                // TODO: Is this the best to get the fully metadata name?
                var parts = symbol.ToDisplayParts();
                var filteredParts = parts.Where(x => x.Kind != SymbolDisplayPartKind.Punctuation).ToArray();
                var typeName = new StringBuilder();
                foreach (var part in filteredParts.Take(filteredParts.Length - 1))
                {
                    typeName.Append(part.Symbol.Name);
                    typeName.Append(".");
                }
                typeName.Append(symbol.MetadataName);

                return typeName.ToString();
            }

            return symbol.ToDisplayString();
        }
Example #2
0
            public TypeConfig(RoslynMetadataHelper roslyn, Type contract, Type implementation, Func <INamedTypeSymbol, INamedTypeSymbol, CollectionImplementation> implementationFactory)
            {
                _contractType          = contract;
                _implementationType    = implementation;
                _implementationFactory = implementationFactory;

                _contract       = (INamedTypeSymbol)roslyn.FindTypeByFullName(contract.FullName);
                _implementation = (INamedTypeSymbol)roslyn.FindTypeByFullName(implementation.FullName);

                _contractFullName = _contract?.ConstructUnboundGenericType().ToDisplayString();
            }
Example #3
0
 public static bool IsNullable(this INamedTypeSymbol symbol)
 {
     if (symbol.IsGenericType)
     {
         if (symbol.ConstructUnboundGenericType().ToDisplayString() == "T?")
         {
             return(true);
         }
     }
     return(false);
 }
Example #4
0
        private static string GetDisplayString(INamedTypeSymbol symbol)
        {
            string implementationType;

            if (symbol.IsGenericType)
            {
                implementationType = symbol.ConstructUnboundGenericType().ToDisplayString();
            }
            else
            {
                implementationType = symbol.ToDisplayString();
            }
            return(implementationType);
        }
        private static IMethodSymbol GenerateMethodSymbol(
            INamedTypeSymbol typeToGenerateIn, INamedTypeSymbol parameterSymbol)
        {
            // Remove any generic parameters
            if (typeToGenerateIn.IsGenericType)
            {
                typeToGenerateIn = typeToGenerateIn.ConstructUnboundGenericType().ConstructedFrom;
            }

            return(CodeGenerationSymbolFactory.CreateMethodSymbol(
                       attributes: ImmutableArray <AttributeData> .Empty,
                       accessibility: default(Accessibility),
                       modifiers: default(DeclarationModifiers),
                       returnType: typeToGenerateIn,
                       returnsByRef: false,
                       explicitInterfaceImplementations: default,
Example #6
0
    public static bool IsNullableT(Compilation compilation, INamedTypeSymbol type)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        if (type.IsValueType)
        {
            if (type.IsGenericType && type.IsUnboundGenericType == false)
            {
                INamedTypeSymbol symbolNullableT = compilation.GetSpecialType(SpecialType.System_Nullable_T);

                return(symbolNullableT.ConstructUnboundGenericType().Equals(type.ConstructUnboundGenericType(), SymbolEqualityComparer.Default));
            }
        }

        return(false);
    }
Example #7
0
        private static IMethodSymbol GenerateMethodSymbol(INamedTypeSymbol typeToGenerateIn, INamedTypeSymbol parameterSymbol)
        {
            // Remove any generic parameters
            if (typeToGenerateIn.IsGenericType)
            {
                typeToGenerateIn = typeToGenerateIn.ConstructUnboundGenericType().ConstructedFrom;
            }

            return(CodeGenerationSymbolFactory.CreateMethodSymbol(
                       attributes: SpecializedCollections.EmptyList <AttributeData>(),
                       accessibility: default(Accessibility),
                       modifiers: default(DeclarationModifiers),
                       returnType: typeToGenerateIn,
                       explicitInterfaceSymbol: null,
                       name: null,
                       typeParameters: SpecializedCollections.EmptyList <ITypeParameterSymbol>(),
                       parameters: new[] { CodeGenerationSymbolFactory.CreateParameterSymbol(parameterSymbol, "v") },
                       methodKind: MethodKind.Conversion));
        }
Example #8
0
        private static bool IsIEnumerableOf(INamedTypeSymbol namedType, Predicate <ITypeSymbol> predicate)
        {
            if (!namedType.IsGenericType)
            {
                return(false);
            }

            var constructedType = namedType
                                  .ConstructUnboundGenericType()
                                  .ToDisplayString(FullyQualifiedFormat);

            if (constructedType == "global::System.Collections.Generic.IEnumerable<>")
            {
                var elementType = namedType.TypeArguments.First();
                return(predicate(elementType));
            }
            else
            {
                return(false);
            }
        }
Example #9
0
 static JToken GetDefForProp(INamedTypeSymbol type)
 {
     if (type.Name == nameof(Type))
     {
         var refType = new JObject();
         refType.Add("$ref", JToken.FromObject("#/definitions/TYPES_ENUM"));
         return(refType);
     }
     else if (IsPrimitive(type))
     {
         var propObj = new JObject();
         GeneratePrimitiveTypeConstraintWithVarSupport(propObj, type);
         return(propObj);
     }
     else if (type.IsGenericType && type.ConstructUnboundGenericType().Name.Contains("DefRef"))
     {
         return(GenerateDefForRefField(type.TypeArguments[0]));
     }
     else if (!type.IsValueType || (type.IsValueType && !IsPrimitive(type) && type.EnumUnderlyingType == null))
     {
         return(GenerateDefForClassProp(type));
     }
     else if (type.EnumUnderlyingType != null)
     {
         var refType = new JObject();
         refType.Add("type", JToken.FromObject("string"));
         var enumArray = new JArray();
         //foreach (var eName in ((EnumDeclarationSyntax)type.DeclaringSyntaxReferences.Single().GetSyntax()).Members)
         foreach (var member in type.GetMembers().Where(x => x.Kind == SymbolKind.Field))
         {
             enumArray.Add(JToken.FromObject(member.Name));
         }
         refType.Add("enum", enumArray);
         return(refType);
     }
     return(new JObject());
 }
        private void CollectGeneric(INamedTypeSymbol type)
        {
            INamedTypeSymbol genericType = type.ConstructUnboundGenericType();
            var genericTypeString        = genericType.ToDisplayString();
            var fullName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

            // special case
            if (fullName == "global::System.ArraySegment<byte>" || fullName == "global::System.ArraySegment<byte>?")
            {
                return;
            }


            // Collect substituted types for the type parameters (e.g. Bar in Foo<Bar>)
            foreach (var item in type.TypeArguments)
            {
                this.CollectCore(item);
            }

            // Collect only closed generic types (e.g. Foo<string>).
            var unboundGenericInfo = GetObjectInfo(type);

            collectedClosedTypeGenericInfo.Add(unboundGenericInfo);
        }
        public Func <string, IEnumerable <StatementSyntax> > GetStatement(IBeforeCompileContext context, INamedTypeSymbol symbol, ClassDeclarationSyntax declaration)
        {
            var attributeSymbol      = symbol.GetAttributes().Single(x => x.AttributeClass.Name.ToString().Contains("ServiceDescriptorAttribute"));
            var attributeDeclaration = declaration.AttributeLists
                                       .SelectMany(z => z.Attributes)
                                       .Single(z => z.Name.ToString().Contains("ServiceDescriptor"));

            var implementationType          = symbol.ConstructUnboundGenericType().ToDisplayString();
            var implementationQualifiedName = BuildQualifiedName(implementationType, symbol.TypeParameters.Count());

            string serviceType = null;
            IEnumerable <NameSyntax> serviceQualifiedNames = symbol.AllInterfaces
                                                             .Select(z => BuildQualifiedName(z.ConstructUnboundGenericType().ToDisplayString(), z.TypeParameters.Count()));

            if (declaration.Modifiers.Any(z => z.RawKind == (int)SyntaxKind.PublicKeyword))
            {
                // TODO:  Should this include all base types?  Should it be the lowest base type (HttpContext for example)?
                serviceQualifiedNames = serviceQualifiedNames.Union(new NameSyntax[] { implementationQualifiedName });
            }

            if (attributeSymbol.ConstructorArguments.Count() > 0 && attributeSymbol.ConstructorArguments[0].Value != null)
            {
                var serviceNameTypedSymbol = (INamedTypeSymbol)attributeSymbol.ConstructorArguments[0].Value;
                if (serviceNameTypedSymbol == null)
                {
                    throw new Exception("Could not infer service symbol");
                }
                serviceType           = serviceNameTypedSymbol.ConstructUnboundGenericType().ToString();
                serviceQualifiedNames = new NameSyntax[] { BuildQualifiedName(serviceType, serviceNameTypedSymbol.TypeParameters.Count()) };
            }


            var baseTypes = new List <string>();
            var impType   = symbol;

            while (impType != null)
            {
                baseTypes.Add(impType.ToDisplayString());
                impType = impType.BaseType;
            }

            // TODO: Enforce implementation is assignable to service
            // Diagnostic error?
            var potentialBaseTypes = baseTypes.Concat(
                symbol.AllInterfaces.Select(z => z.ConstructUnboundGenericType().ToDisplayString())
                );

            // This is where some of the power comes out.
            // We now have the ability to throw compile time errors if we believe something is wrong.
            // This could be extended to support generic types, and potentially matching compatible open generic types together to build a list.
            if (serviceType != null && !potentialBaseTypes.Any(z => serviceType.Equals(z, StringComparison.OrdinalIgnoreCase)))
            {
                var serviceName        = serviceType.Split('.').Last();
                var implementationName = implementationType.Split('.').Last();

                context.Diagnostics.Add(
                    Diagnostic.Create(
                        new DiagnosticDescriptor(
                            "DI0001",
                            "Implementation miss-match",
                            "The implementation '{0}' does not implement the service '{1}'",
                            "DependencyInjection",
                            DiagnosticSeverity.Error,
                            true
                            ),
                        Location.Create(attributeDeclaration.SyntaxTree, attributeDeclaration.Span),
                        implementationName,
                        serviceName
                        )
                    );
            }

            var hasLifecycle = attributeSymbol.NamedArguments.Any(z => z.Key == "Lifecycle");
            var lifecycle    = "Transient";

            if (hasLifecycle)
            {
                lifecycle = GetLifecycle((int)attributeSymbol.NamedArguments.Single(z => z.Key == "Lifecycle").Value.Value);
            }

            // Build the Statement
            return(GetCollectionExpressionStatement(lifecycle, serviceQualifiedNames, implementationQualifiedName));
        }
 private bool IsGenericTaskType(Compilation compilation, INamedTypeSymbol namedReturnType)
 {
     return(namedReturnType.IsGenericType && namedReturnType.ConstructUnboundGenericType().Equals(compilation.RequireType(typeof(Task <>)).ConstructUnboundGenericType()));
 }
 public INamedTypeSymbol ConstructUnboundGenericType()
 {
     return(_symbol.ConstructUnboundGenericType());
 }
Example #14
0
        private string ComputeOwnedTypeName(INamedTypeSymbol ownedType, bool noGenericArgs = false)
        {
            //Both the owned type and the DB Context type need to be generic
            //if the owned type name we reference will be generic.
            //Otherwise owned type derives as non-generic when generated
            if (!noGenericArgs && ownedType.IsGenericType && OriginalContextSymbol.IsGenericType)
            {
                return(new GenericTypeBuilder(OriginalContextSymbol.TypeParameters.ToArray()).Build($"{ClassName}_{ownedType.ConstructUnboundGenericType().Name}"));
            }

            return($"{ClassName}_{ownedType.Name}");
        }
 /// <summary>
 /// Returns an unbound generic type of this named type if it is generic, or self otherwise
 /// </summary>
 /// <param name="type">Type to be sagely unbounded</param>
 /// <returns>Type with unbounded generics or type itself if it is not generic</returns>
 private static INamedTypeSymbol SafelyConstructUnboundGenericType(this INamedTypeSymbol type)
 {
     return(type.IsGenericType ? type.ConstructUnboundGenericType() : type);
 }
        void CollectGeneric(INamedTypeSymbol type)
        {
            var genericType       = type.ConstructUnboundGenericType();
            var genericTypeString = genericType.ToDisplayString();
            var fullName          = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

            // special case
            if (fullName == "global::System.ArraySegment<byte>" || fullName == "global::System.ArraySegment<byte>?")
            {
                return;
            }

            // nullable
            if (genericTypeString == "T?")
            {
                CollectCore(type.TypeArguments[0]);

                if (!embeddedTypes.Contains(type.TypeArguments[0].ToString()))
                {
                    var info = new GenericSerializationInfo
                    {
                        FormatterName = $"global::MessagePack.Formatters.NullableFormatter<{type.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>",
                        FullName      = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    };

                    collectedGenericInfo.Add(info);
                }
                return;
            }

            // collection
            if (knownGenericTypes.TryGetValue(genericTypeString, out var formatter))
            {
                foreach (var item in type.TypeArguments)
                {
                    CollectCore(item);
                }

                var typeArgs = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                var f        = formatter.Replace("TREPLACE", typeArgs);

                var info = new GenericSerializationInfo
                {
                    FormatterName = f,
                    FullName      = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                };

                collectedGenericInfo.Add(info);

                if (genericTypeString == "System.Linq.ILookup<,>")
                {
                    formatter = knownGenericTypes["System.Linq.IGrouping<,>"];
                    f         = formatter.Replace("TREPLACE", typeArgs);

                    var groupingInfo = new GenericSerializationInfo
                    {
                        FormatterName = f,
                        FullName      = $"global::System.Linq.IGrouping<{typeArgs}>",
                    };

                    collectedGenericInfo.Add(groupingInfo);

                    formatter = knownGenericTypes["System.Collections.Generic.IEnumerable<>"];
                    typeArgs  = type.TypeArguments[1].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                    f         = formatter.Replace("TREPLACE", typeArgs);

                    var enumerableInfo = new GenericSerializationInfo
                    {
                        FormatterName = f,
                        FullName      = $"global::System.Collections.Generic.IEnumerable<{typeArgs}>",
                    };

                    collectedGenericInfo.Add(enumerableInfo);
                }
            }
        }
Example #17
0
        void CollectObjectSegment(INamedTypeSymbol type, bool fromNullable, bool asKey)
        {
            if (type == null)
            {
                return;
            }
            if (!alreadyCollected.Add(Tuple.Create(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), fromNullable, asKey)))
            {
                return;
            }
            if (KnownFormatterSpec.IsPrimitive(type))
            {
                return;
            }
            if (type.GetAttributes().FindAttributeShortName(UnionAttributeShortName) != null)
            {
                return;
            }

            if (type.GetAttributes().FindAttributeShortName(DynamicUnionAttributeShortName) != null)
            {
                return;
            }
            if (type.TypeKind == TypeKind.Enum)
            {
                CollectEnum(type, fromNullable, asKey);
                return;
            }
            if (allowCustomTypes.Contains(type.ToDisplayString()))
            {
                return;
            }

            if (disallowInMetadata && type.Locations[0].IsInMetadata)
            {
                return;
            }

            if (!IsAllowType(type))
            {
                return;
            }

            if (type.IsGenericType)
            {
                var genericType       = type.ConstructUnboundGenericType();
                var genericTypeString = genericType.ToDisplayString();

                if (genericTypeString == "T?")
                {
                    CollectObjectSegment(type.TypeArguments[0] as INamedTypeSymbol, true, asKey);
                    return;
                }
                else if (allowCustomTypes.Contains(genericTypeString))
                {
                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                    }
                    return;
                }
                else if (genericTypeString == "System.Collections.Generic.IList<>" ||
                         genericTypeString == "System.Collections.Generic.IDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.Dictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyList<>" ||
                         genericTypeString == "System.Collections.Generic.ICollection<>" ||
                         genericTypeString == "System.Collections.Generic.IEnumerable<>" ||
                         genericTypeString == "System.Collections.Generic.ISet<>" ||
                         genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>" ||
                         genericTypeString == "System.Collections.ObjectModel.ReadOnlyCollection<>" ||
                         genericTypeString == "System.Linq.ILookup<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyLookup<,>" ||
                         genericTypeString.StartsWith("System.Collections.Generic.KeyValuePair") ||
                         genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                {
                    var elementTypes    = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    var isDictionaryKey = false;

                    if (genericTypeString == "System.Collections.Generic.IList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.List, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyList, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IDictionary<,>" || genericTypeString == "System.Collections.Generic.Dictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Dictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyDictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyLookup<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyLookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Linq.ILookup<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Lookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyTuple, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.Generic.KeyValuePair"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyValuePair, ElementTypes = elementTypes
                        });
                    }

                    else if (genericTypeString.StartsWith("System.Collections.Generic.ICollection<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.InterfaceCollection, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.Generic.IEnumerable<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Enumerable, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.ObjectModel.ReadOnlyCollection<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyCollection, ElementTypes = elementTypes
                        });
                    }

                    var argIndex = 0;
                    foreach (var t in type.TypeArguments)
                    {
                        if (isDictionaryKey && argIndex == 0)
                        {
                            CollectObjectSegment(t as INamedTypeSymbol, fromNullable, true);
                        }
                        else
                        {
                            CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                        }
                        argIndex++;
                    }
                    return;
                }
                else if (type.AllInterfaces.Any(x => (x.IsGenericType ? x.ConstructUnboundGenericType().ToDisplayString() : "") == "System.Collections.Generic.ICollection<>"))
                {
                    var elementTypes = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))) + ", " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                    genericTypeContainer.Add(new GenericType {
                        TypeKind = GenericTypeKind.Collection, ElementTypes = elementTypes
                    });

                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                    }
                    return;
                }
            }

            if (type.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName) == null)
            {
                throw new Exception($"Type must be marked with ZeroFormattableAttribute. {type.Name}.  Location:{type.Locations[0]}");
            }

            if (!type.IsValueType)
            {
                if (!type.Constructors.Any(x => x.Parameters.Length == 0))
                {
                    throw new Exception($"Type must needs parameterless constructor. {type.Name}. Location:{type.Locations[0]}");
                }
            }
            else
            {
                var indexes = new List <Tuple <int, IPropertySymbol> >();
                foreach (var item in type.GetMembers().OfType <IPropertySymbol>())
                {
                    if (item.IsStatic)
                    {
                        continue;
                    }
                    if (item.ExplicitInterfaceImplementations.Length != 0)
                    {
                        continue;
                    }

                    var indexAttr = item.GetAttributes().FindAttributeShortName(IndexAttributeShortName);
                    if (indexAttr != null)
                    {
                        var index = (int)indexAttr.ConstructorArguments[0].Value;
                        indexes.Add(Tuple.Create(index, item));
                    }
                }
                indexes = indexes.OrderBy(x => x.Item1).ToList();

                var expected = 0;
                foreach (var item in indexes)
                {
                    if (item.Item1 != expected)
                    {
                        throw new Exception($"Struct index must be started with 0 and be sequential. Type: {type.Name}, InvalidIndex: {item.Item1}");
                    }
                    expected++;
                }

                var foundConstructor = false;
                var ctors            = (type as INamedTypeSymbol)?.Constructors;
                foreach (var ctor in ctors)
                {
                    var isMatch = indexes.Select(x => x.Item2.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
                                  .SequenceEqual(ctor.Parameters.Select(x => x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    if (isMatch)
                    {
                        foundConstructor = true;
                    }
                }
                if (!foundConstructor && indexes.Count != 0)
                {
                    throw new Exception($"Struct needs full parameter constructor of index property types. Type: {type.Name}");
                }
            }

            var list = new List <ObjectSegmentType.PropertyTuple>();

            var definedIndexes = new HashSet <int>();

            var distinctName = new HashSet <string>();

            foreach (var property in type.GetAllMembers())
            {
                if (!distinctName.Add(property.Name))
                {
                    continue;
                }


                if (property.IsStatic)
                {
                    continue;
                }

                var propSymbol  = property as IPropertySymbol;
                var fieldSymbol = property as IFieldSymbol;

                if ((propSymbol == null && fieldSymbol == null))
                {
                    continue;
                }

                if (property.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                if (propSymbol != null && propSymbol.ExplicitInterfaceImplementations.Length != 0)
                {
                    continue;
                }

                var attributes = property.GetAttributes();
                if (attributes.FindAttributeShortName(IgnoreAttributeShortName) != null)
                {
                    continue;
                }

                if (!type.IsValueType)
                {
                    if (!property.IsVirtual)
                    {
                        if (property.IsOverride && !property.IsSealed)
                        {
                            // okay, it is override property.
                        }
                        else
                        {
                            throw new Exception($"Public property's accessor must be virtual. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                        }
                    }
                }

                if (propSymbol != null && propSymbol.FindAttributeIncludeBasePropertyShortName(UnionKeyAttributeShortName) != null)
                {
                    continue;
                }

                var indexAttr = attributes.FindAttributeShortName(IndexAttributeShortName);
                if (indexAttr == null || indexAttr.ConstructorArguments.Length == 0)
                {
                    throw new Exception($"Public property must be marked with IndexAttribute or IgnoreFormatAttribute. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                }

                var index = indexAttr.ConstructorArguments[0];
                if (index.IsNull)
                {
                    continue; // null is normal compiler error.
                }

                if (!definedIndexes.Add((int)index.Value))
                {
                    throw new Exception($"IndexAttribute is not allow duplicate number. {type.Name}.{property.Name}, Index:{index.Value} Location:{type.Locations[0]}");
                }

                if (!type.IsValueType)
                {
                    if (propSymbol == null)
                    {
                        throw new Exception($"Class does not allow that field marks IndexAttribute. {type.Name }{property.Name}");
                    }

                    if (propSymbol.GetMethod == null || propSymbol.SetMethod == null ||
                        propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Private)
                    {
                        throw new Exception($"Public property must needs both public/protected get and set accessor. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var memberType = (propSymbol != null) ? propSymbol.Type : fieldSymbol.Type;

                if (memberType.TypeKind == TypeKind.Array)
                {
                    var array = memberType as IArrayTypeSymbol;
                    while (array != null)
                    {
                        var t = array.ElementType;
                        if (!KnownFormatterSpec.AllowArrayType(t))
                        {
                            genericTypeContainer.Add(new GenericType {
                                TypeKind = GenericTypeKind.Array, ElementTypes = t.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
                            });
                        }

                        var namedType = t as INamedTypeSymbol;
                        if (namedType != null && namedType.Kind != SymbolKind.ArrayType) // if <T> is unnamed type, it can't analyze.
                        {
                            // Recursive
                            CollectObjectSegment(namedType, fromNullable, asKey);
                            break;
                        }
                        array = t as IArrayTypeSymbol;
                    }
                }
                else
                {
                    var namedType = memberType as INamedTypeSymbol;
                    if (namedType != null) // if <T> is unnamed type, it can't analyze.
                    {
                        // Recursive
                        CollectObjectSegment(namedType, fromNullable, asKey);
                    }
                }

                var length = KnownFormatterSpec.GetLength(memberType);
                var prop   = new ObjectSegmentType.PropertyTuple
                {
                    Name           = property.Name,
                    Type           = memberType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    Index          = (int)index.Value,
                    IsGetProtected = (propSymbol != null) ? propSymbol?.GetMethod?.DeclaredAccessibility == Accessibility.Protected : false,
                    IsSetProtected = (propSymbol != null) ? propSymbol?.SetMethod?.DeclaredAccessibility == Accessibility.Protected : false,
                    FixedSize      = length ?? 0,
                    IsProperty     = propSymbol != null,
                    IsCacheSegment = !KnownFormatterSpec.IsLazySegment(memberType),
                    IsFixedSize    = (length != null)
                };

                list.Add(prop);
            }

            var segment = new ObjectSegmentType
            {
                Name       = type.ToDisplayString(typeNameFormat).Replace(".", "_"),
                FullName   = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                Namespace  = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(),
                LastIndex  = list.Select(x => x.Index).DefaultIfEmpty(0).Max(),
                Properties = list.OrderBy(x => x.Index).ToArray(),
            };

            if (type.IsValueType)
            {
                structContainer.Add(segment);
            }
            else
            {
                objectContainer.Add(segment);
            }
        }
Example #18
0
        void CollectObjectSegment(INamedTypeSymbol type)
        {
            if (type == null)
            {
                return;
            }
            if (!alreadyCollected.Add(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
            {
                return;
            }
            if (KnownFormatterSpec.IsPrimitive(type))
            {
                return;
            }
            if (type.TypeKind == TypeKind.Enum)
            {
                CollectEnum(type);
                return;
            }
            if (type.IsGenericType)
            {
                var genericType       = type.ConstructUnboundGenericType();
                var genericTypeString = genericType.ToDisplayString();

                if (genericTypeString == "T?")
                {
                    CollectObjectSegment(type.TypeArguments[0] as INamedTypeSymbol);
                    return;
                }
                else if (genericTypeString == "System.Collections.Generic.List<>")
                {
                    throw new Exception($"List does not support in ZeroFormatter because List have to deserialize all objects. You can use IList<T> instead of List. {type.Name}.");
                }
                else if (genericTypeString == "System.Collections.Generic.Dictionary<,>")
                {
                    throw new Exception($"Dictionary does not support in ZeroFormatter because Dictionary have to deserialize all objects. You can use IDictionary<TK, TV> instead of Dictionary. {type.Name}.");
                }
                else if (genericTypeString == "System.Collections.Generic.IList<>" ||
                         genericTypeString == "System.Collections.Generic.IDictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyList<>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyDictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>" ||
                         genericTypeString == "System.Linq.ILookup<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyLookup<,>" ||
                         genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                {
                    var elementTypes = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));

                    if (genericTypeString == "System.Collections.Generic.IList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.List, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyList, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Dictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyLookup<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyLookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Linq.ILookup<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Lookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyTuple, ElementTypes = elementTypes
                        });
                    }

                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol);
                    }
                    return;
                }
            }

            if (type.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName) == null)
            {
                throw new Exception($"Type must mark ZeroFormattableAttribute. {type.Name}.  Location:{type.Locations[0]}");
            }

            if (!type.IsValueType)
            {
                if (!type.Constructors.Any(x => x.Parameters.Length == 0))
                {
                    throw new Exception($"Type must needs parameterless constructor. {type.Name}. Location:{type.Locations[0]}");
                }
            }
            else
            {
                var indexes = new List <Tuple <int, IPropertySymbol> >();
                foreach (var item in type.GetMembers().OfType <IPropertySymbol>())
                {
                    var indexAttr = item.GetAttributes().FindAttributeShortName(IndexAttributeShortName);
                    if (indexAttr != null)
                    {
                        var index = (int)indexAttr.ConstructorArguments[0].Value;
                        indexes.Add(Tuple.Create(index, item));
                    }
                }
                indexes = indexes.OrderBy(x => x.Item1).ToList();

                var expected = 0;
                foreach (var item in indexes)
                {
                    if (item.Item1 != expected)
                    {
                        throw new Exception($"Struct index must be started with 0 and be sequential. Type: {type.Name}, InvalidIndex: {item.Item1}");
                    }
                    expected++;
                }

                var foundConstructor = false;
                var ctors            = (type as INamedTypeSymbol)?.Constructors;
                foreach (var ctor in ctors)
                {
                    var isMatch = indexes.Select(x => x.Item2.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
                                  .SequenceEqual(ctor.Parameters.Select(x => x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    if (isMatch)
                    {
                        foundConstructor = true;
                    }
                }
                if (!foundConstructor && indexes.Count != 0)
                {
                    throw new Exception($"Struct needs full parameter constructor of index property types. Type: {type.Name}");
                }
            }

            var list = new List <ObjectSegmentType.PropertyTuple>();

            var definedIndexes = new HashSet <int>();

            foreach (var property in type.GetAllMembers())
            {
                var propSymbol  = property as IPropertySymbol;
                var fieldSymbol = property as IFieldSymbol;

                if ((propSymbol == null && fieldSymbol == null))
                {
                    continue;
                }

                if (property.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                var attributes = property.GetAttributes();
                if (attributes.FindAttributeShortName(IgnoreAttributeShortName) != null)
                {
                    continue;
                }

                if (!type.IsValueType)
                {
                    if (!property.IsVirtual)
                    {
                        throw new Exception($"Public property's accessor must be virtual. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var indexAttr = attributes.FindAttributeShortName(IndexAttributeShortName);
                if (indexAttr == null || indexAttr.ConstructorArguments.Length == 0)
                {
                    throw new Exception($"Public property must mark IndexAttribute or IgnoreFormatAttribute. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                }

                var index = indexAttr.ConstructorArguments[0];
                if (index.IsNull)
                {
                    continue; // null is normal compiler error.
                }

                if (!definedIndexes.Add((int)index.Value))
                {
                    throw new Exception($"IndexAttribute can not allow duplicate. {type.Name}.{property.Name}, Index:{index.Value} Location:{type.Locations[0]}");
                }

                if (!type.IsValueType)
                {
                    if (propSymbol == null)
                    {
                        throw new Exception($"Class does not allow that field marks IndexAttribute. {type.Name }{property.Name}");
                    }

                    if (propSymbol.GetMethod == null || propSymbol.SetMethod == null ||
                        propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Private)
                    {
                        throw new Exception($"Public property's accessor must needs both public/protected get and set. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var memberType = (propSymbol != null) ? propSymbol.Type : fieldSymbol.Type;

                if (memberType.TypeKind == TypeKind.Array)
                {
                    var array = memberType as IArrayTypeSymbol;
                    var t     = array.ElementType;
                    if (t.SpecialType != SpecialType.System_Byte) // allows byte[]
                    {
                        throw new Exception($"Array does not support in ZeroFormatter(except byte[]) because Array have to deserialize all objects. You can use IList<T> instead of T[]. {type.Name}.{property.Name}.  Location:{type.Locations[0]}");
                    }
                }
                else
                {
                    var namedType = memberType as INamedTypeSymbol;
                    if (namedType != null) // if <T> is unnamed type, it can't analyze.
                    {
                        // Recursive
                        CollectObjectSegment(namedType);
                    }
                }

                var length = KnownFormatterSpec.GetLength(memberType);
                var prop   = new ObjectSegmentType.PropertyTuple
                {
                    Name           = property.Name,
                    Type           = memberType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    Index          = (int)index.Value,
                    IsGetProtected = (propSymbol != null) ? propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Protected : false,
                    IsSetProtected = (propSymbol != null) ? propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Protected : false,
                    FixedSize      = length ?? 0,
                    IsProperty     = propSymbol != null,
                    IsCacheSegment = KnownFormatterSpec.CanAcceptCacheSegment(memberType),
                    IsFixedSize    = (length != null)
                };

                list.Add(prop);
            }

            var segment = new ObjectSegmentType
            {
                Name       = type.Name,
                FullName   = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                Namespace  = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(),
                LastIndex  = list.Select(x => x.Index).DefaultIfEmpty(0).Max(),
                Properties = list.OrderBy(x => x.Index).ToArray(),
            };

            if (type.IsValueType)
            {
                structContainer.Add(segment);
            }
            else
            {
                objectContainer.Add(segment);
            }
        }
Example #19
0
 public static bool IsFunc(INamedTypeSymbol type)
 {
     return(type.IsGenericType && type.ConstructUnboundGenericType().Name == "Func");
 }
Example #20
0
 public static bool IsAction(INamedTypeSymbol namedTypeSymbol)
 {
     return(namedTypeSymbol.IsGenericType && namedTypeSymbol.ConstructUnboundGenericType().Name == "Action");
 }
Example #21
0
 internal virtual bool CanImplement(INamedTypeSymbol requestedType) => _contractFullName == requestedType.ConstructUnboundGenericType().ToDisplayString();
Example #22
0
        public MarshallingInfo ParseMarshallingInfo(
            ITypeSymbol managedType,
            IEnumerable <AttributeData> useSiteAttributes,
            MarshallingInfo inner)
        {
            JSTypeFlags        jsType          = JSTypeFlags.None;
            List <JSTypeFlags> jsTypeArguments = new List <JSTypeFlags>();

            foreach (AttributeData useSiteAttribute in useSiteAttributes)
            {
                INamedTypeSymbol attributeClass = useSiteAttribute.AttributeClass !;
                if (attributeClass.IsGenericType && SymbolEqualityComparer.Default.Equals(_jsMarshalAsAttribute, attributeClass.ConstructUnboundGenericType()))
                {
                    INamedTypeSymbol?jsTypeArgs = attributeClass.TypeArguments[0] as INamedTypeSymbol;
                    if (jsTypeArgs.IsGenericType)
                    {
                        string gt   = jsTypeArgs.ConstructUnboundGenericType().ToDisplayString();
                        string name = gt.Substring(gt.IndexOf("JSType") + "JSType.".Length);
                        name = name.Substring(0, name.IndexOf("<"));

                        Enum.TryParse(name, out jsType);

                        foreach (var ta in jsTypeArgs.TypeArguments.Cast <INamedTypeSymbol>().Select(x => x.ToDisplayString()))
                        {
                            string      argName   = ta.Substring(ta.IndexOf("JSType") + "JSType.".Length);
                            JSTypeFlags jsTypeArg = JSTypeFlags.None;
                            Enum.TryParse(argName, out jsTypeArg);
                            jsTypeArguments.Add(jsTypeArg);
                        }
                    }
                    else
                    {
                        string st   = jsTypeArgs.ToDisplayString();
                        string name = st.Substring(st.IndexOf("JSType") + "JSType.".Length);
                        Enum.TryParse(name, out jsType);
                    }
                }
                if (SymbolEqualityComparer.Default.Equals(_marshalUsingAttribute, attributeClass))
                {
                    return(new JSMarshallingInfo(inner)
                    {
                        JSType = JSTypeFlags.Array,
                        JSTypeArguments = Array.Empty <JSTypeFlags>(),
                    });
                }
            }

            if (jsType == JSTypeFlags.None)
            {
                return(new JSMissingMarshallingInfo());
            }

            return(new JSMarshallingInfo(inner)
            {
                JSType = jsType,
                JSTypeArguments = jsTypeArguments.ToArray(),
            });
        }