summaryrefslogtreecommitdiffstats
path: root/modules/mono
diff options
context:
space:
mode:
authorAlberto Vilches <194074+avilches@users.noreply.github.com>2023-12-25 23:21:09 +0100
committerAlberto Vilches <194074+avilches@users.noreply.github.com>2024-01-15 11:31:12 +0100
commit7a90c56c00e7d63199bd3abe409622c3c24e0ec5 (patch)
treee2ce1d0d75ab6b2ea6a2eafaeab7037ab67a7641 /modules/mono
parent13a0d6e9b253654f5cc2a44f3d0b3cae10440443 (diff)
downloadredot-engine-7a90c56c00e7d63199bd3abe409622c3c24e0ec5.tar.gz
C# Add test suite for Diagnostic Analyzers: GlobalClass and MustBeVariant
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/GlobalClass.cs14
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs164
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs56
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/GlobalClassAnalyzerTests.cs20
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/MustBeVariantAnalyzerTests.cs20
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs22
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs15
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs71
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0302.cs27
12 files changed, 418 insertions, 0 deletions
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
index 03a7dc453c..9674626183 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
@@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators", "G
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Sample", "Godot.SourceGenerators.Sample\Godot.SourceGenerators.Sample.csproj", "{7297A614-8DF5-43DE-9EAD-99671B26BD1F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Tests", "Godot.SourceGenerators.Tests\Godot.SourceGenerators.Tests.csproj", "{07E6D201-35C9-4463-9B29-D16621EA733D}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "..\..\glue\GodotSharp\GodotSharp\GodotSharp.csproj", "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}"
EndProject
Global
@@ -26,6 +28,10 @@ Global
{7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07E6D201-35C9-4463-9B29-D16621EA733D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07E6D201-35C9-4463-9B29-D16621EA733D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07E6D201-35C9-4463-9B29-D16621EA733D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07E6D201-35C9-4463-9B29-D16621EA733D}.Release|Any CPU.Build.0 = Release|Any CPU
{AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/GlobalClass.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/GlobalClass.cs
new file mode 100644
index 0000000000..b9f11908e1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/GlobalClass.cs
@@ -0,0 +1,14 @@
+namespace Godot.SourceGenerators.Sample;
+
+[GlobalClass]
+public partial class CustomGlobalClass : GodotObject
+{
+}
+
+// This doesn't works because global classes can't have any generic type parameter.
+/*
+[GlobalClass]
+public partial class CustomGlobalClass<T> : Node
+{
+}
+*/
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
index 3f569ebac3..d0907c1cd4 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
@@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
+ <LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs
new file mode 100644
index 0000000000..1e06091e80
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs
@@ -0,0 +1,164 @@
+using System;
+using Godot.Collections;
+using Array = Godot.Collections.Array;
+
+namespace Godot.SourceGenerators.Sample;
+
+public class MustBeVariantMethods
+{
+ public void MustBeVariantMethodCalls()
+ {
+ Method<bool>();
+ Method<char>();
+ Method<sbyte>();
+ Method<byte>();
+ Method<short>();
+ Method<ushort>();
+ Method<int>();
+ Method<uint>();
+ Method<long>();
+ Method<ulong>();
+ Method<float>();
+ Method<double>();
+ Method<string>();
+ Method<Vector2>();
+ Method<Vector2I>();
+ Method<Rect2>();
+ Method<Rect2I>();
+ Method<Transform2D>();
+ Method<Vector3>();
+ Method<Vector3I>();
+ Method<Vector4>();
+ Method<Vector4I>();
+ Method<Basis>();
+ Method<Quaternion>();
+ Method<Transform3D>();
+ Method<Projection>();
+ Method<Aabb>();
+ Method<Color>();
+ Method<Plane>();
+ Method<Callable>();
+ Method<Signal>();
+ Method<GodotObject>();
+ Method<StringName>();
+ Method<NodePath>();
+ Method<Rid>();
+ Method<Dictionary>();
+ Method<Array>();
+ Method<byte[]>();
+ Method<int[]>();
+ Method<long[]>();
+ Method<float[]>();
+ Method<double[]>();
+ Method<string[]>();
+ Method<Vector2[]>();
+ Method<Vector3[]>();
+ Method<Color[]>();
+ Method<GodotObject[]>();
+ Method<StringName[]>();
+ Method<NodePath[]>();
+ Method<Rid[]>();
+
+ // This call fails because generic type is not Variant-compatible.
+ //Method<object>();
+ }
+
+ public void Method<[MustBeVariant] T>()
+ {
+ }
+
+ public void MustBeVariantClasses()
+ {
+ new ClassWithGenericVariant<bool>();
+ new ClassWithGenericVariant<char>();
+ new ClassWithGenericVariant<sbyte>();
+ new ClassWithGenericVariant<byte>();
+ new ClassWithGenericVariant<short>();
+ new ClassWithGenericVariant<ushort>();
+ new ClassWithGenericVariant<int>();
+ new ClassWithGenericVariant<uint>();
+ new ClassWithGenericVariant<long>();
+ new ClassWithGenericVariant<ulong>();
+ new ClassWithGenericVariant<float>();
+ new ClassWithGenericVariant<double>();
+ new ClassWithGenericVariant<string>();
+ new ClassWithGenericVariant<Vector2>();
+ new ClassWithGenericVariant<Vector2I>();
+ new ClassWithGenericVariant<Rect2>();
+ new ClassWithGenericVariant<Rect2I>();
+ new ClassWithGenericVariant<Transform2D>();
+ new ClassWithGenericVariant<Vector3>();
+ new ClassWithGenericVariant<Vector3I>();
+ new ClassWithGenericVariant<Vector4>();
+ new ClassWithGenericVariant<Vector4I>();
+ new ClassWithGenericVariant<Basis>();
+ new ClassWithGenericVariant<Quaternion>();
+ new ClassWithGenericVariant<Transform3D>();
+ new ClassWithGenericVariant<Projection>();
+ new ClassWithGenericVariant<Aabb>();
+ new ClassWithGenericVariant<Color>();
+ new ClassWithGenericVariant<Plane>();
+ new ClassWithGenericVariant<Callable>();
+ new ClassWithGenericVariant<Signal>();
+ new ClassWithGenericVariant<GodotObject>();
+ new ClassWithGenericVariant<StringName>();
+ new ClassWithGenericVariant<NodePath>();
+ new ClassWithGenericVariant<Rid>();
+ new ClassWithGenericVariant<Dictionary>();
+ new ClassWithGenericVariant<Array>();
+ new ClassWithGenericVariant<byte[]>();
+ new ClassWithGenericVariant<int[]>();
+ new ClassWithGenericVariant<long[]>();
+ new ClassWithGenericVariant<float[]>();
+ new ClassWithGenericVariant<double[]>();
+ new ClassWithGenericVariant<string[]>();
+ new ClassWithGenericVariant<Vector2[]>();
+ new ClassWithGenericVariant<Vector3[]>();
+ new ClassWithGenericVariant<Color[]>();
+ new ClassWithGenericVariant<GodotObject[]>();
+ new ClassWithGenericVariant<StringName[]>();
+ new ClassWithGenericVariant<NodePath[]>();
+ new ClassWithGenericVariant<Rid[]>();
+
+ // This class fails because generic type is not Variant-compatible.
+ //new ClassWithGenericVariant<object>();
+ }
+}
+
+public class ClassWithGenericVariant<[MustBeVariant] T>
+{
+}
+
+public class MustBeVariantAnnotatedMethods
+{
+ [GenericTypeAttribute<string>()]
+ public void MethodWithAttributeOk()
+ {
+ }
+
+ // This method definition fails because generic type is not Variant-compatible.
+ /*
+ [GenericTypeAttribute<object>()]
+ public void MethodWithWrongAttribute()
+ {
+ }
+ */
+}
+
+[GenericTypeAttribute<string>()]
+public class ClassVariantAnnotated
+{
+}
+
+// This class definition fails because generic type is not Variant-compatible.
+/*
+[GenericTypeAttribute<object>()]
+public class ClassNonVariantAnnotated
+{
+}
+*/
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public class GenericTypeAttribute<[MustBeVariant] T> : Attribute
+{
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs
new file mode 100644
index 0000000000..e3e7373b2e
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators.Tests;
+
+public static class CSharpAnalyzerVerifier<TAnalyzer>
+where TAnalyzer : DiagnosticAnalyzer, new()
+{
+ public class Test : CSharpAnalyzerTest<TAnalyzer, XUnitVerifier>
+ {
+ public Test()
+ {
+ ReferenceAssemblies = ReferenceAssemblies.Net.Net60;
+
+ SolutionTransforms.Add((Solution solution, ProjectId projectId) =>
+ {
+ Project project =
+ solution.GetProject(projectId)!.AddMetadataReference(Constants.GodotSharpAssembly
+ .CreateMetadataReference());
+
+ return project.Solution;
+ });
+ }
+ }
+
+ public static Task Verify(string sources, params DiagnosticResult[] expected)
+ {
+ return MakeVerifier(new string[] { sources }, expected).RunAsync();
+ }
+
+ public static Test MakeVerifier(ICollection<string> sources, params DiagnosticResult[] expected)
+ {
+ var verifier = new Test();
+
+ verifier.TestState.AnalyzerConfigFiles.Add(("/.globalconfig", $"""
+ is_global = true
+ build_property.GodotProjectDir = {Constants.ExecutingAssemblyPath}
+ """));
+
+ verifier.TestState.Sources.AddRange(sources.Select(source =>
+ {
+ return (source, SourceText.From(File.ReadAllText(Path.Combine(Constants.SourceFolderPath, source))));
+ }));
+
+ verifier.ExpectedDiagnostics.AddRange(expected);
+ return verifier;
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/GlobalClassAnalyzerTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/GlobalClassAnalyzerTests.cs
new file mode 100644
index 0000000000..74d6afceb3
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/GlobalClassAnalyzerTests.cs
@@ -0,0 +1,20 @@
+using Xunit;
+
+namespace Godot.SourceGenerators.Tests;
+
+public class GlobalClassAnalyzerTests
+{
+ [Fact]
+ public async void GlobalClassMustDeriveFromGodotObjectTest()
+ {
+ const string GlobalClassGD0401 = "GlobalClass.GD0401.cs";
+ await CSharpAnalyzerVerifier<GlobalClassAnalyzer>.Verify(GlobalClassGD0401);
+ }
+
+ [Fact]
+ public async void GlobalClassMustNotBeGenericTest()
+ {
+ const string GlobalClassGD0402 = "GlobalClass.GD0402.cs";
+ await CSharpAnalyzerVerifier<GlobalClassAnalyzer>.Verify(GlobalClassGD0402);
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
index e39c14f049..13e54a543f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
@@ -17,6 +17,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
+ <PackageReference Include="Microsoft.CodeAnalysis.Testing.Verifiers.XUnit" Version="1.1.1" />
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit" Version="1.1.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/MustBeVariantAnalyzerTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/MustBeVariantAnalyzerTests.cs
new file mode 100644
index 0000000000..62c602efbb
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/MustBeVariantAnalyzerTests.cs
@@ -0,0 +1,20 @@
+using Xunit;
+
+namespace Godot.SourceGenerators.Tests;
+
+public class MustBeVariantAnalyzerTests
+{
+ [Fact]
+ public async void GenericTypeArgumentMustBeVariantTest()
+ {
+ const string MustBeVariantGD0301 = "MustBeVariant.GD0301.cs";
+ await CSharpAnalyzerVerifier<MustBeVariantAnalyzer>.Verify(MustBeVariantGD0301);
+ }
+
+ [Fact]
+ public async void GenericTypeParameterMustBeVariantAnnotatedTest()
+ {
+ const string MustBeVariantGD0302 = "MustBeVariant.GD0302.cs";
+ await CSharpAnalyzerVerifier<MustBeVariantAnalyzer>.Verify(MustBeVariantGD0302);
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs
new file mode 100644
index 0000000000..6e6d3a6f39
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs
@@ -0,0 +1,22 @@
+using Godot;
+
+// This works because it inherits from GodotObject.
+[GlobalClass]
+public partial class CustomGlobalClass1 : GodotObject
+{
+
+}
+
+// This works because it inherits from an object that inherits from GodotObject
+[GlobalClass]
+public partial class CustomGlobalClass2 : Node
+{
+
+}
+
+// This raises a GD0401 diagnostic error: global classes must inherit from GodotObject
+{|GD0401:[GlobalClass]
+public partial class CustomGlobalClass3
+{
+
+}|}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs
new file mode 100644
index 0000000000..1c0a169841
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs
@@ -0,0 +1,15 @@
+using Godot;
+
+// This works because it inherits from GodotObject and it doesn't have any generic type parameter.
+[GlobalClass]
+public partial class CustomGlobalClass : GodotObject
+{
+
+}
+
+// This raises a GD0402 diagnostic error: global classes can't have any generic type parameter
+{|GD0402:[GlobalClass]
+public partial class CustomGlobalClass<T> : GodotObject
+{
+
+}|}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
new file mode 100644
index 0000000000..031039cba1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
@@ -0,0 +1,71 @@
+using System;
+using Godot;
+using Godot.Collections;
+using Array = Godot.Collections.Array;
+
+public class MustBeVariantGD0301
+{
+ public void MethodCallsError()
+ {
+ // This raises a GD0301 diagnostic error: object is not Variant (and Method<T> requires a variant generic type).
+ Method<{|GD0301:object|}>();
+ }
+ public void MethodCallsOk()
+ {
+ // All these calls are valid because they are Variant types.
+ Method<bool>();
+ Method<char>();
+ Method<sbyte>();
+ Method<byte>();
+ Method<short>();
+ Method<ushort>();
+ Method<int>();
+ Method<uint>();
+ Method<long>();
+ Method<ulong>();
+ Method<float>();
+ Method<double>();
+ Method<string>();
+ Method<Vector2>();
+ Method<Vector2I>();
+ Method<Rect2>();
+ Method<Rect2I>();
+ Method<Transform2D>();
+ Method<Vector3>();
+ Method<Vector3I>();
+ Method<Vector4>();
+ Method<Vector4I>();
+ Method<Basis>();
+ Method<Quaternion>();
+ Method<Transform3D>();
+ Method<Projection>();
+ Method<Aabb>();
+ Method<Color>();
+ Method<Plane>();
+ Method<Callable>();
+ Method<Signal>();
+ Method<GodotObject>();
+ Method<StringName>();
+ Method<NodePath>();
+ Method<Rid>();
+ Method<Dictionary>();
+ Method<Array>();
+ Method<byte[]>();
+ Method<int[]>();
+ Method<long[]>();
+ Method<float[]>();
+ Method<double[]>();
+ Method<string[]>();
+ Method<Vector2[]>();
+ Method<Vector3[]>();
+ Method<Color[]>();
+ Method<GodotObject[]>();
+ Method<StringName[]>();
+ Method<NodePath[]>();
+ Method<Rid[]>();
+ }
+
+ public void Method<[MustBeVariant] T>()
+ {
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0302.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0302.cs
new file mode 100644
index 0000000000..ce182e8c62
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0302.cs
@@ -0,0 +1,27 @@
+using Godot;
+
+public class MustBeVariantGD0302
+{
+ public void MethodOk<[MustBeVariant] T>()
+ {
+ // T is guaranteed to be a Variant-compatible type because it's annotated with the [MustBeVariant] attribute, so it can be used here.
+ new ExampleClass<T>();
+ Method<T>();
+ }
+
+ public void MethodFail<T>()
+ {
+ // These two calls raise a GD0302 diagnostic error: T is not valid here because it may not a Variant type and method call and class require it.
+ new ExampleClass<{|GD0302:T|}>();
+ Method<{|GD0302:T|}>();
+ }
+
+ public void Method<[MustBeVariant] T>()
+ {
+ }
+}
+
+public class ExampleClass<[MustBeVariant] T>
+{
+
+}