mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* Add Prototype analyzer * Add Prototype fixer * Early return after finding prototype attribute * Add PrototypeEndsWithPrototypeRule diagnostic * Oops. Uncomment parallelizable. * Rework to ignore redundancy for non-literal string values * Allow redundancy when removal would expose class name not ending in "Prototype" * Promote PrototypeEndsWithPrototypeRule from warning to error, since it causes a runtime error. * No need to get the symbol to get the class identifier * Minor cleanup * A little more cleanup * More specific location for redundant name * Refactor redundant name fixer so argument order is no longer important * Add failing test * Use symbol analysis to fix alias handling * Oops! We have to go back to the previous syntax-based approach. Now it's a hybrid. Also fixed tests to not copy the prototype definitions. --------- Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
178 lines
6.1 KiB
C#
178 lines
6.1 KiB
C#
using System.Threading.Tasks;
|
|
using Microsoft.CodeAnalysis.Testing;
|
|
using NUnit.Framework;
|
|
using VerifyCS =
|
|
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.PrototypeAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
|
|
|
|
namespace Robust.Analyzers.Tests;
|
|
|
|
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
|
[TestFixture]
|
|
[TestOf(typeof(PrototypeAnalyzer))]
|
|
public sealed class PrototypeAnalyzerTest
|
|
{
|
|
private static Task Verifier(string code, params DiagnosticResult[] expected)
|
|
{
|
|
var test = new RTAnalyzerTest<PrototypeAnalyzer>()
|
|
{
|
|
TestState =
|
|
{
|
|
Sources = { code }
|
|
},
|
|
};
|
|
|
|
TestHelper.AddEmbeddedSources(
|
|
test.TestState,
|
|
"Robust.Shared.Prototypes.Attributes.cs",
|
|
"Robust.Shared.Prototypes.IPrototype.cs",
|
|
"Robust.Shared.Serialization.Manager.Attributes.DataFieldAttribute.cs"
|
|
);
|
|
|
|
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
|
|
test.TestState.ExpectedDiagnostics.AddRange(expected);
|
|
|
|
return test.RunAsync();
|
|
}
|
|
|
|
[Test]
|
|
public async Task RedundantTypeTest()
|
|
{
|
|
const string code = """
|
|
using Robust.Shared.Prototypes;
|
|
|
|
[Prototype]
|
|
public sealed partial class GoodAutoPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype("someOtherName")]
|
|
public sealed partial class GoodUnmatchedPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype("badMatched")]
|
|
public sealed partial class BadMatchedPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype(ProtoName)]
|
|
public sealed partial class GoodNonLiteralMatchedPrototype : IPrototype
|
|
{
|
|
public const string ProtoName = "goodNonLiteralMatched";
|
|
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype(ProtoName)]
|
|
public sealed partial class GoodNonLiteralUnmatchedPrototype : IPrototype
|
|
{
|
|
public const string ProtoName = "someOtherNameEntirely";
|
|
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype("goodDoesNotEndWithPrototypeWord")]
|
|
public sealed partial class GoodDoesNotEndWithPrototypeWord : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
""";
|
|
|
|
await Verifier(code,
|
|
// /0/Test0.cs(9,2): warning RA0033: Prototype BadMatchedPrototype has explicitly set type "badMatched" that matches autogenerated value
|
|
VerifyCS.Diagnostic(PrototypeAnalyzer.PrototypeRedundantTypeRule).WithSpan(17, 12, 17, 24).WithArguments("BadMatchedPrototype", "badMatched")
|
|
);
|
|
}
|
|
|
|
[Test]
|
|
public async Task AliasTest()
|
|
{
|
|
const string code = """
|
|
using Robust.Shared.Prototypes;
|
|
using PPrototypeAttribute = Robust.Shared.Prototypes.PrototypeAttribute;
|
|
|
|
[PPrototype("badMatched")]
|
|
public sealed partial class BadMatchedPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
""";
|
|
|
|
await Verifier(code,
|
|
// /0/Test0.cs(4,2): warning RA0042: Prototype BadMatchedPrototype has explicitly set type "badMatched" that matches autogenerated value
|
|
VerifyCS.Diagnostic(PrototypeAnalyzer.PrototypeRedundantTypeRule).WithSpan(4, 13, 4, 25).WithArguments("BadMatchedPrototype", "badMatched")
|
|
);
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task MoreAttributesTest()
|
|
{
|
|
const string code = """
|
|
using System;
|
|
using Robust.Shared.Prototypes;
|
|
using PPrototypeAttribute = Robust.Shared.Prototypes.PrototypeAttribute;
|
|
|
|
[FooBarAttribute]
|
|
[PPrototype("badMatched")]
|
|
public sealed partial class BadMatchedPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
|
public sealed class FooBarAttribute : Attribute;
|
|
""";
|
|
|
|
await Verifier(code,
|
|
// /0/Test0.cs(4,2): warning RA0042: Prototype BadMatchedPrototype has explicitly set type "badMatched" that matches autogenerated value
|
|
VerifyCS.Diagnostic(PrototypeAnalyzer.PrototypeRedundantTypeRule).WithSpan(6, 13, 6, 25).WithArguments("BadMatchedPrototype", "badMatched")
|
|
);
|
|
}
|
|
|
|
[Test]
|
|
public async Task NameEndsWithPrototypeTest()
|
|
{
|
|
const string code = """
|
|
using Robust.Shared.Prototypes;
|
|
|
|
[Prototype]
|
|
public sealed partial class GoodAutoPrototype : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype("ThisIsFine")]
|
|
public sealed partial class GoodManual : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
|
|
[Prototype]
|
|
public sealed partial class BadAuto : IPrototype
|
|
{
|
|
[IdDataField]
|
|
public string ID { get; private set; } = default!;
|
|
}
|
|
""";
|
|
|
|
await Verifier(code,
|
|
// /0/Test0.cs(18,29): error RA0043: Prototype BadAuto does not end with the word Prototype
|
|
VerifyCS.Diagnostic(PrototypeAnalyzer.PrototypeEndsWithPrototypeRule).WithSpan(18, 29, 18, 36).WithArguments("BadAuto")
|
|
);
|
|
}
|
|
}
|