diff --git a/osu.Framework.Benchmarks/BenchmarkDependencyInjection.cs b/osu.Framework.Benchmarks/BenchmarkDependencyInjection.cs index f05315e64b..1cc54402d5 100644 --- a/osu.Framework.Benchmarks/BenchmarkDependencyInjection.cs +++ b/osu.Framework.Benchmarks/BenchmarkDependencyInjection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Diagnostics.CodeAnalysis; using BenchmarkDotNet.Attributes; using osu.Framework.Allocation; @@ -40,7 +41,8 @@ public void TestWithSourceGenerator() } } - public class ClassInjectedWithReflection + [SuppressMessage("Performance", "OFSG001:Class contributes to dependency injection and should be partial")] + public class ClassInjectedWithReflection : IDependencyInjectionCandidate { // ReSharper disable once UnusedAutoPropertyAccessor.Local [Resolved] @@ -49,7 +51,7 @@ public class ClassInjectedWithReflection // This inspection can be removed once the source generator is merged in/referenced as a package. // ReSharper disable once PartialTypeWithSinglePart - public partial class ClassInjectedWithSourceGenerator + public partial class ClassInjectedWithSourceGenerator : IDependencyInjectionCandidate { // ReSharper disable once UnusedAutoPropertyAccessor.Local [Resolved] diff --git a/osu.Framework.SourceGeneration.Tests/DependencyInjectionSourceGeneratorTests.cs b/osu.Framework.SourceGeneration.Tests/DependencyInjectionSourceGeneratorTests.cs index 4e172eebba..32a2a5041e 100644 --- a/osu.Framework.SourceGeneration.Tests/DependencyInjectionSourceGeneratorTests.cs +++ b/osu.Framework.SourceGeneration.Tests/DependencyInjectionSourceGeneratorTests.cs @@ -31,8 +31,7 @@ public class DependencyInjectionSourceGeneratorTests : AbstractGeneratorTests [InlineData("NestedCachedClass")] [InlineData("MultipleCachedMember")] [InlineData("CachedInheritedInterface")] - // Todo: Fix this. - // [InlineData("CachedBaseType")] + [InlineData("CachedBaseType")] public async Task Check(string name) => await RunTest(name).ConfigureAwait(false); protected override Task Verify((string filename, string content)[] sources, (string filename, string content)[] generated) diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Generated/g_DerivedType_Dependencies.txt b/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Generated/g_DerivedType_Dependencies.txt index a6847c04b6..fbaf3f5f64 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Generated/g_DerivedType_Dependencies.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Generated/g_DerivedType_Dependencies.txt @@ -4,10 +4,11 @@ partial class DerivedType : osu.Framework.Allocation.ISourceGeneratedDependencyActivator { - public virtual void RegisterForDependencyActivation(osu.Framework.Allocation.IDependencyActivatorRegistry registry) + public override void RegisterForDependencyActivation(osu.Framework.Allocation.IDependencyActivatorRegistry registry) { if (registry.IsRegistered(typeof(DerivedType))) return; + base.RegisterForDependencyActivation(registry); registry.Register(typeof(DerivedType), null, null); } } \ No newline at end of file diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Sources/BaseType.txt b/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Sources/BaseType.txt index 9668043dc3..de4881b245 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Sources/BaseType.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CachedBaseType/Sources/BaseType.txt @@ -1,4 +1,4 @@ [osu.Framework.Allocation.Cached] -public partial class BaseType +public partial class BaseType : osu.Framework.Allocation.IDependencyInjectionCandidate { } \ No newline at end of file diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/DependencyContainer.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/DependencyContainer.txt index cf8f16f55b..c939a5ceac 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/DependencyContainer.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/DependencyContainer.txt @@ -34,6 +34,6 @@ namespace osu.Framework.Allocation public object Get(Type type, CacheInfo info) => default; - public void Inject(T instance) where T : class { } + public void Inject(T instance) where T : class, IDependencyInjectionCandidate { } } } diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/Drawable.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/Drawable.txt index 1cb2f0543c..aa850d3733 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/Drawable.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/Drawable.txt @@ -1,6 +1,6 @@ namespace osu.Framework.Graphics { - public partial class Drawable : IDrawable + public partial class Drawable : osu.Framework.Allocation.IDependencyInjectionCandidate { } } \ No newline at end of file diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDependencyInjectionCandidate.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDependencyInjectionCandidate.txt new file mode 100644 index 0000000000..5ea24b97a4 --- /dev/null +++ b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDependencyInjectionCandidate.txt @@ -0,0 +1,6 @@ +namespace osu.Framework.Allocation +{ + public interface IDependencyInjectionCandidate + { + } +} diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDrawable.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDrawable.txt deleted file mode 100644 index 62fecab69f..0000000000 --- a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IDrawable.txt +++ /dev/null @@ -1,6 +0,0 @@ -namespace osu.Framework.Graphics -{ - public interface IDrawable - { - } -} \ No newline at end of file diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IReadOnlyDependencyContainer.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IReadOnlyDependencyContainer.txt index 8713c6a525..589e521594 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IReadOnlyDependencyContainer.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/IReadOnlyDependencyContainer.txt @@ -6,7 +6,7 @@ namespace osu.Framework.Allocation { object Get(Type type); object Get(Type type, CacheInfo info); - void Inject(T instance) where T : class; + void Inject(T instance) where T : class, IDependencyInjectionCandidate; } public static class ReadOnlyDependencyContainerExtensions diff --git a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/SourceGeneratorUtils.txt b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/SourceGeneratorUtils.txt index 1323a3e998..edf9c5b236 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/SourceGeneratorUtils.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/CommonSources/SourceGeneratorUtils.txt @@ -7,7 +7,7 @@ namespace osu.Framework.Utils { public static class SourceGeneratorUtils { - public static void CacheDependency(DependencyContainer container, Type callerType, object obj, CacheInfo info, Type? asType, string? cachedName, string? propertyName) + public static void CacheDependency(DependencyContainer container, Type callerType, object? obj, CacheInfo info, Type? asType, string? cachedName, string? propertyName) { } diff --git a/osu.Framework.SourceGeneration.Tests/Resources/PartialCachedClass/Sources/A.txt b/osu.Framework.SourceGeneration.Tests/Resources/PartialCachedClass/Sources/A.txt index df2d44be57..ba928abdc4 100644 --- a/osu.Framework.SourceGeneration.Tests/Resources/PartialCachedClass/Sources/A.txt +++ b/osu.Framework.SourceGeneration.Tests/Resources/PartialCachedClass/Sources/A.txt @@ -1,4 +1,4 @@ [osu.Framework.Allocation.Cached] -public partial class A +public partial class A : osu.Framework.Allocation.IDependencyInjectionCandidate { } \ No newline at end of file diff --git a/osu.Framework.SourceGeneration/Analysers/DiagnosticRules.cs b/osu.Framework.SourceGeneration/Analysers/DiagnosticRules.cs index 433231cade..dc6a827867 100644 --- a/osu.Framework.SourceGeneration/Analysers/DiagnosticRules.cs +++ b/osu.Framework.SourceGeneration/Analysers/DiagnosticRules.cs @@ -13,12 +13,12 @@ public class DiagnosticRules public static readonly DiagnosticDescriptor MAKE_DI_CLASS_PARTIAL = new DiagnosticDescriptor( "OFSG001", - "Class contributes to dependency injection and should be partial", - "Class contributes to dependency injection and should be partial", + "This class is a candidate for dependency injection and should be partial", + "This class is a candidate for dependency injection and should be partial", "Performance", DiagnosticSeverity.Warning, true, - "Classes contributing to dependency injection should be made partial to be subject to compile-time optimisations. This includes usages of `DependencyActivator` and `CachedModelDependencyContainer`."); + "Classes that are candidates for dependency injection should be made partial to benefit from compile-time optimisations."); #pragma warning restore RS2008 } diff --git a/osu.Framework.SourceGeneration/Analysers/DrawableAnalyser.cs b/osu.Framework.SourceGeneration/Analysers/DrawableAnalyser.cs index 18a25db0cc..ae43c90abf 100644 --- a/osu.Framework.SourceGeneration/Analysers/DrawableAnalyser.cs +++ b/osu.Framework.SourceGeneration/Analysers/DrawableAnalyser.cs @@ -21,88 +21,6 @@ public override void Initialize(AnalysisContext context) context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterSyntaxNodeAction(analyseClass, SyntaxKind.ClassDeclaration); - context.RegisterSyntaxNodeAction(analyseInvocation, SyntaxKind.InvocationExpression); - context.RegisterSyntaxNodeAction(analyseObjectCreation, SyntaxKind.ObjectCreationExpression); - } - - /// - /// Analyses construction of CachedModelDependencyContainer{T}. - /// - private void analyseObjectCreation(SyntaxNodeAnalysisContext context) - { - var objectCreationSyntax = (ObjectCreationExpressionSyntax)context.Node; - - GenericNameSyntax? genericName = objectCreationSyntax.Type as GenericNameSyntax; - - if (objectCreationSyntax.Type is QualifiedNameSyntax qualified) - genericName = qualified.Right as GenericNameSyntax; - - if (genericName == null) - return; - - if (genericName.Identifier.ValueText != "CachedModelDependencyContainer") - return; - - TypeSyntax? typeSyntax = genericName.TypeArgumentList.Arguments.FirstOrDefault(); - - if (typeSyntax == null) - return; - - ITypeSymbol? argumentType = context.SemanticModel.GetTypeInfo(typeSyntax).Type; - SyntaxTree? argumentSyntaxTree = argumentType?.DeclaringSyntaxReferences.FirstOrDefault()?.SyntaxTree; - ClassDeclarationSyntax? argumentClassSyntax = argumentSyntaxTree?.GetRoot().DescendantNodesAndSelf() - .OfType() - .FirstOrDefault(c => c.Identifier.ValueText == argumentType?.Name); - - if (argumentClassSyntax == null) - return; - - if (argumentClassSyntax.Modifiers.Any(SyntaxKind.PartialKeyword)) - return; - - // Todo: Why doesn't this work for nested class? It _is_ getting here... - context.ReportDiagnostic(Diagnostic.Create(DiagnosticRules.MAKE_DI_CLASS_PARTIAL, typeSyntax.GetLocation(), typeSyntax)); - } - - /// - /// Analyses invocations of DependencyContainer.Inject{T}(T obj). - /// - private void analyseInvocation(SyntaxNodeAnalysisContext context) - { - var invocationSyntax = (InvocationExpressionSyntax)context.Node; - - if (invocationSyntax.ArgumentList.Arguments.Count == 0) - return; - - if (invocationSyntax.Expression is not MemberAccessExpressionSyntax memberAccessSyntax) - return; - - if (memberAccessSyntax.Name.Identifier.ValueText != "Inject") - return; - - ITypeSymbol? expressionType = context.SemanticModel.GetTypeInfo(memberAccessSyntax.Expression).Type; - - if (expressionType == null) - return; - - if (!SyntaxHelpers.IsIReadOnlyDependencyContainerInterface(expressionType) && !expressionType.AllInterfaces.Any(SyntaxHelpers.IsIReadOnlyDependencyContainerInterface)) - return; - - ExpressionSyntax argumentExpression = invocationSyntax.ArgumentList.Arguments[0].Expression; - ITypeSymbol? argumentType = context.SemanticModel.GetTypeInfo(argumentExpression).Type; - SyntaxTree? argumentSyntaxTree = argumentType?.DeclaringSyntaxReferences.FirstOrDefault()?.SyntaxTree; - ClassDeclarationSyntax? argumentClassSyntax = argumentSyntaxTree?.GetRoot().DescendantNodesAndSelf() - .OfType() - .FirstOrDefault(c => c.Identifier.ValueText == argumentType?.Name); - - if (argumentClassSyntax == null) - return; - - if (argumentClassSyntax.Modifiers.Any(SyntaxKind.PartialKeyword)) - return; - - // Todo: Why doesn't this work for nested class? It _is_ getting here... - context.ReportDiagnostic(Diagnostic.Create(DiagnosticRules.MAKE_DI_CLASS_PARTIAL, argumentExpression.GetLocation(), argumentExpression)); } /// @@ -117,26 +35,8 @@ private void analyseClass(SyntaxNodeAnalysisContext context) INamedTypeSymbol? type = context.SemanticModel.GetDeclaredSymbol(classSyntax); - if (type != null && requiresPartialClass(type)) + if (type?.AllInterfaces.Any(SyntaxHelpers.IsIDependencyInjectionCandidateInterface) == true) context.ReportDiagnostic(Diagnostic.Create(DiagnosticRules.MAKE_DI_CLASS_PARTIAL, context.Node.GetLocation(), context.Node)); } - - private bool requiresPartialClass(ITypeSymbol type) - { - // "Transformable" is a special class below "Drawable" but still a part of the drawable hierarchy. - // It's the base-most type of all drawable objects, and so needs to be partial (see below). - if (SyntaxHelpers.IsTransformableType(type)) - return true; - - // "IDrawable" classes need to be partial since dependency injection happens implicitly through the drawable hierarchy. - if (type.AllInterfaces.Any(SyntaxHelpers.IsIDrawableInterface)) - return true; - - // "ISourceGeneratedDependencyActivatorInterface" classes need to be partial since their base type is used in dependency injection. - if (type.AllInterfaces.Any(SyntaxHelpers.IsISourceGeneratedDependencyActivatorInterface)) - return true; - - return false; - } } } diff --git a/osu.Framework.SourceGeneration/SyntaxContextReceiver.cs b/osu.Framework.SourceGeneration/SyntaxContextReceiver.cs index 48ed5a7768..8b3f29b709 100644 --- a/osu.Framework.SourceGeneration/SyntaxContextReceiver.cs +++ b/osu.Framework.SourceGeneration/SyntaxContextReceiver.cs @@ -35,31 +35,24 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) return; // Determine if the class is a candidate for the source generator. - // Classes may be candidates even if they don't resolve/cache anything themselves, but a base type does. - foreach (var iFace in symbol.AllInterfaces) - { - // All classes that derive from IDrawable need to use the source generator. - // This is conservative for all other (i.e. non-Drawable) classes to avoid polluting irrelevant classes. - if (SyntaxHelpers.IsIDrawableInterface(iFace) || SyntaxHelpers.IsITransformableInterface(iFace) || SyntaxHelpers.IsISourceGeneratedDependencyActivatorInterface(iFace)) - { - addCandidate(context, classSyntax); - break; - } - } + if (!symbol.AllInterfaces.Any(SyntaxHelpers.IsIDependencyInjectionCandidateInterface)) + return; + + GeneratorClassCandidate candidate = addCandidate(context, classSyntax); // Process any [Cached] attributes on any interface on the class excluding base types. foreach (var iFace in SyntaxHelpers.GetDeclaredInterfacesOnType(symbol)) { // Add an entry if this interface has a cached attribute. if (iFace.GetAttributes().Any(attrib => SyntaxHelpers.IsCachedAttribute(attrib.AttributeClass))) - addCandidate(context, classSyntax).CachedInterfaces.Add(iFace); + candidate.CachedInterfaces.Add(iFace); } // Process any [Cached] attributes on the class. foreach (var attrib in enumerateAttributes(context.SemanticModel, classSyntax)) { if (SyntaxHelpers.IsCachedAttribute(context.SemanticModel, attrib)) - addCandidate(context, classSyntax).CachedClasses.Add(new SyntaxWithSymbol(context, classSyntax)); + candidate.CachedClasses.Add(new SyntaxWithSymbol(context, classSyntax)); } // Process any attributes of members of the class. @@ -68,16 +61,16 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context) foreach (var attrib in enumerateAttributes(context.SemanticModel, member)) { if (SyntaxHelpers.IsBackgroundDependencyLoaderAttribute(context.SemanticModel, attrib)) - addCandidate(context, classSyntax).DependencyLoaderMemebers.Add(new SyntaxWithSymbol(context, member)); + candidate.DependencyLoaderMemebers.Add(new SyntaxWithSymbol(context, member)); if (member is not PropertyDeclarationSyntax && member is not FieldDeclarationSyntax) continue; if (SyntaxHelpers.IsResolvedAttribute(context.SemanticModel, attrib)) - addCandidate(context, classSyntax).ResolvedMembers.Add(new SyntaxWithSymbol(context, member)); + candidate.ResolvedMembers.Add(new SyntaxWithSymbol(context, member)); if (SyntaxHelpers.IsCachedAttribute(context.SemanticModel, attrib)) - addCandidate(context, classSyntax).CachedMembers.Add(new SyntaxWithSymbol(context, member)); + candidate.CachedMembers.Add(new SyntaxWithSymbol(context, member)); } } } diff --git a/osu.Framework.SourceGeneration/SyntaxHelpers.cs b/osu.Framework.SourceGeneration/SyntaxHelpers.cs index 04eda93c7e..e1b0266a91 100644 --- a/osu.Framework.SourceGeneration/SyntaxHelpers.cs +++ b/osu.Framework.SourceGeneration/SyntaxHelpers.cs @@ -131,20 +131,14 @@ public static bool IsResolvedAttribute(ITypeSymbol? type) public static bool IsCachedAttribute(ITypeSymbol? type) => type?.Name == "CachedAttribute"; - public static bool IsIDrawableInterface(ITypeSymbol? type) - => type?.Name == "IDrawable"; - - public static bool IsITransformableInterface(ITypeSymbol? type) - => type?.Name == "ITransformable"; - public static bool IsISourceGeneratedDependencyActivatorInterface(ITypeSymbol? type) => type?.Name == "ISourceGeneratedDependencyActivator"; public static bool IsIReadOnlyDependencyContainerInterface(ITypeSymbol? type) => type?.Name == "IReadOnlyDependencyContainer"; - public static bool IsTransformableType(ITypeSymbol? type) - => type?.Name == "Transformable"; + public static bool IsIDependencyInjectionCandidateInterface(ITypeSymbol? type) + => type?.Name == "IDependencyInjectionCandidate"; public static IEnumerable EnumerateBaseTypes(ITypeSymbol type) { diff --git a/osu.Framework.Tests/Dependencies/Reflection/CachedAttributeTest.cs b/osu.Framework.Tests/Dependencies/Reflection/CachedAttributeTest.cs index 56c32aa829..1d545aae89 100644 --- a/osu.Framework.Tests/Dependencies/Reflection/CachedAttributeTest.cs +++ b/osu.Framework.Tests/Dependencies/Reflection/CachedAttributeTest.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics.CodeAnalysis; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing.Dependencies; @@ -13,6 +14,7 @@ namespace osu.Framework.Tests.Dependencies.Reflection { [TestFixture] + [SuppressMessage("Performance", "OFSG001:Class contributes to dependency injection and should be partial")] public class CachedAttributeTest { [Test] @@ -319,12 +321,12 @@ private struct ProvidedType3 : IProvidedInterface1 } [Cached] - private class Provider1 + private class Provider1 : IDependencyInjectionCandidate { } [Cached(Type = typeof(object))] - private class Provider2 + private class Provider2 : IDependencyInjectionCandidate { } @@ -333,7 +335,7 @@ private class Provider3 : Provider1 { } - private class Provider4 + private class Provider4 : IDependencyInjectionCandidate { [Cached] #pragma warning disable 169 @@ -341,7 +343,7 @@ private class Provider4 #pragma warning restore 169 } - private class Provider5 + private class Provider5 : IDependencyInjectionCandidate { [Cached] public ProvidedType1 Provided1 { get; } = new ProvidedType1(); @@ -356,7 +358,7 @@ private class Provider6 : Provider5 public ProvidedType1 Provided3 { get; } = new ProvidedType1(); } - private class Provider7 + private class Provider7 : IDependencyInjectionCandidate { [Cached] [Cached(Type = typeof(object))] @@ -365,66 +367,66 @@ private class Provider7 [Cached] [Cached(Type = typeof(object))] - private class Provider8 + private class Provider8 : IDependencyInjectionCandidate { } - private class Provider9 + private class Provider9 : IDependencyInjectionCandidate { [Cached(Type = typeof(ProvidedType1))] private object provided1 = new object(); } - private class Provider10 + private class Provider10 : IDependencyInjectionCandidate { [Cached] private object provided1 = new ProvidedType1(); } - private class Provider11 + private class Provider11 : IDependencyInjectionCandidate { [Cached] [Cached(Type = typeof(IProvidedInterface1))] private IProvidedInterface1 provided1 = new ProvidedType1(); } - private class Provider12 + private class Provider12 : IDependencyInjectionCandidate { [Cached(Type = typeof(IProvidedInterface1))] private IProvidedInterface1 provided1 = new ProvidedType3(); } - private class Provider13 + private class Provider13 : IDependencyInjectionCandidate { [Cached] public object Provided1 = new ProvidedType1(); } - private class Provider14 + private class Provider14 : IDependencyInjectionCandidate { [Cached] protected object Provided1 = new ProvidedType1(); } - private class Provider15 + private class Provider15 : IDependencyInjectionCandidate { [Cached] internal object Provided1 = new ProvidedType1(); } - private class Provider16 + private class Provider16 : IDependencyInjectionCandidate { [Cached] protected internal object Provided1 = new ProvidedType1(); } - private class Provider17 + private class Provider17 : IDependencyInjectionCandidate { [Cached] public readonly object Provided1 = new ProvidedType1(); } - private class Provider18 + private class Provider18 : IDependencyInjectionCandidate { #pragma warning disable 649 [Cached] @@ -432,25 +434,25 @@ private class Provider18 #pragma warning restore 649 } - private class Provider19 + private class Provider19 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; private set; } = new object(); } - private class Provider20 + private class Provider20 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; } = new object(); } - private class Provider21 + private class Provider21 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; set; } } - private class Provider22 + private class Provider22 : IDependencyInjectionCandidate { [Cached] public object Provided1 @@ -463,7 +465,7 @@ public object Provided1 } } - private class Provider23 + private class Provider23 : IDependencyInjectionCandidate { [Cached] public object Provided1 @@ -475,7 +477,7 @@ public object Provided1 } } - private class Provider24 + private class Provider24 : IDependencyInjectionCandidate { [Cached] public object Provided1 => null; @@ -499,7 +501,7 @@ private interface IProviderInterface3 : IProviderInterface2 } [Cached] - private interface IProviderInterface2 + private interface IProviderInterface2 : IDependencyInjectionCandidate { } diff --git a/osu.Framework.Tests/Dependencies/Reflection/CachedModelDependenciesTest.cs b/osu.Framework.Tests/Dependencies/Reflection/CachedModelDependenciesTest.cs index a213e4983a..8c27434c91 100644 --- a/osu.Framework.Tests/Dependencies/Reflection/CachedModelDependenciesTest.cs +++ b/osu.Framework.Tests/Dependencies/Reflection/CachedModelDependenciesTest.cs @@ -144,7 +144,7 @@ public void TestCrossDependentBindsDoNotPollute() Assert.AreEqual(3, model2.BindableTwo.Value); } - private class CrossDependentFieldModel + private class CrossDependentFieldModel : IDependencyInjectionCandidate { [Cached] public readonly Bindable Bindable = new Bindable(1); @@ -269,34 +269,34 @@ public void TestResolveIndividualProperties() Assert.AreEqual(null, resolver.BindableString.Value); } - private class NonBindablePublicFieldModel + private class NonBindablePublicFieldModel : IDependencyInjectionCandidate { #pragma warning disable 649 public readonly int FailingField; #pragma warning restore 649 } - private class NonBindablePrivateFieldModel + private class NonBindablePrivateFieldModel : IDependencyInjectionCandidate { #pragma warning disable 169 private readonly int failingField; #pragma warning restore 169 } - private class NonReadOnlyFieldModel + private class NonReadOnlyFieldModel : IDependencyInjectionCandidate { #pragma warning disable 649 public Bindable Bindable; #pragma warning restore 649 } - private class PropertyModel + private class PropertyModel : IDependencyInjectionCandidate { // ReSharper disable once UnusedMember.Local public Bindable Bindable { get; private set; } } - private class FieldModel + private class FieldModel : IDependencyInjectionCandidate { [Cached] public readonly Bindable Bindable = new Bindable(1); @@ -308,19 +308,19 @@ private class DerivedFieldModel : FieldModel public readonly Bindable BindableString = new Bindable(); } - private class FieldModelResolver + private class FieldModelResolver : IDependencyInjectionCandidate { [Resolved] public FieldModel Model { get; private set; } } - private class DerivedFieldModelResolver + private class DerivedFieldModelResolver : IDependencyInjectionCandidate { [Resolved] public DerivedFieldModel Model { get; private set; } } - private class DerivedFieldModelPropertyResolver + private class DerivedFieldModelPropertyResolver : IDependencyInjectionCandidate { [Resolved(typeof(DerivedFieldModel))] public Bindable Bindable { get; private set; } diff --git a/osu.Framework.Tests/Dependencies/Reflection/DependencyContainerTest.cs b/osu.Framework.Tests/Dependencies/Reflection/DependencyContainerTest.cs index d4b28dbe63..b3eb6c4507 100644 --- a/osu.Framework.Tests/Dependencies/Reflection/DependencyContainerTest.cs +++ b/osu.Framework.Tests/Dependencies/Reflection/DependencyContainerTest.cs @@ -353,7 +353,7 @@ private class DerivedObject : BaseObject { } - private class Receiver1 + private class Receiver1 : IDependencyInjectionCandidate { public Action OnLoad; @@ -361,11 +361,11 @@ private class Receiver1 private void load(BaseObject baseObject, DerivedObject derivedObject) => OnLoad?.Invoke(baseObject, derivedObject); } - private class Receiver2 + private class Receiver2 : IDependencyInjectionCandidate { } - private class Receiver3 + private class Receiver3 : IDependencyInjectionCandidate { public Action OnLoad; @@ -373,7 +373,7 @@ private class Receiver3 private void load(BaseObject baseObject) => OnLoad?.Invoke(baseObject); } - private class Receiver4 + private class Receiver4 : IDependencyInjectionCandidate { public Action Loaded4; @@ -389,7 +389,7 @@ private class Receiver5 : Receiver4 private void load() => Loaded5?.Invoke(); } - private class Receiver6 + private class Receiver6 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] public void Load() @@ -397,7 +397,7 @@ public void Load() } } - private class Receiver7 + private class Receiver7 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] protected void Load() @@ -405,7 +405,7 @@ protected void Load() } } - private class Receiver8 + private class Receiver8 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] internal void Load() @@ -413,7 +413,7 @@ internal void Load() } } - private class Receiver9 + private class Receiver9 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] protected internal void Load() @@ -421,7 +421,7 @@ protected internal void Load() } } - private class Receiver10 + private class Receiver10 : IDependencyInjectionCandidate { public CachedStructProvider.Struct TestObject { get; private set; } @@ -429,7 +429,7 @@ private class Receiver10 private void load(CachedStructProvider.Struct testObject) => TestObject = testObject; } - private class Receiver11 + private class Receiver11 : IDependencyInjectionCandidate { public int? TestObject { get; private set; } @@ -437,7 +437,7 @@ private class Receiver11 private void load(int? testObject) => TestObject = testObject; } - private class Receiver12 + private class Receiver12 : IDependencyInjectionCandidate { [UsedImplicitly] // param used implicitly [BackgroundDependencyLoader] @@ -446,7 +446,7 @@ private void load(int testObject) } } - private class Receiver13 + private class Receiver13 : IDependencyInjectionCandidate { public int? TestObject { get; private set; } = 1; @@ -456,7 +456,7 @@ private class Receiver13 #nullable enable [SuppressMessage("ReSharper", "UnusedParameter.Local")] - private class Receiver14 + private class Receiver14 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] private void load(BaseObject nonNullObject, DerivedObject? nullableObject) diff --git a/osu.Framework.Tests/Dependencies/Reflection/ResolvedAttributeTest.cs b/osu.Framework.Tests/Dependencies/Reflection/ResolvedAttributeTest.cs index 86a1a0f479..9060e21cbb 100644 --- a/osu.Framework.Tests/Dependencies/Reflection/ResolvedAttributeTest.cs +++ b/osu.Framework.Tests/Dependencies/Reflection/ResolvedAttributeTest.cs @@ -225,7 +225,7 @@ private class BaseObject { } - private class Receiver1 + private class Receiver1 : IDependencyInjectionCandidate { #pragma warning disable 649, IDE0032 private BaseObject obj; @@ -235,7 +235,7 @@ private class Receiver1 public BaseObject Obj => obj; } - private class Receiver2 + private class Receiver2 : IDependencyInjectionCandidate { [Resolved] private BaseObject obj { get; set; } @@ -243,7 +243,7 @@ private class Receiver2 public BaseObject Obj => obj; } - private class Receiver3 + private class Receiver3 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] private BaseObject obj { get; set; } @@ -257,37 +257,37 @@ private class Receiver4 : Receiver2 public BaseObject Obj2 => obj; } - private class Receiver5 + private class Receiver5 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; set; } } - private class Receiver6 + private class Receiver6 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; protected set; } } - private class Receiver7 + private class Receiver7 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; internal set; } } - private class Receiver8 + private class Receiver8 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; private set; } } - private class Receiver9 + private class Receiver9 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; protected internal set; } } - private class Receiver10 + private class Receiver10 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; } @@ -297,31 +297,31 @@ private class Receiver11 : Receiver8 { } - private class Receiver12 + private class Receiver12 : IDependencyInjectionCandidate { [Resolved] public CachedStructProvider.Struct Obj { get; private set; } } - private class Receiver13 + private class Receiver13 : IDependencyInjectionCandidate { [Resolved] public int? Obj { get; private set; } } - private class Receiver14 + private class Receiver14 : IDependencyInjectionCandidate { [Resolved] public int Obj { get; private set; } } - private class Receiver15 + private class Receiver15 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public int Obj { get; private set; } = 1; } - private class Receiver16 + private class Receiver16 : IDependencyInjectionCandidate { [Resolved] public Bindable Obj { get; private set; } @@ -331,13 +331,13 @@ private class Receiver16 } #nullable enable - private class Receiver17 + private class Receiver17 : IDependencyInjectionCandidate { [Resolved] public Bindable? Obj { get; private set; } } - private class Receiver18 + private class Receiver18 : IDependencyInjectionCandidate { [Resolved] public Bindable Obj { get; private set; } = null!; diff --git a/osu.Framework.Tests/Dependencies/SourceGeneration/CachedAttributeTest.cs b/osu.Framework.Tests/Dependencies/SourceGeneration/CachedAttributeTest.cs index adf9134492..e7fce72e88 100644 --- a/osu.Framework.Tests/Dependencies/SourceGeneration/CachedAttributeTest.cs +++ b/osu.Framework.Tests/Dependencies/SourceGeneration/CachedAttributeTest.cs @@ -141,11 +141,11 @@ public void TestCacheStructAsInterface() [Test] public void TestCacheStructInternal() { - var provider = new CachedStructProvider(); + var provider = new PartialCachedStructProvider(); var dependencies = DependencyActivator.MergeDependencies(provider, new DependencyContainer()); - Assert.AreEqual(provider.CachedObject.Value, dependencies.GetValue().Value); + Assert.AreEqual(provider.CachedObject.Value, dependencies.GetValue().Value); } [Test] @@ -161,7 +161,7 @@ public void TestGetValueNullInternal() [TestCase(10)] public void TestCacheNullableInternal(int? testValue) { - var provider = new CachedNullableProvider(); + var provider = new PartialCachedNullableProvider(); provider.SetValue(testValue); @@ -318,12 +318,12 @@ private struct ProvidedType3 : IProvidedInterface1 } [Cached] - private partial class Provider1 + private partial class Provider1 : IDependencyInjectionCandidate { } [Cached(Type = typeof(object))] - private partial class Provider2 + private partial class Provider2 : IDependencyInjectionCandidate { } @@ -332,7 +332,7 @@ private partial class Provider3 : Provider1 { } - private partial class Provider4 + private partial class Provider4 : IDependencyInjectionCandidate { [Cached] #pragma warning disable 0649 @@ -340,7 +340,7 @@ private partial class Provider4 #pragma warning restore 0649 } - private partial class Provider5 + private partial class Provider5 : IDependencyInjectionCandidate { [Cached] public ProvidedType1 Provided1 { get; } = new ProvidedType1(); @@ -355,7 +355,7 @@ private partial class Provider6 : Provider5 public ProvidedType1 Provided3 { get; } = new ProvidedType1(); } - private partial class Provider7 + private partial class Provider7 : IDependencyInjectionCandidate { [Cached] [Cached(Type = typeof(object))] @@ -364,66 +364,66 @@ private partial class Provider7 [Cached] [Cached(Type = typeof(object))] - private partial class Provider8 + private partial class Provider8 : IDependencyInjectionCandidate { } - private partial class Provider9 + private partial class Provider9 : IDependencyInjectionCandidate { [Cached(Type = typeof(ProvidedType1))] private object provided1 = new object(); } - private partial class Provider10 + private partial class Provider10 : IDependencyInjectionCandidate { [Cached] private object provided1 = new ProvidedType1(); } - private partial class Provider11 + private partial class Provider11 : IDependencyInjectionCandidate { [Cached] [Cached(Type = typeof(IProvidedInterface1))] private IProvidedInterface1 provided1 = new ProvidedType1(); } - private partial class Provider12 + private partial class Provider12 : IDependencyInjectionCandidate { [Cached(Type = typeof(IProvidedInterface1))] private IProvidedInterface1 provided1 = new ProvidedType3(); } - private partial class Provider13 + private partial class Provider13 : IDependencyInjectionCandidate { [Cached] public object Provided1 = new ProvidedType1(); } - private partial class Provider14 + private partial class Provider14 : IDependencyInjectionCandidate { [Cached] protected object Provided1 = new ProvidedType1(); } - private partial class Provider15 + private partial class Provider15 : IDependencyInjectionCandidate { [Cached] internal object Provided1 = new ProvidedType1(); } - private partial class Provider16 + private partial class Provider16 : IDependencyInjectionCandidate { [Cached] protected internal object Provided1 = new ProvidedType1(); } - private partial class Provider17 + private partial class Provider17 : IDependencyInjectionCandidate { [Cached] public readonly object Provided1 = new ProvidedType1(); } - private partial class Provider18 + private partial class Provider18 : IDependencyInjectionCandidate { #pragma warning disable 649 [Cached] @@ -431,25 +431,25 @@ private partial class Provider18 #pragma warning restore 649 } - private partial class Provider19 + private partial class Provider19 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; private set; } = new object(); } - private partial class Provider20 + private partial class Provider20 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; } = new object(); } - private partial class Provider21 + private partial class Provider21 : IDependencyInjectionCandidate { [Cached] public object Provided1 { get; set; } } - private partial class Provider22 + private partial class Provider22 : IDependencyInjectionCandidate { [Cached] public object Provided1 @@ -462,7 +462,7 @@ public object Provided1 } } - private partial class Provider24 + private partial class Provider24 : IDependencyInjectionCandidate { [Cached] public object Provided1 => null; @@ -487,7 +487,7 @@ private interface IProviderInterface3 : IProviderInterface2 } [Cached] - private interface IProviderInterface2 + private interface IProviderInterface2 : IDependencyInjectionCandidate { } diff --git a/osu.Framework.Tests/Dependencies/SourceGeneration/CachedModelDependenciesTest.cs b/osu.Framework.Tests/Dependencies/SourceGeneration/CachedModelDependenciesTest.cs index 5b43294c74..5048379cbb 100644 --- a/osu.Framework.Tests/Dependencies/SourceGeneration/CachedModelDependenciesTest.cs +++ b/osu.Framework.Tests/Dependencies/SourceGeneration/CachedModelDependenciesTest.cs @@ -142,7 +142,7 @@ public void TestCrossDependentBindsDoNotPollute() Assert.AreEqual(3, model2.BindableTwo.Value); } - private partial class CrossDependentFieldModel + private partial class CrossDependentFieldModel : IDependencyInjectionCandidate { [Cached] public readonly Bindable Bindable = new Bindable(1); @@ -268,7 +268,7 @@ public void TestResolveIndividualProperties() } [Cached] - private partial class NonBindablePublicFieldModel + private partial class NonBindablePublicFieldModel : IDependencyInjectionCandidate { #pragma warning disable 649 public readonly int FailingField; @@ -276,7 +276,7 @@ private partial class NonBindablePublicFieldModel } [Cached] - private partial class NonBindablePrivateFieldModel + private partial class NonBindablePrivateFieldModel : IDependencyInjectionCandidate { #pragma warning disable 169 private readonly int failingField; @@ -284,7 +284,7 @@ private partial class NonBindablePrivateFieldModel } [Cached] - private partial class NonReadOnlyFieldModel + private partial class NonReadOnlyFieldModel : IDependencyInjectionCandidate { #pragma warning disable 649 public Bindable Bindable; @@ -292,13 +292,13 @@ private partial class NonReadOnlyFieldModel } [Cached] - private partial class PropertyModel + private partial class PropertyModel : IDependencyInjectionCandidate { // ReSharper disable once UnusedMember.Local public Bindable Bindable { get; private set; } } - private partial class FieldModel + private partial class FieldModel : IDependencyInjectionCandidate { [Cached] public readonly Bindable Bindable = new Bindable(1); @@ -310,19 +310,19 @@ private partial class DerivedFieldModel : FieldModel public readonly Bindable BindableString = new Bindable(); } - private partial class FieldModelResolver + private partial class FieldModelResolver : IDependencyInjectionCandidate { [Resolved] public FieldModel Model { get; private set; } } - private partial class DerivedFieldModelResolver + private partial class DerivedFieldModelResolver : IDependencyInjectionCandidate { [Resolved] public DerivedFieldModel Model { get; private set; } } - private partial class DerivedFieldModelPropertyResolver + private partial class DerivedFieldModelPropertyResolver : IDependencyInjectionCandidate { [Resolved(typeof(DerivedFieldModel))] public Bindable Bindable { get; private set; } diff --git a/osu.Framework.Tests/Dependencies/SourceGeneration/DependencyContainerTest.cs b/osu.Framework.Tests/Dependencies/SourceGeneration/DependencyContainerTest.cs index 8e6bb54477..0e644e1e5d 100644 --- a/osu.Framework.Tests/Dependencies/SourceGeneration/DependencyContainerTest.cs +++ b/osu.Framework.Tests/Dependencies/SourceGeneration/DependencyContainerTest.cs @@ -216,7 +216,7 @@ public void TestReceiveStructInternal() { var receiver = new Receiver10(); - var testObject = new CachedStructProvider(); + var testObject = new PartialCachedStructProvider(); var dependencies = DependencyActivator.MergeDependencies(testObject, new DependencyContainer()); @@ -230,7 +230,7 @@ public void TestResolveNullableInternal(int? testValue) { var receiver = new Receiver11(); - var testObject = new CachedNullableProvider(); + var testObject = new PartialCachedNullableProvider(); testObject.SetValue(testValue); var dependencies = DependencyActivator.MergeDependencies(testObject, new DependencyContainer()); @@ -356,7 +356,7 @@ private class DerivedObject : BaseObject { } - private partial class Receiver1 + private partial class Receiver1 : IDependencyInjectionCandidate { public Action OnLoad; @@ -365,11 +365,11 @@ private partial class Receiver1 } [Cached] - private partial class Receiver2 + private partial class Receiver2 : IDependencyInjectionCandidate { } - private partial class Receiver3 + private partial class Receiver3 : IDependencyInjectionCandidate { public Action OnLoad; @@ -377,7 +377,7 @@ private partial class Receiver3 private void load(BaseObject baseObject) => OnLoad?.Invoke(baseObject); } - private partial class Receiver4 + private partial class Receiver4 : IDependencyInjectionCandidate { public Action Loaded4; @@ -393,7 +393,7 @@ private partial class Receiver5 : Receiver4 private void load() => Loaded5?.Invoke(); } - private partial class Receiver6 + private partial class Receiver6 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] public void Load() @@ -401,7 +401,7 @@ public void Load() } } - private partial class Receiver7 + private partial class Receiver7 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] protected void Load() @@ -409,7 +409,7 @@ protected void Load() } } - private partial class Receiver8 + private partial class Receiver8 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] internal void Load() @@ -417,7 +417,7 @@ internal void Load() } } - private partial class Receiver9 + private partial class Receiver9 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] protected internal void Load() @@ -425,15 +425,15 @@ protected internal void Load() } } - private partial class Receiver10 + private partial class Receiver10 : IDependencyInjectionCandidate { - public CachedStructProvider.Struct TestObject { get; private set; } + public PartialCachedStructProvider.Struct TestObject { get; private set; } [BackgroundDependencyLoader] - private void load(CachedStructProvider.Struct testObject) => TestObject = testObject; + private void load(PartialCachedStructProvider.Struct testObject) => TestObject = testObject; } - private partial class Receiver11 + private partial class Receiver11 : IDependencyInjectionCandidate { public int? TestObject { get; private set; } @@ -441,7 +441,7 @@ private partial class Receiver11 private void load(int? testObject) => TestObject = testObject; } - private partial class Receiver12 + private partial class Receiver12 : IDependencyInjectionCandidate { [UsedImplicitly] // param used implicitly [BackgroundDependencyLoader] @@ -450,7 +450,7 @@ private void load(int testObject) } } - private partial class Receiver13 + private partial class Receiver13 : IDependencyInjectionCandidate { public int? TestObject { get; private set; } = 1; @@ -460,7 +460,7 @@ private partial class Receiver13 #nullable enable [SuppressMessage("ReSharper", "UnusedParameter.Local")] - private partial class Receiver14 + private partial class Receiver14 : IDependencyInjectionCandidate { [BackgroundDependencyLoader] private void load(BaseObject nonNullObject, DerivedObject? nullableObject) diff --git a/osu.Framework.Tests/Dependencies/SourceGeneration/ResolvedAttributeTest.cs b/osu.Framework.Tests/Dependencies/SourceGeneration/ResolvedAttributeTest.cs index 0208b46ca9..b599c29f54 100644 --- a/osu.Framework.Tests/Dependencies/SourceGeneration/ResolvedAttributeTest.cs +++ b/osu.Framework.Tests/Dependencies/SourceGeneration/ResolvedAttributeTest.cs @@ -130,7 +130,7 @@ public void TestResolveInternalStruct() { var receiver = new Receiver12(); - var testObject = new CachedStructProvider(); + var testObject = new PartialCachedStructProvider(); var dependencies = DependencyActivator.MergeDependencies(testObject, new DependencyContainer()); @@ -144,7 +144,7 @@ public void TestResolveNullableInternal(int? testValue) { var receiver = new Receiver13(); - var testObject = new CachedNullableProvider(); + var testObject = new PartialCachedNullableProvider(); testObject.SetValue(testValue); var dependencies = DependencyActivator.MergeDependencies(testObject, new DependencyContainer()); @@ -222,7 +222,7 @@ private partial class BaseObject { } - private partial class Receiver1 + private partial class Receiver1 : IDependencyInjectionCandidate { #pragma warning disable 649, IDE0032 private BaseObject obj; @@ -232,7 +232,7 @@ private partial class Receiver1 public BaseObject Obj => obj; } - private partial class Receiver2 + private partial class Receiver2 : IDependencyInjectionCandidate { [Resolved] private BaseObject obj { get; set; } @@ -240,7 +240,7 @@ private partial class Receiver2 public BaseObject Obj => obj; } - private partial class Receiver3 + private partial class Receiver3 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] private BaseObject obj { get; set; } @@ -254,31 +254,31 @@ private partial class Receiver4 : Receiver2 public BaseObject Obj2 => obj; } - private partial class Receiver5 + private partial class Receiver5 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; set; } } - private partial class Receiver6 + private partial class Receiver6 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; protected set; } } - private partial class Receiver7 + private partial class Receiver7 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; internal set; } } - private partial class Receiver8 + private partial class Receiver8 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; private set; } } - private partial class Receiver9 + private partial class Receiver9 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public BaseObject Obj { get; protected internal set; } @@ -288,31 +288,31 @@ private partial class Receiver11 : Receiver8 { } - private partial class Receiver12 + private partial class Receiver12 : IDependencyInjectionCandidate { [Resolved] - public CachedStructProvider.Struct Obj { get; private set; } + public PartialCachedStructProvider.Struct Obj { get; private set; } } - private partial class Receiver13 + private partial class Receiver13 : IDependencyInjectionCandidate { [Resolved] public int? Obj { get; private set; } } - private partial class Receiver14 + private partial class Receiver14 : IDependencyInjectionCandidate { [Resolved] public int Obj { get; private set; } } - private partial class Receiver15 + private partial class Receiver15 : IDependencyInjectionCandidate { [Resolved(CanBeNull = true)] public int Obj { get; private set; } = 1; } - private partial class Receiver16 + private partial class Receiver16 : IDependencyInjectionCandidate { [Resolved] public Bindable Obj { get; private set; } @@ -322,13 +322,13 @@ private partial class Receiver16 } #nullable enable - private partial class Receiver17 + private partial class Receiver17 : IDependencyInjectionCandidate { [Resolved] public Bindable? Obj { get; private set; } } - private partial class Receiver18 + private partial class Receiver18 : IDependencyInjectionCandidate { [Resolved] public Bindable Obj { get; private set; } = null!; diff --git a/osu.Framework/Allocation/CachedModelDependencyContainer.cs b/osu.Framework/Allocation/CachedModelDependencyContainer.cs index 86bce3b2ba..ec3f0768f1 100644 --- a/osu.Framework/Allocation/CachedModelDependencyContainer.cs +++ b/osu.Framework/Allocation/CachedModelDependencyContainer.cs @@ -19,7 +19,7 @@ namespace osu.Framework.Allocation /// /// The type of the model to cache. Must contain only fields or auto-properties. public class CachedModelDependencyContainer : IReadOnlyDependencyContainer - where TModel : class, new() + where TModel : class, IDependencyInjectionCandidate, new() { private const BindingFlags activator_flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; @@ -67,7 +67,9 @@ public object Get(Type type, CacheInfo info) return parent?.Get(type, info); } - public void Inject(T instance) where T : class => DependencyActivator.Activate(instance, this); + public void Inject(T instance) + where T : class, IDependencyInjectionCandidate + => DependencyActivator.Activate(instance, this); /// /// Creates a new shadow model bound to . diff --git a/osu.Framework/Allocation/DependencyActivator.cs b/osu.Framework/Allocation/DependencyActivator.cs index 02eca51115..0b6391653f 100644 --- a/osu.Framework/Allocation/DependencyActivator.cs +++ b/osu.Framework/Allocation/DependencyActivator.cs @@ -64,7 +64,8 @@ private DependencyActivator(Type type) /// /// The object to inject the dependencies into. /// The dependencies to use for injection. - public static void Activate(object obj, IReadOnlyDependencyContainer dependencies) + public static void Activate(T obj, IReadOnlyDependencyContainer dependencies) + where T : IDependencyInjectionCandidate { initialiseSourceGeneratedActivators(obj); activateRecursively(obj, dependencies, obj.GetType()); @@ -88,7 +89,8 @@ static void activateRecursively(object obj, IReadOnlyDependencyContainer depende /// The existing dependencies. /// Extra information to identify parameters of in the cache with. /// A new if provides any dependencies, otherwise . - public static IReadOnlyDependencyContainer MergeDependencies(object obj, IReadOnlyDependencyContainer dependencies, CacheInfo info = default) + public static IReadOnlyDependencyContainer MergeDependencies(T obj, IReadOnlyDependencyContainer dependencies, CacheInfo info = default) + where T : IDependencyInjectionCandidate { initialiseSourceGeneratedActivators(obj); return mergeRecursively(obj, dependencies, info, obj.GetType()); diff --git a/osu.Framework/Allocation/DependencyContainer.cs b/osu.Framework/Allocation/DependencyContainer.cs index 72e9ac77e1..897f663d0d 100644 --- a/osu.Framework/Allocation/DependencyContainer.cs +++ b/osu.Framework/Allocation/DependencyContainer.cs @@ -184,7 +184,7 @@ public object Get(Type type, CacheInfo info) /// The instance to inject dependencies into. /// When the injection process was cancelled. public void Inject(T instance) - where T : class + where T : class, IDependencyInjectionCandidate => DependencyActivator.Activate(instance, this); } diff --git a/osu.Framework/Allocation/IDependencyInjectionCandidate.cs b/osu.Framework/Allocation/IDependencyInjectionCandidate.cs new file mode 100644 index 0000000000..5c6849a0d8 --- /dev/null +++ b/osu.Framework/Allocation/IDependencyInjectionCandidate.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Framework.Allocation +{ + /// + /// An interface that may be attached to objects to allow them to be used in . + /// + public interface IDependencyInjectionCandidate + { + } +} diff --git a/osu.Framework/Allocation/IReadOnlyDependencyContainer.cs b/osu.Framework/Allocation/IReadOnlyDependencyContainer.cs index 8b2524ad89..3189e7e7f9 100644 --- a/osu.Framework/Allocation/IReadOnlyDependencyContainer.cs +++ b/osu.Framework/Allocation/IReadOnlyDependencyContainer.cs @@ -33,7 +33,7 @@ public interface IReadOnlyDependencyContainer /// /// The type of the instance to inject dependencies into. /// The instance to inject dependencies into. - void Inject(T instance) where T : class; + void Inject(T instance) where T : class, IDependencyInjectionCandidate; } public static class ReadOnlyDependencyContainerExtensions diff --git a/osu.Framework/Graphics/Transforms/Transformable.cs b/osu.Framework/Graphics/Transforms/Transformable.cs index 6856b422d3..564258073b 100644 --- a/osu.Framework/Graphics/Transforms/Transformable.cs +++ b/osu.Framework/Graphics/Transforms/Transformable.cs @@ -17,7 +17,7 @@ namespace osu.Framework.Graphics.Transforms /// An implementer of this class must call to /// update and apply its s. /// - public abstract partial class Transformable : ITransformable + public abstract partial class Transformable : ITransformable, IDependencyInjectionCandidate { /// /// The clock that is used to provide the timing for this object's s. diff --git a/osu.Framework/Testing/Dependencies/CachedNullableProvider.cs b/osu.Framework/Testing/Dependencies/CachedNullableProvider.cs index d09d9c42a7..b702c53740 100644 --- a/osu.Framework/Testing/Dependencies/CachedNullableProvider.cs +++ b/osu.Framework/Testing/Dependencies/CachedNullableProvider.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable +#pragma warning disable OFSG001 // Must not be partial - used in reflection-based dependency injection tests. using osu.Framework.Allocation; @@ -10,7 +10,7 @@ namespace osu.Framework.Testing.Dependencies /// /// Used for internal testing purposes. /// - public class CachedNullableProvider + internal class CachedNullableProvider : IDependencyInjectionCandidate { [Cached] public int? CachedObject { get; private set; } = 5; diff --git a/osu.Framework/Testing/Dependencies/CachedStructProvider.cs b/osu.Framework/Testing/Dependencies/CachedStructProvider.cs index 454ddcdc08..2e9f7c37a1 100644 --- a/osu.Framework/Testing/Dependencies/CachedStructProvider.cs +++ b/osu.Framework/Testing/Dependencies/CachedStructProvider.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable +#pragma warning disable OFSG001 // Must not be partial - used in reflection-based dependency injection tests. using osu.Framework.Allocation; @@ -10,7 +10,7 @@ namespace osu.Framework.Testing.Dependencies /// /// This is used for internal testing purposes. /// - internal class CachedStructProvider + internal class CachedStructProvider : IDependencyInjectionCandidate { [Cached] public Struct CachedObject { get; } = new Struct { Value = 10 }; diff --git a/osu.Framework/Testing/Dependencies/PartialCachedNullableProvider.cs b/osu.Framework/Testing/Dependencies/PartialCachedNullableProvider.cs new file mode 100644 index 0000000000..e94532c839 --- /dev/null +++ b/osu.Framework/Testing/Dependencies/PartialCachedNullableProvider.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; + +namespace osu.Framework.Testing.Dependencies +{ + /// + /// Used for internal testing purposes. + /// + internal partial class PartialCachedNullableProvider : IDependencyInjectionCandidate + { + [Cached] + public int? CachedObject { get; private set; } = 5; + + public void SetValue(int? value) => CachedObject = value; + } +} diff --git a/osu.Framework/Testing/Dependencies/PartialCachedStructProvider.cs b/osu.Framework/Testing/Dependencies/PartialCachedStructProvider.cs new file mode 100644 index 0000000000..0db35edf15 --- /dev/null +++ b/osu.Framework/Testing/Dependencies/PartialCachedStructProvider.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; + +namespace osu.Framework.Testing.Dependencies +{ + /// + /// This is used for internal testing purposes. + /// + internal partial class PartialCachedStructProvider : IDependencyInjectionCandidate + { + [Cached] + public Struct CachedObject { get; } = new Struct { Value = 10 }; + + public struct Struct + { + public int Value; + } + } +} diff --git a/osu.Framework/Utils/SourceGeneratorUtils.cs b/osu.Framework/Utils/SourceGeneratorUtils.cs index 3334a2146d..a0126b2758 100644 --- a/osu.Framework/Utils/SourceGeneratorUtils.cs +++ b/osu.Framework/Utils/SourceGeneratorUtils.cs @@ -25,7 +25,7 @@ public static class SourceGeneratorUtils /// The name which should be cached as. /// A fallback name for to be cached as. /// If is null. - public static void CacheDependency(DependencyContainer container, Type callerType, object obj, CacheInfo info, Type? asType, string? cachedName, string? propertyName) + public static void CacheDependency(DependencyContainer container, Type callerType, object? obj, CacheInfo info, Type? asType, string? cachedName, string? propertyName) { bool allowValueTypes = callerType.Assembly == typeof(Drawable).Assembly;