diff --git a/Directory.Packages.props b/Directory.Packages.props index 6686a4be5..6027bac98 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,8 @@ - + + @@ -94,8 +95,5 @@ - - + + \ No newline at end of file diff --git a/sample/Sample.DependencyOne/Class1.cs b/sample/Sample.DependencyOne/Class1.cs index 3b1747374..a658cce26 100644 --- a/sample/Sample.DependencyOne/Class1.cs +++ b/sample/Sample.DependencyOne/Class1.cs @@ -1,4 +1,5 @@ -using Rocket.Surgery.Conventions; +using FluentValidation; +using Rocket.Surgery.Conventions; using Sample.DependencyOne; [assembly: ExportConventions(Namespace = "Dep1", ClassName = "Dep1Exports")] @@ -6,4 +7,18 @@ namespace Sample.DependencyOne; -public class Class1 : IConvention; \ No newline at end of file +public class Class1 : IConvention; + +public static class Example1 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} diff --git a/sample/Sample.DependencyOne/Sample.DependencyOne.csproj b/sample/Sample.DependencyOne/Sample.DependencyOne.csproj index be6c37c85..36c49ee23 100644 --- a/sample/Sample.DependencyOne/Sample.DependencyOne.csproj +++ b/sample/Sample.DependencyOne/Sample.DependencyOne.csproj @@ -13,4 +13,7 @@ + + + diff --git a/sample/Sample.DependencyThree/Class3.cs b/sample/Sample.DependencyThree/Class3.cs index 77bca7e36..15270cbd0 100644 --- a/sample/Sample.DependencyThree/Class3.cs +++ b/sample/Sample.DependencyThree/Class3.cs @@ -1,3 +1,4 @@ +using FluentValidation; using Rocket.Surgery.Conventions; using Sample.DependencyOne; using Sample.DependencyThree; @@ -10,3 +11,17 @@ public class Class3 : IConvention { public Class1? Class1 { get; set; } } + +public static class Example3 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} diff --git a/sample/Sample.DependencyThree/Sample.DependencyThree.csproj b/sample/Sample.DependencyThree/Sample.DependencyThree.csproj index 700abeb93..39e8653aa 100644 --- a/sample/Sample.DependencyThree/Sample.DependencyThree.csproj +++ b/sample/Sample.DependencyThree/Sample.DependencyThree.csproj @@ -16,4 +16,7 @@ + + + diff --git a/sample/Sample.DependencyTwo/Class2.cs b/sample/Sample.DependencyTwo/Class2.cs index 2ae5a87bf..020362289 100644 --- a/sample/Sample.DependencyTwo/Class2.cs +++ b/sample/Sample.DependencyTwo/Class2.cs @@ -1,4 +1,5 @@ -using Rocket.Surgery.Conventions; +using FluentValidation; +using Rocket.Surgery.Conventions; [assembly: ExportConventions(Namespace = null, ClassName = "Dep2Exports")] @@ -8,4 +9,19 @@ public static class Nested { [ExportConvention] public class Class2 : IConvention; -} \ No newline at end of file +} + + +public static class Example2 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} diff --git a/sample/Sample.DependencyTwo/Sample.DependencyTwo.csproj b/sample/Sample.DependencyTwo/Sample.DependencyTwo.csproj index be6c37c85..36c49ee23 100644 --- a/sample/Sample.DependencyTwo/Sample.DependencyTwo.csproj +++ b/sample/Sample.DependencyTwo/Sample.DependencyTwo.csproj @@ -13,4 +13,7 @@ + + + diff --git a/src/Conventions.Abstractions/ConventionContextBuilder.cs b/src/Conventions.Abstractions/ConventionContextBuilder.cs index d3d34f667..496900856 100644 --- a/src/Conventions.Abstractions/ConventionContextBuilder.cs +++ b/src/Conventions.Abstractions/ConventionContextBuilder.cs @@ -379,4 +379,4 @@ public ConventionContextBuilder IncludeConvention(Assembly assembly, params Asse _includeAssemblyConventions.AddRange(assemblies); return this; } -} \ No newline at end of file +} diff --git a/src/Conventions.Analyzers/Helpers.cs b/src/Conventions.Analyzers/Helpers.cs index 7cbfc4109..e37b092af 100644 --- a/src/Conventions.Analyzers/Helpers.cs +++ b/src/Conventions.Analyzers/Helpers.cs @@ -18,7 +18,9 @@ public static string GetFullMetadataName(ISymbol? s) return string.Empty; } - var sb = new StringBuilder(s.MetadataName); + var sb =s is INamedTypeSymbol { Arity: > 0, IsUnboundGenericType: true } namedTypeSymbol + ? new StringBuilder(namedTypeSymbol.Name + ("<" + (string.Concat(Enumerable.Range(0,3).Select(z => ","))) + ">")) + :new StringBuilder(s.MetadataName); var last = s; s = s.ContainingSymbol; @@ -34,7 +36,7 @@ public static string GetFullMetadataName(ISymbol? s) sb.Insert(0, '.'); } - sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); + sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); //sb.Insert(0, s.MetadataName); s = s.ContainingSymbol; } @@ -347,4 +349,4 @@ internal static SyntaxTrivia GetXmlSummary(string text) } private static readonly SyntaxToken XmlNewLine = XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()); -} \ No newline at end of file +} diff --git a/src/Conventions/Testing/TestConventionContextBuilderExtensions.cs b/src/Conventions/Testing/TestConventionContextBuilderExtensions.cs index afb61637c..ad1db33ae 100644 --- a/src/Conventions/Testing/TestConventionContextBuilderExtensions.cs +++ b/src/Conventions/Testing/TestConventionContextBuilderExtensions.cs @@ -306,4 +306,4 @@ private static void EnsureConfigured(ConventionContextBuilder builder) // // return builder; // } -} \ No newline at end of file +} diff --git a/test/Analyzers.Tests.roslyn4.8/Rocket.Surgery.Conventions.Analyzers.Tests.roslyn4.8.csproj b/test/Analyzers.Tests.roslyn4.8/Rocket.Surgery.Conventions.Analyzers.Tests.roslyn4.8.csproj index ea6e068da..004ae61df 100644 --- a/test/Analyzers.Tests.roslyn4.8/Rocket.Surgery.Conventions.Analyzers.Tests.roslyn4.8.csproj +++ b/test/Analyzers.Tests.roslyn4.8/Rocket.Surgery.Conventions.Analyzers.Tests.roslyn4.8.csproj @@ -8,6 +8,7 @@ + diff --git a/test/Analyzers.Tests/AssemblyProviderTests.cs b/test/Analyzers.Tests/AssemblyProviderTests.cs index 34efea152..d4e699d44 100644 --- a/test/Analyzers.Tests/AssemblyProviderTests.cs +++ b/test/Analyzers.Tests/AssemblyProviderTests.cs @@ -129,6 +129,7 @@ public async Task Should_Generate_Assembly_Provider_For_GetTypes(GetTypesTestsDa using Rocket.Surgery.Conventions.Reflection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using FluentValidation; using System.ComponentModel; using System.Threading; using System.Threading.Tasks; @@ -168,6 +169,7 @@ public async Task Should_Generate_Assembly_Provider_For_GetTypes_From_Another_As using Rocket.Surgery.Conventions.Reflection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using FluentValidation; using System.ComponentModel; using System.Threading; using System.Threading.Tasks; @@ -220,4 +222,4 @@ public override async Task InitializeAsync() ) ); } -} \ No newline at end of file +} diff --git a/test/Analyzers.Tests/GenerationHelpers.cs b/test/Analyzers.Tests/GenerationHelpers.cs index 78a101fd1..8107ab946 100644 --- a/test/Analyzers.Tests/GenerationHelpers.cs +++ b/test/Analyzers.Tests/GenerationHelpers.cs @@ -1,3 +1,5 @@ +using System.Linq.Expressions; +using FluentValidation; using Rocket.Surgery.Extensions.Testing.SourceGenerators; namespace Rocket.Surgery.Conventions.Analyzers.Tests; @@ -6,7 +8,7 @@ public static class GenerationHelpers { public static async Task CreateDeps(GeneratorTestContextBuilder rootBuilder) { - var baseBuilder = rootBuilder; + var baseBuilder = rootBuilder.AddReferences(typeof(IValidator).Assembly, typeof(Expression<>).Assembly); var c1 = await Class1(baseBuilder); var c2 = await Class2(baseBuilder); var c3 = await Class3(baseBuilder, c1); @@ -29,6 +31,7 @@ public static Task Class1(GeneratorTestContextBuilder buil .AddSources( @"using Rocket.Surgery.Conventions; using Sample.DependencyOne; +using FluentValidation; [assembly: ExportConventions(Namespace = ""Dep1"", ClassName = ""Dep1Exports"")] [assembly: Convention(typeof(Class1))] @@ -38,6 +41,21 @@ namespace Sample.DependencyOne; public class Class1 : IConvention { } + +public static class Example1 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} + " ) .Build() @@ -50,6 +68,7 @@ public static Task Class2(GeneratorTestContextBuilder buil .WithProjectName("SampleDependencyTwo") .AddSources( @"using Rocket.Surgery.Conventions; +using FluentValidation; [assembly: ExportConventions(Namespace = null, ClassName = ""Dep2Exports"")] namespace Sample.DependencyTwo; @@ -58,7 +77,23 @@ public static class Nested { [ExportConvention] public class Class2 : IConvention; -}" +} + +public static class Example2 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} + +" ) .Build() .GenerateAsync(); @@ -73,6 +108,7 @@ public static Task Class3(GeneratorTestContextBuilder buil @"using Rocket.Surgery.Conventions; using Sample.DependencyOne; using Sample.DependencyThree; +using FluentValidation; [assembly: Convention(typeof(Class3))] @@ -82,6 +118,21 @@ public class Class3 : IConvention { public Class1? Class1 { get; set; } } + +public static class Example3 +{ + public record Request(string A, double B); + + private class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.A).NotEmpty(); + RuleFor(x => x.B).GreaterThan(0); + } + } +} + " ) .Build() @@ -154,4 +205,4 @@ public class Class3 : IConvention .Build() .GenerateAsync(); } -} \ No newline at end of file +} diff --git a/test/Analyzers.Tests/GeneratorTestContextBuilderExtensions.cs b/test/Analyzers.Tests/GeneratorTestContextBuilderExtensions.cs index 5d7b1dc78..78279c83a 100644 --- a/test/Analyzers.Tests/GeneratorTestContextBuilderExtensions.cs +++ b/test/Analyzers.Tests/GeneratorTestContextBuilderExtensions.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Reflection; +using FluentValidation; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -26,7 +27,8 @@ public static GeneratorTestContextBuilder AddCommonReferences(this GeneratorTest typeof(ConventionContext).Assembly, typeof(IConventionContext).Assembly, typeof(IServiceProvider).Assembly, - typeof(IConfiguration).Assembly + typeof(IConfiguration).Assembly, + typeof(IValidator).Assembly ); } @@ -48,4 +50,4 @@ public static GeneratorTestContextBuilder AddCommonGenerators(this GeneratorTest && z.GetCustomAttributes().Any() ) .ToImmutableArray(); -} \ No newline at end of file +} diff --git a/test/Analyzers.Tests/GetTypesTestsData.cs b/test/Analyzers.Tests/GetTypesTestsData.cs index 5aa36f5ce..f5cfe7d30 100644 --- a/test/Analyzers.Tests/GetTypesTestsData.cs +++ b/test/Analyzers.Tests/GetTypesTestsData.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Runtime.CompilerServices; +using FluentValidation; using Microsoft.Extensions.Configuration; using Rocket.Surgery.Conventions.Configuration; using Rocket.Surgery.Conventions.DependencyInjection; @@ -12,7 +13,10 @@ public class GetTypesTestsData public static IEnumerable GetTypesData() { // ReSharper disable RedundantNameQualifier - + yield return TestMethod(z => z + .FromAssemblyDependenciesOf() + .GetTypes(x => x.NotInfoOf(TypeInfoFilter.Abstract).AssignableTo(typeof(AbstractValidator<>)))); +yield break; yield return TestMethod(z => z.FromAssemblyOf().GetTypes(x => x.StartsWith("IService"))); yield return TestMethod(z => z.FromAssemblyOf().GetTypes(x => x.StartsWith("S").EndsWith("Convention"))); @@ -221,4 +225,4 @@ public override string ToString() return Name; } } -} \ No newline at end of file +} diff --git a/test/Analyzers.Tests/Rocket.Surgery.Conventions.Analyzers.Tests.csproj b/test/Analyzers.Tests/Rocket.Surgery.Conventions.Analyzers.Tests.csproj index c09b43a44..a6fd81960 100644 --- a/test/Analyzers.Tests/Rocket.Surgery.Conventions.Analyzers.Tests.csproj +++ b/test/Analyzers.Tests/Rocket.Surgery.Conventions.Analyzers.Tests.csproj @@ -5,6 +5,7 @@ + diff --git a/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55#Compiled_AssemblyProvider.verified.cs b/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55#Compiled_AssemblyProvider.verified.cs new file mode 100644 index 000000000..50b42c1f9 --- /dev/null +++ b/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55#Compiled_AssemblyProvider.verified.cs @@ -0,0 +1,48 @@ +//HintName: Rocket.Surgery.Conventions.Analyzers/Rocket.Surgery.Conventions.ConventionAttributesGenerator/Compiled_AssemblyProvider.cs +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; +using Rocket.Surgery.Conventions; +using Rocket.Surgery.Conventions.Reflection; +using System.Runtime.Loader; + +[assembly: System.Reflection.AssemblyMetadata("Rocket.Surgery.ConventionConfigurationData.AssemblyProvider.GetTypes","")] +namespace TestProject.Conventions +{ + internal sealed partial class Imports + { +#pragma warning disable CA1822 + public IAssemblyProvider CreateAssemblyProvider(ConventionContextBuilder builder) => new AssemblyProvider(builder.Properties.GetRequiredService()); + [System.CodeDom.Compiler.GeneratedCode("Rocket.Surgery.Conventions.Analyzers", "version"), System.Runtime.CompilerServices.CompilerGenerated, System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + private class AssemblyProvider(AssemblyLoadContext context) : IAssemblyProvider + { + IEnumerable IAssemblyProvider.GetAssemblies(Action action, string filePath, string memberName, int lineNumber) + { + yield break; + } + + IEnumerable IAssemblyProvider.GetTypes(Func> selector, string filePath, string memberName, int lineNumber) + { + switch (lineNumber) + { + // FilePath: Input1.cs Member: Register + case 18: + yield return SampleDependencyOne.GetType("Sample.DependencyOne.Example1+Validator"); + yield return SampleDependencyThree.GetType("Sample.DependencyThree.Example3+Validator"); + yield return SampleDependencyTwo.GetType("Sample.DependencyTwo.Example2+Validator"); + break; + } + } + + private Assembly _SampleDependencyOne; + private Assembly SampleDependencyOne => _SampleDependencyOne ??= context.LoadFromAssemblyName(new AssemblyName("SampleDependencyOne, Version=version, Culture=neutral, PublicKeyToken=null")); + + private Assembly _SampleDependencyThree; + private Assembly SampleDependencyThree => _SampleDependencyThree ??= context.LoadFromAssemblyName(new AssemblyName("SampleDependencyThree, Version=version, Culture=neutral, PublicKeyToken=null")); + + private Assembly _SampleDependencyTwo; + private Assembly SampleDependencyTwo => _SampleDependencyTwo ??= context.LoadFromAssemblyName(new AssemblyName("SampleDependencyTwo, Version=version, Culture=neutral, PublicKeyToken=null")); + } + } +} \ No newline at end of file diff --git a/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55.verified.txt b/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55.verified.txt new file mode 100644 index 000000000..ace28914d --- /dev/null +++ b/test/Analyzers.Tests/snapshots/AssemblyProviderTests.Should_Generate_Assembly_Provider_For_GetTypes_ab0faba7cb546c55.verified.txt @@ -0,0 +1,23 @@ +{ + FinalDiagnostics: [], + GeneratorDiagnostics: { + Rocket.Surgery.Conventions.ConventionAttributesGenerator: [] + }, + References: [ + , + , + , + FluentValidation.dll, + Microsoft.Extensions.Configuration.Abstractions.dll, + Microsoft.Extensions.DependencyInjection.Abstractions.dll, + mscorlib.dll, + netstandard.dll, + Rocket.Surgery.Conventions.Abstractions.dll, + Rocket.Surgery.Conventions.dll, + System.ComponentModel.dll, + System.Core.dll, + System.dll, + System.Private.CoreLib.dll, + System.Runtime.dll + ] +} \ No newline at end of file