diff --git a/Schema Build Tests/attributes/sequence/ClassSequenceTests.cs b/Schema Build Tests/attributes/sequence/ClassSequenceTests.cs index f1a68ab..ced57a8 100644 --- a/Schema Build Tests/attributes/sequence/ClassSequenceTests.cs +++ b/Schema Build Tests/attributes/sequence/ClassSequenceTests.cs @@ -24,12 +24,12 @@ public override bool Equals(object other) { [BinarySchema] - public partial class StructArraySequenceWrapper : IBinaryConvertible { + public partial class ClassArraySequenceWrapper : IBinaryConvertible { [SequenceLengthSource(SchemaIntegerType.BYTE)] public SchemaClass[] Values { get; set; } public override bool Equals(object other) { - if (other is StructArraySequenceWrapper otherSequenceWrapper) { + if (other is ClassArraySequenceWrapper otherSequenceWrapper) { return this.Values.SequenceEqual(otherSequenceWrapper.Values); } @@ -39,7 +39,7 @@ public override bool Equals(object other) { [Test] public void TestWriteAndReadArrayObject() { - var expectedSw = new StructArraySequenceWrapper { + var expectedSw = new ClassArraySequenceWrapper { Values = new[] { new SchemaClass { Value = 1 }, @@ -58,13 +58,13 @@ public void TestWriteAndReadArrayObject() { var er = new SchemaBinaryReader(ms, endianness); er.Position = 0; - var actualSws = er.ReadNew(); + var actualSws = er.ReadNew(); Assert.AreEqual(expectedSw, actualSws); } [Test] public void TestWriteAndReadArrayValues() { - var expectedSw = new StructArraySequenceWrapper { + var expectedSw = new ClassArraySequenceWrapper { Values = new[] { new SchemaClass { Value = 1 }, @@ -89,13 +89,13 @@ public void TestWriteAndReadArrayValues() { [BinarySchema] - public partial class StructListSequenceWrapper : IBinaryConvertible + public partial class ClassListSequenceWrapper : IBinaryConvertible { [SequenceLengthSource(SchemaIntegerType.BYTE)] public List Values { get; set; } = new(); public override bool Equals(object other) { - if (other is StructListSequenceWrapper otherSequenceWrapper) { + if (other is ClassListSequenceWrapper otherSequenceWrapper) { return this.Values.SequenceEqual(otherSequenceWrapper.Values); } @@ -105,7 +105,7 @@ public override bool Equals(object other) { [Test] public void TestWriteAndReadListObject() { - var expectedSw = new StructListSequenceWrapper { + var expectedSw = new ClassListSequenceWrapper { Values = new List { new() { Value = 1 }, @@ -124,7 +124,7 @@ public void TestWriteAndReadListObject() { ms.Position = 0; var er = new SchemaBinaryReader(ms, endianness); - var actualSw = er.ReadNew(); + var actualSw = er.ReadNew(); Assert.AreEqual(expectedSw, actualSw); } } diff --git a/Schema/src/binary/BinarySchemaAnalyzer.cs b/Schema/src/binary/BinarySchemaAnalyzer.cs index 6d635b4..d0ff00a 100644 --- a/Schema/src/binary/BinarySchemaAnalyzer.cs +++ b/Schema/src/binary/BinarySchemaAnalyzer.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using schema.util.symbols; using schema.util.syntax; using schema.util.types; @@ -24,6 +25,7 @@ public override ImmutableArray Rules.ChildTypeCanOnlyBeContainedInParent, Rules.ChildTypeMustBeContainedInParent, Rules.ConstUninitialized, + Rules.ContainerMemberBinaryConvertabilityNeedsToSatisfyParent, Rules.ContainerTypeMustBePartial, Rules.DependentMustComeAfterSource, Rules.EnumNeedsIntegerFormat, @@ -38,7 +40,7 @@ public override ImmutableArray Rules.ReadAlreadyDefined, Rules.SchemaTypeMustBePartial, Rules.SourceMustBePrivate, - Rules.ContainerMemberBinaryConvertabilityNeedsToSatisfyParent, + Rules.SymbolException, Rules.UnexpectedAttribute, Rules.UnexpectedSequenceAttribute, Rules.UnsupportedArrayType, @@ -83,10 +85,8 @@ public void CheckType( SyntaxNodeAnalysisContext context, TypeDeclarationSyntax syntax, INamedTypeSymbol symbol) { - var typeV2 = TypeV2.FromSymbol(symbol); - try { - if (!typeV2.HasAttribute()) { + if (!symbol.HasAttribute()) { return; } diff --git a/Schema/src/binary/BinarySchemaGenerator.cs b/Schema/src/binary/BinarySchemaGenerator.cs index 9fecd7e..096b9b0 100644 --- a/Schema/src/binary/BinarySchemaGenerator.cs +++ b/Schema/src/binary/BinarySchemaGenerator.cs @@ -8,6 +8,7 @@ using schema.binary.parser; using schema.binary.text; using schema.util.generators; +using schema.util.symbols; using schema.util.syntax; using schema.util.types; @@ -70,20 +71,21 @@ public override void PreprocessCompilation(Compilation compilation) { public override IEnumerable<(string fileName, string source)> GenerateSourcesForMappedNamedType(IBinarySchemaContainer container) { - var containerTypeV2 = TypeV2.FromSymbol(container.TypeSymbol); - if (containerTypeV2.Implements() && - container.TypeSymbol.MemberNames.All(member => member != "Read")) { + var containerSymbol = container.TypeSymbol; + if (containerSymbol.Implements() && + containerSymbol.MemberNames.All(member => member != "Read")) { var readerCode = this.readerImpl_.Generate(container); - yield return ($"{containerTypeV2.FullyQualifiedName}_{containerTypeV2.Arity}_reader.g", - readerCode); + yield return ( + $"{containerSymbol.GetUniqueNameForGenerator()}_reader.g", + readerCode); } - if (containerTypeV2.Implements() && - container.TypeSymbol.MemberNames.All( - member => member != "Write")) { + if (containerSymbol.Implements() && + containerSymbol.MemberNames.All(member => member != "Write")) { var writerCode = this.writerImpl_.Generate(container); - yield return ($"{containerTypeV2.FullyQualifiedName}_{containerTypeV2.Arity}_writer.g", - writerCode); + yield return ( + $"{containerSymbol.GetUniqueNameForGenerator()}_writer.g", + writerCode); } } } diff --git a/Schema/src/binary/BinarySchemaStructureParser.cs b/Schema/src/binary/BinarySchemaStructureParser.cs index 8992b74..a8044c4 100644 --- a/Schema/src/binary/BinarySchemaStructureParser.cs +++ b/Schema/src/binary/BinarySchemaStructureParser.cs @@ -156,28 +156,25 @@ public class BinarySchemaContainerParser : IBinarySchemaContainerParser { public IBinarySchemaContainer ParseContainer( INamedTypeSymbol containerSymbol) { var containerBetterSymbol = BetterSymbol.FromType(containerSymbol); - var containerTypeV2 = - TypeV2.FromSymbol(containerBetterSymbol.TypedSymbol, - containerBetterSymbol); // All of the types that contain the container need to be partial new PartialContainerAsserter(containerBetterSymbol) .AssertContainersArePartial(containerSymbol); - if (containerTypeV2.IsChild(out var parentTypeV2)) { - if (!parentTypeV2.ContainsMemberWithType(containerTypeV2)) { + if (containerSymbol.IsChild(out var parentSymbol)) { + if (!parentSymbol.ContainsMemberWithType(containerSymbol)) { containerBetterSymbol.ReportDiagnostic( Rules.ChildTypeMustBeContainedInParent); } - if (!parentTypeV2.IsAtLeastAsBinaryConvertibleAs(containerTypeV2)) { + if (!parentSymbol.IsAtLeastAsBinaryConvertibleAs(containerSymbol)) { containerBetterSymbol.ReportDiagnostic( Rules.ParentBinaryConvertabilityMustSatisfyChild); } } var localPositions = - containerTypeV2.HasAttribute(); + containerSymbol.HasAttribute(); var containerEndianness = new EndiannessParser().GetEndianness(containerBetterSymbol); @@ -225,7 +222,7 @@ public IBinarySchemaContainer ParseContainer( bool isSkipped = memberBetterSymbol.HasAttribute() || (memberSymbol.Name == nameof(IChildOf.Parent) && - parentTypeV2 != null); + parentSymbol != null); // Skips parent field for child types diff --git a/Schema/src/binary/BinarySchemaSymbolUtil.cs b/Schema/src/binary/BinarySchemaSymbolUtil.cs index 63950b8..f1253a8 100644 --- a/Schema/src/binary/BinarySchemaSymbolUtil.cs +++ b/Schema/src/binary/BinarySchemaSymbolUtil.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis; using schema.binary.attributes; +using schema.util.asserts; using schema.util.symbols; using schema.util.types; @@ -22,9 +23,11 @@ public static bool IsBinarySerializable(this ISymbol symbol) public static bool IsBinaryDeserializable(this ISymbol symbol) => symbol.Implements(); - public static bool IsChild(this ISymbol symbol, out ISymbol parent) { + public static bool + IsChild(this ISymbol symbol, out INamedTypeSymbol parent) { if (symbol.Implements(typeof(IChildOf<>), out var matchingType)) { - parent = matchingType.TypeArguments.First(); + parent = Asserts.AsA( + matchingType.TypeArguments.First()); return true; } diff --git a/Schema/src/binary/rules/Rules.cs b/Schema/src/binary/rules/Rules.cs index 88d7932..0f4f47a 100644 --- a/Schema/src/binary/rules/Rules.cs +++ b/Schema/src/binary/rules/Rules.cs @@ -1,5 +1,6 @@ using System; using System.Linq; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -39,10 +40,11 @@ public static readonly DiagnosticDescriptor ChildTypeMustBeContainedInParent "Child type must be contained in parent", "Type '{0}' is defined as a child, but is not actually contained in its parent type."); - public static readonly DiagnosticDescriptor ParentBinaryConvertabilityMustSatisfyChild - = Rules.CreateDiagnosticDescriptor_( - "Parent's binary convertability must satisfy child's", - "Type '{0}' is defined as a child, but its binary convertability is not satisfied by its parent's. The parent must at least implement the same binary serializable/deserializable interface as the child."); + public static readonly DiagnosticDescriptor + ParentBinaryConvertabilityMustSatisfyChild + = Rules.CreateDiagnosticDescriptor_( + "Parent's binary convertability must satisfy child's", + "Type '{0}' is defined as a child, but its binary convertability is not satisfied by its parent's. The parent must at least implement the same binary serializable/deserializable interface as the child."); public static readonly DiagnosticDescriptor @@ -130,6 +132,11 @@ public static readonly DiagnosticDescriptor UnsupportedArrayType "Array type '{0}' is not currently supported."); public static DiagnosticDescriptor Exception { get; } + = Rules.CreateDiagnosticDescriptor_( + "Exception", + "Ran into an exception while generating source ({0}),{1}"); + + public static DiagnosticDescriptor SymbolException { get; } = Rules.CreateDiagnosticDescriptor_( "Exception", "Ran into an exception while parsing ({0}),{1}"); @@ -154,11 +161,20 @@ public static Diagnostic CreateExceptionDiagnostic( ISymbol symbol, Exception exception) => Diagnostic.Create( - Rules.Exception, + Rules.SymbolException, symbol.Locations.First(), exception.Message, exception.StackTrace.Replace("\r\n", "").Replace("\n", "")); + public static Diagnostic CreateExceptionDiagnostic( + Exception exception) + => Diagnostic.Create( + Rules.Exception, + null, + exception.Message, + exception.StackTrace.Replace("\r\n", "").Replace("\n", "")); + + public static void ReportExceptionDiagnostic( SyntaxNodeAnalysisContext? context, ISymbol symbol, diff --git a/Schema/src/readOnly/ReadOnlyTypeGenerator.cs b/Schema/src/readOnly/ReadOnlyTypeGenerator.cs index 1f07a49..514ad2f 100644 --- a/Schema/src/readOnly/ReadOnlyTypeGenerator.cs +++ b/Schema/src/readOnly/ReadOnlyTypeGenerator.cs @@ -41,8 +41,7 @@ internal override bool FilterNamedTypesBeforeGenerating( GenerateSourcesForNamedType(INamedTypeSymbol symbol, SemanticModel semanticModel, TypeDeclarationSyntax syntax) { - var typeV2 = TypeV2.FromSymbol(symbol); - yield return ($"{typeV2.FullyQualifiedName}_{typeV2.Arity}_readOnly.g", + yield return ($"{symbol.GetUniqueNameForGenerator()}_readOnly.g", this.GenerateSourceForNamedType( symbol, semanticModel, diff --git a/Schema/src/util/AccessChainUtil.cs b/Schema/src/util/AccessChainUtil.cs index 073e6dd..2ab8725 100644 --- a/Schema/src/util/AccessChainUtil.cs +++ b/Schema/src/util/AccessChainUtil.cs @@ -180,9 +180,8 @@ string prevMemberName IsOrderValid = comesAfter, }); - var containerTypeV2 = TypeV2.FromSymbol(containerSymbol); if (currentMemberName == nameof(IChildOf.Parent) && - containerTypeV2.IsChild(out _)) { + containerSymbol.IsChild(out _)) { upDownStack.PushUpFrom(prevMemberName); } else { upDownStack.PushDownTo(currentMemberName); diff --git a/Schema/src/util/diagnostics/DiagnosticReporter.cs b/Schema/src/util/diagnostics/DiagnosticReporter.cs index 79f23ea..a4996ed 100644 --- a/Schema/src/util/diagnostics/DiagnosticReporter.cs +++ b/Schema/src/util/diagnostics/DiagnosticReporter.cs @@ -56,7 +56,7 @@ public void ReportDiagnostic(ISymbol symbol, public void ReportException(Exception exception) => this.ReportDiagnosticImpl_( - Diagnostic.Create(Rules.Exception, + Diagnostic.Create(Rules.SymbolException, this.symbol_.Locations.First(), exception.Message, exception.StackTrace.Replace("\r\n", "") diff --git a/Schema/src/util/enumerables/EnumerableExtensions.cs b/Schema/src/util/enumerables/EnumerableExtensions.cs index dc098f0..ec0e327 100644 --- a/Schema/src/util/enumerables/EnumerableExtensions.cs +++ b/Schema/src/util/enumerables/EnumerableExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace schema.util.enumerables { public static class EnumerableExtensions { @@ -6,6 +7,12 @@ public static IEnumerable Yield(this T value) { yield return value; } + public static IEnumerable WhereNonnull( + this IEnumerable enumerable) + => enumerable.Select(v => (v != null, v)) + .Where(pair => pair.Item1) + .Select(pair => pair.v!); + public static IEnumerable Resized( this IEnumerable? enumerable, int length) where T : new() { diff --git a/Schema/src/util/generators/BMappedNamedTypesWithAttributeGenerator.cs b/Schema/src/util/generators/BMappedNamedTypesWithAttributeGenerator.cs index a65f3da..d6e10d2 100644 --- a/Schema/src/util/generators/BMappedNamedTypesWithAttributeGenerator.cs +++ b/Schema/src/util/generators/BMappedNamedTypesWithAttributeGenerator.cs @@ -29,8 +29,12 @@ public abstract void PreprocessCompilation( public void Initialize(IncrementalGeneratorInitializationContext context) { context.RegisterImplementationSourceOutput( context.CompilationProvider, - (_, compilation) => { - PreprocessCompilation(compilation); + (context, compilation) => { + try { + this.PreprocessCompilation(compilation); + } catch (Exception e) { + context.ReportDiagnostic(Rules.CreateExceptionDiagnostic(e)); + } }); var syntaxAndSymbolProvider diff --git a/Schema/src/util/symbols/FileName.cs b/Schema/src/util/symbols/FileName.cs new file mode 100644 index 0000000..4b2e708 --- /dev/null +++ b/Schema/src/util/symbols/FileName.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +using Microsoft.CodeAnalysis; + +namespace schema.util.symbols { + public static class NamespaceExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsInSameNamespaceAs(this ISymbol symbol) + => symbol.IsInSameNamespaceAs(typeof(T)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsInSameNamespaceAs(this ISymbol symbol, Type other) + => symbol.IsInNamespace(other.Namespace); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsInNamespace(this ISymbol symbol, + string fullNamespacePath) { + var fullNamespacePathLength = fullNamespacePath.Length; + + var currentNamespace = symbol.ContainingNamespace; + var currentNamespaceName = currentNamespace.Name; + var currentNamespaceNameLength = currentNamespaceName.Length; + + if (fullNamespacePathLength == 0 && currentNamespaceNameLength == 0) { + return true; + } + + var fullNamespaceI = fullNamespacePathLength - 1; + var currentNamespaceI = currentNamespaceNameLength - 1; + + for (; fullNamespaceI >= 0; --fullNamespaceI, --currentNamespaceI) { + if (currentNamespaceI == -1) { + if (fullNamespacePath[fullNamespaceI] != '.') { + return false; + } + + --fullNamespaceI; + currentNamespace = currentNamespace.ContainingNamespace; + currentNamespaceName = currentNamespace.Name; + currentNamespaceNameLength = currentNamespaceName.Length; + if (currentNamespaceNameLength == 0) { + return false; + } + + currentNamespaceI = currentNamespaceNameLength - 1; + } + + if (fullNamespacePath[fullNamespaceI] != + currentNamespaceName[currentNamespaceI]) { + return false; + } + } + + return fullNamespaceI == -1 && + currentNamespaceI == -1 && + currentNamespace.ContainingNamespace.Name.Length == 0; + } + + public static string? GetFullyQualifiedNamespace(this ISymbol symbol) { + var containingNamespaces = symbol.GetContainingNamespaces().ToArray(); + if (containingNamespaces.Length == 0) { + return null; + } + + return string.Join(".", containingNamespaces); + } + + public static IEnumerable GetContainingNamespaces( + this ISymbol symbol) + => symbol.GetContainingNamespacesReversed_().Reverse(); + + private static IEnumerable GetContainingNamespacesReversed_( + this ISymbol symbol) { + var namespaceSymbol = symbol.ContainingNamespace; + if (namespaceSymbol?.IsGlobalNamespace ?? true) { + yield break; + } + + while (!namespaceSymbol?.IsGlobalNamespace ?? true) { + if (namespaceSymbol.Name.Length > 0) { + yield return namespaceSymbol.Name.EscapeKeyword(); + } + + namespaceSymbol = namespaceSymbol.ContainingNamespace; + } + } + } +} diff --git a/Schema/src/util/symbols/IsExtensions.cs b/Schema/src/util/symbols/IsExtensions.cs new file mode 100644 index 0000000..6acf6c9 --- /dev/null +++ b/Schema/src/util/symbols/IsExtensions.cs @@ -0,0 +1,182 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +using Microsoft.CodeAnalysis; + +using schema.binary; +using schema.util.sequences; + +namespace schema.util.symbols { + public static class IsExtensions { + public static bool IsEnum(this ISymbol symbol, + out SchemaIntegerType underlyingType) { + var underlyingSymbol = (symbol as INamedTypeSymbol)?.EnumUnderlyingType; + if (underlyingSymbol == null) { + underlyingType = default; + return false; + } + + var returnStatus = underlyingSymbol.IsPrimitive(out var primitiveType) && + primitiveType != SchemaPrimitiveType.UNDEFINED; + underlyingType = primitiveType.AsIntegerType(); + return returnStatus; + } + + public static bool IsPrimitive(this ISymbol symbol, + out SchemaPrimitiveType primitiveType) { + var typeSymbol = symbol as ITypeSymbol; + + if (typeSymbol?.TypeKind == TypeKind.Enum) { + primitiveType = SchemaPrimitiveType.ENUM; + return true; + } + + primitiveType = typeSymbol?.SpecialType switch { + SpecialType.System_Boolean => SchemaPrimitiveType.BOOLEAN, + SpecialType.System_Char => SchemaPrimitiveType.CHAR, + SpecialType.System_SByte => SchemaPrimitiveType.SBYTE, + SpecialType.System_Byte => SchemaPrimitiveType.BYTE, + SpecialType.System_Int16 => SchemaPrimitiveType.INT16, + SpecialType.System_UInt16 => SchemaPrimitiveType.UINT16, + SpecialType.System_Int32 => SchemaPrimitiveType.INT32, + SpecialType.System_UInt32 => SchemaPrimitiveType.UINT32, + SpecialType.System_Int64 => SchemaPrimitiveType.INT64, + SpecialType.System_UInt64 => SchemaPrimitiveType.UINT64, + SpecialType.System_Single => SchemaPrimitiveType.SINGLE, + SpecialType.System_Double => SchemaPrimitiveType.DOUBLE, + _ => SchemaPrimitiveType.UNDEFINED + }; + return primitiveType != SchemaPrimitiveType.UNDEFINED; + } + + public static bool IsClass(this ISymbol symbol) + => symbol is INamedTypeSymbol { TypeKind: TypeKind.Class }; + + public static bool IsAbstractClass(this ISymbol symbol) + => symbol is INamedTypeSymbol { + IsAbstract: true, TypeKind: TypeKind.Class + }; + + public static bool IsInterface(this ISymbol symbol) + => symbol is INamedTypeSymbol { TypeKind: TypeKind.Interface }; + + public static bool IsStruct(this ISymbol symbol) + => symbol is INamedTypeSymbol { TypeKind: TypeKind.Struct }; + + public static bool IsString(this ISymbol symbol) + => symbol is ITypeSymbol { SpecialType: SpecialType.System_String }; + + public static bool IsGenericZipped(this ISymbol symbol, + out IEnumerable<(ITypeParameterSymbol, + ITypeSymbol)> typeParamsAndArgs) { + if (symbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol) { + typeParamsAndArgs = namedTypeSymbol.GetTypeParamsAndArgs(); + return true; + } + + typeParamsAndArgs = default; + return false; + } + + public static bool IsGeneric( + this ISymbol symbol, + out ImmutableArray typeParameterSymbols, + out ImmutableArray typeArgumentSymbols) { + if (symbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol) { + typeParameterSymbols = namedTypeSymbol.TypeParameters; + typeArgumentSymbols = namedTypeSymbol.TypeArguments; + return true; + } + + typeParameterSymbols = default; + typeArgumentSymbols = default; + return false; + } + + public static bool IsGenericTypeParameter( + this ISymbol symbol, + out ITypeParameterSymbol typeParameterSymbol) { + if (symbol is not ITypeParameterSymbol tps) { + typeParameterSymbol = default; + return false; + } + + typeParameterSymbol = tps; + return true; + } + + public static bool IsArray(this ISymbol symbol, + out ITypeSymbol elementType) { + var arrayTypeSymbol = symbol as IArrayTypeSymbol; + elementType = arrayTypeSymbol != null + ? arrayTypeSymbol.ElementType + : default; + return arrayTypeSymbol != null; + } + + public static bool IsTuple(this ISymbol symbol, + out IEnumerable tupleParameters) { + if (symbol is INamedTypeSymbol { IsTupleType: true } namedTypeSymbol) { + tupleParameters = namedTypeSymbol.TupleElements; + return true; + } + + tupleParameters = default; + return false; + } + + public static bool IsSequence(this ISymbol symbol, + out ITypeSymbol elementType, + out SequenceType sequenceType) { + if (symbol.IsArray(out elementType)) { + sequenceType = SequenceType.MUTABLE_ARRAY; + return true; + } + + if (symbol.Implements(typeof(ImmutableArray<>), + out var immutableArrayTypeV2)) { + elementType = immutableArrayTypeV2.TypeArguments.ToArray()[0]; + sequenceType = SequenceType.IMMUTABLE_ARRAY; + return true; + } + + if (symbol.Implements(typeof(ISequence<,>), out var sequenceTypeV2)) { + elementType = sequenceTypeV2.TypeArguments.ToArray()[1]; + sequenceType = SequenceType.MUTABLE_SEQUENCE; + return true; + } + + if (symbol.Implements(typeof(IConstLengthSequence<,>), + out var constLengthSequenceTypeV2)) { + elementType = constLengthSequenceTypeV2.TypeArguments.ToArray()[1]; + sequenceType = SequenceType.MUTABLE_SEQUENCE; + return true; + } + + if (symbol.Implements(typeof(IReadOnlySequence<,>), + out var readOnlySequence)) { + elementType = readOnlySequence.TypeArguments.ToArray()[1]; + sequenceType = SequenceType.READ_ONLY_SEQUENCE; + return true; + } + + if (symbol.Implements(typeof(List<>), out var listTypeV2)) { + elementType = listTypeV2.TypeArguments.ToArray()[0]; + sequenceType = SequenceType.MUTABLE_LIST; + return true; + } + + if (symbol.Implements(typeof(IReadOnlyList<>), + out var readonlyListTypeV2)) { + elementType = readonlyListTypeV2.TypeArguments.ToArray()[0]; + sequenceType = SequenceType.READ_ONLY_LIST; + return true; + } + + elementType = default; + sequenceType = default; + return false; + } + } +} \ No newline at end of file diff --git a/Schema/src/util/symbols/ParentExtensions.cs b/Schema/src/util/symbols/ParentExtensions.cs new file mode 100644 index 0000000..1163f51 --- /dev/null +++ b/Schema/src/util/symbols/ParentExtensions.cs @@ -0,0 +1,30 @@ +using Microsoft.CodeAnalysis; + +using System.Linq; + +using schema.util.enumerables; + +namespace schema.util.symbols { + public static class ParentExtensions { + public static bool ContainsMemberWithType(this INamedTypeSymbol symbol, + ISymbol other) + => symbol.GetMembers() + .Select(member => { + switch (member) { + case IFieldSymbol fieldSymbol: + return fieldSymbol.Type; + case IPropertySymbol propertySymbol: + return propertySymbol.Type; + default: return null; + } + }) + .Distinct(SymbolEqualityComparer.Default) + .WhereNonnull() + .Select( + memberSymbol + => memberSymbol.IsSequence(out var elementTypeV2, out _) + ? elementTypeV2 + : memberSymbol) + .Any(other.IsSameAs); + } +} \ No newline at end of file diff --git a/Schema/src/util/symbols/SymbolUtil.cs b/Schema/src/util/symbols/SymbolUtil.cs index 4db6e8d..77b6ae0 100644 --- a/Schema/src/util/symbols/SymbolUtil.cs +++ b/Schema/src/util/symbols/SymbolUtil.cs @@ -1,271 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.CompilerServices; +using System.Text; using Microsoft.CodeAnalysis; -using schema.binary; -using schema.util.sequences; - namespace schema.util.symbols { public static class SymbolUtil { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsInSameNamespaceAs(this ISymbol symbol) - => symbol.IsInSameNamespaceAs(typeof(T)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsInSameNamespaceAs(this ISymbol symbol, Type other) - => symbol.IsInNamespace(other.Namespace); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsInNamespace(this ISymbol symbol, - string fullNamespacePath) { - var fullNamespacePathLength = fullNamespacePath.Length; - - var currentNamespace = symbol.ContainingNamespace; - var currentNamespaceName = currentNamespace.Name; - var currentNamespaceNameLength = currentNamespaceName.Length; - - if (fullNamespacePathLength == 0 && currentNamespaceNameLength == 0) { - return true; - } - - var fullNamespaceI = fullNamespacePathLength - 1; - var currentNamespaceI = currentNamespaceNameLength - 1; - - for (; fullNamespaceI >= 0; --fullNamespaceI, --currentNamespaceI) { - if (currentNamespaceI == -1) { - if (fullNamespacePath[fullNamespaceI] != '.') { - return false; - } - - --fullNamespaceI; - currentNamespace = currentNamespace.ContainingNamespace; - currentNamespaceName = currentNamespace.Name; - currentNamespaceNameLength = currentNamespaceName.Length; - if (currentNamespaceNameLength == 0) { - return false; - } - - currentNamespaceI = currentNamespaceNameLength - 1; - } - - if (fullNamespacePath[fullNamespaceI] != - currentNamespaceName[currentNamespaceI]) { - return false; - } - } - - return fullNamespaceI == -1 && - currentNamespaceI == -1 && - currentNamespace.ContainingNamespace.Name.Length == 0; - } - - - public static string? GetFullyQualifiedNamespace(this ISymbol symbol) { - var containingNamespaces = symbol.GetContainingNamespaces().ToArray(); - if (containingNamespaces.Length == 0) { - return null; - } + public static string GetUniqueNameForGenerator(this ISymbol symbol) { + var sb = new StringBuilder(); - return string.Join(".", containingNamespaces); - } - - public static IEnumerable GetContainingNamespaces( - this ISymbol symbol) - => symbol.GetContainingNamespacesReversed_().Reverse(); - - private static IEnumerable GetContainingNamespacesReversed_( - this ISymbol symbol) { - var namespaceSymbol = symbol.ContainingNamespace; - if (namespaceSymbol?.IsGlobalNamespace ?? true) { - yield break; + var fullyQualifiedNamespace = symbol.GetFullyQualifiedNamespace(); + if (fullyQualifiedNamespace != null) { + sb.Append(fullyQualifiedNamespace) + .Append("."); } - while (!namespaceSymbol?.IsGlobalNamespace ?? true) { - if (namespaceSymbol.Name.Length > 0) { - yield return namespaceSymbol.Name.EscapeKeyword(); - } - - namespaceSymbol = namespaceSymbol.ContainingNamespace; + var declaringTypes = symbol.GetDeclaringTypesDownward(); + foreach (var declaringType in declaringTypes) { + sb.Append(declaringType.Name) + .Append('.'); } - } - public static bool IsEnum(this ISymbol symbol, - out SchemaIntegerType underlyingType) { - var underlyingSymbol = (symbol as INamedTypeSymbol)?.EnumUnderlyingType; - if (underlyingSymbol == null) { - underlyingType = default; - return false; - } + sb.Append(symbol.Name) + .Append("_") + .Append(symbol.GetArity()); - var returnStatus = underlyingSymbol.IsPrimitive(out var primitiveType) && - primitiveType != SchemaPrimitiveType.UNDEFINED; - underlyingType = primitiveType.AsIntegerType(); - return returnStatus; - } - - public static bool IsPrimitive(this ISymbol symbol, - out SchemaPrimitiveType primitiveType) { - var typeSymbol = symbol as ITypeSymbol; - - if (typeSymbol?.TypeKind == TypeKind.Enum) { - primitiveType = SchemaPrimitiveType.ENUM; - return true; - } - - primitiveType = typeSymbol?.SpecialType switch { - SpecialType.System_Boolean => SchemaPrimitiveType.BOOLEAN, - SpecialType.System_Char => SchemaPrimitiveType.CHAR, - SpecialType.System_SByte => SchemaPrimitiveType.SBYTE, - SpecialType.System_Byte => SchemaPrimitiveType.BYTE, - SpecialType.System_Int16 => SchemaPrimitiveType.INT16, - SpecialType.System_UInt16 => SchemaPrimitiveType.UINT16, - SpecialType.System_Int32 => SchemaPrimitiveType.INT32, - SpecialType.System_UInt32 => SchemaPrimitiveType.UINT32, - SpecialType.System_Int64 => SchemaPrimitiveType.INT64, - SpecialType.System_UInt64 => SchemaPrimitiveType.UINT64, - SpecialType.System_Single => SchemaPrimitiveType.SINGLE, - SpecialType.System_Double => SchemaPrimitiveType.DOUBLE, - _ => SchemaPrimitiveType.UNDEFINED - }; - return primitiveType != SchemaPrimitiveType.UNDEFINED; + return sb.ToString(); } public static int GetArity(this ISymbol symbol) => (symbol as INamedTypeSymbol)?.TypeArguments.Length ?? 0; - public static bool IsClass(this ISymbol symbol) - => symbol is INamedTypeSymbol { TypeKind: TypeKind.Class }; - - public static bool IsAbstractClass(this ISymbol symbol) - => symbol is INamedTypeSymbol { - IsAbstract: true, TypeKind: TypeKind.Class - }; - - public static bool IsInterface(this ISymbol symbol) - => symbol is INamedTypeSymbol { TypeKind: TypeKind.Interface }; - - public static bool IsStruct(this ISymbol symbol) - => symbol is INamedTypeSymbol { TypeKind: TypeKind.Struct }; - - public static bool IsString(this ISymbol symbol) - => symbol is ITypeSymbol { SpecialType: SpecialType.System_String }; - - public static bool IsGenericZipped(this ISymbol symbol, - out IEnumerable<(ITypeParameterSymbol, - ITypeSymbol)> typeParamsAndArgs) { - if (symbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol) { - typeParamsAndArgs = namedTypeSymbol.GetTypeParamsAndArgs(); - return true; - } - - typeParamsAndArgs = default; - return false; - } - - public static bool IsGeneric( - this ISymbol symbol, - out ImmutableArray typeParameterSymbols, - out ImmutableArray typeArgumentSymbols) { - if (symbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol) { - typeParameterSymbols = namedTypeSymbol.TypeParameters; - typeArgumentSymbols = namedTypeSymbol.TypeArguments; - return true; - } - - typeParameterSymbols = default; - typeArgumentSymbols = default; - return false; - } - - public static bool IsGenericTypeParameter( - this ISymbol symbol, - out ITypeParameterSymbol typeParameterSymbol) { - if (symbol is not ITypeParameterSymbol tps) { - typeParameterSymbol = default; - return false; - } - - typeParameterSymbol = tps; - return true; - } - - public static bool IsArray(this ISymbol symbol, - out ITypeSymbol elementType) { - var arrayTypeSymbol = symbol as IArrayTypeSymbol; - elementType = arrayTypeSymbol != null - ? arrayTypeSymbol.ElementType - : default; - return arrayTypeSymbol != null; - } - - public static bool IsTuple(this ISymbol symbol, - out IEnumerable tupleParameters) { - if (symbol is INamedTypeSymbol { IsTupleType: true } namedTypeSymbol) { - tupleParameters = namedTypeSymbol.TupleElements; - return true; - } - - tupleParameters = default; - return false; - } - - public static bool IsSequence(this ISymbol symbol, - out ITypeSymbol elementType, - out SequenceType sequenceType) { - if (symbol.IsArray(out elementType)) { - sequenceType = SequenceType.MUTABLE_ARRAY; - return true; - } - - if (symbol.Implements(typeof(ImmutableArray<>), - out var immutableArrayTypeV2)) { - elementType = immutableArrayTypeV2.TypeArguments.ToArray()[0]; - sequenceType = SequenceType.IMMUTABLE_ARRAY; - return true; - } - - if (symbol.Implements(typeof(ISequence<,>), out var sequenceTypeV2)) { - elementType = sequenceTypeV2.TypeArguments.ToArray()[1]; - sequenceType = SequenceType.MUTABLE_SEQUENCE; - return true; - } - - if (symbol.Implements(typeof(IConstLengthSequence<,>), - out var constLengthSequenceTypeV2)) { - elementType = constLengthSequenceTypeV2.TypeArguments.ToArray()[1]; - sequenceType = SequenceType.MUTABLE_SEQUENCE; - return true; - } - - if (symbol.Implements(typeof(IReadOnlySequence<,>), - out var readOnlySequence)) { - elementType = readOnlySequence.TypeArguments.ToArray()[1]; - sequenceType = SequenceType.READ_ONLY_SEQUENCE; - return true; - } - - if (symbol.Implements(typeof(List<>), out var listTypeV2)) { - elementType = listTypeV2.TypeArguments.ToArray()[0]; - sequenceType = SequenceType.MUTABLE_LIST; - return true; - } - - if (symbol.Implements(typeof(IReadOnlyList<>), - out var readonlyListTypeV2)) { - elementType = readonlyListTypeV2.TypeArguments.ToArray()[0]; - sequenceType = SequenceType.READ_ONLY_LIST; - return true; - } - - elementType = default; - sequenceType = default; - return false; - } - public static bool Exists(this ISymbol symbol) => symbol.Locations.Length > 1; } diff --git a/Schema/src/util/types/BSymbolTypeV2.cs b/Schema/src/util/types/BSymbolTypeV2.cs deleted file mode 100644 index ac8e6ab..0000000 --- a/Schema/src/util/types/BSymbolTypeV2.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -using Microsoft.CodeAnalysis; - -using schema.binary; -using schema.binary.attributes; -using schema.util.sequences; -using schema.util.symbols; - -namespace schema.util.types { - public static partial class TypeV2 { - private abstract class BSymbolTypeV2 : ITypeV2 { - public abstract string Name { get; } - public abstract bool Exists { get; } - - public abstract string? FullyQualifiedNamespace { get; } - public abstract IEnumerable NamespaceParts { get; } - public abstract IEnumerable DeclaringTypeNamesDownward { get; } - - public abstract bool Implements(Type type, out ITypeV2 matchingType); - - public abstract int Arity { get; } - - public virtual bool HasNullableAnnotation => false; - public abstract bool IsClass { get; } - public abstract bool IsAbstractClass { get; } - public abstract bool IsInterface { get; } - public abstract bool IsStruct { get; } - public abstract bool IsString { get; } - public abstract bool IsArray(out ITypeV2 elementType); - public abstract bool IsPrimitive(out SchemaPrimitiveType primitiveType); - public abstract bool IsEnum(out SchemaIntegerType underlyingType); - - public abstract bool HasGenericArguments( - out IEnumerable genericArguments); - - public abstract bool IsGenericTypeParameter( - out IEnumerable genericConstraints); - - public abstract IEnumerable<(string, ITypeV2)> GetTupleElements(); - - - public abstract bool ContainsMemberWithType(ITypeV2 other); - - public abstract bool HasAttribute() - where TAttribute : Attribute; - - public abstract TAttribute GetAttribute() - where TAttribute : Attribute; - - public abstract IEnumerable GetAttributes() - where TAttribute : Attribute; - - - // Common - public string FullyQualifiedName { - get { - var namespacePortion = this.FullyQualifiedNamespace ?? ""; - if (namespacePortion.Length > 0) { - namespacePortion += "."; - } - - var declaringTypesPortion = ""; - var declaringTypes = this.DeclaringTypeNamesDownward.ToArray(); - if (declaringTypes.Length > 0) { - declaringTypesPortion = $"{string.Join(".", declaringTypes)}."; - } - - var name = this.Name; - - return $"{namespacePortion}{declaringTypesPortion}{name}"; - } - } - - private bool Matches_(string name, - string? fullyQualifiedNamespace, - int genericArgCount) - => this.Name == name && - this.FullyQualifiedNamespace == fullyQualifiedNamespace && - this.Arity == genericArgCount; - - public bool IsExactly(ITypeV2 other) => this.Matches_( - other.Name, - other.FullyQualifiedNamespace, - other.Arity); - - public bool IsExactly(Type other) { - var expectedName = other.Name; - - int expectedArity = 0; - var indexOfBacktick = expectedName.IndexOf('`'); - if (indexOfBacktick != -1) { - expectedArity = - int.Parse(expectedName.Substring(indexOfBacktick + 1)); - expectedName = expectedName.Substring(0, indexOfBacktick); - } - - return this.Matches_( - expectedName, - other.Namespace, - expectedArity); - } - - public bool IsExactly(ISymbol other) => this.Matches_( - other.Name, - other.GetFullyQualifiedNamespace(), - (other as INamedTypeSymbol)?.TypeParameters.Length ?? 0); - - public bool IsExactly() => this.IsExactly(typeof(T)); - - public bool Implements() => this.Implements(typeof(T)); - - public bool Implements(out ITypeV2 matchingType) - => this.Implements(typeof(T), out matchingType); - - public bool Implements(Type type) => this.Implements(type, out _); - - public bool IsAtLeastAsBinaryConvertibleAs(ITypeV2 other) - => (!other.IsBinaryDeserializable || this.IsBinaryDeserializable) && - (!other.IsBinarySerializable || this.IsBinarySerializable); - - public bool IsBinarySerializable - => this.Implements(); - - public bool IsBinaryDeserializable - => this.Implements(); - - public bool IsChild(out ITypeV2 parent) { - if (this.Implements(typeof(IChildOf<>), out var matchingType)) { - parent = matchingType.GenericArguments.First(); - return true; - } - - parent = default; - return false; - } - - public IEnumerable GenericArguments - => this.HasGenericArguments(out var genericArguments) - ? genericArguments - : Enumerable.Empty(); - - public IEnumerable GenericConstraints - => this.IsGenericTypeParameter(out var genericConstraints) - ? genericConstraints - : Enumerable.Empty(); - - public bool IsSequence(out ITypeV2 elementType, - out SequenceType sequenceType) { - if (this.IsArray(out elementType)) { - sequenceType = SequenceType.MUTABLE_ARRAY; - return true; - } - - if (this.Implements(typeof(ImmutableArray<>), - out var immutableArrayTypeV2)) { - elementType = immutableArrayTypeV2.GenericArguments.ToArray()[0]; - sequenceType = SequenceType.IMMUTABLE_ARRAY; - return true; - } - - if (this.Implements(typeof(ISequence<,>), out var sequenceTypeV2)) { - elementType = sequenceTypeV2.GenericArguments.ToArray()[1]; - sequenceType = SequenceType.MUTABLE_SEQUENCE; - return true; - } - - if (this.Implements(typeof(IConstLengthSequence<,>), - out var constLengthSequenceTypeV2)) { - elementType = constLengthSequenceTypeV2.GenericArguments.ToArray()[1]; - sequenceType = SequenceType.MUTABLE_SEQUENCE; - return true; - } - - if (this.Implements(typeof(IReadOnlySequence<,>), - out var readOnlySequence)) { - elementType = readOnlySequence.GenericArguments.ToArray()[1]; - sequenceType = SequenceType.READ_ONLY_SEQUENCE; - return true; - } - - if (this.Implements(typeof(List<>), out var listTypeV2)) { - elementType = listTypeV2.GenericArguments.ToArray()[0]; - sequenceType = SequenceType.MUTABLE_LIST; - return true; - } - - if (this.Implements(typeof(IReadOnlyList<>), - out var readonlyListTypeV2)) { - elementType = readonlyListTypeV2.GenericArguments.ToArray()[0]; - sequenceType = SequenceType.READ_ONLY_LIST; - return true; - } - - elementType = default; - sequenceType = default; - return false; - } - } - } -} \ No newline at end of file diff --git a/Schema/src/util/types/ITypeV2.cs b/Schema/src/util/types/ITypeV2.cs deleted file mode 100644 index 8a1bb79..0000000 --- a/Schema/src/util/types/ITypeV2.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; - -using Microsoft.CodeAnalysis; - -using schema.binary; - -namespace schema.util.types { - public interface ITypeV2 { - string Name { get; } - string FullyQualifiedName { get; } - bool Exists { get; } - - string? FullyQualifiedNamespace { get; } - IEnumerable NamespaceParts { get; } - - IEnumerable DeclaringTypeNamesDownward { get; } - - bool IsExactly(ITypeV2 other); - bool IsExactly(); - bool IsExactly(Type other); - bool IsExactly(ISymbol other); - - bool Implements(); - bool Implements(Type type); - - bool Implements(out ITypeV2 matchingType); - bool Implements(Type type, out ITypeV2 matchingType); - - int Arity { get; } - bool HasGenericArguments(out IEnumerable genericArguments); - IEnumerable GenericArguments { get; } - bool IsGenericTypeParameter(out IEnumerable genericConstraints); - IEnumerable GenericConstraints { get; } - IEnumerable<(string, ITypeV2)> GetTupleElements(); - - bool HasNullableAnnotation { get; } - bool IsAtLeastAsBinaryConvertibleAs(ITypeV2 other); - bool IsBinarySerializable { get; } - bool IsBinaryDeserializable { get; } - bool IsClass { get; } - bool IsAbstractClass { get; } - bool IsInterface { get; } - bool IsStruct { get; } - bool IsString { get; } - bool IsArray(out ITypeV2 elementType); - bool IsPrimitive(out SchemaPrimitiveType primitiveType); - bool IsEnum(out SchemaIntegerType underlyingType); - - bool IsSequence(out ITypeV2 elementType, - out SequenceType sequenceType); - - bool IsChild(out ITypeV2 parent); - bool ContainsMemberWithType(ITypeV2 other); - - bool HasAttribute() where TAttribute : Attribute; - TAttribute GetAttribute() where TAttribute : Attribute; - - IEnumerable GetAttributes() - where TAttribute : Attribute; - } -} \ No newline at end of file diff --git a/Schema/src/util/types/SymbolBasedTypeV2.cs b/Schema/src/util/types/SymbolBasedTypeV2.cs deleted file mode 100644 index 3e76d17..0000000 --- a/Schema/src/util/types/SymbolBasedTypeV2.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis; - -using schema.binary; -using schema.binary.attributes; -using schema.util.diagnostics; -using schema.util.enumerables; -using schema.util.symbols; - -namespace schema.util.types { - public static partial class TypeV2 { - public static ITypeV2 FromSymbol(ITypeSymbol symbol) - => new SymbolBasedTypeV2(symbol, null); - - internal static ITypeV2 FromSymbol( - ITypeSymbol symbol, - IDiagnosticReporter diagnosticReporter) - => new SymbolBasedTypeV2(symbol, diagnosticReporter); - - private class SymbolBasedTypeV2 : BSymbolTypeV2 { - private readonly ITypeSymbol symbol_; - private IDiagnosticReporter? diagnosticReporter_; - - public SymbolBasedTypeV2(ITypeSymbol symbol, - IDiagnosticReporter? diagnosticReporter) { - this.symbol_ = symbol; - this.diagnosticReporter_ = diagnosticReporter; - } - - public override string Name => this.symbol_.Name; - - public override bool Exists => this.symbol_.Locations.Length > 1; - - public override string? FullyQualifiedNamespace - => this.symbol_.GetFullyQualifiedNamespace(); - - public override IEnumerable NamespaceParts - => this.symbol_.GetContainingNamespaces(); - - public override IEnumerable DeclaringTypeNamesDownward - => this.symbol_.GetDeclaringTypesDownward().Select(type => type.Name); - - public override bool Implements(Type type, out ITypeV2 matchingType) { - var matchingTypeImpl = - this.symbol_.Yield() - .Concat( - (this.symbol_ as ITypeSymbol)?.AllInterfaces ?? - Enumerable.Empty()) - .Concat(BaseTypes) - .SingleOrDefault( - symbol => SymbolComparisonUtil.IsType((ISymbol) symbol, type)); - matchingType = matchingTypeImpl != null - ? TypeV2.FromSymbol(matchingTypeImpl) - : null; - return matchingType != null; - } - - private IEnumerable BaseTypes { - get { - var baseType = this.symbol_.BaseType; - while (baseType != null) { - yield return baseType; - baseType = baseType.BaseType; - } - } - } - - public override int Arity - => (this.symbol_ as INamedTypeSymbol)?.TypeArguments.Length ?? 0; - - public override bool IsClass - => this.symbol_ is INamedTypeSymbol { TypeKind: TypeKind.Class }; - - public override bool IsAbstractClass - => this.symbol_ is INamedTypeSymbol { - IsAbstract: true, TypeKind: TypeKind.Class - }; - - public override bool IsInterface - => this.symbol_ is INamedTypeSymbol { TypeKind: TypeKind.Interface }; - - public override bool IsStruct - => this.symbol_ is INamedTypeSymbol { TypeKind: TypeKind.Struct }; - - public override bool IsString - => this.symbol_ is { SpecialType: SpecialType.System_String }; - - public override bool IsArray(out ITypeV2 elementType) { - var arrayTypeSymbol = this.symbol_ as IArrayTypeSymbol; - elementType = arrayTypeSymbol != null - ? TypeV2.FromSymbol(arrayTypeSymbol.ElementType) - : default; - return arrayTypeSymbol != null; - } - - public override bool IsPrimitive(out SchemaPrimitiveType primitiveType) { - primitiveType = GetPrimitiveType_(this.symbol_); - return primitiveType != SchemaPrimitiveType.UNDEFINED; - } - - public override bool IsEnum(out SchemaIntegerType underlyingType) { - var underlyingSymbol = - (this.symbol_ as INamedTypeSymbol)?.EnumUnderlyingType; - if (underlyingSymbol == null) { - underlyingType = default; - return false; - } - - underlyingType = GetPrimitiveType_(underlyingSymbol).AsIntegerType(); - return underlyingType != SchemaIntegerType.UNDEFINED; - } - - private static SchemaPrimitiveType GetPrimitiveType_(ISymbol symbol) { - var typeSymbol = symbol as ITypeSymbol; - - if (typeSymbol?.TypeKind == TypeKind.Enum) { - return SchemaPrimitiveType.ENUM; - } - - return typeSymbol?.SpecialType switch { - SpecialType.System_Boolean => SchemaPrimitiveType.BOOLEAN, - SpecialType.System_Char => SchemaPrimitiveType.CHAR, - SpecialType.System_SByte => SchemaPrimitiveType.SBYTE, - SpecialType.System_Byte => SchemaPrimitiveType.BYTE, - SpecialType.System_Int16 => SchemaPrimitiveType.INT16, - SpecialType.System_UInt16 => SchemaPrimitiveType.UINT16, - SpecialType.System_Int32 => SchemaPrimitiveType.INT32, - SpecialType.System_UInt32 => SchemaPrimitiveType.UINT32, - SpecialType.System_Int64 => SchemaPrimitiveType.INT64, - SpecialType.System_UInt64 => SchemaPrimitiveType.UINT64, - SpecialType.System_Single => SchemaPrimitiveType.SINGLE, - SpecialType.System_Double => SchemaPrimitiveType.DOUBLE, - _ => SchemaPrimitiveType.UNDEFINED - }; - } - - public override bool HasGenericArguments( - out IEnumerable genericArguments) { - if (this.Arity == 0) { - genericArguments = default; - return false; - } - - genericArguments = - (this.symbol_ as INamedTypeSymbol)!.TypeArguments.Select( - TypeV2.FromSymbol); - return true; - } - - public override bool IsGenericTypeParameter( - out IEnumerable genericConstraints) { - if (this.symbol_ is not ITypeParameterSymbol typeParameterSymbol) { - genericConstraints = null; - return false; - } - - genericConstraints = - typeParameterSymbol - .ConstraintTypes - .Where(constraint => constraint is not IErrorTypeSymbol) - .Select(TypeV2.FromSymbol); - return true; - } - - public override IEnumerable<(string, ITypeV2)> GetTupleElements() - => (this.symbol_ as INamedTypeSymbol)!.TupleElements.Select( - fieldSymbol => (fieldSymbol.Name, - TypeV2.FromSymbol(fieldSymbol.Type))); - - - public override bool HasNullableAnnotation - => this.symbol_.NullableAnnotation == NullableAnnotation.Annotated; - - public override bool HasAttribute() - => this.GetAttributeData_().Any(); - - public override TAttribute GetAttribute() - => this.symbol_.GetAttributes(this.diagnosticReporter_) - .SingleOrDefault(); - - public override IEnumerable GetAttributes() - => this.symbol_.GetAttributeData() - .Select(attributeData => { - var attribute = - attributeData - .Instantiate(this.symbol_); - if (attribute is BMemberAttribute memberAttribute) { - memberAttribute.Init(this.diagnosticReporter_, - this.symbol_.ContainingType, - this.symbol_.Name); - } - - return attribute; - }); - - private IEnumerable GetAttributeData_() - where TAttribute : Attribute { - var attributeType = typeof(TAttribute); - return this.symbol_ - .GetAttributes() - .Where(attributeData - => attributeData.AttributeClass?.IsType( - attributeType) ?? - false); - } - - public override bool ContainsMemberWithType(ITypeV2 other) - => this.symbol_ - .GetMembers() - .Select(member => { - switch (member) { - case IFieldSymbol fieldSymbol: - return fieldSymbol.Type; - case IPropertySymbol propertySymbol: - return propertySymbol.Type; - default: return null; - } - }) - .Where(type => type != null) - .Distinct() - .Select(TypeV2.FromSymbol) - .Select( - typeV2 => typeV2.IsSequence(out var elementTypeV2, out _) - ? elementTypeV2 - : typeV2) - .Any(other.IsExactly); - } - } -} \ No newline at end of file diff --git a/Schema/src/util/types/TypeBasedTypeV2.cs b/Schema/src/util/types/TypeBasedTypeV2.cs deleted file mode 100644 index 05b4b48..0000000 --- a/Schema/src/util/types/TypeBasedTypeV2.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -using schema.binary; -using schema.util.enumerables; - -namespace schema.util.types { - public static partial class TypeV2 { - public static ITypeV2 FromType() => FromType(typeof(T)); - - public static ITypeV2 FromType(Type type) - => new TypeBasedTypeV2(type); - - private class TypeBasedTypeV2 : BSymbolTypeV2 { - private readonly Type type_; - - public TypeBasedTypeV2(Type type) { - this.type_ = type; - } - - public override string Name => this.type_.Name; - public override bool Exists => true; - - public override string? FullyQualifiedNamespace => this.type_.Namespace; - - public override IEnumerable NamespaceParts - => this.type_.Namespace?.Split('.') ?? Enumerable.Empty(); - - public override IEnumerable DeclaringTypeNamesDownward - => DeclaringTypeNamesUpward.Reverse(); - - private IEnumerable DeclaringTypeNamesUpward { - get { - var declaringType = this.type_.DeclaringType; - while (declaringType != null) { - yield return declaringType.Name; - declaringType = declaringType.DeclaringType; - } - } - } - - public override bool Implements(Type other, out ITypeV2 matchingType) { - var matchingTypeImpl = this.type_.Yield() - .Concat(this.type_.GetInterfaces()) - .Concat(BaseTypes) - .SingleOrDefault(type => type == other); - matchingType = matchingTypeImpl != null - ? TypeV2.FromType(matchingTypeImpl) - : null; - return matchingType != null; - } - - private IEnumerable BaseTypes { - get { - var baseType = this.type_.BaseType; - while (baseType != null) { - yield return baseType; - baseType = baseType.BaseType; - } - } - } - - public override int Arity - => this.type_.IsGenericParameter - ? this.type_.GetGenericParameterConstraints().Length - : 0; - - public override bool IsClass => this.type_.IsClass; - - public override bool IsAbstractClass - => this.type_ is { IsClass: true, IsAbstract: true }; - - public override bool IsInterface => this.type_.IsInterface; - - public override bool IsStruct => this.type_ is - { IsValueType: true, IsEnum: false }; - - public override bool IsString => this.type_ == typeof(string); - - public override bool IsArray(out ITypeV2 elementType) { - var elementTypeImpl = this.type_.GetElementType(); - elementType = elementTypeImpl != null - ? TypeV2.FromType(elementTypeImpl) - : null; - return this.type_.IsArray; - } - - public override bool IsPrimitive( - out SchemaPrimitiveType primitiveType) { - primitiveType = this.GetPrimitiveType_(this.type_); - return primitiveType != SchemaPrimitiveType.UNDEFINED; - } - - public override bool IsEnum( - out SchemaIntegerType underlyingType) { - underlyingType = - this.GetPrimitiveType_(this.type_.GetEnumUnderlyingType()) - .AsIntegerType(); - return underlyingType != SchemaIntegerType.UNDEFINED; - } - - - public override bool ContainsMemberWithType(ITypeV2 other) { - var fieldTypeV2s = - this.type_.GetFields(BindingFlags.Public | BindingFlags.Instance) - .Concat( - this.type_.GetFields(BindingFlags.NonPublic | - BindingFlags.Instance)) - .Where(field => !field.Name.Contains("k__BackingField")) - .Select(field => field.FieldType) - .Distinct() - .Select(TypeV2.FromType); - var propertyTypeV2s = - this.type_.GetProperties( - BindingFlags.Public | BindingFlags.Instance) - .Concat( - this.type_.GetProperties(BindingFlags.NonPublic | - BindingFlags.Instance)) - .Where(property => property.GetIndexParameters().Length == 0) - .Select(property => property.PropertyType) - .Distinct() - .Select(TypeV2.FromType); - - return fieldTypeV2s - .Concat(propertyTypeV2s) - .Select(typeV2 => typeV2.IsSequence(out var elementTypeV2, out _) - ? elementTypeV2 - : typeV2) - .Any(other.IsExactly); - } - - public override bool HasAttribute() - => this.GetAttribute() != null; - - public override TAttribute GetAttribute() - => this.GetAttributes().Single(); - - public override IEnumerable GetAttributes() - => this.type_.GetCustomAttributes(); - - public override bool HasGenericArguments( - out IEnumerable genericArguments) { - if (this.Arity == 0) { - genericArguments = default; - return false; - } - - genericArguments = - this.type_.GenericTypeArguments.Select(TypeV2.FromType); - return true; - } - - public override bool IsGenericTypeParameter( - out IEnumerable genericConstraints) { - if (!this.type_.IsGenericParameter) { - genericConstraints = default; - return false; - } - - genericConstraints = this.type_.GetGenericParameterConstraints() - .Select(TypeV2.FromType); - return true; - } - - public override IEnumerable<(string, ITypeV2)> GetTupleElements() - => throw new NotImplementedException(); - - private SchemaPrimitiveType GetPrimitiveType_(Type type) { - if (type.IsEnum) { - return SchemaPrimitiveType.ENUM; - } - - if (type == typeof(bool)) return SchemaPrimitiveType.BOOLEAN; - if (type == typeof(char)) return SchemaPrimitiveType.CHAR; - if (type == typeof(byte)) return SchemaPrimitiveType.BYTE; - if (type == typeof(sbyte)) return SchemaPrimitiveType.SBYTE; - if (type == typeof(short)) return SchemaPrimitiveType.INT16; - if (type == typeof(ushort)) return SchemaPrimitiveType.UINT16; - if (type == typeof(int)) return SchemaPrimitiveType.INT32; - if (type == typeof(uint)) return SchemaPrimitiveType.UINT32; - if (type == typeof(long)) return SchemaPrimitiveType.INT64; - if (type == typeof(ulong)) return SchemaPrimitiveType.UINT64; - if (type == typeof(float)) return SchemaPrimitiveType.SINGLE; - if (type == typeof(double)) return SchemaPrimitiveType.DOUBLE; - - return SchemaPrimitiveType.UNDEFINED; - } - } - } -} \ No newline at end of file