diff --git a/src/xunit.analyzers/PublicMethodShouldBeMarkedAsTest.cs b/src/xunit.analyzers/PublicMethodShouldBeMarkedAsTest.cs index 70a1ad8d..50c51841 100644 --- a/src/xunit.analyzers/PublicMethodShouldBeMarkedAsTest.cs +++ b/src/xunit.analyzers/PublicMethodShouldBeMarkedAsTest.cs @@ -26,7 +26,8 @@ internal override void AnalyzeCompilation(CompilationStartAnalysisContext compil var type = (INamedTypeSymbol)symbolContext.Symbol; if (type.TypeKind != TypeKind.Class || - type.DeclaredAccessibility != Accessibility.Public) + type.DeclaredAccessibility != Accessibility.Public || + type.IsAbstract) return; var methodsToIgnore = interfacesToIgnore.Where(i => i != null && type.AllInterfaces.Contains(i)) @@ -42,7 +43,11 @@ internal override void AnalyzeCompilation(CompilationStartAnalysisContext compil symbolContext.CancellationToken.ThrowIfCancellationRequested(); var method = (IMethodSymbol)member; - if (method.MethodKind != MethodKind.Ordinary) + // Check for method.IsAbstract and earlier for type.IsAbstract is done + // twice to enable better diagnostics during code editing. It is useful with + // incomplete code for abstract types - missing abstract keyword on type + // or on abstract method + if (method.MethodKind != MethodKind.Ordinary || method.IsAbstract) continue; var isTestMethod = method.GetAttributes().ContainsAttributeType(xunitContext.FactAttributeType); diff --git a/test/xunit.analyzers.tests/PublicMethodShouldBeMarkedAsTestTests.cs b/test/xunit.analyzers.tests/PublicMethodShouldBeMarkedAsTestTests.cs index 55b1e2a8..420d39e6 100644 --- a/test/xunit.analyzers.tests/PublicMethodShouldBeMarkedAsTestTests.cs +++ b/test/xunit.analyzers.tests/PublicMethodShouldBeMarkedAsTestTests.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using System; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; namespace Xunit.Analyzers @@ -37,6 +38,29 @@ public void Dispose() { } Assert.Empty(diagnostics); } + [Fact] + public async void DoesNotFindErrorForPublicAbstractMethod() + { + var diagnostics = await CodeAnalyzerHelper.GetDiagnosticsAsync(analyzer, +@"public abstract class TestClass { + [Xunit.Fact] public void TestMethod() { } + public abstract void AbstractMethod(); +}"); + + Assert.Empty(diagnostics); + } + + [Fact] + public async void DoesNotFindErrorForPublicAbstractMethodMarkedWithFact() + { + var diagnostics = await CodeAnalyzerHelper.GetDiagnosticsAsync(analyzer, +@"public abstract class TestClass { + [Xunit.Fact] public void TestMethod() { } + [Xunit.Fact] public abstract void AbstractMethod(); +}"); + Assert.Empty(diagnostics); + } + [Fact] public async void DoesNotFindErrorForIDisposableDisposeMethodOverrideFromParentClass() {