diff --git a/BlueWest.Data/Finance/Currency/TestData.cs b/BlueWest.Data/Finance/Currency/TestData.cs new file mode 100644 index 0000000..bef54d9 --- /dev/null +++ b/BlueWest.Data/Finance/Currency/TestData.cs @@ -0,0 +1,6 @@ +namespace BlueWest.Data; + +public class TestData +{ + +} \ No newline at end of file diff --git a/include/BlueWest.MapTo/src/BlueWest.MapTo/BlueWest.MapTo.csproj b/include/BlueWest.MapTo/src/BlueWest.MapTo/BlueWest.MapTo.csproj index 6061e68..01debfe 100644 --- a/include/BlueWest.MapTo/src/BlueWest.MapTo/BlueWest.MapTo.csproj +++ b/include/BlueWest.MapTo/src/BlueWest.MapTo/BlueWest.MapTo.csproj @@ -18,6 +18,7 @@ bin\Release\MapTo.xml + false diff --git a/include/BlueWest.MapTo/src/BlueWest.MapTo/Extensions/RoslynExtensions.cs b/include/BlueWest.MapTo/src/BlueWest.MapTo/Extensions/RoslynExtensions.cs index 402996e..b38c6ff 100644 --- a/include/BlueWest.MapTo/src/BlueWest.MapTo/Extensions/RoslynExtensions.cs +++ b/include/BlueWest.MapTo/src/BlueWest.MapTo/Extensions/RoslynExtensions.cs @@ -33,11 +33,13 @@ namespace MapTo.Extensions public static AttributeSyntax? GetAttribute(this TypeDeclarationSyntax typeDeclarationSyntax, string attributeName) { - return typeDeclarationSyntax.AttributeLists - .SelectMany(al => al.Attributes) - .SingleOrDefault(a => - (a.Name as IdentifierNameSyntax)?.Identifier.ValueText == attributeName || - ((a.Name as QualifiedNameSyntax)?.Right as IdentifierNameSyntax)?.Identifier.ValueText == attributeName); + var attributeLists = typeDeclarationSyntax.AttributeLists; + var selection = attributeLists + .SelectMany(al => al.Attributes); + var result = selection + .FirstOrDefault(); + + return result; } public static bool HasAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) => @@ -86,7 +88,7 @@ namespace MapTo.Extensions public static IPropertySymbol? FindProperty(this IEnumerable properties, IPropertySymbol targetProperty) { - return properties.SingleOrDefault(p => + return properties.FirstOrDefault(p => p.Name == targetProperty.Name && (p.NullableAnnotation != NullableAnnotation.Annotated || p.NullableAnnotation == NullableAnnotation.Annotated && diff --git a/include/BlueWest.MapTo/src/BlueWest.MapTo/MapToSyntaxReceiver.cs b/include/BlueWest.MapTo/src/BlueWest.MapTo/MapToSyntaxReceiver.cs index 03c35ac..786f9ad 100644 --- a/include/BlueWest.MapTo/src/BlueWest.MapTo/MapToSyntaxReceiver.cs +++ b/include/BlueWest.MapTo/src/BlueWest.MapTo/MapToSyntaxReceiver.cs @@ -20,7 +20,7 @@ namespace MapTo var attributeSyntax = attributes .SelectMany(a => a.Attributes) - .SingleOrDefault(a => a.Name is + .FirstOrDefault(a => a.Name is IdentifierNameSyntax { Identifier: { ValueText: MapFromAttributeSource.AttributeName } } // For: [MapFrom] or QualifiedNameSyntax // For: [MapTo.MapFrom] diff --git a/include/BlueWest.MapTo/src/BlueWest.MapTo/MappingContext.cs b/include/BlueWest.MapTo/src/BlueWest.MapTo/MappingContext.cs index 37cc076..2f762f4 100644 --- a/include/BlueWest.MapTo/src/BlueWest.MapTo/MappingContext.cs +++ b/include/BlueWest.MapTo/src/BlueWest.MapTo/MappingContext.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; +using System.Threading; using MapTo.Extensions; using MapTo.Sources; using Microsoft.CodeAnalysis; @@ -70,6 +72,8 @@ namespace MapTo public static MappingContext Create(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax) { + //SpinWait.SpinUntil(() => Debugger.IsAttached); + MappingContext context = typeSyntax switch { StructDeclarationSyntax => new StructMappingContext(compilation, sourceGenerationOptions, typeSyntax), @@ -107,20 +111,20 @@ namespace MapTo var propertyName = property .GetAttribute(MapPropertyAttributeTypeSymbol) ?.NamedArguments - .SingleOrDefault(a => a.Key == MapPropertyAttributeSource.SourcePropertyNamePropertyName) + .FirstOrDefault(a => a.Key == MapPropertyAttributeSource.SourcePropertyNamePropertyName) .Value.Value as string ?? property.Name; - return sourceProperties.SingleOrDefault(p => p.Name == propertyName); + return sourceProperties.FirstOrDefault(p => p.Name == propertyName); } protected IFieldSymbol? FindSourceField(IEnumerable sourceProperties, ISymbol property) { var propertyName = property .GetAttribute(MapPropertyAttributeTypeSymbol) ?.NamedArguments - .SingleOrDefault(a => a.Key == MapPropertyAttributeSource.SourcePropertyNamePropertyName) + .FirstOrDefault(a => a.Key == MapPropertyAttributeSource.SourcePropertyNamePropertyName) .Value.Value as string ?? property.Name; - return sourceProperties.SingleOrDefault(p => p.Name == propertyName); + return sourceProperties.FirstOrDefault(p => p.Name == propertyName); } protected abstract ImmutableArray GetSourceMappedProperties(ITypeSymbol typeSymbol, ITypeSymbol sourceTypeSymbol, bool isInheritFromMappedBaseClass); @@ -131,8 +135,12 @@ namespace MapTo protected abstract ImmutableArray GetTypeMappedFields(ITypeSymbol typeSymbol, ITypeSymbol sourceTypeSymbol, bool isInheritFromMappedBaseClass); - protected ImmutableArray GetSourceTypeSymbol(TypeDeclarationSyntax typeDeclarationSyntax, SemanticModel? semanticModel = null) => - GetSourceTypeSymbol(typeDeclarationSyntax.GetAttribute(MapFromAttributeSource.AttributeName), semanticModel); + protected ImmutableArray GetSourceTypeSymbol(TypeDeclarationSyntax typeDeclarationSyntax, SemanticModel? semanticModel = null) + { + var attributeData = typeDeclarationSyntax.GetAttribute(MapFromAttributeSource.AttributeName); + var sourceSymbol = GetSourceTypeSymbol(attributeData, semanticModel); + return sourceSymbol; + } // we need two possible InamedTypeSymbol protected ImmutableArray GetSourceTypeSymbol(SyntaxNode? attributeSyntax, SemanticModel? semanticModel = null) @@ -143,11 +151,13 @@ namespace MapTo } semanticModel ??= Compilation.GetSemanticModel(attributeSyntax.SyntaxTree); - var sourceTypeExpressionSyntax = attributeSyntax - .DescendantNodes() + var descendentNodes = attributeSyntax + .DescendantNodes(); + + var sourceTypeExpressionSyntax = descendentNodes .OfType() .ToImmutableArray(); - + // cast var resultList = new List(); for (int i = 0; i < sourceTypeExpressionSyntax.Length; i++) @@ -503,8 +513,8 @@ namespace MapTo var typeIdentifierName = TypeSyntax.GetIdentifierName(); var sourceTypeIdentifierName = sourceTypeSymbol.Name; var isTypeInheritFromMappedBaseClass = IsTypeInheritFromMappedBaseClass(semanticModel); - var isTypeUpdatable = IsTypeUpdatable(); - var hasJsonExtension = HasJsonExtension(); + var isTypeUpdatable = false; //IsTypeUpdatable(); + var hasJsonExtension = false; // HasJsonExtension(); var shouldGenerateSecondaryConstructor = ShouldGenerateSecondaryConstructor(semanticModel, sourceTypeSymbol); var mappedProperties = GetSourceMappedProperties(typeSymbol, sourceTypeSymbol, isTypeInheritFromMappedBaseClass); @@ -551,7 +561,7 @@ namespace MapTo } return converterTypeSymbol.AllInterfaces - .SingleOrDefault(i => + .FirstOrDefault(i => i.TypeArguments.Length == 2 && SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, TypeConverterInterfaceTypeSymbol) && SymbolEqualityComparer.Default.Equals(sourceProperty.Type, i.TypeArguments[0]) && @@ -565,7 +575,7 @@ namespace MapTo } return converterTypeSymbol.AllInterfaces - .SingleOrDefault(i => + .FirstOrDefault(i => i.TypeArguments.Length == 2 && SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, TypeConverterInterfaceTypeSymbol) && SymbolEqualityComparer.Default.Equals(sourceProperty.Type, i.TypeArguments[0]) && @@ -576,7 +586,7 @@ namespace MapTo { var constructorSyntax = TypeSyntax.DescendantNodes() .OfType() - .SingleOrDefault(c => + .FirstOrDefault(c => c.ParameterList.Parameters.Count == 1 && SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeInfo(c.ParameterList.Parameters.Single().Type!).ConvertedType, sourceTypeSymbol)); diff --git a/include/BlueWest.MapTo/src/BlueWest.MapTo/Sources/MapFromAttributeSource.cs b/include/BlueWest.MapTo/src/BlueWest.MapTo/Sources/MapFromAttributeSource.cs index 70c48ef..e944025 100644 --- a/include/BlueWest.MapTo/src/BlueWest.MapTo/Sources/MapFromAttributeSource.cs +++ b/include/BlueWest.MapTo/src/BlueWest.MapTo/Sources/MapFromAttributeSource.cs @@ -42,6 +42,13 @@ namespace MapTo.Sources builder .WriteLine($"public {AttributeName}Attribute(Type sourceType)") .WriteOpeningBracket() + .WriteLine("SourceType = new [] { sourceType };") + .WriteClosingBracket() + .WriteLine(); + + builder + .WriteLine($"public {AttributeName}Attribute(Type[] sourceType)") + .WriteOpeningBracket() .WriteLine("SourceType = sourceType;") .WriteClosingBracket() .WriteLine(); @@ -55,7 +62,7 @@ namespace MapTo.Sources } builder - .WriteLine("public Type SourceType { get; }") + .WriteLine("public Type[] SourceType { get; }") .WriteClosingBracket() // class .WriteClosingBracket(); // namespace diff --git a/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/RoslynExtensions.cs b/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/RoslynExtensions.cs index cddafeb..b9f81d4 100644 --- a/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/RoslynExtensions.cs +++ b/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/RoslynExtensions.cs @@ -8,7 +8,7 @@ namespace MapTo.Tests.Extensions internal static class RoslynExtensions { internal static SyntaxTree? GetGeneratedSyntaxTree(this Compilation compilation, string className) => - compilation.SyntaxTrees.SingleOrDefault(s => s.FilePath.EndsWith($"{className}.g.cs")); + compilation.SyntaxTrees.FirstOrDefault(s => s.FilePath.EndsWith($"{className}.g.cs")); internal static string PrintSyntaxTree(this Compilation compilation) { diff --git a/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/ShouldlyExtensions.cs b/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/ShouldlyExtensions.cs index 2b9dd87..5aeee7c 100644 --- a/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/ShouldlyExtensions.cs +++ b/include/BlueWest.MapTo/test/BlueWest.MapTo.Tests/Extensions/ShouldlyExtensions.cs @@ -15,7 +15,7 @@ namespace MapTo.Tests.Extensions { var syntax = syntaxTree .Select(s => s.ToString().Trim()) - .SingleOrDefault(s => s.Contains(typeName)); + .FirstOrDefault(s => s.Contains(typeName)); syntax.ShouldNotBeNullOrWhiteSpace(); syntax.ShouldBe(expectedSource, customMessage); @@ -25,7 +25,7 @@ namespace MapTo.Tests.Extensions { var syntax = syntaxTree .Select(s => s.ToString().Trim()) - .SingleOrDefault(s => s.Contains(typeName)); + .FirstOrDefault(s => s.Contains(typeName)); syntax.ShouldNotBeNullOrWhiteSpace(); syntax.ShouldContainWithoutWhitespace(expectedSource, customMessage); @@ -68,7 +68,7 @@ namespace MapTo.Tests.Extensions internal static void ShouldNotBeSuccessful(this ImmutableArray diagnostics, Diagnostic expectedError) { - var actualDiagnostics = diagnostics.SingleOrDefault(d => d.Id == expectedError.Id); + var actualDiagnostics = diagnostics.FirstOrDefault(d => d.Id == expectedError.Id); var compilationDiagnostics = actualDiagnostics == null ? diagnostics : diagnostics.Except(new[] { actualDiagnostics }); compilationDiagnostics.ShouldBeSuccessful();