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(); }
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(); }
public static bool IsNullable(this INamedTypeSymbol symbol) { if (symbol.IsGenericType) { if (symbol.ConstructUnboundGenericType().ToDisplayString() == "T?") { return(true); } } return(false); }
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,
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); }
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)); }
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); } }
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()); }
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); } } }
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); } }
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); } }
public static bool IsFunc(INamedTypeSymbol type) { return(type.IsGenericType && type.ConstructUnboundGenericType().Name == "Func"); }
public static bool IsAction(INamedTypeSymbol namedTypeSymbol) { return(namedTypeSymbol.IsGenericType && namedTypeSymbol.ConstructUnboundGenericType().Name == "Action"); }
internal virtual bool CanImplement(INamedTypeSymbol requestedType) => _contractFullName == requestedType.ConstructUnboundGenericType().ToDisplayString();
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(), }); }