Find duplicate code
Recipe ID
io.moderne.prethink.quality.FindDuplicateCodeArtifact
io.moderne.recipe:rewrite-prethinkDetect duplicate and likely-duplicate code across the codebase by AST-subtree fingerprinting and MinHash/LSH method alignment (zero AI). Reports Type-1 (exact), Type-2 (renamed), and Type-3 (gapped: inserted/removed/edited statements) clone groups ranked by the volume of code that would collapse if the duplication were refactored away.
Usage
This recipe has no required configuration options. You’ll need the Moderne CLI configured before running the command below.
mod run . --recipe io.moderne.prethink.quality.FindDuplicateCodeIf the recipe isn’t available locally, install it with:
mod config recipes jar install io.moderne.recipe:rewrite-prethink:0.11.1Options
| Name | Type | Description |
|---|---|---|
minNodes | Integer | Minimum number of AST nodes a subtree must contain to be considered for exact (Type-1) duplication. Larger values reduce noise. Defaults to 75. e.g. 75 |
minNodesType2 | Integer | Minimum number of AST nodes a subtree must contain to be considered for renamed (Type-2) duplication. Should be at least the Type-1 minimum because anonymization is noisier. Defaults to 110. e.g. 110 |
minOccurrences | Integer | Minimum number of occurrences for a fragment to be reported as a clone group. Defaults to 2. e.g. 2 |
detectType2 | Boolean | Whether to detect renamed (Type-2) clones in addition to exact (Type-1) clones. Defaults to true. e.g. true |
includeTestSources | Boolean | Whether to include test sources (paths under src/test). Defaults to false. e.g. false |
maxOccurrencesPerGroup | Integer | Cap on the number of individual occurrences reported per clone group. The true count is always reported; only the enumerated locations/rows are capped. Defaults to 200. e.g. 200 |
snippetMaxLines | Integer | Maximum number of lines of the representative fragment to include in the snippet. Defaults to 40. e.g. 40 |
minStatements | Integer | Minimum number of consecutive statements that must match to seed a statement-sequence clone. Defaults to 5. e.g. 5 |
gapBudget | Integer | Maximum number of statement edits (insertions, deletions, or substitutions) tolerated inside a statement-sequence clone (Type-3). 0 detects only exact/renamed runs; 1 (the default) also catches copy-paste-then-edit/insert/remove-one-statement. Higher values catch more divergent copies. e.g. 1 |
detectStatementSequences | Boolean | Whether to detect duplicated runs of consecutive statements (in addition to whole-subtree clones). Defaults to true. e.g. true |
suppressBoilerplate | Boolean | Whether to structurally suppress low-value boilerplate: getters/setters, equals/hashCode/toString, runs or blocks composed entirely of trivial data statements (constant declarations, map/collection population), and subtrees dominated by a large string-literal concatenation (embedded doc/JSON/prompt blobs). Suppressed fragments are still descended into, so genuine clones nested inside them are still found. Defaults to true. e.g. true |
detectSimilarMethods | Boolean | Whether to also detect gapped (Type-3) clones between whole methods that share no long run of identical statements, by aligning MinHash/LSH-similar method pairs. Catches copy-edited methods the statement-run detector misses because it needs a run of identical statements to anchor. Defaults to true. e.g. true |
Data tables
Structured output this recipe can produce.
- Duplicate codeGroups of duplicated code detected across the codebase by AST-subtree fingerprinting. One row per clone group; sort by redundant volume to surface the highest-value refactoring targets.
io.moderne.prethink.table.DuplicateCode - Duplicate code occurrencesOne row per individual occurrence of a duplicated fragment, with the machine coordinates a remediation recipe needs to locate and converge each clone. Join to the duplicate code data table on clone group id.
io.moderne.prethink.table.DuplicateCodeOccurrences - Source files that had resultsSource files that were modified by the recipe run.
org.openrewrite.table.SourcesFileResults - Source files that had search resultsSearch results that were found during the recipe run.
org.openrewrite.table.SearchResults - Source files that errored on a recipeThe details of all errors produced by a recipe run.
org.openrewrite.table.SourcesFileErrors - Recipe performanceStatistics used in analyzing the performance of recipes.
org.openrewrite.table.RecipeRunStats