Skip to content

duplicate-code-renamed

Category: Duplicate Code
Severity: Warning
Triggered by: pyscn analyze, pyscn check --select clones

What it does

Flags code blocks with the same structure but different identifiers or literals (Type-2 clones, similarity ≥ 0.75).

Why is this a problem?

Renamed clones are what happens when someone copies a function, runs a find-and-replace on the variable names, and moves on. The structure is identical; only the nouns changed. The maintenance cost is the same as for textually identical clones — every change has to be applied in multiple places — but the duplication is harder to spot by eye because the words differ.

This is also a signal that the original code wasn't parameterized when it should have been. The thing that varies (a type, a field name, a constant) is a natural function argument.

Example

def total_for_orders(orders):
    total = 0
    for order in orders:
        if order.status == "paid":
            total += order.amount
    return total

def total_for_invoices(invoices):
    total = 0
    for invoice in invoices:
        if invoice.status == "settled":
            total += invoice.amount
    return total

Use instead

Extract a generic helper that takes the varying predicate and field accessors as parameters.

def total_where(items, is_active):
    return sum(item.amount for item in items if is_active(item))

def total_for_orders(orders):
    return total_where(orders, lambda o: o.status == "paid")

def total_for_invoices(invoices):
    return total_where(invoices, lambda i: i.status == "settled")

Options

Option Default Description
clones.type2_threshold 0.75 Minimum similarity for a pair to be reported as renamed.
clones.similarity_threshold 0.65 Global floor applied before per-type thresholds.
clones.ignore_identifiers true Treat differing variable names as equivalent when computing similarity.
clones.ignore_literals true Treat differing numeric and string literals as equivalent.
clones.min_lines 5 Minimum fragment size in lines.
clones.enabled_clone_types ["type1","type2","type4"] Include "type2" to keep this rule active.

References