Skip to content

[duplicate-code] Duplicate Code: ObjectPool(T) Implemented Twice in Analyzers and Platform #9097

@Evangelink

Description

@Evangelink

Analysis of commit 916e3a0

Assignee: @copilot

Summary

ObjectPool<T> is implemented independently in two separate projects — MSTest.Analyzers and Microsoft.Testing.Platform — with 160 duplicated lines across 6 clone pairs. Both implementations are internal copies of the same Roslyn object-pooling pattern with near-identical logic and comments.

Duplication Details

Pattern: Parallel ObjectPool(T) Implementations

  • Severity: Medium
  • Occurrences: 6 clone pairs, 160 duplicated lines
  • Locations:
    • src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ObjectPool.cs (lines 44–276, 281 lines total)
    • src/Platform/Microsoft.Testing.Platform/Helpers/ObjectPool.cs (lines 52–289, 294 lines total)

The two files share:

  • The Element struct definition (lines 44–94 / 52–102, 51 lines)
  • The Allocate / Free loop pattern (lines 134–159 / 147–172, 26 lines)
  • The CreateInstance factory overloads (lines 161–178 / 174–191, 18 lines)
  • The ObjectPool<T>.Clear method (lines 197–213 / 210–226, 17 lines)
  • The ForgetTrackedObject / leak-detection block (lines 229–266 / 242–279, 38 lines)
  • The DebugViewOfPool helpers (lines 267–276 / 280–289, 10 lines)

Code Sample (shared Allocate logic):

// src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ObjectPool.cs  lines 134-159
// src/Platform/Microsoft.Testing.Platform/Helpers/ObjectPool.cs         lines 147-172
public T Allocate()
{
    // PERF: Examine the first element. If that fails, AllocateSlow will look at the remaining elements.
    // Note that the initial read is optimistically not synchronized. That is intentional.
    // We will interlock only when we have a candidate. In a worst case we may miss some
    // recently returned objects. Not a big deal.
    T? inst = _firstItem;
    if (inst == null || inst != Interlocked.CompareExchange(ref _firstItem, null, inst))
    {
        inst = AllocateSlow();
    }
    ...
}

Impact Analysis

  • Maintainability: Any bug fix or improvement to the pool implementation must be applied twice. The two copies have already diverged — e.g. the Platform copy adds [ExcludeFromCodeCoverage], #pragma warning disable SA1201, and extra StyleCop suppressions not present in the Analyzer copy.
  • Bug Risk: Fixes applied to one copy will silently miss the other, causing inconsistent behavior.
  • Code Bloat: ~300 lines of duplicated infrastructure code.

Refactoring Recommendations

  1. Move to a shared internal package or linked file

    • Create src/Platform/SharedExtensionHelpers/ObjectPool.cs (the SharedExtensionHelpers pattern already exists in the repo)
    • Or use <Compile Include="..." Link="..." /> MSBuild linking to share the file between the two projects
    • Estimated effort: 2–3 hours
    • Benefits: Single source of truth; fixes and improvements propagate to both consumers
  2. Expose via InternalsVisibleTo from Platform

    • If the Platform project is already a dependency of the Analyzers project (or a shared helpers project), expose the existing ObjectPool<T> as internal-visible to Analyzers
    • Estimated effort: 1 hour

Implementation Checklist

  • Review whether a project reference from MSTest.Analyzers to Microsoft.Testing.Platform is feasible (analyzer packages typically can't reference runtime packages)
  • Determine best sharing mechanism (linked file vs shared project vs InternalsVisibleTo)
  • Extract the consolidated implementation
  • Remove the duplicate copy
  • Verify all existing usages compile and pass tests

Analysis Metadata

  • Analyzed Files: 1003 C# source files
  • Detection Method: jscpd semantic code analysis (threshold: minLines=6, minTokens=50)
  • Commit: 916e3a0
  • Analysis Date: 2026-06-13

🤖 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. · 734 AIC · ⌖ 14.1 AIC · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on Jun 15, 2026, 5:51 AM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions