Project-wide context derived from the full scanned root.
Dimension scores across all quality axes.
Split is based on baseline: known duplicates are already recorded in baseline, new duplicates are absent from baseline.
1 | def transform_alpha(items: list[int]) -> tuple[list[int], int]: 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 28 | checksum2 = extra + 6 29 | checksum3 = checksum2 + 7 30 | checksum4 = checksum3 + 8 31 | checksum5 = checksum4 + 9 32 | checksum6 = checksum5 + 10 33 | checksum7 = checksum6 + 11 34 | checksum8 = checksum7 + 12 35 | checksum9 = checksum8 + 13 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 43 | return prepared, checksum15 1 | def transform_beta(items: list[int]) -> tuple[list[int], int]: 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 28 | checksum2 = extra + 6 29 | checksum3 = checksum2 + 7 30 | checksum4 = checksum3 + 8 31 | checksum5 = checksum4 + 9 32 | checksum6 = checksum5 + 10 33 | checksum7 = checksum6 + 11 34 | checksum8 = checksum7 + 12 35 | checksum9 = checksum8 + 13 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 43 | return prepared, checksum15 11 | return transform_shared_a(values) 12 | 13 | 14 | def transform_shared_a(items: list[int]) -> tuple[list[int], int]: 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5 41 | checksum2 = extra + 6 42 | checksum3 = checksum2 + 7 43 | checksum4 = checksum3 + 8 44 | checksum5 = checksum4 + 9 45 | checksum6 = checksum5 + 10 46 | checksum7 = checksum6 + 11 47 | checksum8 = checksum7 + 12 48 | checksum9 = checksum8 + 13 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 56 | return prepared, checksum15 11 | return transform_shared_b(values) 12 | 13 | 14 | def transform_shared_b(items: list[int]) -> tuple[list[int], int]: 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5 41 | checksum2 = extra + 6 42 | checksum3 = checksum2 + 7 43 | checksum4 = checksum3 + 8 44 | checksum5 = checksum4 + 9 45 | checksum6 = checksum5 + 10 46 | checksum7 = checksum6 + 11 47 | checksum8 = checksum7 + 12 48 | checksum9 = checksum8 + 13 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 56 | return prepared, checksum15 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 28 | checksum2 = extra + 6 29 | checksum3 = checksum2 + 7 30 | checksum4 = checksum3 + 8 31 | checksum5 = checksum4 + 9 32 | checksum6 = checksum5 + 10 33 | checksum7 = checksum6 + 11 34 | checksum8 = checksum7 + 12 35 | checksum9 = checksum8 + 13 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 28 | checksum2 = extra + 6 29 | checksum3 = checksum2 + 7 30 | checksum4 = checksum3 + 8 31 | checksum5 = checksum4 + 9 32 | checksum6 = checksum5 + 10 33 | checksum7 = checksum6 + 11 34 | checksum8 = checksum7 + 12 35 | checksum9 = checksum8 + 13 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5 41 | checksum2 = extra + 6 42 | checksum3 = checksum2 + 7 43 | checksum4 = checksum3 + 8 44 | checksum5 = checksum4 + 9 45 | checksum6 = checksum5 + 10 46 | checksum7 = checksum6 + 11 47 | checksum8 = checksum7 + 12 48 | checksum9 = checksum8 + 13 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5 41 | checksum2 = extra + 6 42 | checksum3 = checksum2 + 7 43 | checksum4 = checksum3 + 8 44 | checksum5 = checksum4 + 9 45 | checksum6 = checksum5 + 10 46 | checksum7 = checksum6 + 11 47 | checksum8 = checksum7 + 12 48 | checksum9 = checksum8 + 13 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 43 | return prepared, checksum15 36 | checksum10 = checksum9 + 14 37 | checksum11 = checksum10 + 15 38 | checksum12 = checksum11 + 16 39 | checksum13 = checksum12 + 17 40 | checksum14 = checksum13 + 18 41 | checksum15 = checksum14 + 19 42 | 43 | return prepared, checksum15 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 56 | return prepared, checksum15 49 | checksum10 = checksum9 + 14 50 | checksum11 = checksum10 + 15 51 | checksum12 = checksum11 + 16 52 | checksum13 = checksum12 + 17 53 | checksum14 = checksum13 + 18 54 | checksum15 = checksum14 + 19 55 | 56 | return prepared, checksum15 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 1 | def transform_alpha(items: list[int]) -> tuple[list[int], int]: 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 1 | def transform_beta(items: list[int]) -> tuple[list[int], int]: 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 12 | 13 | 14 | def transform_shared_a(items: list[int]) -> tuple[list[int], int]: 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 12 | 13 | 14 | def transform_shared_b(items: list[int]) -> tuple[list[int], int]: 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 2 | if not items: 3 | return [], 0 4 | 5 | prepared: list[int] = [] 6 | total = 0 7 | count = 0 8 | 9 | for item in items: 10 | doubled = item * 2 11 | if doubled % 3 == 0: 12 | prepared.append(doubled) 13 | else: 14 | prepared.append(doubled + 1) 15 | total += prepared[-1] 16 | count += 1 17 | 18 | average = total // count if count else 0 19 | marker = len(prepared) 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 15 | if not items: 16 | return [], 0 17 | 18 | prepared: list[int] = [] 19 | total = 0 20 | count = 0 21 | 22 | for item in items: 23 | doubled = item * 2 24 | if doubled % 3 == 0: 25 | prepared.append(doubled) 26 | else: 27 | prepared.append(doubled + 1) 28 | total += prepared[-1] 29 | count += 1 30 | 31 | average = total // count if count else 0 32 | marker = len(prepared) 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 18 | average = total // count if count else 0 19 | marker = len(prepared) 20 | audit = marker + average 21 | checksum = audit + total 22 | signature = checksum - marker 23 | offset = signature + 1 24 | window = offset + 2 25 | anchor = window + 3 26 | tail = anchor + 4 27 | extra = tail + 5 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5 31 | average = total // count if count else 0 32 | marker = len(prepared) 33 | audit = marker + average 34 | checksum = audit + total 35 | signature = checksum - marker 36 | offset = signature + 1 37 | window = offset + 2 38 | anchor = window + 3 39 | tail = anchor + 4 40 | extra = tail + 5| Function ? | File ? | CC ? | Nesting ? | Risk ? |
|---|---|---|---|---|
| _encode_wire_file_entry | codeclone/cache.py | 20 | 4 | medium |
| Cache._decode_segment_report_projection | codeclone/cache.py | 20 | 3 | medium |
| write_report_outputs | codeclone/_cli_reports.py | 20 | 3 | medium |
| metric_gate_reasons | codeclone/pipeline.py | 20 | 2 | medium |
| Cache.get_file_entry | codeclone/cache.py | 20 | 2 | medium |
| compute_lcom4 | codeclone/metrics/cohesion.py | 19 | 4 | medium |
| resolve_clone_baseline_state | codeclone/_cli_baselines.py | 18 | 5 | medium |
| extract_units_and_stats_from_source | codeclone/extractor.py | 18 | 3 | medium |
| _run_analysis_stages | codeclone/cli.py | 17 | 3 | medium |
| Cache._load_and_validate | codeclone/cache.py | 17 | 2 | medium |
| _FunctionStructureScanner._visit_statement | codeclone/structural_findings.py | 16 | 3 | medium |
| compute_cbo | codeclone/metrics/coupling.py | 16 | 3 | medium |
| render_meta_panel | codeclone/_html_report/_sections/_meta.py | 16 | 3 | medium |
| CFGBuilder._visit_try | codeclone/cfg.py | 15 | 2 | medium |
| Baseline.save | codeclone/baseline.py | 14 | 3 | medium |
| _render_group_explanation | codeclone/_html_report/_sections/_clones.py | 14 | 2 | medium |
| _derive_group_display_name | codeclone/_html_report/_sections/_clones.py | 13 | 4 | medium |
| build_html_report | codeclone/_html_report/_assemble.py | 13 | 3 | medium |
| _enforce_gating | codeclone/cli.py | 13 | 2 | medium |
| report | codeclone/pipeline.py | 13 | 1 | medium |
| process | codeclone/pipeline.py | 12 | 7 | medium |
| _collect_report_file_list | codeclone/report/json_contract.py | 12 | 4 | medium |
| _location_entry | codeclone/report/sarif.py | 12 | 2 | medium |
| Baseline.load | codeclone/baseline.py | 12 | 2 | medium |
| load_pyproject_config | codeclone/_cli_config.py | 12 | 1 | medium |
| _summarize_branch | codeclone/structural_findings.py | 11 | 6 | medium |
| _build_layer_groups | codeclone/_html_report/_sections/_dependencies.py | 11 | 3 | medium |
| MetricsBaseline.load | codeclone/metrics_baseline.py | 11 | 2 | medium |
| _main_impl | codeclone/cli.py | 11 | 2 | medium |
| _decode_wire_file_entry | codeclone/cache.py | 11 | 2 | medium |
| _decode_wire_dead_candidate | codeclone/cache.py | 11 | 2 | medium |
| _health_gauge_html | codeclone/_html_report/_sections/_overview.py | 11 | 2 | medium |
| _baseline_payload | tests/test_cli_inprocess.py | 10 | 3 | low |
| _collect_paths_from_metrics | codeclone/report/json_contract.py | 10 | 3 | low |
| assert_range_stats | codeclone/report/explain.py | 10 | 3 | low |
| merge_overlapping_items | codeclone/report/merge.py | 10 | 2 | low |
| _derive_inventory_code_counts | codeclone/report/json_contract.py | 10 | 2 | low |
| extract_blocks | codeclone/blocks.py | 10 | 2 | low |
| serialize_finding_group_card | codeclone/report/overview.py | 9 | 8 | low |
| render_markdown_report_document | codeclone/report/markdown.py | 9 | 4 | low |
| iter_py_files | codeclone/scanner.py | 9 | 3 | low |
| discover | codeclone/pipeline.py | 9 | 3 | low |
| render_dead_code_panel | codeclone/_html_report/_sections/_dead_code.py | 9 | 3 | low |
| _terminal_kind | codeclone/structural_findings.py | 9 | 2 | low |
| _structural_summary | codeclone/report/suggestions.py | 9 | 2 | low |
| render_text_report_document | codeclone/report/serialize.py | 9 | 2 | low |
| _clone_summary_from_group | codeclone/report/overview.py | 9 | 2 | low |
| _build_design_groups | codeclone/report/json_contract.py | 9 | 2 | low |
| _decode_wire_structural_group | codeclone/cache.py | 9 | 2 | low |
| _decode_optional_wire_coupled_classes | codeclone/cache.py | 9 | 2 | low |
| Class ? | File ? | CBO ? | Risk ? | Coupled classes ? |
|---|---|---|---|---|
| Cache | codeclone/cache.py | 10 | medium | CacheDataCacheEntryCacheStatus(+7 more) |
| CacheEntry | codeclone/cache.py | 6 | medium | CacheEntryBaseClassMetricsDictDeadCandidateDict(+3 more) |
| AstNormalizer | codeclone/normalize.py | 3 | low | Normaliz..onConfigastcopy |
| ProjectMetrics | codeclone/models.py | 3 | low | DeadItemHealthScoreModuleDep |
| FileMetrics | codeclone/models.py | 3 | low | ClassMetricsDeadCandidateModuleDep |
| CFGBuilder | codeclone/cfg.py | 3 | low | _LoopContext_TryLikeast |
| MetricsBaseline | codeclone/metrics_baseline.py | 2 | low | MetricsB..neStatushmac |
| _FunctionStructureScanner | codeclone/structural_findings.py | 2 | low | Function..ureFactsast |
| CacheData | codeclone/cache.py | 2 | low | AnalysisProfileCacheEntry |
| _ArgumentParser | codeclone/_cli_args.py | 2 | low | argparsesys |
| Baseline | codeclone/baseline.py | 1 | low | hmac |
| _DummyExecutor | tests/test_golden_v2.py | 1 | low | _DummyFuture |
| _FixedExecutor | tests/test_cli_inprocess.py | 1 | low | _FixedFuture |
| Block | codeclone/cfg_model.py | 1 | low | ast |
| _FileCache | codeclone/_html_snippets.py | 1 | low | _CacheInfo |
| _DummyExecutor | tests/test_cli_inprocess.py | 1 | low | _DummyFuture |
| ReportArtifacts | scripts/build_docs_example_report.py | 1 | low | json |
| _StatementRecord | codeclone/report/explain.py | 1 | low | ast |
| BootstrapResult | codeclone/pipeline.py | 1 | low | OutputPaths |
| Suggestion | codeclone/models.py | 1 | low | ReportLocation |
| StructuralFindingGroup | codeclone/models.py | 1 | low | Structur..currence |
| FunctionGroupItem | codeclone/models.py | 1 | low | Function..ItemBase |
| DepGraph | codeclone/models.py | 1 | low | ModuleDep |
| _QualnameCollector | codeclone/extractor.py | 1 | low | ast |
| _ModuleWalkState | codeclone/extractor.py | 1 | low | ast |
| ValidationError | codeclone/errors.py | 1 | low | CodeCloneError |
| ParseError | codeclone/errors.py | 1 | low | FileProc..ingError |
| FileProcessingError | codeclone/errors.py | 1 | low | CodeCloneError |
| CacheError | codeclone/errors.py | 1 | low | CodeCloneError |
| BaselineValidationError | codeclone/errors.py | 1 | low | Baseline..emaError |
| BaselineSchemaError | codeclone/errors.py | 1 | low | CodeCloneError |
| CFG | codeclone/cfg_model.py | 1 | low | Block |
| _TryLike | codeclone/cfg.py | 1 | low | ast |
| StructuralFindingGroupDict | codeclone/cache.py | 1 | low | Structur..enceDict |
| DeadCandidateDict | codeclone/cache.py | 1 | low | DeadCand..DictBase |
| ClassMetricsDict | codeclone/cache.py | 1 | low | ClassMet..DictBase |
| CacheEntryBase | codeclone/cache.py | 1 | low | FileStat |
| _HelpFormatter | codeclone/_cli_args.py | 1 | low | argparse |
| _FailExec | tests/test_pipeline_process.py | 0 | low | - |
| _FailingExecutor | tests/test_cli_inprocess.py | 0 | low | - |
| ReportContext | codeclone/_html_report/_context.py | 0 | low | - |
| _CacheLike | codeclone/_cli_runtime.py | 0 | low | - |
| TestAdmissionThresholdBoundaries | tests/test_extractor.py | 0 | low | - |
| ServiceB | tests/fixtures/golden_v2/clone_metrics_cycle/pkg/b.py | 0 | low | - |
| ServiceA | tests/fixtures/golden_v2/clone_metrics_cycle/pkg/a.py | 0 | low | - |
| PlainConsole | codeclone/_cli_rich.py | 0 | low | - |
| _UnexpectedExec | tests/test_pipeline_process.py | 0 | low | - |
| _DummyFuture | tests/test_golden_v2.py | 0 | low | - |
| _RecordingPrinter | tests/test_cli_unit.py | 0 | low | - |
| _FixedFuture | tests/test_cli_inprocess.py | 0 | low | - |
| Class ? | File ? | LCOM4 ? | Risk ? | Methods ? | Fields ? |
|---|---|---|---|---|---|
| Cache | codeclone/cache.py | 1 | low | 20 | 30 |
| CacheEntry | codeclone/cache.py | 1 | low | 0 | 0 |
| AstNormalizer | codeclone/normalize.py | 2 | medium | 13 | 5 |
| ProjectMetrics | codeclone/models.py | 1 | low | 0 | 0 |
| FileMetrics | codeclone/models.py | 1 | low | 0 | 0 |
| CFGBuilder | codeclone/cfg.py | 1 | low | 18 | 19 |
| MetricsBaseline | codeclone/metrics_baseline.py | 5 | high | 7 | 8 |
| _FunctionStructureScanner | codeclone/structural_findings.py | 2 | medium | 8 | 10 |
| CacheData | codeclone/cache.py | 1 | low | 0 | 0 |
| _ArgumentParser | codeclone/_cli_args.py | 1 | low | 1 | 2 |
| Baseline | codeclone/baseline.py | 5 | high | 7 | 4 |
| _DummyExecutor | tests/test_golden_v2.py | 4 | high | 4 | 1 |
| _FixedExecutor | tests/test_cli_inprocess.py | 3 | medium | 4 | 1 |
| Block | codeclone/cfg_model.py | 2 | medium | 3 | 2 |
| _FileCache | codeclone/_html_snippets.py | 2 | medium | 4 | 3 |
| _DummyExecutor | tests/test_cli_inprocess.py | 1 | low | 4 | 2 |
| ReportArtifacts | scripts/build_docs_example_report.py | 1 | low | 0 | 0 |
| _StatementRecord | codeclone/report/explain.py | 1 | low | 0 | 0 |
| BootstrapResult | codeclone/pipeline.py | 1 | low | 0 | 0 |
| Suggestion | codeclone/models.py | 1 | low | 0 | 0 |
| StructuralFindingGroup | codeclone/models.py | 1 | low | 0 | 0 |
| FunctionGroupItem | codeclone/models.py | 1 | low | 0 | 0 |
| DepGraph | codeclone/models.py | 1 | low | 0 | 0 |
| _QualnameCollector | codeclone/extractor.py | 1 | low | 5 | 9 |
| _ModuleWalkState | codeclone/extractor.py | 1 | low | 0 | 0 |
| ValidationError | codeclone/errors.py | 1 | low | 0 | 0 |
| ParseError | codeclone/errors.py | 1 | low | 0 | 0 |
| FileProcessingError | codeclone/errors.py | 1 | low | 0 | 0 |
| CacheError | codeclone/errors.py | 1 | low | 0 | 0 |
| BaselineValidationError | codeclone/errors.py | 1 | low | 1 | 1 |
| BaselineSchemaError | codeclone/errors.py | 1 | low | 0 | 0 |
| CFG | codeclone/cfg_model.py | 1 | low | 2 | 4 |
| _TryLike | codeclone/cfg.py | 1 | low | 0 | 0 |
| StructuralFindingGroupDict | codeclone/cache.py | 1 | low | 0 | 0 |
| DeadCandidateDict | codeclone/cache.py | 1 | low | 0 | 0 |
| ClassMetricsDict | codeclone/cache.py | 1 | low | 0 | 0 |
| CacheEntryBase | codeclone/cache.py | 1 | low | 0 | 0 |
| _HelpFormatter | codeclone/_cli_args.py | 1 | low | 0 | 0 |
| _FailExec | tests/test_pipeline_process.py | 3 | medium | 3 | 0 |
| _FailingExecutor | tests/test_cli_inprocess.py | 3 | medium | 3 | 1 |
| ReportContext | codeclone/_html_report/_context.py | 3 | medium | 6 | 6 |
| _CacheLike | codeclone/_cli_runtime.py | 3 | medium | 3 | 0 |
| TestAdmissionThresholdBoundaries | tests/test_extractor.py | 2 | medium | 14 | 1 |
| ServiceB | tests/fixtures/golden_v2/clone_metrics_cycle/pkg/b.py | 2 | medium | 2 | 1 |
| ServiceA | tests/fixtures/golden_v2/clone_metrics_cycle/pkg/a.py | 2 | medium | 2 | 1 |
| PlainConsole | codeclone/_cli_rich.py | 2 | medium | 2 | 0 |
| _UnexpectedExec | tests/test_pipeline_process.py | 1 | low | 1 | 0 |
| _DummyFuture | tests/test_golden_v2.py | 1 | low | 1 | 1 |
| _RecordingPrinter | tests/test_cli_unit.py | 1 | low | 2 | 1 |
| _FixedFuture | tests/test_cli_inprocess.py | 1 | low | 1 | 2 |
| Longest chain ? | Length ? |
|---|---|
| test_cli_unit→cli→pipeline→segments→extractor→blocks→blockhash→normalize→meta_markers→__future__ | 10 |
| test_cor..coverage→cli→pipeline→segments→extractor→blocks→blockhash→normalize→meta_markers→__future__ | 10 |
| test_security→cli→pipeline→segments→extractor→blocks→blockhash→normalize→meta_markers→__future__ | 10 |
| cli→pipeline→segments→extractor→blocks→blockhash→normalize→meta_markers→__future__ | 9 |
| test_cli_inprocess→pipeline→segments→extractor→blocks→blockhash→normalize→meta_markers→__future__ | 9 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 992-992 |
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 998-998 |
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 1088-1088 |
| File | Location | Lines |
|---|---|---|
| codeclone/pipeline.py | Production codeclone.pipeline:report | 1529-1545 |
| codeclone/pipeline.py | Production codeclone.pipeline:report | 1548-1564 |
| File | Location | Lines |
|---|---|---|
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_reason_list_html | 186-207 |
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_reason_list_html | 209-219 |
| File | Location | Lines |
|---|---|---|
| codeclone/metrics/cohesion.py | Production codeclone.metrics.cohesion:compute_lcom4 | 69-69 |
| codeclone/metrics/cohesion.py | Production codeclone.metrics.cohesion:compute_lcom4 | 75-75 |
| File | Location | Lines |
|---|---|---|
| codeclone/cache.py | Production codeclone.cache:_encode_wire_file_entry | 2156-2156 |
| codeclone/cache.py | Production codeclone.cache:_encode_wire_file_entry | 2159-2159 |
| File | Location | Lines |
|---|---|---|
| codeclone/metrics/coupling.py | Production codeclone.metrics.coupling:compute_cbo | 59-62 |
| codeclone/metrics/coupling.py | Production codeclone.metrics.coupling:compute_cbo | 64-67 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_collect_dead_candidates | 771-771 |
| codeclone/extractor.py | Production codeclone.extractor:_collect_dead_candidates | 777-777 |
| File | Location | Lines |
|---|---|---|
| codeclone/_html_report/_assemble.py | Production codeclone._html_report._assemble:build_html_report | 288-288 |
| codeclone/_html_report/_assemble.py | Production codeclone._html_report._assemble:build_html_report | 290-290 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_collect_module_walk_data | 691-697 |
| codeclone/extractor.py | Production codeclone.extractor:_collect_module_walk_data | 699-705 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_resolve_referenced_qualnames | 653-653 |
| codeclone/extractor.py | Production codeclone.extractor:_resolve_referenced_qualnames | 660-660 |
| File | Location | Lines |
|---|---|---|
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_matters_html | 260-265 |
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_matters_html | 267-272 |
| File | Location | Lines |
|---|---|---|
| codeclone/blocks.py | Production codeclone.blocks:extract_blocks | 53-53 |
| codeclone/blocks.py | Production codeclone.blocks:extract_blocks | 56-56 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 992-992 |
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 998-998 |
| codeclone/extractor.py | Production codeclone.extractor:extract_units_and_stats_from_source | 1088-1088 |
| File | Location | Lines |
|---|---|---|
| codeclone/pipeline.py | Production codeclone.pipeline:report | 1529-1545 |
| codeclone/pipeline.py | Production codeclone.pipeline:report | 1548-1564 |
| File | Location | Lines |
|---|---|---|
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_reason_list_html | 186-207 |
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_reason_list_html | 209-219 |
| File | Location | Lines |
|---|---|---|
| codeclone/metrics/cohesion.py | Production codeclone.metrics.cohesion:compute_lcom4 | 69-69 |
| codeclone/metrics/cohesion.py | Production codeclone.metrics.cohesion:compute_lcom4 | 75-75 |
| File | Location | Lines |
|---|---|---|
| codeclone/cache.py | Production codeclone.cache:_encode_wire_file_entry | 2156-2156 |
| codeclone/cache.py | Production codeclone.cache:_encode_wire_file_entry | 2159-2159 |
| File | Location | Lines |
|---|---|---|
| codeclone/metrics/coupling.py | Production codeclone.metrics.coupling:compute_cbo | 59-62 |
| codeclone/metrics/coupling.py | Production codeclone.metrics.coupling:compute_cbo | 64-67 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_collect_dead_candidates | 771-771 |
| codeclone/extractor.py | Production codeclone.extractor:_collect_dead_candidates | 777-777 |
| File | Location | Lines |
|---|---|---|
| codeclone/_html_report/_assemble.py | Production codeclone._html_report._assemble:build_html_report | 288-288 |
| codeclone/_html_report/_assemble.py | Production codeclone._html_report._assemble:build_html_report | 290-290 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_collect_module_walk_data | 691-697 |
| codeclone/extractor.py | Production codeclone.extractor:_collect_module_walk_data | 699-705 |
| File | Location | Lines |
|---|---|---|
| codeclone/extractor.py | Production codeclone.extractor:_resolve_referenced_qualnames | 653-653 |
| codeclone/extractor.py | Production codeclone.extractor:_resolve_referenced_qualnames | 660-660 |
| File | Location | Lines |
|---|---|---|
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_matters_html | 260-265 |
| codeclone/report/findings.py | Production codeclone.report.findings:_finding_matters_html | 267-272 |
| File | Location | Lines |
|---|---|---|
| codeclone/blocks.py | Production codeclone.blocks:extract_blocks | 53-53 |
| codeclone/blocks.py | Production codeclone.blocks:extract_blocks | 56-56 |
This group reports 3 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 3 structurally matching branch bodies inside codeclone.extractor:extract_units_and_stats_from_source.
989 | end = getattr(node, "end_lineno", None) 990 | 991 | if not start or not end or end < start: 992 | continue 993 | 994 | loc = end - start + 1 995 | stmt_count = _stmt_count(node) 995 | stmt_count = _stmt_count(node) 996 | 997 | if loc < min_loc or stmt_count < min_stmt: 998 | continue 999 | 1000 | qualname = f"{module_name}:{local_name}" 1001 | fingerprint, complexity = _cfg_fingerprint_and_complexity(node, cfg, qualname)This group reports 2 branches with the same local shape (ImportFrom,Assign). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.pipeline:report.
1526 | contents["json"] = render_json_report_document(report_document) 1527 | 1528 | if boot.output_paths.md and report_document is not None: 1529 | from .report.markdown import to_markdown_report 1530 | 1531 | contents["md"] = to_markdown_report( 1532 | report_document=report_document, 1533 | meta=report_meta, 1534 | inventory=report_inventory, 1535 | func_groups=analysis.func_groups, 1536 | block_groups=analysis.block_groups_report, 1537 | segment_groups=analysis.segment_groups, 1538 | block_facts=analysis.block_group_facts, 1539 | new_function_group_keys=new_func, 1540 | new_block_group_keys=new_block, 1541 | new_segment_group_keys=set(analysis.segment_groups.keys()), 1542 | metrics=analysis.metrics_payload, 1543 | suggestions=analysis.suggestions, 1544 | structural_findings=sf, 1545 | ) 1546 | 1547 | if boot.output_paths.sarif and report_document is not None: 1548 | from .report.sarif import to_sarif_report 1545 | ) 1546 | 1547 | if boot.output_paths.sarif and report_document is not None: 1548 | from .report.sarif import to_sarif_report 1549 | 1550 | contents["sarif"] = to_sarif_report( 1551 | report_document=report_document, 1552 | meta=report_meta, 1553 | inventory=report_inventory, 1554 | func_groups=analysis.func_groups, 1555 | block_groups=analysis.block_groups_report, 1556 | segment_groups=analysis.segment_groups, 1557 | block_facts=analysis.block_group_facts, 1558 | new_function_group_keys=new_func, 1559 | new_block_group_keys=new_block, 1560 | new_segment_group_keys=set(analysis.segment_groups.keys()), 1561 | metrics=analysis.metrics_payload, 1562 | suggestions=analysis.suggestions, 1563 | structural_findings=sf, 1564 | ) 1565 | 1566 | if boot.output_paths.text and report_document is not None: 1567 | contents["text"] = render_text_report_document(report_document)This group reports 2 branches with the same local shape (Assign,Return). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.report.findings:_finding_reason_list_html.
183 | ) -> str: 184 | spread = _spread(items) 185 | if group.finding_kind == STRUCTURAL_KIND_CLONE_GUARD_EXIT_DIVERGENCE: 186 | reasons = [ 187 | ( 188 | f"{len(items)} divergent clone members were detected after " 189 | "stable sorting and deduplication." 190 | ), 191 | ( 192 | "Members were compared by entry-guard count/profile, terminal " 193 | "kind, and side-effect-before-guard marker." 194 | ), 195 | ( 196 | f"Cohort id: {group.signature.get('cohort_id', 'unknown')}; " 197 | "majority guard count: " 198 | f"{group.signature.get('majority_guard_count', '0')}." 199 | ), 200 | ( 201 | f"Spread includes {spread['functions']} " 202 | f"{'function' if spread['functions'] == 1 else 'functions'} in " 203 | f"{spread['files']} {'file' if spread['files'] == 1 else 'files'}." 204 | ), 205 | "This is a report-only finding and does not affect clone gating.", 206 | ] 207 | return _render_reason_list_html(reasons) 208 | if group.finding_kind == STRUCTURAL_KIND_CLONE_COHORT_DRIFT: 209 | reasons = [ 210 | f"{len(items)} clone members diverge from the cohort majority profile.", 206 | ] 207 | return _render_reason_list_html(reasons) 208 | if group.finding_kind == STRUCTURAL_KIND_CLONE_COHORT_DRIFT: 209 | reasons = [ 210 | f"{len(items)} clone members diverge from the cohort majority profile.", 211 | f"Drift fields: {group.signature.get('drift_fields', 'n/a')}.", 212 | ( 213 | f"Cohort id: {group.signature.get('cohort_id', 'unknown')} with " 214 | f"arity {group.signature.get('cohort_arity', 'n/a')}." 215 | ), 216 | ("Majority profile is compared deterministically with lexical tie-breaks."), 217 | "This is a report-only finding and does not affect clone gating.", 218 | ] 219 | return _render_reason_list_html(reasons) 220 | 221 | stmt_seq = group.signature.get("stmt_seq", "n/a") 222 | terminal = group.signature.get("terminal", "n/a")This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.metrics.cohesion:compute_lcom4.
66 | 67 | for method_name in method_names: 68 | if method_name in visited: 69 | continue 70 | components += 1 71 | stack = [method_name] 72 | while stack: 72 | while stack: 73 | current = stack.pop() 74 | if current in visited: 75 | continue 76 | visited.add(current) 77 | stack.extend(sorted(adjacency[current] - visited)) 78 | This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.cache:_encode_wire_file_entry.
2153 | for metric in class_metrics: 2154 | coupled_classes_raw = metric.get("coupled_classes", []) 2155 | if not _is_string_list(coupled_classes_raw): 2156 | continue 2157 | coupled_classes = sorted(set(coupled_classes_raw)) 2158 | if not coupled_classes: 2159 | continue 2156 | continue 2157 | coupled_classes = sorted(set(coupled_classes_raw)) 2158 | if not coupled_classes: 2159 | continue 2160 | coupled_classes_rows.append([metric["qualname"], coupled_classes]) 2161 | if coupled_classes_rows: 2162 | wire["cc"] = coupled_classes_rowsThis group reports 2 branches with the same local shape (Assign,If,Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.metrics.coupling:compute_cbo.
56 | couplings.add(node.attr) 57 | continue 58 | if isinstance(node, ast.Call): 59 | candidate = _annotation_name(node.func) 60 | if candidate: 61 | couplings.add(candidate) 62 | continue 63 | if isinstance(node, ast.AnnAssign) and node.annotation is not None: 64 | candidate = _annotation_name(node.annotation) 65 | if candidate: 61 | couplings.add(candidate) 62 | continue 63 | if isinstance(node, ast.AnnAssign) and node.annotation is not None: 64 | candidate = _annotation_name(node.annotation) 65 | if candidate: 66 | couplings.add(candidate) 67 | continue 68 | if isinstance(node, ast.arg) and node.annotation is not None: 69 | candidate = _annotation_name(node.annotation) 70 | if candidate:This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.extractor:_collect_dead_candidates.
768 | protocol_class_qualnames=protocol_class_qualnames, 769 | ) 770 | if candidate is None: 771 | continue 772 | candidates.append(candidate) 773 | 774 | for class_qualname, class_node in collector.class_nodes: 774 | for class_qualname, class_node in collector.class_nodes: 775 | span = _node_line_span(class_node) 776 | if span is None: 777 | continue 778 | start, end = span 779 | candidates.append( 780 | _build_dead_candidate(This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone._html_report._assemble:build_html_report.
285 | for line in css.splitlines(): 286 | stripped = line.strip() 287 | if not stripped or stripped.startswith("/*"): 288 | continue 289 | if not stripped.startswith(".codebox"): 290 | continue 291 | out.append(stripped) 287 | if not stripped or stripped.startswith("/*"): 288 | continue 289 | if not stripped.startswith(".codebox"): 290 | continue 291 | out.append(stripped) 292 | return "\n".join(out) 293 | This group reports 2 branches with the same local shape (Expr,Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.extractor:_collect_module_walk_data.
688 | state = _ModuleWalkState() 689 | for node in ast.walk(tree): 690 | if isinstance(node, ast.Import): 691 | _collect_import_node( 692 | node=node, 693 | module_name=module_name, 694 | state=state, 695 | collect_referenced_names=collect_referenced_names, 696 | ) 697 | continue 698 | if isinstance(node, ast.ImportFrom): 699 | _collect_import_from_node( 700 | node=node, 696 | ) 697 | continue 698 | if isinstance(node, ast.ImportFrom): 699 | _collect_import_from_node( 700 | node=node, 701 | module_name=module_name, 702 | state=state, 703 | collect_referenced_names=collect_referenced_names, 704 | ) 705 | continue 706 | if collect_referenced_names: 707 | _collect_load_reference_node(node=node, state=state) 708 | This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.extractor:_resolve_referenced_qualnames.
650 | for attr_node in state.attr_nodes: 651 | base = attr_node.value 652 | if not isinstance(base, ast.Name): 653 | continue 654 | imported_module = state.imported_module_aliases.get(base.id) 655 | if imported_module is not None: 656 | resolved.add(f"{imported_module}:{attr_node.attr}") 657 | continue 658 | class_qualname = top_level_class_by_name.get(base.id) 659 | if class_qualname is None: 660 | continue 661 | local_method_qualname = f"{module_name}:{class_qualname}.{attr_node.attr}" 662 | if local_method_qualname in local_method_qualnames: 663 | resolved.add(local_method_qualname)This group reports 2 branches with the same local shape (Assign,Return). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.report.findings:_finding_matters_html.
257 | spread = _spread(items) 258 | count = len(items) 259 | if group.finding_kind == STRUCTURAL_KIND_CLONE_GUARD_EXIT_DIVERGENCE: 260 | message = ( 261 | "Members of one function-clone cohort diverged in guard/exit behavior. " 262 | "This often points to a partial fix where one path was updated and " 263 | "other siblings were left unchanged." 264 | ) 265 | return _finding_matters_paragraph(message) 266 | if group.finding_kind == STRUCTURAL_KIND_CLONE_COHORT_DRIFT: 267 | message = ( 268 | "Members of one function-clone cohort drifted from a stable majority " 264 | ) 265 | return _finding_matters_paragraph(message) 266 | if group.finding_kind == STRUCTURAL_KIND_CLONE_COHORT_DRIFT: 267 | message = ( 268 | "Members of one function-clone cohort drifted from a stable majority " 269 | "profile (terminal, guard, try/finally, side-effect order). Review " 270 | "whether divergence is intentional." 271 | ) 272 | return _finding_matters_paragraph(message) 273 | 274 | terminal = str(group.signature.get("terminal", "")).strip() 275 | stmt_seq = str(group.signature.get("stmt_seq", "")).strip()This group reports 2 branches with the same local shape (Continue). Review whether the shared branch body should stay duplicated or become a helper.
CodeClone reported this group because it found 2 structurally matching branch bodies inside codeclone.blocks:extract_blocks.
50 | start = getattr(body[i], "lineno", None) 51 | end = getattr(body[i + block_size - 1], "end_lineno", None) 52 | if not start or not end: 53 | continue 54 | 55 | if last_start is not None and start - last_start < min_line_distance: 56 | continue 53 | continue 54 | 55 | if last_start is not None and start - last_start < min_line_distance: 56 | continue 57 | 58 | bh = "|".join(stmt_hash_rows[i : i + block_size]) 59 |