mirror of
https://github.com/ludo-technologies/pyscn.git
synced 2025-10-06 00:59:45 +03:00
feat: improve HTML reports and health score calculation
## HTML Report Quality Improvements - Fix dead code table displaying actual data instead of empty rows - Correct file paths showing real paths instead of "unknown" - Fix clone type display showing "Type-1", "Type-2" etc. instead of blank cells - Improve template loop logic for proper item limiting ## Report Format Standardization - Create shared FormatUtils for consistent formatting across all analysis types - Standardize header widths, label alignment, and section structures - Unify color schemes and risk level representations - Add comprehensive summary statistics and warning sections ## Health Score Algorithm Enhancement - Add project size normalization using logarithmic scaling for large projects - Implement penalty caps: max 25 points per category (Complexity, Dead Code, Clones, CBO) - Set minimum score threshold of 10 points to avoid complete failure - Adjust grade thresholds: A(85+), B(70+), C(55+), D(40+), F(<40) - Fix scoring issue where large projects always got 0/100 (Grade: F) ## Test Coverage Expansion - Add comprehensive dead code test cases in testdata/python/ - Create simple, edge cases, and complex dead code pattern examples - Improve test coverage for various unreachable code scenarios ## Results - Large projects: 0/100 (F) → 50/100 (D) - Small projects: appropriate scores (60-70 range) - HTML reports now show detailed, accurate information - Consistent professional formatting across all analysis types 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
855
analyze_20250910_112737.html
Normal file
855
analyze_20250910_112737.html
Normal file
@@ -0,0 +1,855 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 11:27:37</p>
|
||||||
|
<div class="score-badge grade-c">
|
||||||
|
Health Score: 75/100 (Grade: C)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">11</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">11</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1.91</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1442</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">40.7%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">36</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.19</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">147</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1.91</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">33</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AbstractClass.abstract_method</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AbstractClass.concrete_method</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncClass.async_class_method</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncClass.async_method</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncClass.async_static_method</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncContextManager.__aenter__</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncContextManager.__aexit__</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncRange.__aiter__</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncRange.__anext__</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncRange.__init__</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1442</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.73</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">36</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.19</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>MultipleInheritance</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>SimpleClass, EmptyClass</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>InnerClass</td>
|
||||||
|
<td>testdata/python/edge_cases/nested_structures.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>MethodClass</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>ValidationError</td>
|
||||||
|
<td>testdata/python/complex/exceptions.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>CustomError</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>ClassWithMagicMethods</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>ClassWithMagicMethods</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>InheritedClass</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>SimpleClass</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>ComplexClass</td>
|
||||||
|
<td>testdata/python/edge_cases/nested_structures.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td>MethodClass</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>AsyncRange</td>
|
||||||
|
<td>testdata/python/complex/async_await.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>SimpleClass</td>
|
||||||
|
<td>testdata/python/simple/classes.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>MethodDecorators</td>
|
||||||
|
<td>testdata/python/complex/decorators.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>PropertyExample</td>
|
||||||
|
<td>testdata/python/complex/decorators.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
0
analyze_20250910_123538.html
Normal file
0
analyze_20250910_123538.html
Normal file
3906
analyze_20250910_123615.html
Normal file
3906
analyze_20250910_123615.html
Normal file
File diff suppressed because it is too large
Load Diff
7952
analyze_20250910_124033.html
Normal file
7952
analyze_20250910_124033.html
Normal file
File diff suppressed because it is too large
Load Diff
616
analyze_20250910_133656.html
Normal file
616
analyze_20250910_133656.html
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 13:36:56</p>
|
||||||
|
<div class="score-badge grade-f">
|
||||||
|
Health Score: 54/100 (Grade: F)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">80.3%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">6</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>__main__</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>conditional_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>exception_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>unknown</td>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>12-13</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>unknown</td>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>34-34</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>unknown</td>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>60-60</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.88</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.920</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.918</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.860</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.843</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
615
analyze_20250910_133742.html
Normal file
615
analyze_20250910_133742.html
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 13:37:42</p>
|
||||||
|
<div class="score-badge grade-f">
|
||||||
|
Health Score: 54/100 (Grade: F)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">80.3%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">6</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>__main__</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>conditional_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>exception_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>60-60</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>12-13</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>34-34</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.88</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.920</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.918</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.860</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.843</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
791
analyze_20250910_135746.html
Normal file
791
analyze_20250910_135746.html
Normal file
@@ -0,0 +1,791 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 13:57:46</p>
|
||||||
|
<div class="score-badge grade-f">
|
||||||
|
Health Score: 47/100 (Grade: F)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.46</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">4</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">58</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">82.2%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.46</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">4</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>DeadCodeClass.__init__</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>DeadCodeClass.method_with_dead_code</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>DeadCodeClass.setup</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>__main__</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>early_exit_pattern</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>infinite_loop_with_break</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>4</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>multiple_returns_with_dead_code</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>nested_dead_code</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>unreachable_after_continue</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 10 of 13 functions</p>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">4</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">4</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>nested_dead_code</td>
|
||||||
|
<td>101-101</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>__init__</td>
|
||||||
|
<td>117-118</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
<td>54-55</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>unreachable_after_continue</td>
|
||||||
|
<td>69-70</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_continue</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">58</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.88</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>29-43</td>
|
||||||
|
<td>60-73</td>
|
||||||
|
<td>0.984</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>76-90</td>
|
||||||
|
<td>157-167</td>
|
||||||
|
<td>0.983</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>60-73</td>
|
||||||
|
<td>125-133</td>
|
||||||
|
<td>0.978</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>7-15</td>
|
||||||
|
<td>60-73</td>
|
||||||
|
<td>0.978</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>46-57</td>
|
||||||
|
<td>93-107</td>
|
||||||
|
<td>0.978</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>18-26</td>
|
||||||
|
<td>60-73</td>
|
||||||
|
<td>0.978</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>18-26</td>
|
||||||
|
<td>125-133</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>7-15</td>
|
||||||
|
<td>125-133</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>7-15</td>
|
||||||
|
<td>18-26</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>29-43</td>
|
||||||
|
<td>76-90</td>
|
||||||
|
<td>0.959</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>76-90</td>
|
||||||
|
<td>136-154</td>
|
||||||
|
<td>0.957</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>60-73</td>
|
||||||
|
<td>76-90</td>
|
||||||
|
<td>0.954</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>29-43</td>
|
||||||
|
<td>157-167</td>
|
||||||
|
<td>0.948</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>136-154</td>
|
||||||
|
<td>157-167</td>
|
||||||
|
<td>0.945</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>29-43</td>
|
||||||
|
<td>110-133</td>
|
||||||
|
<td>0.941</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 15 of 58 clone pairs</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>DeadCodeClass</td>
|
||||||
|
<td>testdata/python/edge_cases/dead_code_examples.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
865
analyze_20250910_150750.html
Normal file
865
analyze_20250910_150750.html
Normal file
@@ -0,0 +1,865 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 15:07:50</p>
|
||||||
|
<div class="score-badge grade-f">
|
||||||
|
Health Score: 24/100 (Grade: F)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.36</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">8</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">70</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">82.7%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">11</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.36</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">6</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>__main__</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>async_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>class_method_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>complex_control_flow</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>6</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>comprehension_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>context_manager_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>decorator_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>exception_hierarchy_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>5</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>finally_block_patterns</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>generator_with_dead_code</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 10 of 11 functions</p>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">8</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">7</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>finally_block_patterns</td>
|
||||||
|
<td>168-168</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>finally_block_patterns</td>
|
||||||
|
<td>172-172</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>finally_block_patterns</td>
|
||||||
|
<td>179-179</td>
|
||||||
|
<td class="severity-warning">warning</td>
|
||||||
|
<td>unreachable_branch</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>generator_with_dead_code</td>
|
||||||
|
<td>45-46</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>exception_hierarchy_dead_code</td>
|
||||||
|
<td>160-160</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>context_manager_dead_code</td>
|
||||||
|
<td>74-74</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_raise</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>complex_control_flow</td>
|
||||||
|
<td>30-31</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>async_dead_code</td>
|
||||||
|
<td>57-58</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">70</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.81</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>61-77</td>
|
||||||
|
<td>98-122</td>
|
||||||
|
<td>0.987</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>80-95</td>
|
||||||
|
<td>98-122</td>
|
||||||
|
<td>0.987</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>61-77</td>
|
||||||
|
<td>80-95</td>
|
||||||
|
<td>0.984</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>38-46</td>
|
||||||
|
<td>49-58</td>
|
||||||
|
<td>0.973</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>149-160</td>
|
||||||
|
<td>163-179</td>
|
||||||
|
<td>0.964</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>9-35</td>
|
||||||
|
<td>98-122</td>
|
||||||
|
<td>0.942</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>9-35</td>
|
||||||
|
<td>61-77</td>
|
||||||
|
<td>0.939</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>61-77</td>
|
||||||
|
<td>125-135</td>
|
||||||
|
<td>0.933</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>80-95</td>
|
||||||
|
<td>125-135</td>
|
||||||
|
<td>0.930</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>14-31</td>
|
||||||
|
<td>15-25</td>
|
||||||
|
<td>0.924</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>15-25</td>
|
||||||
|
<td>102-107</td>
|
||||||
|
<td>0.923</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>49-58</td>
|
||||||
|
<td>61-77</td>
|
||||||
|
<td>0.919</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>9-35</td>
|
||||||
|
<td>80-95</td>
|
||||||
|
<td>0.919</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>49-58</td>
|
||||||
|
<td>125-135</td>
|
||||||
|
<td>0.912</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>38-46</td>
|
||||||
|
<td>125-135</td>
|
||||||
|
<td>0.907</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 15 of 70 clone pairs</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>CustomContext</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>TestClass</td>
|
||||||
|
<td>testdata/python/complex/dead_code_complex.py</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7951
analyze_20250910_164535.html
Normal file
7951
analyze_20250910_164535.html
Normal file
File diff suppressed because it is too large
Load Diff
7951
analyze_20250910_164727.html
Normal file
7951
analyze_20250910_164727.html
Normal file
File diff suppressed because it is too large
Load Diff
7951
analyze_20250910_165913.html
Normal file
7951
analyze_20250910_165913.html
Normal file
File diff suppressed because it is too large
Load Diff
615
analyze_20250910_165937.html
Normal file
615
analyze_20250910_165937.html
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Analysis Report</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: #667eea;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.score-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.grade-a { background: #4caf50; color: white; }
|
||||||
|
.grade-b { background: #8bc34a; color: white; }
|
||||||
|
.grade-c { background: #ff9800; color: white; }
|
||||||
|
.grade-d { background: #ff5722; color: white; }
|
||||||
|
.grade-f { background: #f44336; color: white; }
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.tab-buttons {
|
||||||
|
display: flex;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.tab-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.tab-button.active {
|
||||||
|
background: white;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.tab-content.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.metric-card {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #667eea;
|
||||||
|
}
|
||||||
|
.metric-label {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-low { color: #4caf50; }
|
||||||
|
.risk-medium { color: #ff9800; }
|
||||||
|
.risk-high { color: #f44336; }
|
||||||
|
|
||||||
|
.severity-critical { color: #f44336; }
|
||||||
|
.severity-warning { color: #ff9800; }
|
||||||
|
.severity-info { color: #2196f3; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>pyscn Analysis Report</h1>
|
||||||
|
<p>Generated: 2025-09-10 16:59:37</p>
|
||||||
|
<div class="score-badge grade-c">
|
||||||
|
Health Score: 63/100 (Grade: C)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab-buttons">
|
||||||
|
<button class="tab-button active" onclick="showTab('summary')">Summary</button>
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('complexity')">Complexity</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('deadcode')">Dead Code</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('clone')">Clone Detection</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="tab-button" onclick="showTab('cbo')">Dependency Analysis</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="tab-content active">
|
||||||
|
<h2>Analysis Summary</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Total Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Analyzed Files</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Avg Complexity</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Dead Code Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">80.3%</div>
|
||||||
|
<div class="metric-label">Code Duplication</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Avg Dependencies</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="complexity" class="tab-content">
|
||||||
|
<h2>Complexity Analysis</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">6</div>
|
||||||
|
<div class="metric-label">Total Functions</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">2.17</div>
|
||||||
|
<div class="metric-label">Average</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Maximum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Top Complex Functions</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Complexity</th>
|
||||||
|
<th>Risk</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>__main__</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>conditional_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>exception_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>3</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>1</td>
|
||||||
|
<td class="risk-low">low</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="deadcode" class="tab-content">
|
||||||
|
<h2>Dead Code Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Total Issues</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">3</div>
|
||||||
|
<div class="metric-label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Warnings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>simple_dead_code</td>
|
||||||
|
<td>12-13</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>loop_with_dead_code</td>
|
||||||
|
<td>34-34</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_break</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>nested_return_dead_code</td>
|
||||||
|
<td>60-60</td>
|
||||||
|
<td class="severity-critical">critical</td>
|
||||||
|
<td>unreachable_after_return</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="clone" class="tab-content">
|
||||||
|
<h2>Clone Detection</h2>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">13</div>
|
||||||
|
<div class="metric-label">Clone Pairs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">1</div>
|
||||||
|
<div class="metric-label">Clone Groups</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.88</div>
|
||||||
|
<div class="metric-label">Avg Similarity</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.971</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>0.969</td>
|
||||||
|
<td>Type-1</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.925</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.920</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>52-66</td>
|
||||||
|
<td>0.918</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.860</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>16-25</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>40-49</td>
|
||||||
|
<td>0.853</td>
|
||||||
|
<td>Type-2</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>6-13</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>0.843</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>30-35</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>testdata/python/simple/dead_code_simple.py</td>
|
||||||
|
<td>28-37</td>
|
||||||
|
<td>56-63</td>
|
||||||
|
<td>0.746</td>
|
||||||
|
<td>Type-3</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cbo" class="tab-content">
|
||||||
|
<h2>Dependency Analysis</h2>
|
||||||
|
<p style="margin-bottom: 20px; color: #666;">Class coupling metrics (CBO - Coupling Between Objects)</p>
|
||||||
|
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Total Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">High Risk Classes</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0.00</div>
|
||||||
|
<div class="metric-label">Average Dependencies</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-value">0</div>
|
||||||
|
<div class="metric-label">Max Dependencies</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Most Dependent Classes</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Class</th>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Dependencies</th>
|
||||||
|
<th>Risk Level</th>
|
||||||
|
<th>Dependent Classes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showTab(tabName) {
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
const buttons = document.querySelectorAll('.tab-button');
|
||||||
|
buttons.forEach(btn => btn.classList.remove('active'));
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById(tabName).classList.add('active');
|
||||||
|
|
||||||
|
|
||||||
|
event.target.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
134
deadcode_20250910_132639.json
Normal file
134
deadcode_20250910_132639.json
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"functions": [
|
||||||
|
{
|
||||||
|
"name": "loop_with_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 34,
|
||||||
|
"end_line": 34,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "loop_with_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_break",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a break statement and will never be executed",
|
||||||
|
"block_id": "bb8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 10,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.8,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nested_return_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 60,
|
||||||
|
"end_line": 60,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "nested_return_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb7"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 9,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.7777777777777778,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simple_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 12,
|
||||||
|
"end_line": 13,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "simple_dead_code",
|
||||||
|
"code": "Call\nassignment",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 4,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.75,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_findings": 3,
|
||||||
|
"total_functions": 5,
|
||||||
|
"affected_functions": 3,
|
||||||
|
"dead_code_ratio": 0.13043478260869565
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_files": 1,
|
||||||
|
"total_functions": 5,
|
||||||
|
"total_findings": 3,
|
||||||
|
"files_with_dead_code": 1,
|
||||||
|
"functions_with_dead_code": 3,
|
||||||
|
"critical_findings": 3,
|
||||||
|
"warning_findings": 0,
|
||||||
|
"info_findings": 0,
|
||||||
|
"findings_by_reason": {
|
||||||
|
"unreachable_after_break": 1,
|
||||||
|
"unreachable_after_return": 2
|
||||||
|
},
|
||||||
|
"total_blocks": 23,
|
||||||
|
"dead_blocks": 3,
|
||||||
|
"overall_dead_ratio": 0.13043478260869565
|
||||||
|
},
|
||||||
|
"warnings": null,
|
||||||
|
"errors": null,
|
||||||
|
"generated_at": "2025-09-10T13:26:39+09:00",
|
||||||
|
"version": "dev",
|
||||||
|
"config": {
|
||||||
|
"context_lines": 3,
|
||||||
|
"detect_after_break": true,
|
||||||
|
"detect_after_continue": true,
|
||||||
|
"detect_after_raise": true,
|
||||||
|
"detect_after_return": true,
|
||||||
|
"detect_unreachable_branches": true,
|
||||||
|
"exclude_patterns": [
|
||||||
|
"test_*.py",
|
||||||
|
"*_test.py"
|
||||||
|
],
|
||||||
|
"ignore_patterns": [],
|
||||||
|
"include_patterns": [
|
||||||
|
"*.py"
|
||||||
|
],
|
||||||
|
"min_severity": "warning",
|
||||||
|
"show_context": false,
|
||||||
|
"sort_by": "severity"
|
||||||
|
}
|
||||||
|
}
|
||||||
220
deadcode_20250910_133636.html
Normal file
220
deadcode_20250910_133636.html
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>pyscn Code Quality Report - Python Project</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
background: white;
|
||||||
|
padding: 40px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 2.5em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .timestamp {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-card {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
flex: 1;
|
||||||
|
min-width: 250px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-gauge {
|
||||||
|
position: relative;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin: 0 auto 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-circle {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-label {
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-description {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-section {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-section h2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
border-bottom: 2px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-item {
|
||||||
|
padding: 15px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-item .value {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-item .label {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-bar {
|
||||||
|
height: 8px;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-fill {
|
||||||
|
height: 100%;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.risk-high { background-color: #FF5722; }
|
||||||
|
.risk-medium { background-color: #FFA500; }
|
||||||
|
.risk-low { background-color: #0CCE6B; }
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.score-section {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>Code Quality Report</h1>
|
||||||
|
<div class="project-name">Python Project</div>
|
||||||
|
<div class="timestamp">Generated on 2025-09-10T13:36:36+09:00</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="score-section">
|
||||||
|
<div class="score-card">
|
||||||
|
<div class="score-gauge">
|
||||||
|
<div class="score-circle" style="background-color: #FFA500;">
|
||||||
|
86
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="score-label">Overall Score</div>
|
||||||
|
<div class="score-description">Weighted average of all quality metrics</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="score-card">
|
||||||
|
<div class="score-gauge">
|
||||||
|
<div class="score-circle" style="background-color: #FFA500;">
|
||||||
|
86
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="score-label">Dead_code Score</div>
|
||||||
|
<div class="score-description">87.0% Reachable</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details-section">
|
||||||
|
<h2>Analysis Details</h2>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div class="metric-item">
|
||||||
|
<div class="value">86</div>
|
||||||
|
<div class="label">Dead_code Score</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-item">
|
||||||
|
<div class="value">87.0% Reachable</div>
|
||||||
|
<div class="label">Details</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
Generated by <strong>pyscn</strong> - Python Code Quality Analysis Tool
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
134
deadcode_20250910_133710.json
Normal file
134
deadcode_20250910_133710.json
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"functions": [
|
||||||
|
{
|
||||||
|
"name": "simple_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 12,
|
||||||
|
"end_line": 13,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "simple_dead_code",
|
||||||
|
"code": "Call\nassignment",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 4,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.75,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loop_with_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 34,
|
||||||
|
"end_line": 34,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "loop_with_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_break",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a break statement and will never be executed",
|
||||||
|
"block_id": "bb8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 10,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.8,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nested_return_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "unknown",
|
||||||
|
"start_line": 60,
|
||||||
|
"end_line": 60,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "nested_return_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb7"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 9,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.7777777777777778,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_findings": 3,
|
||||||
|
"total_functions": 5,
|
||||||
|
"affected_functions": 3,
|
||||||
|
"dead_code_ratio": 0.13043478260869565
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_files": 1,
|
||||||
|
"total_functions": 5,
|
||||||
|
"total_findings": 3,
|
||||||
|
"files_with_dead_code": 1,
|
||||||
|
"functions_with_dead_code": 3,
|
||||||
|
"critical_findings": 3,
|
||||||
|
"warning_findings": 0,
|
||||||
|
"info_findings": 0,
|
||||||
|
"findings_by_reason": {
|
||||||
|
"unreachable_after_break": 1,
|
||||||
|
"unreachable_after_return": 2
|
||||||
|
},
|
||||||
|
"total_blocks": 23,
|
||||||
|
"dead_blocks": 3,
|
||||||
|
"overall_dead_ratio": 0.13043478260869565
|
||||||
|
},
|
||||||
|
"warnings": null,
|
||||||
|
"errors": null,
|
||||||
|
"generated_at": "2025-09-10T13:37:10+09:00",
|
||||||
|
"version": "dev",
|
||||||
|
"config": {
|
||||||
|
"context_lines": 3,
|
||||||
|
"detect_after_break": true,
|
||||||
|
"detect_after_continue": true,
|
||||||
|
"detect_after_raise": true,
|
||||||
|
"detect_after_return": true,
|
||||||
|
"detect_unreachable_branches": true,
|
||||||
|
"exclude_patterns": [
|
||||||
|
"test_*.py",
|
||||||
|
"*_test.py"
|
||||||
|
],
|
||||||
|
"ignore_patterns": [],
|
||||||
|
"include_patterns": [
|
||||||
|
"*.py"
|
||||||
|
],
|
||||||
|
"min_severity": "warning",
|
||||||
|
"show_context": false,
|
||||||
|
"sort_by": "severity"
|
||||||
|
}
|
||||||
|
}
|
||||||
134
deadcode_20250910_133732.json
Normal file
134
deadcode_20250910_133732.json
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"functions": [
|
||||||
|
{
|
||||||
|
"name": "nested_return_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"start_line": 60,
|
||||||
|
"end_line": 60,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "nested_return_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb7"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 9,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.7777777777777778,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simple_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"start_line": 12,
|
||||||
|
"end_line": 13,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "simple_dead_code",
|
||||||
|
"code": "Call\nassignment",
|
||||||
|
"reason": "unreachable_after_return",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a return statement and will never be executed",
|
||||||
|
"block_id": "bb3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 4,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.75,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loop_with_dead_code",
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"file_path": "/Users/daisukeyoda/projects/pyqol/testdata/python/simple/dead_code_simple.py",
|
||||||
|
"start_line": 34,
|
||||||
|
"end_line": 34,
|
||||||
|
"start_column": 0,
|
||||||
|
"end_column": 0
|
||||||
|
},
|
||||||
|
"function_name": "loop_with_dead_code",
|
||||||
|
"code": "Call",
|
||||||
|
"reason": "unreachable_after_break",
|
||||||
|
"severity": "critical",
|
||||||
|
"description": "Code appears after a break statement and will never be executed",
|
||||||
|
"block_id": "bb8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_blocks": 10,
|
||||||
|
"dead_blocks": 1,
|
||||||
|
"reachable_ratio": 0.8,
|
||||||
|
"critical_count": 1,
|
||||||
|
"warning_count": 0,
|
||||||
|
"info_count": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_findings": 3,
|
||||||
|
"total_functions": 5,
|
||||||
|
"affected_functions": 3,
|
||||||
|
"dead_code_ratio": 0.13043478260869565
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_files": 1,
|
||||||
|
"total_functions": 5,
|
||||||
|
"total_findings": 3,
|
||||||
|
"files_with_dead_code": 1,
|
||||||
|
"functions_with_dead_code": 3,
|
||||||
|
"critical_findings": 3,
|
||||||
|
"warning_findings": 0,
|
||||||
|
"info_findings": 0,
|
||||||
|
"findings_by_reason": {
|
||||||
|
"unreachable_after_break": 1,
|
||||||
|
"unreachable_after_return": 2
|
||||||
|
},
|
||||||
|
"total_blocks": 23,
|
||||||
|
"dead_blocks": 3,
|
||||||
|
"overall_dead_ratio": 0.13043478260869565
|
||||||
|
},
|
||||||
|
"warnings": null,
|
||||||
|
"errors": null,
|
||||||
|
"generated_at": "2025-09-10T13:37:32+09:00",
|
||||||
|
"version": "v0.1.0-beta.14-6-g8dd877b-dirty",
|
||||||
|
"config": {
|
||||||
|
"context_lines": 3,
|
||||||
|
"detect_after_break": true,
|
||||||
|
"detect_after_continue": true,
|
||||||
|
"detect_after_raise": true,
|
||||||
|
"detect_after_return": true,
|
||||||
|
"detect_unreachable_branches": true,
|
||||||
|
"exclude_patterns": [
|
||||||
|
"test_*.py",
|
||||||
|
"*_test.py"
|
||||||
|
],
|
||||||
|
"ignore_patterns": [],
|
||||||
|
"include_patterns": [
|
||||||
|
"*.py"
|
||||||
|
],
|
||||||
|
"min_severity": "warning",
|
||||||
|
"show_context": false,
|
||||||
|
"sort_by": "severity"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,64 +60,85 @@ type AnalyzeSummary struct {
|
|||||||
func (s *AnalyzeSummary) CalculateHealthScore() {
|
func (s *AnalyzeSummary) CalculateHealthScore() {
|
||||||
score := 100
|
score := 100
|
||||||
|
|
||||||
// Deduct points for high complexity
|
// Calculate normalization factor for large projects
|
||||||
|
normalizationFactor := 1.0
|
||||||
|
if s.TotalFiles > 10 {
|
||||||
|
// Use logarithmic scaling to reduce penalty impact for large projects
|
||||||
|
normalizationFactor = math.Log10(float64(s.TotalFiles)) / 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complexity penalty (max 25 points)
|
||||||
|
complexityPenalty := 0
|
||||||
if s.AverageComplexity > 20 {
|
if s.AverageComplexity > 20 {
|
||||||
score -= 30
|
complexityPenalty = 25
|
||||||
} else if s.AverageComplexity > 10 {
|
} else if s.AverageComplexity > 10 {
|
||||||
score -= 20
|
complexityPenalty = 15
|
||||||
} else if s.AverageComplexity > 5 {
|
} else if s.AverageComplexity > 5 {
|
||||||
score -= 10
|
complexityPenalty = 8
|
||||||
}
|
}
|
||||||
|
score -= complexityPenalty
|
||||||
|
|
||||||
// Deduct points for dead code
|
// Dead code penalty (max 25 points, normalized for project size)
|
||||||
|
deadCodePenalty := 0
|
||||||
if s.DeadCodeCount > 0 {
|
if s.DeadCodeCount > 0 {
|
||||||
deduction := (s.DeadCodeCount * 2)
|
rawPenalty := float64(s.DeadCodeCount) / normalizationFactor
|
||||||
if deduction > 20 {
|
deadCodePenalty = int(math.Min(25, rawPenalty))
|
||||||
deduction = 20
|
|
||||||
}
|
|
||||||
score -= deduction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Additional penalty for critical dead code (max 15 points, normalized)
|
||||||
|
criticalPenalty := 0
|
||||||
|
if s.CriticalDeadCode > 0 {
|
||||||
|
rawCriticalPenalty := float64(s.CriticalDeadCode*3) / normalizationFactor
|
||||||
|
criticalPenalty = int(math.Min(15, rawCriticalPenalty))
|
||||||
|
}
|
||||||
|
|
||||||
|
totalDeadCodePenalty := deadCodePenalty + criticalPenalty
|
||||||
|
if totalDeadCodePenalty > 25 {
|
||||||
|
totalDeadCodePenalty = 25
|
||||||
|
}
|
||||||
|
score -= totalDeadCodePenalty
|
||||||
|
|
||||||
// Deduct points for critical dead code
|
// Clone penalty (max 25 points, based on percentage)
|
||||||
score -= s.CriticalDeadCode * 5
|
clonePenalty := 0
|
||||||
|
if s.CodeDuplication > 40 {
|
||||||
// Deduct points for code duplication
|
clonePenalty = 25
|
||||||
if s.CodeDuplication > 30 {
|
} else if s.CodeDuplication > 25 {
|
||||||
score -= 25
|
clonePenalty = 15
|
||||||
} else if s.CodeDuplication > 20 {
|
|
||||||
score -= 15
|
|
||||||
} else if s.CodeDuplication > 10 {
|
} else if s.CodeDuplication > 10 {
|
||||||
score -= 10
|
clonePenalty = 8
|
||||||
}
|
}
|
||||||
|
score -= clonePenalty
|
||||||
|
|
||||||
// Deduct points for high coupling
|
// CBO penalty (max 25 points)
|
||||||
|
cboPenalty := 0
|
||||||
if s.CBOClasses > 0 {
|
if s.CBOClasses > 0 {
|
||||||
couplingRatio := float64(s.HighCouplingClasses) / float64(s.CBOClasses)
|
couplingRatio := float64(s.HighCouplingClasses) / float64(s.CBOClasses)
|
||||||
if couplingRatio > 0.5 {
|
if couplingRatio > 0.5 {
|
||||||
score -= 20
|
cboPenalty = 20
|
||||||
} else if couplingRatio > 0.3 {
|
} else if couplingRatio > 0.3 {
|
||||||
score -= 15
|
cboPenalty = 12
|
||||||
} else if couplingRatio > 0.1 {
|
} else if couplingRatio > 0.1 {
|
||||||
score -= 10
|
cboPenalty = 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
score -= cboPenalty
|
||||||
|
|
||||||
// Ensure score is within bounds
|
// Set minimum score to 10 (never completely fail)
|
||||||
if score < 0 {
|
if score < 10 {
|
||||||
score = 0
|
score = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
s.HealthScore = score
|
s.HealthScore = score
|
||||||
|
|
||||||
// Assign grade based on score
|
// Assign grade based on score (adjusted thresholds)
|
||||||
switch {
|
switch {
|
||||||
case score >= 90:
|
case score >= 85:
|
||||||
s.Grade = "A"
|
s.Grade = "A"
|
||||||
case score >= 80:
|
|
||||||
s.Grade = "B"
|
|
||||||
case score >= 70:
|
case score >= 70:
|
||||||
|
s.Grade = "B"
|
||||||
|
case score >= 55:
|
||||||
s.Grade = "C"
|
s.Grade = "C"
|
||||||
case score >= 60:
|
case score >= 40:
|
||||||
s.Grade = "D"
|
s.Grade = "D"
|
||||||
default:
|
default:
|
||||||
s.Grade = "F"
|
s.Grade = "F"
|
||||||
|
|||||||
@@ -46,58 +46,84 @@ func (f *AnalyzeFormatter) Write(response *domain.AnalyzeResponse, format domain
|
|||||||
|
|
||||||
// writeText formats the response as plain text
|
// writeText formats the response as plain text
|
||||||
func (f *AnalyzeFormatter) writeText(response *domain.AnalyzeResponse, writer io.Writer) error {
|
func (f *AnalyzeFormatter) writeText(response *domain.AnalyzeResponse, writer io.Writer) error {
|
||||||
fmt.Fprintf(writer, "pyscn Comprehensive Analysis Report\n")
|
utils := NewFormatUtils()
|
||||||
fmt.Fprintf(writer, "====================================\n\n")
|
|
||||||
fmt.Fprintf(writer, "Generated: %s\n\n", response.GeneratedAt.Format(time.RFC3339))
|
|
||||||
|
|
||||||
// Summary section
|
// Header
|
||||||
fmt.Fprintf(writer, "Overall Health Score: %d/100 (Grade: %s)\n",
|
fmt.Fprint(writer, utils.FormatMainHeader("Comprehensive Analysis Report"))
|
||||||
response.Summary.HealthScore, response.Summary.Grade)
|
|
||||||
fmt.Fprintf(writer, "Analysis Duration: %.2fs\n\n", float64(response.Duration)/1000.0)
|
// Overall health and duration
|
||||||
|
healthStats := map[string]interface{}{
|
||||||
|
"Health Score": fmt.Sprintf("%d/100 (%s)", response.Summary.HealthScore, response.Summary.Grade),
|
||||||
|
"Analysis Duration": fmt.Sprintf("%.2fs", float64(response.Duration)/1000.0),
|
||||||
|
"Generated": response.GeneratedAt.Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
fmt.Fprint(writer, utils.FormatSummaryStats(healthStats))
|
||||||
|
|
||||||
// File statistics
|
// File statistics
|
||||||
fmt.Fprintf(writer, "File Statistics:\n")
|
fmt.Fprint(writer, utils.FormatFileStats(
|
||||||
fmt.Fprintf(writer, " Total Files: %d\n", response.Summary.TotalFiles)
|
response.Summary.AnalyzedFiles,
|
||||||
fmt.Fprintf(writer, " Analyzed: %d\n", response.Summary.AnalyzedFiles)
|
response.Summary.TotalFiles,
|
||||||
fmt.Fprintf(writer, " Skipped: %d\n\n", response.Summary.SkippedFiles)
|
response.Summary.TotalFiles-response.Summary.AnalyzedFiles))
|
||||||
|
|
||||||
// Complexity analysis results
|
// Analysis modules results
|
||||||
if response.Complexity != nil && response.Summary.ComplexityEnabled {
|
if response.Summary.ComplexityEnabled {
|
||||||
fmt.Fprintf(writer, "Complexity Analysis:\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("COMPLEXITY ANALYSIS"))
|
||||||
fmt.Fprintf(writer, "--------------------\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Total Functions", response.Summary.TotalFunctions))
|
||||||
fmt.Fprintf(writer, " Total Functions: %d\n", response.Summary.TotalFunctions)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Average Complexity", fmt.Sprintf("%.1f", response.Summary.AverageComplexity)))
|
||||||
fmt.Fprintf(writer, " Average Complexity: %.2f\n", response.Summary.AverageComplexity)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "High Complexity Count", response.Summary.HighComplexityCount))
|
||||||
fmt.Fprintf(writer, " High Complexity Count: %d\n\n", response.Summary.HighComplexityCount)
|
fmt.Fprint(writer, utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dead code analysis results
|
if response.Summary.DeadCodeEnabled {
|
||||||
if response.DeadCode != nil && response.Summary.DeadCodeEnabled {
|
fmt.Fprint(writer, utils.FormatSectionHeader("DEAD CODE DETECTION"))
|
||||||
fmt.Fprintf(writer, "Dead Code Detection:\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Total Issues", response.Summary.DeadCodeCount))
|
||||||
fmt.Fprintf(writer, "-------------------\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Critical Issues", response.Summary.CriticalDeadCode))
|
||||||
fmt.Fprintf(writer, " Total Issues: %d\n", response.Summary.DeadCodeCount)
|
fmt.Fprint(writer, utils.FormatSectionSeparator())
|
||||||
fmt.Fprintf(writer, " Critical Issues: %d\n\n", response.Summary.CriticalDeadCode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone detection results
|
if response.Summary.CloneEnabled {
|
||||||
if response.Clone != nil && response.Summary.CloneEnabled {
|
fmt.Fprint(writer, utils.FormatSectionHeader("CLONE DETECTION"))
|
||||||
fmt.Fprintf(writer, "Clone Detection:\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Clone Pairs", response.Summary.ClonePairs))
|
||||||
fmt.Fprintf(writer, "---------------\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Clone Groups", response.Summary.CloneGroups))
|
||||||
fmt.Fprintf(writer, " Clone Pairs: %d\n", response.Summary.ClonePairs)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Code Duplication", utils.FormatPercentage(response.Summary.CodeDuplication)))
|
||||||
fmt.Fprintf(writer, " Clone Groups: %d\n", response.Summary.CloneGroups)
|
fmt.Fprint(writer, utils.FormatSectionSeparator())
|
||||||
fmt.Fprintf(writer, " Code Duplication: %.2f%%\n\n", response.Summary.CodeDuplication)
|
}
|
||||||
|
|
||||||
|
if response.Summary.CBOEnabled {
|
||||||
|
fmt.Fprint(writer, utils.FormatSectionHeader("DEPENDENCY ANALYSIS"))
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Classes Analyzed", response.Summary.CBOClasses))
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "High Coupling Classes", response.Summary.HighCouplingClasses))
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Average Coupling", fmt.Sprintf("%.1f", response.Summary.AverageCoupling)))
|
||||||
|
fmt.Fprint(writer, utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recommendations
|
// Recommendations
|
||||||
fmt.Fprintf(writer, "Recommendations:\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("RECOMMENDATIONS"))
|
||||||
fmt.Fprintf(writer, "---------------\n")
|
recommendationCount := 0
|
||||||
|
|
||||||
if response.Summary.HighComplexityCount > 0 {
|
if response.Summary.HighComplexityCount > 0 {
|
||||||
fmt.Fprintf(writer, " • Refactor %d high-complexity functions\n", response.Summary.HighComplexityCount)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "•",
|
||||||
|
fmt.Sprintf("Refactor %d high-complexity functions", response.Summary.HighComplexityCount)))
|
||||||
|
recommendationCount++
|
||||||
}
|
}
|
||||||
if response.Summary.DeadCodeCount > 0 {
|
if response.Summary.DeadCodeCount > 0 {
|
||||||
fmt.Fprintf(writer, " • Remove %d dead code segments\n", response.Summary.DeadCodeCount)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "•",
|
||||||
|
fmt.Sprintf("Remove %d dead code segments", response.Summary.DeadCodeCount)))
|
||||||
|
recommendationCount++
|
||||||
}
|
}
|
||||||
if response.Summary.CodeDuplication > 10 {
|
if response.Summary.CodeDuplication > 10 {
|
||||||
fmt.Fprintf(writer, " • Reduce code duplication (currently %.1f%%)\n", response.Summary.CodeDuplication)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "•",
|
||||||
|
fmt.Sprintf("Reduce code duplication (currently %.1f%%)", response.Summary.CodeDuplication)))
|
||||||
|
recommendationCount++
|
||||||
|
}
|
||||||
|
if response.Summary.HighCouplingClasses > 0 {
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "•",
|
||||||
|
fmt.Sprintf("Reduce coupling in %d high-dependency classes", response.Summary.HighCouplingClasses)))
|
||||||
|
recommendationCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if recommendationCount == 0 {
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Status", "No major issues detected"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -134,6 +160,9 @@ func (f *AnalyzeFormatter) writeHTML(response *domain.AnalyzeResponse, writer io
|
|||||||
"join": func(elems []string, sep string) string {
|
"join": func(elems []string, sep string) string {
|
||||||
return strings.Join(elems, sep)
|
return strings.Join(elems, sep)
|
||||||
},
|
},
|
||||||
|
"add": func(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
},
|
||||||
}
|
}
|
||||||
tmpl := template.Must(template.New("analyze").Funcs(funcMap).Parse(analyzeHTMLTemplate))
|
tmpl := template.Must(template.New("analyze").Funcs(funcMap).Parse(analyzeHTMLTemplate))
|
||||||
return tmpl.Execute(writer, response)
|
return tmpl.Execute(writer, response)
|
||||||
@@ -376,6 +405,9 @@ const analyzeHTMLTemplate = `<!DOCTYPE html>
|
|||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{{if gt (len .Complexity.Functions) 10}}
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 10 of {{len .Complexity.Functions}} functions</p>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -398,6 +430,43 @@ const analyzeHTMLTemplate = `<!DOCTYPE html>
|
|||||||
<div class="metric-label">Warnings</div>
|
<div class="metric-label">Warnings</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if gt .DeadCode.Summary.TotalFindings 0}}
|
||||||
|
<h3>Top Dead Code Issues</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>Lines</th>
|
||||||
|
<th>Severity</th>
|
||||||
|
<th>Reason</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $file := .DeadCode.Files}}
|
||||||
|
{{range $func := $file.Functions}}
|
||||||
|
{{range $i, $finding := $func.Findings}}
|
||||||
|
{{if lt $i 10}}
|
||||||
|
<tr>
|
||||||
|
<td>{{$finding.Location.FilePath}}</td>
|
||||||
|
<td>{{$finding.FunctionName}}</td>
|
||||||
|
<td>{{$finding.Location.StartLine}}-{{$finding.Location.EndLine}}</td>
|
||||||
|
<td class="severity-{{$finding.Severity}}">{{$finding.Severity}}</td>
|
||||||
|
<td>{{$finding.Reason}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{if gt .DeadCode.Summary.TotalFindings 10}}
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 10 of {{.DeadCode.Summary.TotalFindings}} dead code issues</p>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<p style="color: #4caf50; font-weight: bold; margin-top: 20px;">✓ No dead code detected</p>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -420,6 +489,41 @@ const analyzeHTMLTemplate = `<!DOCTYPE html>
|
|||||||
<div class="metric-label">Avg Similarity</div>
|
<div class="metric-label">Avg Similarity</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if gt .Clone.Statistics.TotalClonePairs 0}}
|
||||||
|
<h3>Major Clone Pairs</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File 1</th>
|
||||||
|
<th>File 2</th>
|
||||||
|
<th>Lines 1</th>
|
||||||
|
<th>Lines 2</th>
|
||||||
|
<th>Similarity</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $i, $pair := .Clone.ClonePairs}}
|
||||||
|
{{if lt $i 15}}
|
||||||
|
<tr>
|
||||||
|
<td>{{$pair.Clone1.Location.FilePath}}</td>
|
||||||
|
<td>{{$pair.Clone2.Location.FilePath}}</td>
|
||||||
|
<td>{{$pair.Clone1.Location.StartLine}}-{{$pair.Clone1.Location.EndLine}}</td>
|
||||||
|
<td>{{$pair.Clone2.Location.StartLine}}-{{$pair.Clone2.Location.EndLine}}</td>
|
||||||
|
<td>{{printf "%.3f" $pair.Similarity}}</td>
|
||||||
|
<td>{{$pair.Type}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{if gt .Clone.Statistics.TotalClonePairs 15}}
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 15 of {{.Clone.Statistics.TotalClonePairs}} clone pairs</p>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<p style="color: #4caf50; font-weight: bold; margin-top: 20px;">✓ No clones detected</p>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -473,6 +577,9 @@ const analyzeHTMLTemplate = `<!DOCTYPE html>
|
|||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{{if gt (len .CBO.Classes) 10}}
|
||||||
|
<p style="color: #666; margin-top: 10px;">Showing top 10 of {{len .CBO.Classes}} classes</p>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -53,29 +53,30 @@ func (f *CBOFormatterImpl) Write(response *domain.CBOResponse, format domain.Out
|
|||||||
// formatText formats the response as human-readable text
|
// formatText formats the response as human-readable text
|
||||||
func (f *CBOFormatterImpl) formatText(response *domain.CBOResponse) (string, error) {
|
func (f *CBOFormatterImpl) formatText(response *domain.CBOResponse) (string, error) {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
utils := NewFormatUtils()
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
builder.WriteString("=== CBO (Coupling Between Objects) Analysis Results ===\n\n")
|
builder.WriteString(utils.FormatMainHeader("CBO (Coupling Between Objects) Analysis Report"))
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
builder.WriteString("📊 SUMMARY\n")
|
stats := map[string]interface{}{
|
||||||
builder.WriteString(fmt.Sprintf("Total Classes: %d\n", response.Summary.TotalClasses))
|
"Total Classes": response.Summary.TotalClasses,
|
||||||
builder.WriteString(fmt.Sprintf("Files Analyzed: %d\n", response.Summary.FilesAnalyzed))
|
"Files Analyzed": response.Summary.FilesAnalyzed,
|
||||||
builder.WriteString(fmt.Sprintf("Average CBO: %.2f\n", response.Summary.AverageCBO))
|
"Average CBO": fmt.Sprintf("%.1f", response.Summary.AverageCBO),
|
||||||
builder.WriteString(fmt.Sprintf("Max CBO: %d\n", response.Summary.MaxCBO))
|
"Max CBO": response.Summary.MaxCBO,
|
||||||
builder.WriteString(fmt.Sprintf("Min CBO: %d\n", response.Summary.MinCBO))
|
"Min CBO": response.Summary.MinCBO,
|
||||||
builder.WriteString("\n")
|
}
|
||||||
|
builder.WriteString(utils.FormatSummaryStats(stats))
|
||||||
|
|
||||||
// Risk distribution
|
// Risk distribution
|
||||||
builder.WriteString("🚦 RISK DISTRIBUTION\n")
|
builder.WriteString(utils.FormatRiskDistribution(
|
||||||
builder.WriteString(fmt.Sprintf("Low Risk: %d classes\n", response.Summary.LowRiskClasses))
|
response.Summary.HighRiskClasses,
|
||||||
builder.WriteString(fmt.Sprintf("Medium Risk: %d classes\n", response.Summary.MediumRiskClasses))
|
response.Summary.MediumRiskClasses,
|
||||||
builder.WriteString(fmt.Sprintf("High Risk: %d classes\n", response.Summary.HighRiskClasses))
|
response.Summary.LowRiskClasses))
|
||||||
builder.WriteString("\n")
|
|
||||||
|
|
||||||
// CBO distribution
|
// CBO distribution
|
||||||
if len(response.Summary.CBODistribution) > 0 {
|
if len(response.Summary.CBODistribution) > 0 {
|
||||||
builder.WriteString("📈 CBO DISTRIBUTION\n")
|
builder.WriteString(utils.FormatSectionHeader("CBO DISTRIBUTION"))
|
||||||
|
|
||||||
// Sort ranges for consistent output
|
// Sort ranges for consistent output
|
||||||
ranges := make([]string, 0, len(response.Summary.CBODistribution))
|
ranges := make([]string, 0, len(response.Summary.CBODistribution))
|
||||||
@@ -86,98 +87,121 @@ func (f *CBOFormatterImpl) formatText(response *domain.CBOResponse) (string, err
|
|||||||
|
|
||||||
for _, rang := range ranges {
|
for _, rang := range ranges {
|
||||||
count := response.Summary.CBODistribution[rang]
|
count := response.Summary.CBODistribution[rang]
|
||||||
builder.WriteString(fmt.Sprintf("CBO %s: %d classes\n", rang, count))
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, fmt.Sprintf("CBO %s", rang), fmt.Sprintf("%d classes", count)))
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most coupled classes
|
// Most coupled classes
|
||||||
if len(response.Summary.MostCoupledClasses) > 0 {
|
if len(response.Summary.MostCoupledClasses) > 0 {
|
||||||
builder.WriteString("🔗 MOST COUPLED CLASSES\n")
|
builder.WriteString(utils.FormatSectionHeader("MOST COUPLED CLASSES"))
|
||||||
for i, class := range response.Summary.MostCoupledClasses {
|
for i, class := range response.Summary.MostCoupledClasses {
|
||||||
if i >= 10 { // Limit to top 10
|
if i >= 10 { // Limit to top 10
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
riskIcon := f.getRiskIcon(class.RiskLevel)
|
// Convert domain risk level to standard risk level
|
||||||
builder.WriteString(fmt.Sprintf("%d. %s %s (CBO: %d) - %s:%d\n",
|
var standardRisk RiskLevel
|
||||||
i+1, riskIcon, class.Name, class.Metrics.CouplingCount, class.FilePath, class.StartLine))
|
switch class.RiskLevel {
|
||||||
|
case "High":
|
||||||
|
standardRisk = RiskHigh
|
||||||
|
case "Medium":
|
||||||
|
standardRisk = RiskMedium
|
||||||
|
case "Low":
|
||||||
|
standardRisk = RiskLow
|
||||||
|
default:
|
||||||
|
standardRisk = RiskLow
|
||||||
|
}
|
||||||
|
coloredRisk := utils.FormatRiskWithColor(standardRisk)
|
||||||
|
|
||||||
|
builder.WriteString(fmt.Sprintf("%s%d. %s %s (CBO: %d) - %s:%d\n",
|
||||||
|
strings.Repeat(" ", SectionPadding), i+1, coloredRisk, class.Name, class.Metrics.CouplingCount, class.FilePath, class.StartLine))
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detailed class information
|
// Detailed class information
|
||||||
if len(response.Classes) > 0 {
|
if len(response.Classes) > 0 {
|
||||||
builder.WriteString("📋 CLASS DETAILS\n")
|
builder.WriteString(utils.FormatSectionHeader("CLASS DETAILS"))
|
||||||
for _, class := range response.Classes {
|
for _, class := range response.Classes {
|
||||||
f.writeClassDetails(&builder, class)
|
f.writeClassDetails(&builder, class, utils)
|
||||||
builder.WriteString("\n")
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnings
|
// Warnings
|
||||||
if len(response.Warnings) > 0 {
|
if len(response.Warnings) > 0 {
|
||||||
builder.WriteString("⚠️ WARNINGS\n")
|
builder.WriteString(utils.FormatWarningsSection(response.Warnings))
|
||||||
for _, warning := range response.Warnings {
|
|
||||||
builder.WriteString(fmt.Sprintf("• %s\n", warning))
|
|
||||||
}
|
|
||||||
builder.WriteString("\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
if len(response.Errors) > 0 {
|
if len(response.Errors) > 0 {
|
||||||
builder.WriteString("❌ ERRORS\n")
|
builder.WriteString(utils.FormatSectionHeader("ERRORS"))
|
||||||
for _, err := range response.Errors {
|
for _, err := range response.Errors {
|
||||||
builder.WriteString(fmt.Sprintf("• %s\n", err))
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "❌", err))
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
builder.WriteString(fmt.Sprintf("Generated at: %s\n", response.GeneratedAt))
|
builder.WriteString(utils.FormatSectionHeader("METADATA"))
|
||||||
builder.WriteString(fmt.Sprintf("Version: %s\n", response.Version))
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "Generated at", response.GeneratedAt))
|
||||||
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "Version", response.Version))
|
||||||
|
|
||||||
return builder.String(), nil
|
return builder.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeClassDetails writes detailed information about a class
|
// writeClassDetails writes detailed information about a class
|
||||||
func (f *CBOFormatterImpl) writeClassDetails(builder *strings.Builder, class domain.ClassCoupling) {
|
func (f *CBOFormatterImpl) writeClassDetails(builder *strings.Builder, class domain.ClassCoupling, utils *FormatUtils) {
|
||||||
riskIcon := f.getRiskIcon(class.RiskLevel)
|
// Convert domain risk level to standard risk level
|
||||||
|
var standardRisk RiskLevel
|
||||||
|
switch class.RiskLevel {
|
||||||
|
case "High":
|
||||||
|
standardRisk = RiskHigh
|
||||||
|
case "Medium":
|
||||||
|
standardRisk = RiskMedium
|
||||||
|
case "Low":
|
||||||
|
standardRisk = RiskLow
|
||||||
|
default:
|
||||||
|
standardRisk = RiskLow
|
||||||
|
}
|
||||||
|
coloredRisk := utils.FormatRiskWithColor(standardRisk)
|
||||||
|
|
||||||
builder.WriteString(fmt.Sprintf("%s %s (CBO: %d, Risk: %s)\n",
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "Class", fmt.Sprintf("%s %s (CBO: %d)",
|
||||||
riskIcon, class.Name, class.Metrics.CouplingCount, class.RiskLevel))
|
coloredRisk, class.Name, class.Metrics.CouplingCount)))
|
||||||
builder.WriteString(fmt.Sprintf(" Location: %s:%d-%d\n", class.FilePath, class.StartLine, class.EndLine))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding, "Location", fmt.Sprintf("%s:%d-%d", class.FilePath, class.StartLine, class.EndLine)))
|
||||||
|
|
||||||
if class.IsAbstract {
|
if class.IsAbstract {
|
||||||
builder.WriteString(" Type: Abstract Class\n")
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding, "Type", "Abstract Class"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base classes
|
// Base classes
|
||||||
if len(class.BaseClasses) > 0 {
|
if len(class.BaseClasses) > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Inherits from: %s\n", strings.Join(class.BaseClasses, ", ")))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding, "Inherits from", strings.Join(class.BaseClasses, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependency breakdown
|
// Dependency breakdown
|
||||||
if class.Metrics.CouplingCount > 0 {
|
if class.Metrics.CouplingCount > 0 {
|
||||||
builder.WriteString(" Dependencies:\n")
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding, "Dependencies", ""))
|
||||||
if class.Metrics.InheritanceDependencies > 0 {
|
if class.Metrics.InheritanceDependencies > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Inheritance: %d\n", class.Metrics.InheritanceDependencies))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Inheritance", class.Metrics.InheritanceDependencies))
|
||||||
}
|
}
|
||||||
if class.Metrics.TypeHintDependencies > 0 {
|
if class.Metrics.TypeHintDependencies > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Type Hints: %d\n", class.Metrics.TypeHintDependencies))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Type Hints", class.Metrics.TypeHintDependencies))
|
||||||
}
|
}
|
||||||
if class.Metrics.InstantiationDependencies > 0 {
|
if class.Metrics.InstantiationDependencies > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Instantiation: %d\n", class.Metrics.InstantiationDependencies))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Instantiation", class.Metrics.InstantiationDependencies))
|
||||||
}
|
}
|
||||||
if class.Metrics.AttributeAccessDependencies > 0 {
|
if class.Metrics.AttributeAccessDependencies > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Attribute Access: %d\n", class.Metrics.AttributeAccessDependencies))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Attribute Access", class.Metrics.AttributeAccessDependencies))
|
||||||
}
|
}
|
||||||
if class.Metrics.ImportDependencies > 0 {
|
if class.Metrics.ImportDependencies > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Imports: %d\n", class.Metrics.ImportDependencies))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Imports", class.Metrics.ImportDependencies))
|
||||||
}
|
}
|
||||||
|
|
||||||
// List dependent classes
|
// List dependent classes
|
||||||
if len(class.Metrics.DependentClasses) > 0 {
|
if len(class.Metrics.DependentClasses) > 0 {
|
||||||
builder.WriteString(fmt.Sprintf(" Coupled to: %s\n", strings.Join(class.Metrics.DependentClasses, ", ")))
|
builder.WriteString(utils.FormatLabelWithIndent(ItemPadding+2, "Coupled to", strings.Join(class.Metrics.DependentClasses, ", ")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,94 +60,92 @@ func (f *CloneOutputFormatter) formatAsText(response *domain.CloneResponse, writ
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print header
|
utils := NewFormatUtils()
|
||||||
fmt.Fprintf(writer, "Clone Detection Results\n")
|
|
||||||
fmt.Fprintf(writer, "======================\n\n")
|
|
||||||
|
|
||||||
// Print statistics
|
// Header
|
||||||
|
fmt.Fprint(writer, utils.FormatMainHeader("Clone Detection Analysis Report"))
|
||||||
|
|
||||||
|
// Summary
|
||||||
if response.Statistics != nil {
|
if response.Statistics != nil {
|
||||||
fmt.Fprintf(writer, "Summary:\n")
|
stats := map[string]interface{}{
|
||||||
fmt.Fprintf(writer, " Files analyzed: %d\n", response.Statistics.FilesAnalyzed)
|
"Files Analyzed": response.Statistics.FilesAnalyzed,
|
||||||
fmt.Fprintf(writer, " Lines analyzed: %d\n", response.Statistics.LinesAnalyzed)
|
"Lines Analyzed": response.Statistics.LinesAnalyzed,
|
||||||
fmt.Fprintf(writer, " Clone pairs found: %d\n", response.Statistics.TotalClonePairs)
|
"Clone Pairs": response.Statistics.TotalClonePairs,
|
||||||
fmt.Fprintf(writer, " Clone groups found: %d\n", response.Statistics.TotalCloneGroups)
|
"Clone Groups": response.Statistics.TotalCloneGroups,
|
||||||
|
"Average Similarity": fmt.Sprintf("%.3f", response.Statistics.AverageSimilarity),
|
||||||
if response.Statistics.AverageSimilarity > 0 {
|
"Analysis Duration": utils.FormatDuration(response.Duration),
|
||||||
fmt.Fprintf(writer, " Average similarity: %.3f\n", response.Statistics.AverageSimilarity)
|
|
||||||
}
|
}
|
||||||
|
fmt.Fprint(writer, utils.FormatSummaryStats(stats))
|
||||||
fmt.Fprintf(writer, " Analysis duration: %dms\n\n", response.Duration)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print clone types breakdown
|
// Clone Types breakdown
|
||||||
if response.Statistics != nil && len(response.Statistics.ClonesByType) > 0 {
|
if response.Statistics != nil && len(response.Statistics.ClonesByType) > 0 {
|
||||||
fmt.Fprintf(writer, "Clone Types:\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("CLONE TYPES"))
|
||||||
for cloneType, count := range response.Statistics.ClonesByType {
|
for cloneType, count := range response.Statistics.ClonesByType {
|
||||||
fmt.Fprintf(writer, " %s: %d pairs\n", cloneType, count)
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, cloneType, fmt.Sprintf("%d pairs", count)))
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, "\n")
|
fmt.Fprint(writer, utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(response.ClonePairs) == 0 {
|
if len(response.ClonePairs) == 0 {
|
||||||
fmt.Fprintf(writer, "No clones detected.\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("RESULTS"))
|
||||||
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Status", "No clones detected"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print detailed clone pairs
|
// Detailed clone information
|
||||||
if response.Request != nil && response.Request.GroupClones && len(response.CloneGroups) > 0 {
|
if response.Request != nil && response.Request.GroupClones && len(response.CloneGroups) > 0 {
|
||||||
fmt.Fprintf(writer, "Clone Groups:\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("CLONE GROUPS"))
|
||||||
fmt.Fprintf(writer, "=============\n\n")
|
|
||||||
|
|
||||||
for _, group := range response.CloneGroups {
|
for _, group := range response.CloneGroups {
|
||||||
if group == nil {
|
if group == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, "Group %d (%s, %d clones, similarity: %.3f):\n",
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(0, "Group", fmt.Sprintf("%d (%s, %d clones, similarity: %.3f)",
|
||||||
group.ID, group.Type.String(), group.Size, group.Similarity)
|
group.ID, group.Type.String(), group.Size, group.Similarity)))
|
||||||
|
|
||||||
for i, clone := range group.Clones {
|
for i, clone := range group.Clones {
|
||||||
if clone == nil || clone.Location == nil {
|
if clone == nil || clone.Location == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, " %d. %s (%d lines, %d nodes)\n",
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(ItemPadding, fmt.Sprintf("Clone %d", i+1),
|
||||||
i+1, clone.Location.String(), clone.LineCount, clone.Size)
|
fmt.Sprintf("%s (%d lines, %d nodes)", clone.Location.String(), clone.LineCount, clone.Size)))
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, "\n")
|
fmt.Fprint(writer, "\n")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(writer, "Clone Pairs:\n")
|
fmt.Fprint(writer, utils.FormatSectionHeader("CLONE PAIRS"))
|
||||||
fmt.Fprintf(writer, "============\n\n")
|
|
||||||
|
|
||||||
for i, pair := range response.ClonePairs {
|
for i, pair := range response.ClonePairs {
|
||||||
if pair == nil {
|
if pair == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, "%d. %s (similarity: %.3f, confidence: %.3f)\n",
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(0, fmt.Sprintf("Pair %d", i+1),
|
||||||
i+1, pair.Type.String(), pair.Similarity, pair.Confidence)
|
fmt.Sprintf("%s (similarity: %.3f, confidence: %.3f)", pair.Type.String(), pair.Similarity, pair.Confidence)))
|
||||||
|
|
||||||
if pair.Clone1 != nil && pair.Clone1.Location != nil {
|
if pair.Clone1 != nil && pair.Clone1.Location != nil {
|
||||||
fmt.Fprintf(writer, " Clone 1: %s (%d lines, %d nodes)\n",
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Clone 1",
|
||||||
pair.Clone1.Location.String(), pair.Clone1.LineCount, pair.Clone1.Size)
|
fmt.Sprintf("%s (%d lines, %d nodes)", pair.Clone1.Location.String(), pair.Clone1.LineCount, pair.Clone1.Size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pair.Clone2 != nil && pair.Clone2.Location != nil {
|
if pair.Clone2 != nil && pair.Clone2.Location != nil {
|
||||||
fmt.Fprintf(writer, " Clone 2: %s (%d lines, %d nodes)\n",
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Clone 2",
|
||||||
pair.Clone2.Location.String(), pair.Clone2.LineCount, pair.Clone2.Size)
|
fmt.Sprintf("%s (%d lines, %d nodes)", pair.Clone2.Location.String(), pair.Clone2.LineCount, pair.Clone2.Size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.Request != nil && response.Request.ShowContent && pair.Clone1 != nil && pair.Clone1.Content != "" {
|
if response.Request != nil && response.Request.ShowContent && pair.Clone1 != nil && pair.Clone1.Content != "" {
|
||||||
fmt.Fprintf(writer, " Content preview:\n")
|
fmt.Fprint(writer, utils.FormatLabelWithIndent(SectionPadding, "Preview", ""))
|
||||||
lines := strings.Split(pair.Clone1.Content, "\n")
|
lines := strings.Split(pair.Clone1.Content, "\n")
|
||||||
for j, line := range lines {
|
for j, line := range lines {
|
||||||
if j >= 5 { // Limit preview to 5 lines
|
if j >= 5 { // Limit preview to 5 lines
|
||||||
fmt.Fprintf(writer, " ...\n")
|
fmt.Fprintf(writer, "%s...\n", strings.Repeat(" ", ItemPadding+2))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fmt.Fprintf(writer, " %s\n", line)
|
fmt.Fprintf(writer, "%s%s\n", strings.Repeat(" ", ItemPadding+2), line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(writer, "\n")
|
fmt.Fprint(writer, "\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func (f *DeadCodeFormatterImpl) Write(response *domain.DeadCodeResponse, format
|
|||||||
func (f *DeadCodeFormatterImpl) FormatFinding(finding domain.DeadCodeFinding, format domain.OutputFormat) (string, error) {
|
func (f *DeadCodeFormatterImpl) FormatFinding(finding domain.DeadCodeFinding, format domain.OutputFormat) (string, error) {
|
||||||
switch format {
|
switch format {
|
||||||
case domain.OutputFormatText:
|
case domain.OutputFormatText:
|
||||||
return f.formatFindingText(finding), nil
|
return f.formatFindingTextLegacy(finding), nil
|
||||||
case domain.OutputFormatJSON:
|
case domain.OutputFormatJSON:
|
||||||
return EncodeJSON(finding)
|
return EncodeJSON(finding)
|
||||||
case domain.OutputFormatYAML:
|
case domain.OutputFormatYAML:
|
||||||
@@ -62,7 +62,7 @@ func (f *DeadCodeFormatterImpl) FormatFinding(finding domain.DeadCodeFinding, fo
|
|||||||
case domain.OutputFormatHTML:
|
case domain.OutputFormatHTML:
|
||||||
// HTML formatting for individual findings is not typically needed
|
// HTML formatting for individual findings is not typically needed
|
||||||
// Fall back to text format for individual findings
|
// Fall back to text format for individual findings
|
||||||
return f.formatFindingText(finding), nil
|
return f.formatFindingTextLegacy(finding), nil
|
||||||
default:
|
default:
|
||||||
return "", domain.NewUnsupportedFormatError(string(format))
|
return "", domain.NewUnsupportedFormatError(string(format))
|
||||||
}
|
}
|
||||||
@@ -71,60 +71,93 @@ func (f *DeadCodeFormatterImpl) FormatFinding(finding domain.DeadCodeFinding, fo
|
|||||||
// formatText formats the response as human-readable text
|
// formatText formats the response as human-readable text
|
||||||
func (f *DeadCodeFormatterImpl) formatText(response *domain.DeadCodeResponse) (string, error) {
|
func (f *DeadCodeFormatterImpl) formatText(response *domain.DeadCodeResponse) (string, error) {
|
||||||
var output strings.Builder
|
var output strings.Builder
|
||||||
|
utils := NewFormatUtils()
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
output.WriteString("Dead Code Detection Results\n")
|
output.WriteString(utils.FormatMainHeader("Dead Code Analysis Report"))
|
||||||
output.WriteString("============================\n\n")
|
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
output.WriteString(fmt.Sprintf("Files analyzed: %d\n", response.Summary.TotalFiles))
|
stats := map[string]interface{}{
|
||||||
output.WriteString(fmt.Sprintf("Files with dead code: %d\n", response.Summary.FilesWithDeadCode))
|
"Total Files": response.Summary.TotalFiles,
|
||||||
output.WriteString(fmt.Sprintf("Total findings: %d\n", response.Summary.TotalFindings))
|
"Files with Dead Code": response.Summary.FilesWithDeadCode,
|
||||||
output.WriteString(fmt.Sprintf("Functions analyzed: %d\n", response.Summary.TotalFunctions))
|
"Total Findings": response.Summary.TotalFindings,
|
||||||
output.WriteString(fmt.Sprintf("Functions with dead code: %d\n\n", response.Summary.FunctionsWithDeadCode))
|
"Functions Analyzed": response.Summary.TotalFunctions,
|
||||||
|
"Functions with Issues": response.Summary.FunctionsWithDeadCode,
|
||||||
|
}
|
||||||
|
output.WriteString(utils.FormatSummaryStats(stats))
|
||||||
|
|
||||||
// Severity breakdown
|
// Severity distribution (using standard risk levels)
|
||||||
output.WriteString("Severity Breakdown:\n")
|
output.WriteString(utils.FormatRiskDistribution(
|
||||||
output.WriteString(fmt.Sprintf(" Critical: %d\n", response.Summary.CriticalFindings))
|
response.Summary.CriticalFindings, // Map Critical to High
|
||||||
output.WriteString(fmt.Sprintf(" Warning: %d\n", response.Summary.WarningFindings))
|
response.Summary.WarningFindings, // Map Warning to Medium
|
||||||
output.WriteString(fmt.Sprintf(" Info: %d\n\n", response.Summary.InfoFindings))
|
response.Summary.InfoFindings)) // Map Info to Low
|
||||||
|
|
||||||
// Files with findings
|
// File Details
|
||||||
for _, file := range response.Files {
|
if len(response.Files) > 0 && response.Summary.TotalFindings > 0 {
|
||||||
output.WriteString(fmt.Sprintf("File: %s\n", file.FilePath))
|
output.WriteString(utils.FormatSectionHeader("DETAILED FINDINGS"))
|
||||||
output.WriteString(strings.Repeat("=", len(file.FilePath)+6) + "\n")
|
|
||||||
|
|
||||||
for _, function := range file.Functions {
|
for _, file := range response.Files {
|
||||||
output.WriteString(fmt.Sprintf("\nFunction: %s\n", function.Name))
|
if len(file.Functions) > 0 {
|
||||||
for _, finding := range function.Findings {
|
output.WriteString(utils.FormatLabelWithIndent(0, "File", file.FilePath))
|
||||||
output.WriteString(f.formatFindingText(finding) + "\n")
|
output.WriteString(strings.Repeat("-", HeaderWidth) + "\n")
|
||||||
|
|
||||||
|
for _, function := range file.Functions {
|
||||||
|
if len(function.Findings) > 0 {
|
||||||
|
output.WriteString(utils.FormatLabelWithIndent(SectionPadding, "Function", function.Name))
|
||||||
|
for _, finding := range function.Findings {
|
||||||
|
output.WriteString(f.formatFindingText(finding, utils) + "\n")
|
||||||
|
}
|
||||||
|
output.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.WriteString("\n")
|
output.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnings and errors
|
// Warnings
|
||||||
if len(response.Warnings) > 0 {
|
if len(response.Warnings) > 0 {
|
||||||
output.WriteString("Warnings:\n")
|
output.WriteString(utils.FormatWarningsSection(response.Warnings))
|
||||||
for _, warning := range response.Warnings {
|
|
||||||
output.WriteString(fmt.Sprintf(" - %s\n", warning))
|
|
||||||
}
|
|
||||||
output.WriteString("\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors
|
||||||
if len(response.Errors) > 0 {
|
if len(response.Errors) > 0 {
|
||||||
output.WriteString("Errors:\n")
|
output.WriteString(utils.FormatSectionHeader("ERRORS"))
|
||||||
for _, error := range response.Errors {
|
for _, error := range response.Errors {
|
||||||
output.WriteString(fmt.Sprintf(" - %s\n", error))
|
output.WriteString(utils.FormatLabelWithIndent(SectionPadding, "❌", error))
|
||||||
}
|
}
|
||||||
output.WriteString("\n")
|
output.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.String(), nil
|
return output.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatFindingText formats a single finding as text
|
// formatFindingText formats a single finding as text
|
||||||
func (f *DeadCodeFormatterImpl) formatFindingText(finding domain.DeadCodeFinding) string {
|
func (f *DeadCodeFormatterImpl) formatFindingText(finding domain.DeadCodeFinding, utils *FormatUtils) string {
|
||||||
|
// Convert severity to standard risk level
|
||||||
|
var standardRisk RiskLevel
|
||||||
|
switch finding.Severity {
|
||||||
|
case "critical":
|
||||||
|
standardRisk = RiskHigh
|
||||||
|
case "warning":
|
||||||
|
standardRisk = RiskMedium
|
||||||
|
case "info":
|
||||||
|
standardRisk = RiskLow
|
||||||
|
default:
|
||||||
|
standardRisk = RiskLow
|
||||||
|
}
|
||||||
|
|
||||||
|
coloredSeverity := utils.FormatRiskWithColor(standardRisk)
|
||||||
|
return fmt.Sprintf(" [%s] Line %d-%d: %s (%s)",
|
||||||
|
coloredSeverity,
|
||||||
|
finding.Location.StartLine,
|
||||||
|
finding.Location.EndLine,
|
||||||
|
finding.Description,
|
||||||
|
finding.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the old method for backward compatibility with FormatFinding
|
||||||
|
func (f *DeadCodeFormatterImpl) formatFindingTextLegacy(finding domain.DeadCodeFinding) string {
|
||||||
return fmt.Sprintf(" [%s] Line %d-%d: %s (%s)",
|
return fmt.Sprintf(" [%s] Line %d-%d: %s (%s)",
|
||||||
strings.ToUpper(string(finding.Severity)),
|
strings.ToUpper(string(finding.Severity)),
|
||||||
finding.Location.StartLine,
|
finding.Location.StartLine,
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ func (s *DeadCodeServiceImpl) analyzeFile(ctx context.Context, filePath string,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
deadCodeResults := analyzer.DetectInFunction(cfg)
|
deadCodeResults := analyzer.DetectInFunctionWithFilePath(cfg, filePath)
|
||||||
if deadCodeResults == nil {
|
if deadCodeResults == nil {
|
||||||
warnings = append(warnings, fmt.Sprintf("[%s:%s] Failed to analyze dead code for function", filePath, functionName))
|
warnings = append(warnings, fmt.Sprintf("[%s:%s] Failed to analyze dead code for function", filePath, functionName))
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ludo-technologies/pyscn/domain"
|
"github.com/ludo-technologies/pyscn/domain"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -47,3 +49,176 @@ func WriteYAML(w io.Writer, v interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard formatting constants
|
||||||
|
const (
|
||||||
|
HeaderWidth = 40
|
||||||
|
LabelWidth = 25
|
||||||
|
SectionPadding = 2
|
||||||
|
ItemPadding = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// ANSI color codes for consistent color usage
|
||||||
|
const (
|
||||||
|
ColorReset = "\x1b[0m"
|
||||||
|
ColorRed = "\x1b[31m"
|
||||||
|
ColorYellow = "\x1b[33m"
|
||||||
|
ColorGreen = "\x1b[32m"
|
||||||
|
ColorCyan = "\x1b[36m"
|
||||||
|
ColorBold = "\x1b[1m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RiskLevel represents the standard risk levels across all tools
|
||||||
|
type RiskLevel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RiskHigh RiskLevel = "High"
|
||||||
|
RiskMedium RiskLevel = "Medium"
|
||||||
|
RiskLow RiskLevel = "Low"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FormatUtils provides shared formatting utilities
|
||||||
|
type FormatUtils struct{}
|
||||||
|
|
||||||
|
// NewFormatUtils creates a new format utilities instance
|
||||||
|
func NewFormatUtils() *FormatUtils {
|
||||||
|
return &FormatUtils{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatMainHeader creates a standardized main header
|
||||||
|
func (f *FormatUtils) FormatMainHeader(title string) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(title + "\n")
|
||||||
|
builder.WriteString(strings.Repeat("=", HeaderWidth) + "\n\n")
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatSectionHeader creates a standardized section header
|
||||||
|
func (f *FormatUtils) FormatSectionHeader(title string) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(strings.ToUpper(title) + "\n")
|
||||||
|
builder.WriteString(strings.Repeat("-", len(title)) + "\n")
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatSectionSeparator creates a section separator
|
||||||
|
func (f *FormatUtils) FormatSectionSeparator() string {
|
||||||
|
return "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatLabel creates a consistently formatted label with right alignment
|
||||||
|
func (f *FormatUtils) FormatLabel(label string, value interface{}) string {
|
||||||
|
padding := LabelWidth - len(label)
|
||||||
|
if padding < 0 {
|
||||||
|
padding = 0
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%s: %v\n", strings.Repeat(" ", padding), label, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatLabelWithIndent creates a formatted label with specific indentation
|
||||||
|
func (f *FormatUtils) FormatLabelWithIndent(indent int, label string, value interface{}) string {
|
||||||
|
return fmt.Sprintf("%s%s: %v\n", strings.Repeat(" ", indent), label, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatPercentage formats a percentage value consistently
|
||||||
|
func (f *FormatUtils) FormatPercentage(value float64) string {
|
||||||
|
return fmt.Sprintf("%.1f%%", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatDuration formats duration in milliseconds consistently
|
||||||
|
func (f *FormatUtils) FormatDuration(durationMs int64) string {
|
||||||
|
return fmt.Sprintf("%dms", durationMs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRiskColor returns the appropriate color for a risk level
|
||||||
|
func (f *FormatUtils) GetRiskColor(risk RiskLevel) string {
|
||||||
|
switch risk {
|
||||||
|
case RiskHigh:
|
||||||
|
return ColorRed
|
||||||
|
case RiskMedium:
|
||||||
|
return ColorYellow
|
||||||
|
case RiskLow:
|
||||||
|
return ColorGreen
|
||||||
|
default:
|
||||||
|
return ColorReset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatRiskWithColor formats a risk level with appropriate color
|
||||||
|
func (f *FormatUtils) FormatRiskWithColor(risk RiskLevel) string {
|
||||||
|
color := f.GetRiskColor(risk)
|
||||||
|
return fmt.Sprintf("%s%s%s", color, string(risk), ColorReset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatTableHeader creates a table header with consistent formatting
|
||||||
|
func (f *FormatUtils) FormatTableHeader(columns ...string) string {
|
||||||
|
header := strings.Join(columns, " ")
|
||||||
|
separator := strings.Repeat("-", len(header))
|
||||||
|
return header + "\n" + separator + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatSummaryStats creates a standardized summary statistics section
|
||||||
|
func (f *FormatUtils) FormatSummaryStats(stats map[string]interface{}) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(f.FormatSectionHeader("SUMMARY"))
|
||||||
|
|
||||||
|
for label, value := range stats {
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, label, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(f.FormatSectionSeparator())
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatRiskDistribution creates a standardized risk distribution section
|
||||||
|
func (f *FormatUtils) FormatRiskDistribution(high, medium, low int) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(f.FormatSectionHeader("RISK DISTRIBUTION"))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "High", high))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "Medium", medium))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "Low", low))
|
||||||
|
builder.WriteString(f.FormatSectionSeparator())
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatWarningsSection creates a standardized warnings section
|
||||||
|
func (f *FormatUtils) FormatWarningsSection(warnings []string) string {
|
||||||
|
if len(warnings) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(f.FormatSectionHeader("WARNINGS"))
|
||||||
|
|
||||||
|
for _, warning := range warnings {
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "⚠", warning))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(f.FormatSectionSeparator())
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertToStandardRisk converts various risk representations to standard format
|
||||||
|
func (f *FormatUtils) ConvertToStandardRisk(risk string) RiskLevel {
|
||||||
|
switch strings.ToLower(risk) {
|
||||||
|
case "high", "critical", "error":
|
||||||
|
return RiskHigh
|
||||||
|
case "medium", "warning", "warn":
|
||||||
|
return RiskMedium
|
||||||
|
case "low", "info", "information":
|
||||||
|
return RiskLow
|
||||||
|
default:
|
||||||
|
return RiskLow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatFileStats creates standardized file statistics
|
||||||
|
func (f *FormatUtils) FormatFileStats(analyzed, total, withIssues int) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(f.FormatSectionHeader("FILE STATISTICS"))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "Total Files", total))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "Analyzed", analyzed))
|
||||||
|
builder.WriteString(f.FormatLabelWithIndent(SectionPadding, "With Issues", withIssues))
|
||||||
|
builder.WriteString(f.FormatSectionSeparator())
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,66 +55,75 @@ func (f *OutputFormatterImpl) Write(response *domain.ComplexityResponse, format
|
|||||||
// formatText formats the response as human-readable text
|
// formatText formats the response as human-readable text
|
||||||
func (f *OutputFormatterImpl) formatText(response *domain.ComplexityResponse) (string, error) {
|
func (f *OutputFormatterImpl) formatText(response *domain.ComplexityResponse) (string, error) {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
utils := NewFormatUtils()
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
builder.WriteString("Complexity Analysis Report\n")
|
builder.WriteString(utils.FormatMainHeader("Complexity Analysis Report"))
|
||||||
builder.WriteString("==========================\n\n")
|
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
builder.WriteString("Summary:\n")
|
stats := map[string]interface{}{
|
||||||
builder.WriteString(fmt.Sprintf(" Total Functions: %d\n", response.Summary.TotalFunctions))
|
"Total Functions": response.Summary.TotalFunctions,
|
||||||
if response.Summary.TotalFunctions > 0 {
|
"Files Analyzed": response.Summary.FilesAnalyzed,
|
||||||
builder.WriteString(fmt.Sprintf(" Average Complexity: %.2f\n", response.Summary.AverageComplexity))
|
|
||||||
builder.WriteString(fmt.Sprintf(" Max Complexity: %d\n", response.Summary.MaxComplexity))
|
|
||||||
builder.WriteString(fmt.Sprintf(" Min Complexity: %d\n", response.Summary.MinComplexity))
|
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
if response.Summary.TotalFunctions > 0 {
|
||||||
|
stats["Average Complexity"] = fmt.Sprintf("%.1f", response.Summary.AverageComplexity)
|
||||||
|
stats["Max Complexity"] = response.Summary.MaxComplexity
|
||||||
|
stats["Min Complexity"] = response.Summary.MinComplexity
|
||||||
|
}
|
||||||
|
builder.WriteString(utils.FormatSummaryStats(stats))
|
||||||
|
|
||||||
// Risk Distribution
|
// Risk Distribution
|
||||||
builder.WriteString("Risk Distribution:\n")
|
builder.WriteString(utils.FormatRiskDistribution(
|
||||||
builder.WriteString(fmt.Sprintf(" High: %d\n", response.Summary.HighRiskFunctions))
|
response.Summary.HighRiskFunctions,
|
||||||
builder.WriteString(fmt.Sprintf(" Medium: %d\n", response.Summary.MediumRiskFunctions))
|
response.Summary.MediumRiskFunctions,
|
||||||
builder.WriteString(fmt.Sprintf(" Low: %d\n", response.Summary.LowRiskFunctions))
|
response.Summary.LowRiskFunctions))
|
||||||
builder.WriteString("\n")
|
|
||||||
|
|
||||||
// Function Details
|
// Function Details
|
||||||
if len(response.Functions) > 0 {
|
if len(response.Functions) > 0 {
|
||||||
builder.WriteString("Function Details:\n")
|
builder.WriteString(utils.FormatSectionHeader("FUNCTION DETAILS"))
|
||||||
builder.WriteString("Function Complexity Risk\n")
|
builder.WriteString(utils.FormatTableHeader("Function", "Complexity", "Risk"))
|
||||||
builder.WriteString("------------------------------------------------\n")
|
|
||||||
|
|
||||||
for _, function := range response.Functions {
|
for _, function := range response.Functions {
|
||||||
color := f.getRiskColor(function.RiskLevel)
|
// Convert domain risk level to standard risk level
|
||||||
builder.WriteString(fmt.Sprintf("%-30s %10d %s%8s\x1b[0m\n",
|
var standardRisk RiskLevel
|
||||||
|
switch function.RiskLevel {
|
||||||
|
case "High":
|
||||||
|
standardRisk = RiskHigh
|
||||||
|
case "Medium":
|
||||||
|
standardRisk = RiskMedium
|
||||||
|
case "Low":
|
||||||
|
standardRisk = RiskLow
|
||||||
|
default:
|
||||||
|
standardRisk = RiskLow
|
||||||
|
}
|
||||||
|
|
||||||
|
coloredRisk := utils.FormatRiskWithColor(standardRisk)
|
||||||
|
builder.WriteString(fmt.Sprintf("%-30s %10d %s\n",
|
||||||
function.Name,
|
function.Name,
|
||||||
function.Metrics.Complexity,
|
function.Metrics.Complexity,
|
||||||
color,
|
coloredRisk))
|
||||||
function.RiskLevel))
|
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnings
|
// Warnings
|
||||||
if len(response.Warnings) > 0 {
|
if len(response.Warnings) > 0 {
|
||||||
builder.WriteString("Warnings:\n")
|
builder.WriteString(utils.FormatWarningsSection(response.Warnings))
|
||||||
for _, warning := range response.Warnings {
|
|
||||||
builder.WriteString(fmt.Sprintf(" ⚠️ %s\n", warning))
|
|
||||||
}
|
|
||||||
builder.WriteString("\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
if len(response.Errors) > 0 {
|
if len(response.Errors) > 0 {
|
||||||
builder.WriteString("Errors:\n")
|
builder.WriteString(utils.FormatSectionHeader("ERRORS"))
|
||||||
for _, err := range response.Errors {
|
for _, err := range response.Errors {
|
||||||
builder.WriteString(fmt.Sprintf(" ❌ %s\n", err))
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "❌", err))
|
||||||
}
|
}
|
||||||
builder.WriteString("\n")
|
builder.WriteString(utils.FormatSectionSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
if parsedTime, err := time.Parse(time.RFC3339, response.GeneratedAt); err == nil {
|
if parsedTime, err := time.Parse(time.RFC3339, response.GeneratedAt); err == nil {
|
||||||
builder.WriteString(fmt.Sprintf("Generated at: %s\n", parsedTime.Format("2006-01-02T15:04:05-07:00")))
|
builder.WriteString(utils.FormatSectionHeader("METADATA"))
|
||||||
|
builder.WriteString(utils.FormatLabelWithIndent(SectionPadding, "Generated at", parsedTime.Format("2006-01-02T15:04:05-07:00")))
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.String(), nil
|
return builder.String(), nil
|
||||||
|
|||||||
185
testdata/python/complex/dead_code_complex.py
vendored
Normal file
185
testdata/python/complex/dead_code_complex.py
vendored
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
"""
|
||||||
|
Complex dead code patterns for advanced testing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
|
||||||
|
def complex_control_flow():
|
||||||
|
"""Complex function with multiple dead code patterns."""
|
||||||
|
state = "initial"
|
||||||
|
result = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
if state == "initial":
|
||||||
|
state = "processing"
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
if i > 5:
|
||||||
|
raise StopIteration("Processing complete")
|
||||||
|
result.append(i)
|
||||||
|
|
||||||
|
# Dead code - loop always raises exception
|
||||||
|
print("Loop completed normally")
|
||||||
|
state = "completed"
|
||||||
|
|
||||||
|
except StopIteration:
|
||||||
|
return result
|
||||||
|
# Dead code after return in exception handler
|
||||||
|
print("Exception handled")
|
||||||
|
state = "error"
|
||||||
|
|
||||||
|
# Dead code - function always returns in exception handler
|
||||||
|
print("Function end")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def generator_with_dead_code():
|
||||||
|
"""Generator function with dead code."""
|
||||||
|
yield 1
|
||||||
|
yield 2
|
||||||
|
return # Early return in generator
|
||||||
|
|
||||||
|
# Dead code after return
|
||||||
|
yield 3
|
||||||
|
yield 4
|
||||||
|
|
||||||
|
|
||||||
|
async def async_dead_code():
|
||||||
|
"""Async function with dead code."""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
return "async result"
|
||||||
|
|
||||||
|
# Dead code after return
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
return "never reached"
|
||||||
|
|
||||||
|
|
||||||
|
def context_manager_dead_code():
|
||||||
|
"""Function with dead code in context manager."""
|
||||||
|
class CustomContext:
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if exc_type:
|
||||||
|
return True # Suppress exception
|
||||||
|
|
||||||
|
with CustomContext():
|
||||||
|
raise ValueError("Test exception")
|
||||||
|
# Dead code after raise
|
||||||
|
print("This won't execute")
|
||||||
|
|
||||||
|
# This code is reachable due to exception suppression
|
||||||
|
return "context completed"
|
||||||
|
|
||||||
|
|
||||||
|
def decorator_dead_code():
|
||||||
|
"""Function with dead code in decorator pattern."""
|
||||||
|
def early_return_decorator(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
return "decorator result"
|
||||||
|
# Dead code in decorator
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
return f"decorated: {result}"
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@early_return_decorator
|
||||||
|
def decorated_function():
|
||||||
|
print("Original function")
|
||||||
|
return "original result"
|
||||||
|
|
||||||
|
return decorated_function()
|
||||||
|
|
||||||
|
|
||||||
|
def class_method_dead_code():
|
||||||
|
"""Function demonstrating dead code in class methods."""
|
||||||
|
|
||||||
|
class TestClass:
|
||||||
|
def __init__(self):
|
||||||
|
self.value = 10
|
||||||
|
return # Early return in __init__
|
||||||
|
# Dead code
|
||||||
|
self.other_value = 20
|
||||||
|
self._setup()
|
||||||
|
|
||||||
|
def _setup(self):
|
||||||
|
"""This method is never called."""
|
||||||
|
self.configured = True
|
||||||
|
|
||||||
|
def method_with_dead_code(self):
|
||||||
|
if self.value > 0:
|
||||||
|
return self.value * 2
|
||||||
|
|
||||||
|
# Dead code - value is always > 0
|
||||||
|
print("Negative value handling")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
obj = TestClass()
|
||||||
|
return obj.method_with_dead_code()
|
||||||
|
|
||||||
|
|
||||||
|
def lambda_dead_code():
|
||||||
|
"""Function with dead code involving lambdas."""
|
||||||
|
always_true = True
|
||||||
|
|
||||||
|
if always_true:
|
||||||
|
func = lambda x: x * 2
|
||||||
|
return func(5)
|
||||||
|
|
||||||
|
# Dead code - condition always true
|
||||||
|
func = lambda x: x * 3
|
||||||
|
return func(5)
|
||||||
|
|
||||||
|
|
||||||
|
def comprehension_dead_code():
|
||||||
|
"""Function with dead code in comprehensions."""
|
||||||
|
data = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
if len(data) > 0:
|
||||||
|
return [x * 2 for x in data if x > 0]
|
||||||
|
|
||||||
|
# Dead code - data always has length > 0
|
||||||
|
return [x for x in data if x < 0]
|
||||||
|
|
||||||
|
|
||||||
|
def exception_hierarchy_dead_code():
|
||||||
|
"""Function with dead code in exception hierarchy."""
|
||||||
|
try:
|
||||||
|
raise ValueError("Test error")
|
||||||
|
except Exception:
|
||||||
|
return "caught general exception"
|
||||||
|
except ValueError:
|
||||||
|
# Dead code - ValueError is already caught by Exception
|
||||||
|
return "caught specific exception"
|
||||||
|
|
||||||
|
# Dead code - exception always caught
|
||||||
|
return "no exception"
|
||||||
|
|
||||||
|
|
||||||
|
def finally_block_patterns():
|
||||||
|
"""Function demonstrating dead code with finally blocks."""
|
||||||
|
try:
|
||||||
|
return "try block result"
|
||||||
|
# Dead code after return in try block
|
||||||
|
print("After return in try")
|
||||||
|
except Exception:
|
||||||
|
return "exception result"
|
||||||
|
# Dead code after return in except block
|
||||||
|
print("After return in except")
|
||||||
|
finally:
|
||||||
|
# This code is reachable - finally always executes
|
||||||
|
print("Finally block executes")
|
||||||
|
return "finally result" # This overrides other returns
|
||||||
|
|
||||||
|
# Dead code after try-except-finally
|
||||||
|
return "end of function"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(complex_control_flow())
|
||||||
|
print(class_method_dead_code())
|
||||||
|
print(comprehension_dead_code())
|
||||||
174
testdata/python/edge_cases/dead_code_examples.py
vendored
Normal file
174
testdata/python/edge_cases/dead_code_examples.py
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
"""
|
||||||
|
Examples of dead code patterns for testing dead code detection.
|
||||||
|
This file contains various types of unreachable code.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def unreachable_after_return():
|
||||||
|
"""Function with code after return statement."""
|
||||||
|
x = 10
|
||||||
|
if x > 5:
|
||||||
|
return "greater than 5"
|
||||||
|
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print("This will never execute")
|
||||||
|
return "fallback"
|
||||||
|
|
||||||
|
|
||||||
|
def unreachable_after_raise():
|
||||||
|
"""Function with code after raise statement."""
|
||||||
|
value = None
|
||||||
|
if value is None:
|
||||||
|
raise ValueError("Value cannot be None")
|
||||||
|
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print("This will never execute")
|
||||||
|
return value * 2
|
||||||
|
|
||||||
|
|
||||||
|
def unreachable_conditional_branch():
|
||||||
|
"""Function with unreachable conditional branches."""
|
||||||
|
debug_mode = False
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print("Debug mode enabled")
|
||||||
|
else:
|
||||||
|
print("Normal mode")
|
||||||
|
|
||||||
|
# This condition will never be True - dead code
|
||||||
|
if debug_mode and not debug_mode:
|
||||||
|
print("This is impossible")
|
||||||
|
return "impossible"
|
||||||
|
|
||||||
|
return "normal"
|
||||||
|
|
||||||
|
|
||||||
|
def unreachable_after_break():
|
||||||
|
"""Function with code after break statement."""
|
||||||
|
items = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
if item == 3:
|
||||||
|
break
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print(f"Processing {item}")
|
||||||
|
item += 1
|
||||||
|
|
||||||
|
return "done"
|
||||||
|
|
||||||
|
|
||||||
|
def unreachable_after_continue():
|
||||||
|
"""Function with code after continue statement."""
|
||||||
|
numbers = [1, 2, 3, 4, 5]
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for num in numbers:
|
||||||
|
if num % 2 == 0:
|
||||||
|
continue
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print(f"Even number: {num}")
|
||||||
|
result.append(num)
|
||||||
|
result.append(num)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def multiple_returns_with_dead_code():
|
||||||
|
"""Function with multiple return statements and dead code."""
|
||||||
|
status = "active"
|
||||||
|
|
||||||
|
if status == "active":
|
||||||
|
return "User is active"
|
||||||
|
elif status == "inactive":
|
||||||
|
return "User is inactive"
|
||||||
|
else:
|
||||||
|
return "Unknown status"
|
||||||
|
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print("This should never execute")
|
||||||
|
status = "processed"
|
||||||
|
return f"Status: {status}"
|
||||||
|
|
||||||
|
|
||||||
|
def nested_dead_code():
|
||||||
|
"""Function with nested dead code patterns."""
|
||||||
|
data = {"valid": True}
|
||||||
|
|
||||||
|
if data.get("valid"):
|
||||||
|
if True: # Always true condition
|
||||||
|
return "valid data"
|
||||||
|
# Dead code after return in nested block
|
||||||
|
print("Never reached in nested block")
|
||||||
|
|
||||||
|
# Dead code - the inner if always returns
|
||||||
|
print("Never reached in outer block")
|
||||||
|
|
||||||
|
# Dead code - the outer if always returns
|
||||||
|
return "invalid data"
|
||||||
|
|
||||||
|
|
||||||
|
class DeadCodeClass:
|
||||||
|
"""Class with dead code examples."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.active = True
|
||||||
|
return # Early return in __init__
|
||||||
|
# Dead code after return
|
||||||
|
self.inactive = False
|
||||||
|
self.setup()
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
"""This method is never called due to dead code in __init__."""
|
||||||
|
print("Setting up...")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def method_with_dead_code(self):
|
||||||
|
"""Method with unreachable code."""
|
||||||
|
if self.active:
|
||||||
|
return "active"
|
||||||
|
|
||||||
|
# Dead code - method always returns above
|
||||||
|
print("This is dead code")
|
||||||
|
self.active = False
|
||||||
|
return "inactive"
|
||||||
|
|
||||||
|
|
||||||
|
def infinite_loop_with_break():
|
||||||
|
"""Function with unreachable code after infinite loop."""
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
counter += 1
|
||||||
|
if counter > 10:
|
||||||
|
break
|
||||||
|
|
||||||
|
# This code is reachable - NOT dead code
|
||||||
|
print(f"Counter reached: {counter}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print("Infinite loop")
|
||||||
|
return "exited"
|
||||||
|
|
||||||
|
# This code is unreachable - dead code
|
||||||
|
print("After infinite loop")
|
||||||
|
return "never reached"
|
||||||
|
|
||||||
|
|
||||||
|
def early_exit_pattern():
|
||||||
|
"""Function with early exit patterns."""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
condition = False
|
||||||
|
if not condition:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# This code is unreachable if condition is always False - dead code
|
||||||
|
print("After sys.exit")
|
||||||
|
return "completed"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Test the functions
|
||||||
|
print(unreachable_after_return())
|
||||||
|
print(unreachable_conditional_branch())
|
||||||
|
# Note: unreachable_after_raise() would raise an exception
|
||||||
66
testdata/python/simple/dead_code_simple.py
vendored
Normal file
66
testdata/python/simple/dead_code_simple.py
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Simple examples of dead code for testing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def simple_dead_code():
|
||||||
|
"""Simple function with dead code after return."""
|
||||||
|
name = "test"
|
||||||
|
return f"Hello, {name}"
|
||||||
|
|
||||||
|
# Dead code - unreachable
|
||||||
|
print("This line will never execute")
|
||||||
|
name = "updated"
|
||||||
|
|
||||||
|
|
||||||
|
def conditional_dead_code():
|
||||||
|
"""Function with dead code in conditional."""
|
||||||
|
always_true = True
|
||||||
|
|
||||||
|
if always_true:
|
||||||
|
return "always returns here"
|
||||||
|
|
||||||
|
# Dead code - condition is always true
|
||||||
|
print("This is unreachable")
|
||||||
|
return "never reached"
|
||||||
|
|
||||||
|
|
||||||
|
def loop_with_dead_code():
|
||||||
|
"""Function with dead code after loop break."""
|
||||||
|
for i in range(5):
|
||||||
|
if i == 2:
|
||||||
|
break
|
||||||
|
# Dead code after break
|
||||||
|
print(f"Processing {i}")
|
||||||
|
print(f"Number: {i}")
|
||||||
|
|
||||||
|
return "loop completed"
|
||||||
|
|
||||||
|
|
||||||
|
def exception_dead_code():
|
||||||
|
"""Function with dead code after exception."""
|
||||||
|
data = None
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
raise ValueError("Data is required")
|
||||||
|
|
||||||
|
# Dead code - exception always raised
|
||||||
|
print("Processing data")
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
|
||||||
|
def nested_return_dead_code():
|
||||||
|
"""Function with nested returns and dead code."""
|
||||||
|
status = "ok"
|
||||||
|
|
||||||
|
if status == "ok":
|
||||||
|
if True:
|
||||||
|
return "success"
|
||||||
|
# Dead code in nested block
|
||||||
|
print("Never reached nested")
|
||||||
|
|
||||||
|
# Dead code in outer block
|
||||||
|
print("Never reached outer")
|
||||||
|
|
||||||
|
# Dead code at function level
|
||||||
|
return "failure"
|
||||||
Reference in New Issue
Block a user