Skip to content

Duplicate Code: Qualified DU Case Name Resolution in LensesGenerator and DUCasesGenerator #251

@github-actions

Description

@github-actions

Analysis of commit 165a7e5

Assignee: @copilot

Summary

The logic for resolving a DU case's fully-qualified SynLongIdent (based on whether RequireQualifiedAccess is in effect) is duplicated between LensesGenerator.fs and DUCasesGenerator.fs. DUCasesGenerator correctly extracted this into a named helper (resolveCaseIdent), but LensesGenerator contains an identical inline copy.

Duplication Details

Pattern: Qualified DU case identifier construction

  • Severity: Medium

  • Occurrences: 2

  • Locations:

    • src/Myriad.Plugins/DUCasesGenerator.fs (lines 18–24) — extracted helper resolveCaseIdent
    • src/Myriad.Plugins/LensesGenerator.fs (lines 68–72) — identical inline logic
  • Code Sample (DUCasesGenerator.fs, lines 18–24):

    let resolveCaseIdent (requiresQualifiedAccess: bool) (parent: LongIdent) (id: Ident) : SynLongIdent =
        let parts =
            if requiresQualifiedAccess then
                (parent |> List.map (fun i -> i.idText)) @ [id.idText]
            else
                [id.idText]
        SynLongIdent.Create parts
  • Code Sample (LensesGenerator.fs, lines 68–72 — duplicate inline):

    let matchCaseIdentParts =
        if requiresQualifiedAccess then
            (parent |> List.map (fun i -> i.idText)) @ [id.idText]
        else
            [id.idText]
    let fullCaseName = SynLongIdent.Create matchCaseIdentParts

Impact Analysis

  • Maintainability: Any change to how DU case names are qualified (e.g., supporting nested modules) must be applied in both files separately.
  • Bug Risk: A future fix to one copy is likely to be missed in the other, leading to inconsistent behaviour between lenses on DUs and DU case utilities.
  • Code Bloat: Minor — 6 duplicate lines — but the semantic impact is higher than the line count suggests.

Refactoring Recommendations

  1. Move resolveCaseIdent to GeneratorHelpers

    • Target file: src/Myriad.Plugins/GeneratorHelpers.fs
    • Make it internal (it already fits the module's helper scope).
    • Replace the inline logic in LensesGenerator.fs with a call to GeneratorHelpers.resolveCaseIdent.
    • Estimated effort: <1 hour
    • Benefits: single source of truth for qualified DU case name resolution; prevents divergence
  2. Alternative: keep resolveCaseIdent in CreateDUModule and open it in LensesGenerator

    • Less ideal (cross-module coupling within the plugin), but avoids moving the function if preferred.

Implementation Checklist

  • Move (or re-expose) resolveCaseIdent in GeneratorHelpers.fs
  • Replace the inline duplication in LensesGenerator.fs createLensForDU with a call to the shared helper
  • Run integration tests: dotnet run --framework net9.0 --fail-on-focused-tests --summary --project ./test/Myriad.IntegrationPluginTests/Myriad.IntegrationPluginTests.fsproj
  • Verify generated output is unchanged

Analysis Metadata

  • Analyzed Files: 3 (FieldsGenerator.fs, LensesGenerator.fs, DUCasesGenerator.fs)
  • Detection Method: Semantic code analysis
  • Commit: 165a7e5
  • Analysis Date: 2026-03-11

Generated by Duplicate Code Detector

To install this workflow, run gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@ee49512da7887942965ac0a0e48357106313c9dd. View source at https://github.com/githubnext/agentics/tree/ee49512da7887942965ac0a0e48357106313c9dd/workflows/duplicate-code-detector.md.

Metadata

Metadata

Labels

bugSomething isn't workingduplicateThis issue or pull request already exists

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions