🔍 Duplicate Code Detected: Identical AnalyzeSymbol in TestInitialize and TestCleanup Analyzers
Analysis of commit 741048f
Assignee: @copilot
Summary
TestInitializeShouldBeValidAnalyzer and TestCleanupShouldBeValidAnalyzer are near-identical classes (66 lines each). Their AnalyzeSymbol method bodies are byte-for-byte identical — both call HasValidFixtureMethodSignature with exactly the same arguments (shouldBeStatic: false, allowGenericType: true, FixtureParameterMode.MustNotHaveTestContext, testContextSymbol: null, fixtureAllowInheritedTestClass: true). The only structural difference between the two classes is the name of the MSTest attribute they validate.
Duplication Details
Pattern: Identical AnalyzeSymbol method body across two fixture lifecycle analyzers
-
Severity: Medium
-
Occurrences: 2 identical implementations (66-line files, 10-line duplicated method body)
-
Locations:
src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs (lines 53–65)
src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs (lines 53–65)
-
Code Sample (identical in both files — only the first parameter name differs):
private static void AnalyzeSymbol(
SymbolAnalysisContext context,
INamedTypeSymbol testInitialize_or_testCleanupAttributeSymbol, // name differs
INamedTypeSymbol? taskSymbol,
INamedTypeSymbol? valueTaskSymbol,
INamedTypeSymbol testClassAttributeSymbol,
bool canDiscoverInternals)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
if (methodSymbol.HasAttribute(testInitialize_or_testCleanupAttributeSymbol)
&& !methodSymbol.HasValidFixtureMethodSignature(
taskSymbol, valueTaskSymbol, canDiscoverInternals,
shouldBeStatic: false,
allowGenericType: true,
FixtureParameterMode.MustNotHaveTestContext,
testContextSymbol: null,
testClassAttributeSymbol,
fixtureAllowInheritedTestClass: true,
out bool isFixable))
{
context.ReportDiagnostic(isFixable
? methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)
: methodSymbol.CreateDiagnostic(Rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
The Initialize method is also structurally identical (both delegate to FixtureMethodAnalyzerHelper.RegisterFixtureMethodSymbolAction with the same lambda shape), and the class-level boilerplate (SupportedDiagnostics, DiagnosticDescriptorHelper.Create call shape) is copy-pasted.
Impact Analysis
- Maintainability: Any change to the fixture validation logic (e.g., updating
HasValidFixtureMethodSignature arguments) must be applied to both files in sync.
- Bug Risk: If one file is updated and the other is not, the two analyzers will silently diverge.
- Code Bloat: ~20 lines of identical code across two files in the same project.
Refactoring Recommendations
- Extend
FixtureMethodAnalyzerHelper with a shared AnalyzeInstanceFixtureMethod helper
- Add a static method to
src/Analyzers/MSTest.Analyzers/Helpers/FixtureMethodAnalyzerHelper.cs:
internal static void AnalyzeInstanceFixtureMethod(
SymbolAnalysisContext context,
INamedTypeSymbol fixtureAttributeSymbol,
INamedTypeSymbol? taskSymbol,
INamedTypeSymbol? valueTaskSymbol,
INamedTypeSymbol testClassAttributeSymbol,
bool canDiscoverInternals,
DiagnosticDescriptor rule)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
if (methodSymbol.HasAttribute(fixtureAttributeSymbol)
&& !methodSymbol.HasValidFixtureMethodSignature(
taskSymbol, valueTaskSymbol, canDiscoverInternals,
shouldBeStatic: false, allowGenericType: true,
FixtureParameterMode.MustNotHaveTestContext, testContextSymbol: null,
testClassAttributeSymbol, fixtureAllowInheritedTestClass: true, out bool isFixable))
{
context.ReportDiagnostic(isFixable
? methodSymbol.CreateDiagnostic(rule, methodSymbol.Name)
: methodSymbol.CreateDiagnostic(rule, DiagnosticDescriptorHelper.CannotFixProperties, methodSymbol.Name));
}
}
- Both
TestInitializeShouldBeValidAnalyzer and TestCleanupShouldBeValidAnalyzer can then collapse their private AnalyzeSymbol to a single line delegating to the helper.
- Estimated effort: Low (~30 lines changed)
- Benefits: Single implementation of instance-fixture validation logic; changes propagate automatically
Implementation Checklist
Analysis Metadata
- Analyzed Files: 2 (
TestInitializeShouldBeValidAnalyzer.cs, TestCleanupShouldBeValidAnalyzer.cs)
- Detection Method: Semantic code analysis (file diff)
- Commit: 741048f
- Analysis Date: 2026-06-11
🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Duplicate Code Detector workflow.{ai_credits_suffix} · [◷]( · ◷)
Add this agentic workflows to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
🔍 Duplicate Code Detected: Identical
AnalyzeSymbolin TestInitialize and TestCleanup AnalyzersAnalysis of commit 741048f
Assignee:
@copilotSummary
TestInitializeShouldBeValidAnalyzerandTestCleanupShouldBeValidAnalyzerare near-identical classes (66 lines each). TheirAnalyzeSymbolmethod bodies are byte-for-byte identical — both callHasValidFixtureMethodSignaturewith exactly the same arguments (shouldBeStatic: false,allowGenericType: true,FixtureParameterMode.MustNotHaveTestContext,testContextSymbol: null,fixtureAllowInheritedTestClass: true). The only structural difference between the two classes is the name of the MSTest attribute they validate.Duplication Details
Pattern: Identical
AnalyzeSymbolmethod body across two fixture lifecycle analyzersSeverity: Medium
Occurrences: 2 identical implementations (66-line files, 10-line duplicated method body)
Locations:
src/Analyzers/MSTest.Analyzers/TestInitializeShouldBeValidAnalyzer.cs(lines 53–65)src/Analyzers/MSTest.Analyzers/TestCleanupShouldBeValidAnalyzer.cs(lines 53–65)Code Sample (identical in both files — only the first parameter name differs):
The
Initializemethod is also structurally identical (both delegate toFixtureMethodAnalyzerHelper.RegisterFixtureMethodSymbolActionwith the same lambda shape), and the class-level boilerplate (SupportedDiagnostics,DiagnosticDescriptorHelper.Createcall shape) is copy-pasted.Impact Analysis
HasValidFixtureMethodSignaturearguments) must be applied to both files in sync.Refactoring Recommendations
FixtureMethodAnalyzerHelperwith a sharedAnalyzeInstanceFixtureMethodhelpersrc/Analyzers/MSTest.Analyzers/Helpers/FixtureMethodAnalyzerHelper.cs:TestInitializeShouldBeValidAnalyzerandTestCleanupShouldBeValidAnalyzercan then collapse their privateAnalyzeSymbolto a single line delegating to the helper.Implementation Checklist
AnalyzeInstanceFixtureMethod(or equivalent) toFixtureMethodAnalyzerHelperTestInitializeShouldBeValidAnalyzerandTestCleanupShouldBeValidAnalyzerto call the shared methodAnalysis Metadata
TestInitializeShouldBeValidAnalyzer.cs,TestCleanupShouldBeValidAnalyzer.cs)Add this agentic workflows to your repo
To install this agentic workflow, run