diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.00.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.00.verified.cs new file mode 100644 index 0000000..c0f90b4 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.00.verified.cs @@ -0,0 +1,149 @@ +//HintName: Splat.DI.Extensions.SourceGenerated.cs + +// +namespace Splat +{ + /// + /// Extension methods for the Splat DI source generator. + /// + internal static partial class SplatRegistrations + { + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// The threading mode. + public static void RegisterLazySingleton(System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + /// The threading mode. + public static void RegisterLazySingleton(string contract, System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a lazy class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + + /// + /// Registers a lazy class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Proxy for the Splat SetService. + /// + public static void RegisterConstant(T instance) => Splat.Locator.CurrentMutable.RegisterConstant(instance); + + /// + /// Proxy for the Splat SetService. + /// + /// Optional contract. + public static void RegisterConstant(T instance, string contract) => Splat.Locator.CurrentMutable.RegisterConstant(instance, contract); + + /// + /// Registers the registrations. + /// + public static void SetupIOC() + { + SetupIOCInternal(Splat.Locator.GetLocator()); + } + + /// + /// Registers the registrations. + /// + /// The resolver to register with. + public static void SetupIOC(Splat.IDependencyResolver resolver) + { + SetupIOCInternal(resolver); + } + + + static partial void SetupIOCInternal(Splat.IDependencyResolver resolver); + } + + /// + /// Makes the property get added by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Property)] + internal class DependencyInjectionPropertyAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionPropertyAttribute() + { + } + } + + /// + /// Makes this the constructor used by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Constructor)] + internal class DependencyInjectionConstructorAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionConstructorAttribute() + { + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.01.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.01.verified.cs new file mode 100644 index 0000000..2abea93 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=.01.verified.cs @@ -0,0 +1,19 @@ +//HintName: Splat.DI.Extensions.Registrations.SourceGenerated.cs + +// +namespace Splat +{ + internal static partial class SplatRegistrations + { + static partial void SetupIOCInternal( Splat.IDependencyResolver resolver) + { + Splat.Locator.CurrentMutable.Register(() => new global::Test.TestConcrete((global::Test.IService1)resolver.GetService(typeof(global::Test.IService1)), (global::System.Lazy)resolver.GetService(typeof(global::System.Lazy))){ ServiceProperty1=(global::Test.IServiceProperty1)resolver.GetService(typeof(global::Test.IServiceProperty1)), ServiceProperty2=(global::Test.IServiceProperty2)resolver.GetService(typeof(global::Test.IServiceProperty2)), ServiceProperty3=(global::Test.IServiceProperty3)resolver.GetService(typeof(global::Test.IServiceProperty3))} , typeof(global::Test.ITest)); + Splat.Locator.CurrentMutable.Register(() => new global::Test.Service1(), typeof(global::Test.IService1)); + { + global::System.Lazy lazy = new global::System.Lazy(() => new global::Test.Service2()); + Splat.Locator.CurrentMutable.Register(() => lazy, typeof(global::System.Lazy)); + Splat.Locator.CurrentMutable.Register(() => lazy.Value, typeof(global::Test.IService2)); + } + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.00.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.00.verified.cs new file mode 100644 index 0000000..c0f90b4 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.00.verified.cs @@ -0,0 +1,149 @@ +//HintName: Splat.DI.Extensions.SourceGenerated.cs + +// +namespace Splat +{ + /// + /// Extension methods for the Splat DI source generator. + /// + internal static partial class SplatRegistrations + { + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// The threading mode. + public static void RegisterLazySingleton(System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + /// The threading mode. + public static void RegisterLazySingleton(string contract, System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a lazy class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + + /// + /// Registers a lazy class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Proxy for the Splat SetService. + /// + public static void RegisterConstant(T instance) => Splat.Locator.CurrentMutable.RegisterConstant(instance); + + /// + /// Proxy for the Splat SetService. + /// + /// Optional contract. + public static void RegisterConstant(T instance, string contract) => Splat.Locator.CurrentMutable.RegisterConstant(instance, contract); + + /// + /// Registers the registrations. + /// + public static void SetupIOC() + { + SetupIOCInternal(Splat.Locator.GetLocator()); + } + + /// + /// Registers the registrations. + /// + /// The resolver to register with. + public static void SetupIOC(Splat.IDependencyResolver resolver) + { + SetupIOCInternal(resolver); + } + + + static partial void SetupIOCInternal(Splat.IDependencyResolver resolver); + } + + /// + /// Makes the property get added by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Property)] + internal class DependencyInjectionPropertyAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionPropertyAttribute() + { + } + } + + /// + /// Makes this the constructor used by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Constructor)] + internal class DependencyInjectionConstructorAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionConstructorAttribute() + { + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.01.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.01.verified.cs new file mode 100644 index 0000000..c3807e1 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test1.01.verified.cs @@ -0,0 +1,19 @@ +//HintName: Splat.DI.Extensions.Registrations.SourceGenerated.cs + +// +namespace Splat +{ + internal static partial class SplatRegistrations + { + static partial void SetupIOCInternal( Splat.IDependencyResolver resolver) + { + Splat.Locator.CurrentMutable.Register(() => new global::Test.TestConcrete((global::Test.IService1)resolver.GetService(typeof(global::Test.IService1)), (global::System.Lazy)resolver.GetService(typeof(global::System.Lazy))){ ServiceProperty1=(global::Test.IServiceProperty1)resolver.GetService(typeof(global::Test.IServiceProperty1)), ServiceProperty2=(global::Test.IServiceProperty2)resolver.GetService(typeof(global::Test.IServiceProperty2)), ServiceProperty3=(global::Test.IServiceProperty3)resolver.GetService(typeof(global::Test.IServiceProperty3))} , typeof(global::Test.ITest), "Test1"); + Splat.Locator.CurrentMutable.Register(() => new global::Test.Service1(), typeof(global::Test.IService1), "Test1"); + { + global::System.Lazy lazy = new global::System.Lazy(() => new global::Test.Service2()); + Splat.Locator.CurrentMutable.Register(() => lazy, typeof(global::System.Lazy), "Test1"); + Splat.Locator.CurrentMutable.Register(() => lazy.Value, typeof(global::Test.IService2), "Test1"); + } + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.00.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.00.verified.cs new file mode 100644 index 0000000..c0f90b4 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.00.verified.cs @@ -0,0 +1,149 @@ +//HintName: Splat.DI.Extensions.SourceGenerated.cs + +// +namespace Splat +{ + /// + /// Extension methods for the Splat DI source generator. + /// + internal static partial class SplatRegistrations + { + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + /// + /// Registers a class with its concrete class. + /// + /// The threading mode. + public static void RegisterLazySingleton(System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + /// The threading mode. + public static void RegisterLazySingleton(string contract, System.Threading.LazyThreadSafetyMode mode) + { + } + + /// + /// Registers a class with its concrete class. + /// + public static void Register() + { + } + + + /// + /// Registers a class with its concrete class. + /// + /// Optional contract. + public static void Register(string contract) + { + } + + /// + /// Registers a lazy class with its concrete class. + /// + public static void RegisterLazySingleton() + { + } + + + /// + /// Registers a lazy class with its concrete class. + /// + /// Optional contract. + public static void RegisterLazySingleton(string contract) + { + } + + /// + /// Proxy for the Splat SetService. + /// + public static void RegisterConstant(T instance) => Splat.Locator.CurrentMutable.RegisterConstant(instance); + + /// + /// Proxy for the Splat SetService. + /// + /// Optional contract. + public static void RegisterConstant(T instance, string contract) => Splat.Locator.CurrentMutable.RegisterConstant(instance, contract); + + /// + /// Registers the registrations. + /// + public static void SetupIOC() + { + SetupIOCInternal(Splat.Locator.GetLocator()); + } + + /// + /// Registers the registrations. + /// + /// The resolver to register with. + public static void SetupIOC(Splat.IDependencyResolver resolver) + { + SetupIOCInternal(resolver); + } + + + static partial void SetupIOCInternal(Splat.IDependencyResolver resolver); + } + + /// + /// Makes the property get added by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Property)] + internal class DependencyInjectionPropertyAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionPropertyAttribute() + { + } + } + + /// + /// Makes this the constructor used by the DI engine. + /// + [System.AttributeUsage(System.AttributeTargets.Constructor)] + internal class DependencyInjectionConstructorAttribute : System.Attribute + { + /// + /// Initializes a new instance of the class. + /// + public DependencyInjectionConstructorAttribute() + { + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.01.verified.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.01.verified.cs new file mode 100644 index 0000000..7226579 --- /dev/null +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.LazyParameterRegisteredLazy_contract=Test2.01.verified.cs @@ -0,0 +1,19 @@ +//HintName: Splat.DI.Extensions.Registrations.SourceGenerated.cs + +// +namespace Splat +{ + internal static partial class SplatRegistrations + { + static partial void SetupIOCInternal( Splat.IDependencyResolver resolver) + { + Splat.Locator.CurrentMutable.Register(() => new global::Test.TestConcrete((global::Test.IService1)resolver.GetService(typeof(global::Test.IService1)), (global::System.Lazy)resolver.GetService(typeof(global::System.Lazy))){ ServiceProperty1=(global::Test.IServiceProperty1)resolver.GetService(typeof(global::Test.IServiceProperty1)), ServiceProperty2=(global::Test.IServiceProperty2)resolver.GetService(typeof(global::Test.IServiceProperty2)), ServiceProperty3=(global::Test.IServiceProperty3)resolver.GetService(typeof(global::Test.IServiceProperty3))} , typeof(global::Test.ITest), "Test2"); + Splat.Locator.CurrentMutable.Register(() => new global::Test.Service1(), typeof(global::Test.IService1), "Test2"); + { + global::System.Lazy lazy = new global::System.Lazy(() => new global::Test.Service2()); + Splat.Locator.CurrentMutable.Register(() => lazy, typeof(global::System.Lazy), "Test2"); + Splat.Locator.CurrentMutable.Register(() => lazy.Value, typeof(global::Test.IService2), "Test2"); + } + } + } +} \ No newline at end of file diff --git a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.cs b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.cs index b4c0485..6fd0b11 100644 --- a/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.cs +++ b/src/Splat.DependencyInjection.SourceGenerator.Tests/RegisterLazySingletonTests.cs @@ -83,5 +83,67 @@ public interface IServiceProperty3 {{ }} return TestPass(source, contract, mode); } + + [Theory] + [InlineData("")] + [InlineData("Test1")] + [InlineData("Test2")] + public Task LazyParameterRegisteredLazy(string contract) + { + string arguments; + if (string.IsNullOrWhiteSpace(contract)) + { + arguments = string.Empty; + } + else + { + arguments = $"\"{contract}\""; + } + + var source = @$" +using System; +using System.Threading; +using Splat; + +namespace Test +{{ + public static class DIRegister + {{ + static DIRegister() + {{ + SplatRegistrations.Register({arguments}); + SplatRegistrations.Register({arguments}); + SplatRegistrations.RegisterLazySingleton({arguments}); + }} + }} + + public interface ITest {{ }} + public class TestConcrete : ITest + {{ + public TestConcrete(IService1 service1, Lazy service) + {{ + }} + + [DependencyInjectionProperty] + public IServiceProperty1 ServiceProperty1 {{ get; set; }} + + [DependencyInjectionProperty] + public IServiceProperty2 ServiceProperty2 {{ get; set; }} + + [DependencyInjectionProperty] + internal IServiceProperty3 ServiceProperty3 {{ get; set; }} + }} + + public interface IService1 {{ }} + public class Service1 : IService1 {{ }} + public interface IService2 {{ }} + public class Service2 : IService2 {{ }} + public interface IServiceProperty1 {{ }} + public interface IServiceProperty2 {{ }} + public interface IServiceProperty3 {{ }} +}}"; + + return TestPass(source, contract); + } } } diff --git a/src/Splat.DependencyInjection.SourceGenerator/MetadataDependencyChecker.cs b/src/Splat.DependencyInjection.SourceGenerator/MetadataDependencyChecker.cs index 259bd49..c38247d 100644 --- a/src/Splat.DependencyInjection.SourceGenerator/MetadataDependencyChecker.cs +++ b/src/Splat.DependencyInjection.SourceGenerator/MetadataDependencyChecker.cs @@ -49,7 +49,10 @@ public static List CheckMetadata(GeneratorExecutionContext conte { if (childConstructor.TypeName == metadataMethod.InterfaceTypeName) { - throw new ContextDiagnosticException(Diagnostic.Create(DiagnosticWarnings.ConstructorsMustNotHaveCircularDependency, childConstructor.Parameter.Locations.FirstOrDefault() ?? metadataMethod.MethodInvocation.GetLocation())); + throw new ContextDiagnosticException( + Diagnostic.Create( + DiagnosticWarnings.ConstructorsMustNotHaveCircularDependency, + childConstructor.Parameter.Locations.FirstOrDefault() ?? metadataMethod.MethodInvocation.GetLocation())); } } } @@ -67,7 +70,15 @@ public static List CheckMetadata(GeneratorExecutionContext conte if (metadataDependencies.TryGetValue(lazyType.ToDisplayString(RoslynCommonHelpers.TypeFormat), out dependencyMethod)) { - throw new ContextDiagnosticException(Diagnostic.Create(DiagnosticWarnings.LazyParameterNotRegisteredLazy, constructorDependency.Parameter.Locations.FirstOrDefault() ?? metadataMethod.MethodInvocation.GetLocation(), metadataMethod.ConcreteTypeName, constructorDependency.Parameter.Name)); + if (!dependencyMethod.IsLazy) + { + throw new ContextDiagnosticException( + Diagnostic.Create( + DiagnosticWarnings.LazyParameterNotRegisteredLazy, + constructorDependency.Parameter.Locations.FirstOrDefault() ?? metadataMethod.MethodInvocation.GetLocation(), + metadataMethod.ConcreteTypeName, + constructorDependency.Parameter.Name)); + } } } }