π 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
-
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.
-
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
Parent Issue
See parent analysis report: #5517
Related to #5517
Generated by Duplicate Code Detector Β· β 1.2M Β· β·
π Duplicate Code Pattern: SecrecyLabel/IntegrityLabel Structural Duplication
Part of duplicate code analysis: #5517
Summary
internal/difc/labels.godefines two wrapper types βSecrecyLabelandIntegrityLabelβ that are structurally identical except for their type names and the boolean flag passed tocheckFlowHelper. The six method pairs below are near-identical.Duplication Details
Pattern: Parallel type hierarchies with identical boilerplate
internal/difc/labels.goNewSecrecyLabel()NewIntegrityLabel()NewSecrecyLabelWithTags()NewIntegrityLabelWithTags()(l *SecrecyLabel) getLabel()(l *IntegrityLabel) getLabel()(l *SecrecyLabel) CanFlowTo()(l *IntegrityLabel) CanFlowTo()(l *SecrecyLabel) CheckFlow()(l *IntegrityLabel) CheckFlow()(l *SecrecyLabel) Clone()(l *IntegrityLabel) Clone()Code Sample (getLabel β identical implementation in both types):
Code Sample (Clone β identical implementation in both types):
Impact Analysis
IsEmpty(),String()) is added to one type, it must be manually added to the other or the two types silently diverge.Refactoring Recommendations
Go Generics (preferred) β Introduce a generic
FlowLabel[T]that wraps*Labeland carries acheckSubset boolconstant at construction time:Keep thin named type aliases (
type SecrecyLabel = FlowLabel[secrecyKind]) for backwards-compatible public API.Composition via embedded struct (simpler alternative) β Embed a shared
baseLabelstruct in both types and promote the shared methods. OnlyCanFlowTo/CheckFlowneed per-type overrides.Implementation Checklist
SecrecyLabel/IntegrityLabelpublic API remains unchangedParent Issue
See parent analysis report: #5517
Related to #5517