mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-13 11:20:31 +00:00
Add source generator for IsLongRunning property
This commit is contained in:
60
osu.Framework.Benchmarks/BenchmarkLongRunningLoad.cs
Normal file
60
osu.Framework.Benchmarks/BenchmarkLongRunningLoad.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Framework.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public partial class BenchmarkLongRunningLoad
|
||||
{
|
||||
private Drawable nonLongRunningReflectionDrawable = null!;
|
||||
private Drawable longRunningReflectionDrawable = null!;
|
||||
private Drawable nonLongRunningSourceGenerationDrawable = null!;
|
||||
private Drawable longRunningSourceGenerationDrawable = null!;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
nonLongRunningReflectionDrawable = new NonLongRunningReflectionDrawable();
|
||||
longRunningReflectionDrawable = new LongRunningReflectionDrawable();
|
||||
|
||||
nonLongRunningSourceGenerationDrawable = new NonLongRunningSourceGenerationDrawable();
|
||||
longRunningSourceGenerationDrawable = new LongRunningSourceGenerationDrawable();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public bool QueryNonLongRunningViaReflection() => nonLongRunningReflectionDrawable.IsLongRunning;
|
||||
|
||||
[Benchmark]
|
||||
public bool QueryLongRunningViaReflection() => longRunningReflectionDrawable.IsLongRunning;
|
||||
|
||||
[Benchmark]
|
||||
public bool QueryNonLongRunningViaSourceGeneration() => nonLongRunningSourceGenerationDrawable.IsLongRunning;
|
||||
|
||||
[Benchmark]
|
||||
public bool QueryLongRunningViaSourceGeneration() => longRunningSourceGenerationDrawable.IsLongRunning;
|
||||
|
||||
#pragma warning disable OFSG001
|
||||
private class NonLongRunningReflectionDrawable : Drawable
|
||||
{
|
||||
}
|
||||
|
||||
[LongRunningLoad]
|
||||
private class LongRunningReflectionDrawable : Drawable
|
||||
{
|
||||
}
|
||||
#pragma warning restore OFSG001
|
||||
|
||||
private partial class NonLongRunningSourceGenerationDrawable : Drawable
|
||||
{
|
||||
}
|
||||
|
||||
[LongRunningLoad]
|
||||
private partial class LongRunningSourceGenerationDrawable : Drawable
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using VerifyCS = osu.Framework.SourceGeneration.Tests.Verifiers.CSharpSourceGeneratorVerifier<osu.Framework.SourceGeneration.Generators.LongRunningLoad.LongRunningLoadSourceGenerator>;
|
||||
|
||||
namespace osu.Framework.SourceGeneration.Tests.LongRunningLoad
|
||||
{
|
||||
public class LongRunningLoadSourceGeneratorTests : AbstractGeneratorTests
|
||||
{
|
||||
protected override string ResourceNamespace => "LongRunningLoad";
|
||||
|
||||
[Theory]
|
||||
[InlineData("LongRunningType")]
|
||||
public Task Check(string name)
|
||||
{
|
||||
GetTestSources(name,
|
||||
out (string filename, string content)[] commonSourceFiles,
|
||||
out (string filename, string content)[] sourceFiles,
|
||||
out (string filename, string content)[] commonGeneratedFiles,
|
||||
out (string filename, string content)[] generatedFiles
|
||||
);
|
||||
|
||||
return VerifyCS.VerifyAsync(commonSourceFiles, sourceFiles, commonGeneratedFiles, generatedFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// <auto-generated/>
|
||||
#nullable enable
|
||||
#pragma warning disable CS4014
|
||||
|
||||
namespace osu.Framework.Graphics
|
||||
{
|
||||
partial class Drawable : global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache
|
||||
{
|
||||
global::System.Type global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache.KnownType => typeof(global::osu.Framework.Graphics.Drawable);
|
||||
bool global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache.IsLongRunning => false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace osu.Framework.Graphics
|
||||
{
|
||||
public partial class Drawable
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
public interface ISourceGeneratedLongRunningLoadCache
|
||||
{
|
||||
protected internal System.Type KnownType { get; }
|
||||
protected internal bool IsLongRunning { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class LongRunningLoadAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// <auto-generated/>
|
||||
#nullable enable
|
||||
#pragma warning disable CS4014
|
||||
|
||||
partial class LongRunningType : global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache
|
||||
{
|
||||
global::System.Type global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache.KnownType => typeof(global::LongRunningType);
|
||||
bool global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache.IsLongRunning => true;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
[LongRunningLoad]
|
||||
public partial class LongRunningType : osu.Framework.Graphics.Drawable
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace osu.Framework.SourceGeneration.Generators.LongRunningLoad
|
||||
{
|
||||
public class LongRunningLoadSemanticTarget : IncrementalSemanticTarget
|
||||
{
|
||||
public bool IsLongRunning { get; private set; }
|
||||
|
||||
public LongRunningLoadSemanticTarget(ClassDeclarationSyntax classSyntax, SemanticModel semanticModel)
|
||||
: base(classSyntax, semanticModel)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool CheckValid(INamedTypeSymbol symbol)
|
||||
{
|
||||
INamedTypeSymbol? s = symbol;
|
||||
|
||||
while (s != null)
|
||||
{
|
||||
if (isDrawableType(s))
|
||||
return true;
|
||||
|
||||
s = s.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This source generator never overrides.
|
||||
protected override bool CheckNeedsOverride(INamedTypeSymbol symbol) => false;
|
||||
|
||||
protected override void Process(INamedTypeSymbol symbol)
|
||||
{
|
||||
if (FullyQualifiedTypeName == "osu.Framework.Graphics.Drawable")
|
||||
return;
|
||||
|
||||
IsLongRunning = symbol.GetAttributes().Any(SyntaxHelpers.IsLongRunningLoadAttribute);
|
||||
}
|
||||
|
||||
private static bool isDrawableType(INamedTypeSymbol type)
|
||||
=> SyntaxHelpers.GetFullyQualifiedTypeName(type) == "osu.Framework.Graphics.Drawable";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace osu.Framework.SourceGeneration.Generators.LongRunningLoad
|
||||
{
|
||||
public class LongRunningLoadSourceEmitter : IncrementalSourceEmitter
|
||||
{
|
||||
private const string interface_name = "global::osu.Framework.Allocation.ISourceGeneratedLongRunningLoadCache";
|
||||
|
||||
protected override string FileSuffix => "LongRunningLoad";
|
||||
|
||||
public new LongRunningLoadSemanticTarget Target => (LongRunningLoadSemanticTarget)base.Target;
|
||||
|
||||
public LongRunningLoadSourceEmitter(IncrementalSemanticTarget target)
|
||||
: base(target)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ClassDeclarationSyntax ConstructClass(ClassDeclarationSyntax initialClass)
|
||||
{
|
||||
return initialClass.WithBaseList(
|
||||
SyntaxFactory.BaseList(
|
||||
SyntaxFactory.SingletonSeparatedList<BaseTypeSyntax>(
|
||||
SyntaxFactory.SimpleBaseType(
|
||||
SyntaxFactory.ParseTypeName(interface_name)))))
|
||||
.WithMembers(
|
||||
SyntaxFactory.List(createProperties()));
|
||||
}
|
||||
|
||||
private IEnumerable<MemberDeclarationSyntax> createProperties()
|
||||
{
|
||||
// Drawable is the base type which always needs to have the members defined.
|
||||
bool isDrawable = Target.FullyQualifiedTypeName == "osu.Framework.Graphics.Drawable";
|
||||
|
||||
yield return SyntaxFactory.PropertyDeclaration(
|
||||
SyntaxFactory.ParseTypeName("global::System.Type"),
|
||||
SyntaxFactory.Identifier("KnownType"))
|
||||
.WithExplicitInterfaceSpecifier(
|
||||
SyntaxFactory.ExplicitInterfaceSpecifier(
|
||||
SyntaxFactory.IdentifierName(interface_name)))
|
||||
.WithExpressionBody(
|
||||
SyntaxFactory.ArrowExpressionClause(
|
||||
SyntaxFactory.TypeOfExpression(
|
||||
SyntaxFactory.ParseTypeName(Target.GlobalPrefixedTypeName))))
|
||||
.WithSemicolonToken(
|
||||
SyntaxFactory.Token(SyntaxKind.SemicolonToken));
|
||||
|
||||
if (Target.IsLongRunning || isDrawable)
|
||||
{
|
||||
yield return SyntaxFactory.PropertyDeclaration(
|
||||
SyntaxFactory.PredefinedType(
|
||||
SyntaxFactory.Token(SyntaxKind.BoolKeyword)),
|
||||
SyntaxFactory.Identifier("IsLongRunning"))
|
||||
.WithExplicitInterfaceSpecifier(
|
||||
SyntaxFactory.ExplicitInterfaceSpecifier(
|
||||
SyntaxFactory.IdentifierName(interface_name)))
|
||||
.WithExpressionBody(
|
||||
SyntaxFactory.ArrowExpressionClause(
|
||||
SyntaxFactory.LiteralExpression(
|
||||
Target.IsLongRunning
|
||||
? SyntaxKind.TrueLiteralExpression
|
||||
: SyntaxKind.FalseLiteralExpression)))
|
||||
.WithSemicolonToken(
|
||||
SyntaxFactory.Token(SyntaxKind.SemicolonToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace osu.Framework.SourceGeneration.Generators.LongRunningLoad
|
||||
{
|
||||
[Generator]
|
||||
public class LongRunningLoadSourceGenerator : AbstractIncrementalGenerator
|
||||
{
|
||||
protected override IncrementalSemanticTarget CreateSemanticTarget(ClassDeclarationSyntax node, SemanticModel semanticModel)
|
||||
=> new LongRunningLoadSemanticTarget(node, semanticModel);
|
||||
|
||||
protected override IncrementalSourceEmitter CreateSourceEmitter(IncrementalSemanticTarget target)
|
||||
=> new LongRunningLoadSourceEmitter(target);
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,9 @@ namespace osu.Framework.SourceGeneration
|
||||
public static bool IsCachedAttribute(AttributeData? attribute)
|
||||
=> IsCachedAttribute(attribute?.AttributeClass);
|
||||
|
||||
public static bool IsLongRunningLoadAttribute(AttributeData? attribute)
|
||||
=> IsLongRunningLoadAttribute(attribute?.AttributeClass);
|
||||
|
||||
public static bool IsBackgroundDependencyLoaderAttribute(ITypeSymbol? type)
|
||||
=> type != null && GetFullyQualifiedTypeName(type) == "osu.Framework.Allocation.BackgroundDependencyLoaderAttribute";
|
||||
|
||||
@@ -109,6 +112,9 @@ namespace osu.Framework.SourceGeneration
|
||||
public static bool IsCachedAttribute(ITypeSymbol? type)
|
||||
=> type != null && GetFullyQualifiedTypeName(type) == "osu.Framework.Allocation.CachedAttribute";
|
||||
|
||||
public static bool IsLongRunningLoadAttribute(ITypeSymbol? type)
|
||||
=> type != null && GetFullyQualifiedTypeName(type) == "osu.Framework.Allocation.LongRunningLoadAttribute";
|
||||
|
||||
public static bool IsIDependencyInjectionCandidateInterface(ITypeSymbol? type)
|
||||
=> type != null && GetFullyQualifiedTypeName(type) == "osu.Framework.Allocation.IDependencyInjectionCandidate";
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
|
||||
namespace osu.Framework.Allocation
|
||||
{
|
||||
public interface ISourceGeneratedLongRunningLoadCache
|
||||
{
|
||||
protected internal Type KnownType { get; }
|
||||
protected internal bool IsLongRunning { get; }
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,6 @@ namespace osu.Framework.Graphics
|
||||
|
||||
private static readonly GlobalStatistic<int> total_count = GlobalStatistics.Get<int>(nameof(Drawable), "Total constructed");
|
||||
|
||||
internal bool IsLongRunning => GetType().GetCustomAttribute<LongRunningLoadAttribute>() != null;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this drawable.
|
||||
/// </summary>
|
||||
|
||||
22
osu.Framework/Graphics/Drawable_IsLongRunning.cs
Normal file
22
osu.Framework/Graphics/Drawable_IsLongRunning.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Reflection;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Framework.Graphics
|
||||
{
|
||||
public partial class Drawable
|
||||
{
|
||||
internal bool IsLongRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this is ISourceGeneratedLongRunningLoadCache sgCache && sgCache.KnownType == GetType())
|
||||
return sgCache.IsLongRunning;
|
||||
|
||||
return GetType().GetCustomAttribute<LongRunningLoadAttribute>() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user