Skip to content

[duplicate-code] Duplicate Code Pattern: SecrecyLabel/IntegrityLabel Structural DuplicationΒ #5518

@github-actions

Description

@github-actions

πŸ” Duplicate Code Pattern: SecrecyLabel/IntegrityLabel Structural Duplication

Part of duplicate code analysis: #5517

Summary

internal/difc/labels.go defines two wrapper types β€” SecrecyLabel and IntegrityLabel β€” that are structurally identical except for their type names and the boolean flag passed to checkFlowHelper. The six method pairs below are near-identical.

Duplication Details

Pattern: Parallel type hierarchies with identical boilerplate

  • Severity: Medium
  • Occurrences: 6 pairs of mirrored methods (~34 duplicated lines)
  • Locations: internal/difc/labels.go
SecrecyLabel IntegrityLabel Lines
NewSecrecyLabel() NewIntegrityLabel() 181–183, 313–315
NewSecrecyLabelWithTags() NewIntegrityLabelWithTags() 186–188, 318–320
(l *SecrecyLabel) getLabel() (l *IntegrityLabel) getLabel() 191–196, 323–328
(l *SecrecyLabel) CanFlowTo() (l *IntegrityLabel) CanFlowTo() 201–204, 334–337
(l *SecrecyLabel) CheckFlow() (l *IntegrityLabel) CheckFlow() 296–298, 340–342
(l *SecrecyLabel) Clone() (l *IntegrityLabel) Clone() 301–303, 345–347

Code Sample (getLabel β€” identical implementation in both types):

// SecrecyLabel version (lines 191–196)
func (l *SecrecyLabel) getLabel() *Label {
    if l == nil {
        return nil
    }
    return l.Label
}

// IntegrityLabel version (lines 323–328) β€” word-for-word identical
func (l *IntegrityLabel) getLabel() *Label {
    if l == nil {
        return nil
    }
    return l.Label
}

Code Sample (Clone β€” identical implementation in both types):

// SecrecyLabel version (line 301–303)
func (l *SecrecyLabel) Clone() *SecrecyLabel {
    return &SecrecyLabel{Label: cloneLabelOrNew(l.getLabel())}
}

// IntegrityLabel version (lines 345–347)
func (l *IntegrityLabel) Clone() *IntegrityLabel {
    return &IntegrityLabel{Label: cloneLabelOrNew(l.getLabel())}
}

Impact Analysis

  • Maintainability: If a new method (e.g., IsEmpty(), String()) is added to one type, it must be manually added to the other or the two types silently diverge.
  • Bug Risk: Low today; medium over time as types evolve independently.
  • Code Bloat: ~34 extra lines of boilerplate that serve no unique purpose.

Refactoring Recommendations

  1. Go Generics (preferred) β€” Introduce a generic FlowLabel[T] that wraps *Label and carries a checkSubset bool constant at construction time:

    type FlowLabel[T any] struct {
        Label      *Label
        checkSubset bool
    }
    func (l *FlowLabel[T]) CanFlowTo(target *FlowLabel[T]) bool { ... }
    func (l *FlowLabel[T]) Clone() *FlowLabel[T]               { ... }

    Keep thin named type aliases (type SecrecyLabel = FlowLabel[secrecyKind]) for backwards-compatible public API.

  2. Composition via embedded struct (simpler alternative) β€” Embed a shared baseLabel struct in both types and promote the shared methods. Only CanFlowTo/CheckFlow need per-type overrides.

Implementation Checklist

  • Review duplication findings
  • Decide between generics and composition approach
  • Implement refactoring
  • Ensure SecrecyLabel/IntegrityLabel public API remains unchanged
  • Verify all existing tests pass

Parent Issue

See parent analysis report: #5517
Related to #5517

Generated by Duplicate Code Detector Β· ● 1.2M Β· β—·

  • expires on May 19, 2026, 3:40 AM UTC

Metadata

Metadata

Assignees

No one assigned

    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