Skip to content

Commit

Permalink
Fixes xunit/xunit#2798: xUnit2007 code fix leads to CS8920 compiler e…
Browse files Browse the repository at this point in the history
…rror (#167)
  • Loading branch information
etherfield committed Nov 18, 2023
1 parent 79ca4d6 commit 0c15399
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
using Verify = CSharpVerifier<Xunit.Analyzers.AssertIsTypeShouldUseGenericOverloadType>;

public class AssertIsTypeShouldUseGenericOverloadTypeTests
{
#if NETCOREAPP // static abstract methods are only supported on .NET, not .NET Framework
public class StaticAbstractInterfaceMethods
{
const string methodCode = "static abstract void Method();";
const string codeTemplate = @"
using Xunit;
public interface IParentClass {{
{0}
}}
public interface IClass : IParentClass {{
{1}
}}
public class Class : IClass {{
public static void Method() {{ }}
}}
public abstract class TestClass {{
[Fact]
public void TestMethod() {{
var data = new Class();
Assert.IsAssignableFrom(typeof(IClass), data);
}}
}}";

[Fact]
public async void DoesNotFindWarning_ForStaticAbstractInterfaceMembers()
{
string source = string.Format(codeTemplate, string.Empty, methodCode);

await Verify.VerifyAnalyzer(LanguageVersion.Preview, source);
}

[Fact]
public async void DoesNotFindWarning_ForNestedStaticAbstractInterfaceMembers()
{
string source = string.Format(codeTemplate, methodCode, string.Empty);

await Verify.VerifyAnalyzer(LanguageVersion.Preview, source);
}

[Theory]
[InlineData("static", "", "{ }")]
[InlineData("", "abstract", ";")]
public async void FindsWarning_ForNotStaticAbstractInterfaceMembers(string staticModifier, string abstractModifier, string methodBody)
{
string source = $@"
using Xunit;
public interface IClass {{
{staticModifier} {abstractModifier} void Method() {methodBody}
}}
public class Class : IClass {{
public {staticModifier} void Method() {{ }}
}}
public abstract class TestClass {{
[Fact]
public void TestMethod() {{
var data = new Class();
Assert.IsAssignableFrom(typeof(IClass), data);
}}
}}";

var expected =
Verify
.Diagnostic()
.WithSpan(17, 9, 17, 54)
.WithArguments("IClass");

await Verify.VerifyAnalyzer(LanguageVersion.CSharp8, source, expected);
}
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ protected override void AnalyzeInvocation(
var type = typeOfOperation.TypeOperand;
var typeName = SymbolDisplay.ToDisplayString(type);

// Static abstract interface members can't be used as types in generics
if (type.TypeKind == TypeKind.Interface)
{
var allInterfaces = (type as INamedTypeSymbol)?.AllInterfaces;
if (allInterfaces != null)
{
var allMembers =
allInterfaces
.Value
.SelectMany(i => i.GetMembers())
.Concat(type.GetMembers());

if (allMembers.Any(m => m is { IsAbstract: true, IsStatic: true }))
return;
}
}

var builder = ImmutableDictionary.CreateBuilder<string, string?>();
builder[Constants.Properties.MethodName] = method.Name;
builder[Constants.Properties.TypeName] = typeName;
Expand Down

0 comments on commit 0c15399

Please sign in to comment.