crackerjack 0.33.0__py3-none-any.whl → 0.33.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +4 -13
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +104 -204
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +171 -174
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +44 -8
- crackerjack/managers/test_command_builder.py +1 -15
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +98 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +17 -16
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +173 -32
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +8 -10
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +0 -2
- crackerjack/mixins/error_handling.py +1 -70
- crackerjack/models/config.py +12 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +122 -122
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +6 -35
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +15 -9
- crackerjack/services/config_merge.py +19 -80
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +27 -25
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +8 -25
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +11 -30
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +19 -87
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +9 -67
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +18 -59
- crackerjack/services/performance_cache.py +20 -81
- crackerjack/services/performance_monitor.py +27 -95
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +605 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +9 -41
- crackerjack/services/security_logger.py +12 -24
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
- crackerjack-0.33.1.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.33.0.dist-info/RECORD +0 -187
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -19,8 +19,6 @@ from .performance_helpers import OptimizationResult
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class PerformanceAgent(SubAgent):
|
|
22
|
-
"""Enhanced PerformanceAgent with automated O(n²) detection and measurable optimizations."""
|
|
23
|
-
|
|
24
22
|
def __init__(self, context: AgentContext) -> None:
|
|
25
23
|
super().__init__(context)
|
|
26
24
|
self.performance_metrics: dict[str, t.Any] = {}
|
|
@@ -36,22 +34,19 @@ class PerformanceAgent(SubAgent):
|
|
|
36
34
|
return {IssueType.PERFORMANCE}
|
|
37
35
|
|
|
38
36
|
async def can_handle(self, issue: Issue) -> float:
|
|
39
|
-
"""Enhanced confidence scoring based on issue complexity."""
|
|
40
37
|
if issue.type != IssueType.PERFORMANCE:
|
|
41
38
|
return 0.0
|
|
42
39
|
|
|
43
|
-
# Higher confidence for specific performance patterns
|
|
44
40
|
confidence = 0.85
|
|
45
41
|
message_lower = issue.message.lower()
|
|
46
42
|
|
|
47
|
-
# Boost confidence for known optimization patterns
|
|
48
43
|
if any(
|
|
49
44
|
pattern in message_lower
|
|
50
45
|
for pattern in (
|
|
51
46
|
"nested loop",
|
|
52
47
|
"o(n²)",
|
|
53
48
|
"string concatenation",
|
|
54
|
-
"list concatenation",
|
|
49
|
+
"list[t.Any] concatenation",
|
|
55
50
|
"inefficient",
|
|
56
51
|
"complexity",
|
|
57
52
|
)
|
|
@@ -61,7 +56,6 @@ class PerformanceAgent(SubAgent):
|
|
|
61
56
|
return confidence
|
|
62
57
|
|
|
63
58
|
async def analyze_and_fix(self, issue: Issue) -> FixResult:
|
|
64
|
-
"""Enhanced analysis with performance measurement and optimization tracking."""
|
|
65
59
|
self.log(f"Analyzing performance issue: {issue.message}")
|
|
66
60
|
start_time = time.time()
|
|
67
61
|
|
|
@@ -81,7 +75,6 @@ class PerformanceAgent(SubAgent):
|
|
|
81
75
|
try:
|
|
82
76
|
result = await self._process_performance_optimization(file_path)
|
|
83
77
|
|
|
84
|
-
# Track performance metrics
|
|
85
78
|
analysis_time = time.time() - start_time
|
|
86
79
|
self.performance_metrics[str(file_path)] = {
|
|
87
80
|
"analysis_duration": analysis_time,
|
|
@@ -89,7 +82,6 @@ class PerformanceAgent(SubAgent):
|
|
|
89
82
|
"timestamp": time.time(),
|
|
90
83
|
}
|
|
91
84
|
|
|
92
|
-
# Add performance statistics to result
|
|
93
85
|
if result.success and result.fixes_applied:
|
|
94
86
|
stats_summary = self._generate_optimization_summary()
|
|
95
87
|
result.recommendations = result.recommendations + [stats_summary]
|
|
@@ -198,40 +190,32 @@ class PerformanceAgent(SubAgent):
|
|
|
198
190
|
content: str,
|
|
199
191
|
file_path: Path,
|
|
200
192
|
) -> list[dict[str, t.Any]]:
|
|
201
|
-
"""Enhanced performance issue detection with comprehensive O(n²) analysis."""
|
|
202
193
|
issues: list[dict[str, t.Any]] = []
|
|
203
194
|
|
|
204
195
|
with suppress(SyntaxError):
|
|
205
196
|
tree = ast.parse(content)
|
|
206
197
|
|
|
207
|
-
# Enhanced nested loop detection with complexity analysis
|
|
208
198
|
nested_issues = self._detect_nested_loops_enhanced(tree)
|
|
209
199
|
issues.extend(nested_issues)
|
|
210
200
|
|
|
211
|
-
# Improved list operations detection
|
|
212
201
|
list_issues = self._detect_inefficient_list_ops_enhanced(content, tree)
|
|
213
202
|
issues.extend(list_issues)
|
|
214
203
|
|
|
215
|
-
# Enhanced repeated operations detection
|
|
216
204
|
repeated_issues = self._detect_repeated_operations_enhanced(content, tree)
|
|
217
205
|
issues.extend(repeated_issues)
|
|
218
206
|
|
|
219
|
-
# Comprehensive string inefficiency detection
|
|
220
207
|
string_issues = self._detect_string_inefficiencies_enhanced(content)
|
|
221
208
|
issues.extend(string_issues)
|
|
222
209
|
|
|
223
|
-
# New: Detect list comprehension opportunities
|
|
224
210
|
comprehension_issues = self._detect_list_comprehension_opportunities(tree)
|
|
225
211
|
issues.extend(comprehension_issues)
|
|
226
212
|
|
|
227
|
-
# New: Detect inefficient built-in usage
|
|
228
213
|
builtin_issues = self._detect_inefficient_builtin_usage(tree, content)
|
|
229
214
|
issues.extend(builtin_issues)
|
|
230
215
|
|
|
231
216
|
return issues
|
|
232
217
|
|
|
233
218
|
def _detect_nested_loops_enhanced(self, tree: ast.AST) -> list[dict[str, t.Any]]:
|
|
234
|
-
"""Enhanced nested loop detection with complexity analysis and optimization suggestions."""
|
|
235
219
|
analyzer = self._create_nested_loop_analyzer()
|
|
236
220
|
analyzer.visit(tree)
|
|
237
221
|
return self._build_nested_loop_issues(analyzer)
|
|
@@ -240,13 +224,11 @@ class PerformanceAgent(SubAgent):
|
|
|
240
224
|
def _create_nested_loop_analyzer() -> (
|
|
241
225
|
performance_helpers.EnhancedNestedLoopAnalyzer
|
|
242
226
|
):
|
|
243
|
-
"""Create and configure the nested loop analyzer."""
|
|
244
227
|
return performance_helpers.EnhancedNestedLoopAnalyzer()
|
|
245
228
|
|
|
246
229
|
def _build_nested_loop_issues(
|
|
247
230
|
self, analyzer: performance_helpers.EnhancedNestedLoopAnalyzer
|
|
248
231
|
) -> list[dict[str, t.Any]]:
|
|
249
|
-
"""Build the final nested loop issues from analyzer results."""
|
|
250
232
|
if not analyzer.nested_loops:
|
|
251
233
|
return []
|
|
252
234
|
|
|
@@ -267,12 +249,10 @@ class PerformanceAgent(SubAgent):
|
|
|
267
249
|
|
|
268
250
|
@staticmethod
|
|
269
251
|
def _count_high_priority_loops(nested_loops: list[dict[str, t.Any]]) -> int:
|
|
270
|
-
"""Count loops with high or critical priority."""
|
|
271
252
|
return len([n for n in nested_loops if n["priority"] in ("high", "critical")])
|
|
272
253
|
|
|
273
254
|
@staticmethod
|
|
274
255
|
def _generate_nested_loop_suggestions(nested_loops: list[dict[str, t.Any]]) -> str:
|
|
275
|
-
"""Generate specific optimization suggestions based on nested loop analysis."""
|
|
276
256
|
suggestions = []
|
|
277
257
|
|
|
278
258
|
critical_count = len(
|
|
@@ -303,7 +283,6 @@ class PerformanceAgent(SubAgent):
|
|
|
303
283
|
content: str,
|
|
304
284
|
tree: ast.AST,
|
|
305
285
|
) -> list[dict[str, t.Any]]:
|
|
306
|
-
"""Enhanced list operations detection with performance impact assessment."""
|
|
307
286
|
analyzer = self._create_enhanced_list_op_analyzer()
|
|
308
287
|
analyzer.visit(tree)
|
|
309
288
|
|
|
@@ -314,11 +293,9 @@ class PerformanceAgent(SubAgent):
|
|
|
314
293
|
|
|
315
294
|
@staticmethod
|
|
316
295
|
def _create_enhanced_list_op_analyzer() -> t.Any:
|
|
317
|
-
"""Create the enhanced list operations analyzer."""
|
|
318
296
|
return performance_helpers.EnhancedListOpAnalyzer()
|
|
319
297
|
|
|
320
298
|
def _build_list_ops_issues(self, analyzer: t.Any) -> list[dict[str, t.Any]]:
|
|
321
|
-
"""Build the final list operations issues from analyzer results."""
|
|
322
299
|
total_impact = sum(int(op["impact_factor"]) for op in analyzer.list_ops)
|
|
323
300
|
high_impact_ops = [
|
|
324
301
|
op for op in analyzer.list_ops if int(op["impact_factor"]) >= 10
|
|
@@ -336,7 +313,6 @@ class PerformanceAgent(SubAgent):
|
|
|
336
313
|
|
|
337
314
|
@staticmethod
|
|
338
315
|
def _generate_list_op_suggestions(list_ops: list[dict[str, t.Any]]) -> str:
|
|
339
|
-
"""Generate specific optimization suggestions for list operations."""
|
|
340
316
|
suggestions = []
|
|
341
317
|
|
|
342
318
|
high_impact_count = len(
|
|
@@ -344,7 +320,7 @@ class PerformanceAgent(SubAgent):
|
|
|
344
320
|
)
|
|
345
321
|
if high_impact_count > 0:
|
|
346
322
|
suggestions.append(
|
|
347
|
-
f"HIGH IMPACT: {high_impact_count} list operations in hot loops"
|
|
323
|
+
f"HIGH IMPACT: {high_impact_count} list[t.Any] operations in hot loops"
|
|
348
324
|
)
|
|
349
325
|
|
|
350
326
|
append_count = len([op for op in list_ops if op["optimization"] == "append"])
|
|
@@ -473,7 +449,7 @@ class PerformanceAgent(SubAgent):
|
|
|
473
449
|
{
|
|
474
450
|
"type": "string_concatenation_in_loop",
|
|
475
451
|
"instances": string_concat_in_loop,
|
|
476
|
-
"suggestion": 'Use list.append() and "".join() for string building',
|
|
452
|
+
"suggestion": 'Use list[t.Any].append() and "".join() for string building',
|
|
477
453
|
},
|
|
478
454
|
)
|
|
479
455
|
|
|
@@ -482,7 +458,6 @@ class PerformanceAgent(SubAgent):
|
|
|
482
458
|
def _detect_string_inefficiencies_enhanced(
|
|
483
459
|
self, content: str
|
|
484
460
|
) -> list[dict[str, t.Any]]:
|
|
485
|
-
"""Enhanced string inefficiency detection with comprehensive analysis."""
|
|
486
461
|
issues: list[dict[str, t.Any]] = []
|
|
487
462
|
lines = content.split("\n")
|
|
488
463
|
|
|
@@ -493,7 +468,6 @@ class PerformanceAgent(SubAgent):
|
|
|
493
468
|
for i, line in enumerate(lines):
|
|
494
469
|
stripped = line.strip()
|
|
495
470
|
|
|
496
|
-
# Detect string concatenation in loops (enhanced)
|
|
497
471
|
if "+=" in stripped and any(quote in stripped for quote in ('"', "'")):
|
|
498
472
|
if self._is_in_loop_context_enhanced(lines, i):
|
|
499
473
|
context_info = self._analyze_string_context(lines, i)
|
|
@@ -508,7 +482,6 @@ class PerformanceAgent(SubAgent):
|
|
|
508
482
|
}
|
|
509
483
|
)
|
|
510
484
|
|
|
511
|
-
# Detect inefficient string joins
|
|
512
485
|
if ".join([])" in stripped:
|
|
513
486
|
inefficient_joins.append(
|
|
514
487
|
{
|
|
@@ -519,7 +492,6 @@ class PerformanceAgent(SubAgent):
|
|
|
519
492
|
}
|
|
520
493
|
)
|
|
521
494
|
|
|
522
|
-
# Detect repeated string formatting in loops
|
|
523
495
|
if any(pattern in stripped for pattern in ('f"', ".format(", "% ")):
|
|
524
496
|
if self._is_in_loop_context_enhanced(lines, i):
|
|
525
497
|
repeated_format_calls.append(
|
|
@@ -555,7 +527,6 @@ class PerformanceAgent(SubAgent):
|
|
|
555
527
|
def _analyze_string_context(
|
|
556
528
|
self, lines: list[str], line_idx: int
|
|
557
529
|
) -> dict[str, t.Any]:
|
|
558
|
-
"""Analyze the context around a string operation for impact assessment."""
|
|
559
530
|
context = self._create_default_string_context()
|
|
560
531
|
loop_context = self._find_loop_context_in_lines(lines, line_idx)
|
|
561
532
|
|
|
@@ -566,7 +537,6 @@ class PerformanceAgent(SubAgent):
|
|
|
566
537
|
|
|
567
538
|
@staticmethod
|
|
568
539
|
def _create_default_string_context() -> dict[str, t.Any]:
|
|
569
|
-
"""Create default context for string operations."""
|
|
570
540
|
return {
|
|
571
541
|
"loop_type": "unknown",
|
|
572
542
|
"loop_depth": 1,
|
|
@@ -576,7 +546,6 @@ class PerformanceAgent(SubAgent):
|
|
|
576
546
|
def _find_loop_context_in_lines(
|
|
577
547
|
self, lines: list[str], line_idx: int
|
|
578
548
|
) -> dict[str, t.Any] | None:
|
|
579
|
-
"""Find loop context by looking back through lines."""
|
|
580
549
|
for i in range(max(0, line_idx - 10), line_idx):
|
|
581
550
|
line = lines[i].strip()
|
|
582
551
|
loop_context = self._analyze_single_line_for_loop_context(line)
|
|
@@ -587,7 +556,6 @@ class PerformanceAgent(SubAgent):
|
|
|
587
556
|
def _analyze_single_line_for_loop_context(
|
|
588
557
|
self, line: str
|
|
589
558
|
) -> dict[str, t.Any] | None:
|
|
590
|
-
"""Analyze a single line for loop context information."""
|
|
591
559
|
if "for " in line and " in " in line:
|
|
592
560
|
return self._analyze_for_loop_context(line)
|
|
593
561
|
elif "while " in line:
|
|
@@ -595,27 +563,24 @@ class PerformanceAgent(SubAgent):
|
|
|
595
563
|
return None
|
|
596
564
|
|
|
597
565
|
def _analyze_for_loop_context(self, line: str) -> dict[str, t.Any]:
|
|
598
|
-
"""Analyze for loop context and estimate impact."""
|
|
599
566
|
context = {"loop_type": "for"}
|
|
600
567
|
|
|
601
568
|
if "range(" in line:
|
|
602
569
|
impact_factor = self._estimate_range_impact_factor(line)
|
|
603
570
|
context["impact_factor"] = str(impact_factor)
|
|
604
571
|
else:
|
|
605
|
-
context["impact_factor"] = "2"
|
|
572
|
+
context["impact_factor"] = "2"
|
|
606
573
|
|
|
607
574
|
return context
|
|
608
575
|
|
|
609
576
|
@staticmethod
|
|
610
577
|
def _analyze_while_loop_context() -> dict[str, t.Any]:
|
|
611
|
-
"""Analyze while loop context."""
|
|
612
578
|
return {
|
|
613
579
|
"loop_type": "while",
|
|
614
|
-
"impact_factor": "3",
|
|
580
|
+
"impact_factor": "3",
|
|
615
581
|
}
|
|
616
582
|
|
|
617
583
|
def _estimate_range_impact_factor(self, line: str) -> int:
|
|
618
|
-
"""Estimate impact factor based on range size."""
|
|
619
584
|
try:
|
|
620
585
|
pattern_obj = SAFE_PATTERNS["extract_range_size"]
|
|
621
586
|
if not pattern_obj.test(line):
|
|
@@ -630,19 +595,15 @@ class PerformanceAgent(SubAgent):
|
|
|
630
595
|
|
|
631
596
|
@staticmethod
|
|
632
597
|
def _extract_range_size_from_string(range_str: str) -> int:
|
|
633
|
-
|
|
634
|
-
import re # REGEX OK: temporary for extracting number from safe pattern
|
|
598
|
+
import re
|
|
635
599
|
|
|
636
|
-
number_match = re.search(
|
|
637
|
-
r"\d+", range_str
|
|
638
|
-
) # REGEX OK: extracting digits from validated pattern
|
|
600
|
+
number_match = re.search(r"\d+", range_str)
|
|
639
601
|
if number_match:
|
|
640
602
|
return int(number_match.group())
|
|
641
603
|
return 0
|
|
642
604
|
|
|
643
605
|
@staticmethod
|
|
644
606
|
def _calculate_impact_from_range_size(range_size: int) -> int:
|
|
645
|
-
"""Calculate impact factor based on range size."""
|
|
646
607
|
if range_size > 1000:
|
|
647
608
|
return 10
|
|
648
609
|
elif range_size > 100:
|
|
@@ -651,14 +612,10 @@ class PerformanceAgent(SubAgent):
|
|
|
651
612
|
|
|
652
613
|
@staticmethod
|
|
653
614
|
def _is_in_loop_context_enhanced(lines: list[str], line_index: int) -> bool:
|
|
654
|
-
"""Enhanced loop context detection with better accuracy."""
|
|
655
615
|
context_start = max(0, line_index - 8)
|
|
656
616
|
context_lines = lines[context_start : line_index + 1]
|
|
657
617
|
|
|
658
|
-
# Check for various loop patterns
|
|
659
|
-
|
|
660
618
|
for ctx_line in context_lines:
|
|
661
|
-
# Use safe pattern matching for loop detection
|
|
662
619
|
pattern_obj = SAFE_PATTERNS["match_loop_patterns"]
|
|
663
620
|
if pattern_obj.test(ctx_line):
|
|
664
621
|
return True
|
|
@@ -671,7 +628,6 @@ class PerformanceAgent(SubAgent):
|
|
|
671
628
|
inefficient_joins: list[dict[str, t.Any]],
|
|
672
629
|
repeated_formatting: list[dict[str, t.Any]],
|
|
673
630
|
) -> str:
|
|
674
|
-
"""Generate comprehensive string optimization suggestions."""
|
|
675
631
|
suggestions = []
|
|
676
632
|
|
|
677
633
|
if concat_patterns:
|
|
@@ -680,7 +636,7 @@ class PerformanceAgent(SubAgent):
|
|
|
680
636
|
)
|
|
681
637
|
suggestions.append(
|
|
682
638
|
f"String concatenation: {len(concat_patterns)} instances "
|
|
683
|
-
f"({high_impact} high-impact) - use list.append + join"
|
|
639
|
+
f"({high_impact} high-impact) - use list[t.Any].append + join"
|
|
684
640
|
)
|
|
685
641
|
|
|
686
642
|
if inefficient_joins:
|
|
@@ -699,7 +655,6 @@ class PerformanceAgent(SubAgent):
|
|
|
699
655
|
def _detect_list_comprehension_opportunities(
|
|
700
656
|
self, tree: ast.AST
|
|
701
657
|
) -> list[dict[str, t.Any]]:
|
|
702
|
-
"""Detect opportunities to replace append loops with list comprehensions."""
|
|
703
658
|
issues: list[dict[str, t.Any]] = []
|
|
704
659
|
|
|
705
660
|
class ComprehensionAnalyzer(ast.NodeVisitor):
|
|
@@ -707,7 +662,6 @@ class PerformanceAgent(SubAgent):
|
|
|
707
662
|
self.opportunities: list[dict[str, t.Any]] = []
|
|
708
663
|
|
|
709
664
|
def visit_For(self, node: ast.For) -> None:
|
|
710
|
-
# Look for simple append patterns that can be comprehensions
|
|
711
665
|
if (
|
|
712
666
|
len(node.body) == 1
|
|
713
667
|
and isinstance(node.body[0], ast.Expr)
|
|
@@ -743,7 +697,7 @@ class PerformanceAgent(SubAgent):
|
|
|
743
697
|
"instances": analyzer.opportunities,
|
|
744
698
|
"total_count": len(analyzer.opportunities),
|
|
745
699
|
"suggestion": f"Convert {len(analyzer.opportunities)} append loops"
|
|
746
|
-
f" to list comprehensions for better performance "
|
|
700
|
+
f" to list[t.Any] comprehensions for better performance "
|
|
747
701
|
f"and readability",
|
|
748
702
|
}
|
|
749
703
|
)
|
|
@@ -753,7 +707,6 @@ class PerformanceAgent(SubAgent):
|
|
|
753
707
|
def _detect_inefficient_builtin_usage(
|
|
754
708
|
self, tree: ast.AST, content: str
|
|
755
709
|
) -> list[dict[str, t.Any]]:
|
|
756
|
-
"""Detect inefficient usage of built-in functions."""
|
|
757
710
|
issues: list[dict[str, t.Any]] = []
|
|
758
711
|
|
|
759
712
|
class BuiltinAnalyzer(ast.NodeVisitor):
|
|
@@ -777,9 +730,7 @@ class PerformanceAgent(SubAgent):
|
|
|
777
730
|
if self.in_loop and isinstance(node.func, ast.Name):
|
|
778
731
|
func_name = node.func.id
|
|
779
732
|
|
|
780
|
-
# Detect expensive operations in loops
|
|
781
733
|
if func_name in ("len", "sum", "max", "min", "sorted"):
|
|
782
|
-
# Check if called on the same variable repeatedly
|
|
783
734
|
if node.args and isinstance(node.args[0], ast.Name):
|
|
784
735
|
self.inefficient_calls.append(
|
|
785
736
|
{
|
|
@@ -811,7 +762,6 @@ class PerformanceAgent(SubAgent):
|
|
|
811
762
|
return issues
|
|
812
763
|
|
|
813
764
|
def _generate_optimization_summary(self) -> str:
|
|
814
|
-
"""Generate a summary of all optimizations applied."""
|
|
815
765
|
total_optimizations = sum(self.optimization_stats.values())
|
|
816
766
|
if total_optimizations == 0:
|
|
817
767
|
return "No optimizations applied in this session"
|
|
@@ -832,7 +782,6 @@ class PerformanceAgent(SubAgent):
|
|
|
832
782
|
content: str,
|
|
833
783
|
issues: list[dict[str, t.Any]],
|
|
834
784
|
) -> str:
|
|
835
|
-
"""Enhanced optimization application with support for new issue types."""
|
|
836
785
|
lines = content.split("\n")
|
|
837
786
|
modified = False
|
|
838
787
|
optimizations_applied = []
|
|
@@ -853,7 +802,6 @@ class PerformanceAgent(SubAgent):
|
|
|
853
802
|
def _process_single_issue(
|
|
854
803
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
855
804
|
) -> OptimizationResult:
|
|
856
|
-
"""Process a single optimization issue and return the result."""
|
|
857
805
|
issue_type = issue["type"]
|
|
858
806
|
|
|
859
807
|
if issue_type in (
|
|
@@ -879,7 +827,6 @@ class PerformanceAgent(SubAgent):
|
|
|
879
827
|
def _handle_list_operations_issue(
|
|
880
828
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
881
829
|
) -> OptimizationResult:
|
|
882
|
-
"""Handle list operations optimization issue."""
|
|
883
830
|
new_lines, changed = self._fix_list_operations_enhanced(lines, issue)
|
|
884
831
|
description = None
|
|
885
832
|
|
|
@@ -893,7 +840,6 @@ class PerformanceAgent(SubAgent):
|
|
|
893
840
|
def _handle_string_operations_issue(
|
|
894
841
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
895
842
|
) -> OptimizationResult:
|
|
896
|
-
"""Handle string operations optimization issue."""
|
|
897
843
|
new_lines, changed = self._fix_string_operations_enhanced(lines, issue)
|
|
898
844
|
description = None
|
|
899
845
|
|
|
@@ -911,7 +857,6 @@ class PerformanceAgent(SubAgent):
|
|
|
911
857
|
def _handle_repeated_operations_issue(
|
|
912
858
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
913
859
|
) -> OptimizationResult:
|
|
914
|
-
"""Handle repeated operations optimization issue."""
|
|
915
860
|
new_lines, changed = self._fix_repeated_operations(lines, issue)
|
|
916
861
|
|
|
917
862
|
if changed:
|
|
@@ -924,7 +869,6 @@ class PerformanceAgent(SubAgent):
|
|
|
924
869
|
def _handle_nested_loops_issue(
|
|
925
870
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
926
871
|
) -> OptimizationResult:
|
|
927
|
-
"""Handle nested loops optimization issue."""
|
|
928
872
|
new_lines, changed = self._add_nested_loop_comments(lines, issue)
|
|
929
873
|
|
|
930
874
|
if changed:
|
|
@@ -937,7 +881,6 @@ class PerformanceAgent(SubAgent):
|
|
|
937
881
|
def _handle_comprehension_opportunities_issue(
|
|
938
882
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
939
883
|
) -> OptimizationResult:
|
|
940
|
-
"""Handle list comprehension opportunities issue."""
|
|
941
884
|
new_lines, changed = self._apply_list_comprehension_optimizations(lines, issue)
|
|
942
885
|
|
|
943
886
|
if changed:
|
|
@@ -950,7 +893,6 @@ class PerformanceAgent(SubAgent):
|
|
|
950
893
|
def _handle_builtin_usage_issue(
|
|
951
894
|
self, lines: list[str], issue: dict[str, t.Any]
|
|
952
895
|
) -> OptimizationResult:
|
|
953
|
-
"""Handle inefficient builtin usage issue."""
|
|
954
896
|
new_lines, changed = self._add_builtin_caching_comments(lines, issue)
|
|
955
897
|
return self._create_optimization_result(new_lines, changed)
|
|
956
898
|
|
|
@@ -958,14 +900,12 @@ class PerformanceAgent(SubAgent):
|
|
|
958
900
|
def _create_optimization_result(
|
|
959
901
|
lines: list[str], modified: bool, description: str | None = None
|
|
960
902
|
) -> OptimizationResult:
|
|
961
|
-
"""Create an optimization result object."""
|
|
962
903
|
return OptimizationResult(
|
|
963
904
|
lines=lines, modified=modified, optimization_description=description
|
|
964
905
|
)
|
|
965
906
|
|
|
966
907
|
@staticmethod
|
|
967
908
|
def _create_no_change_result(lines: list[str]) -> OptimizationResult:
|
|
968
|
-
"""Create a result indicating no changes were made."""
|
|
969
909
|
return OptimizationResult(
|
|
970
910
|
lines=lines, modified=False, optimization_description=None
|
|
971
911
|
)
|
|
@@ -975,7 +915,6 @@ class PerformanceAgent(SubAgent):
|
|
|
975
915
|
lines: list[str],
|
|
976
916
|
issue: dict[str, t.Any],
|
|
977
917
|
) -> tuple[list[str], bool]:
|
|
978
|
-
"""Enhanced list operations fixing with comprehensive optimization."""
|
|
979
918
|
modified = False
|
|
980
919
|
|
|
981
920
|
instances = sorted(
|
|
@@ -987,23 +926,20 @@ class PerformanceAgent(SubAgent):
|
|
|
987
926
|
for instance in instances:
|
|
988
927
|
line_idx = instance["line_number"] - 1
|
|
989
928
|
if line_idx < len(lines):
|
|
990
|
-
original_line =
|
|
929
|
+
original_line = lines[line_idx]
|
|
991
930
|
|
|
992
|
-
# Apply optimization based on instance type
|
|
993
931
|
optimization_type = instance.get(
|
|
994
932
|
"optimization",
|
|
995
933
|
"append",
|
|
996
934
|
)
|
|
997
935
|
|
|
998
936
|
if optimization_type == "append":
|
|
999
|
-
# Use existing safe pattern for single item append
|
|
1000
937
|
list_pattern = SAFE_PATTERNS["list_append_inefficiency_pattern"]
|
|
1001
938
|
if list_pattern.test(original_line):
|
|
1002
939
|
optimized_line = list_pattern.apply(original_line)
|
|
1003
940
|
lines[line_idx] = optimized_line
|
|
1004
941
|
modified = True
|
|
1005
942
|
|
|
1006
|
-
# Add performance comment
|
|
1007
943
|
indent = original_line[
|
|
1008
944
|
: len(original_line) - len(original_line.lstrip())
|
|
1009
945
|
]
|
|
@@ -1015,14 +951,12 @@ class PerformanceAgent(SubAgent):
|
|
|
1015
951
|
lines.insert(line_idx, comment)
|
|
1016
952
|
|
|
1017
953
|
elif optimization_type == "extend":
|
|
1018
|
-
# Use new extend pattern for multiple items
|
|
1019
954
|
extend_pattern = SAFE_PATTERNS["list_extend_optimization_pattern"]
|
|
1020
955
|
if extend_pattern.test(original_line):
|
|
1021
956
|
optimized_line = extend_pattern.apply(original_line)
|
|
1022
957
|
lines[line_idx] = optimized_line
|
|
1023
958
|
modified = True
|
|
1024
959
|
|
|
1025
|
-
# Add performance comment
|
|
1026
960
|
indent = original_line[
|
|
1027
961
|
: len(original_line) - len(original_line.lstrip())
|
|
1028
962
|
]
|
|
@@ -1041,10 +975,8 @@ class PerformanceAgent(SubAgent):
|
|
|
1041
975
|
lines: list[str],
|
|
1042
976
|
issue: dict[str, t.Any],
|
|
1043
977
|
) -> tuple[list[str], bool]:
|
|
1044
|
-
"""Enhanced string operations fixing with comprehensive patterns."""
|
|
1045
978
|
modified = False
|
|
1046
979
|
|
|
1047
|
-
# Handle string concatenation patterns
|
|
1048
980
|
concat_patterns = issue.get("string_concat_patterns", [])
|
|
1049
981
|
if concat_patterns:
|
|
1050
982
|
lines, concat_modified = self._fix_string_concatenation(
|
|
@@ -1052,7 +984,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1052
984
|
)
|
|
1053
985
|
modified = modified or concat_modified
|
|
1054
986
|
|
|
1055
|
-
# Handle inefficient joins
|
|
1056
987
|
inefficient_joins = issue.get("inefficient_joins", [])
|
|
1057
988
|
for join_issue in inefficient_joins:
|
|
1058
989
|
line_idx = join_issue["line_number"] - 1
|
|
@@ -1063,7 +994,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1063
994
|
lines[line_idx] = join_pattern.apply(original_line)
|
|
1064
995
|
modified = True
|
|
1065
996
|
|
|
1066
|
-
# Handle repeated formatting - just add comments for now
|
|
1067
997
|
repeated_formatting = issue.get("repeated_formatting", [])
|
|
1068
998
|
for format_issue in repeated_formatting:
|
|
1069
999
|
line_idx = format_issue["line_number"] - 1
|
|
@@ -1086,7 +1016,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1086
1016
|
lines: list[str],
|
|
1087
1017
|
issue: dict[str, t.Any],
|
|
1088
1018
|
) -> tuple[list[str], bool]:
|
|
1089
|
-
"""Add informative comments about nested loop complexity."""
|
|
1090
1019
|
modified = False
|
|
1091
1020
|
|
|
1092
1021
|
instances = issue.get("instances", [])
|
|
@@ -1108,7 +1037,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1108
1037
|
f" {priority} priority",
|
|
1109
1038
|
]
|
|
1110
1039
|
|
|
1111
|
-
# Add specific suggestions for high priority loops
|
|
1112
1040
|
if priority in ("high", "critical"):
|
|
1113
1041
|
if priority == "critical":
|
|
1114
1042
|
comment_lines.append(
|
|
@@ -1117,11 +1045,10 @@ class PerformanceAgent(SubAgent):
|
|
|
1117
1045
|
)
|
|
1118
1046
|
else:
|
|
1119
1047
|
comment_lines.append(
|
|
1120
|
-
f"{indent}# Suggestion: Consider memoization, caching,"
|
|
1048
|
+
f"{indent}# Suggestion: Consider memoization, caching, "
|
|
1121
1049
|
f" or hash tables"
|
|
1122
1050
|
)
|
|
1123
1051
|
|
|
1124
|
-
# Insert comments before the loop
|
|
1125
1052
|
for i, comment in enumerate(comment_lines):
|
|
1126
1053
|
lines.insert(line_idx + i, comment)
|
|
1127
1054
|
|
|
@@ -1134,7 +1061,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1134
1061
|
lines: list[str],
|
|
1135
1062
|
issue: dict[str, t.Any],
|
|
1136
1063
|
) -> tuple[list[str], bool]:
|
|
1137
|
-
"""Apply list comprehension optimizations where detected."""
|
|
1138
1064
|
modified = False
|
|
1139
1065
|
|
|
1140
1066
|
instances = issue.get("instances", [])
|
|
@@ -1148,9 +1074,8 @@ class PerformanceAgent(SubAgent):
|
|
|
1148
1074
|
: len(original_line) - len(original_line.lstrip())
|
|
1149
1075
|
]
|
|
1150
1076
|
|
|
1151
|
-
# Add suggestion comment for now - actual transformation would need more AST analysis
|
|
1152
1077
|
comment = (
|
|
1153
|
-
f"{indent}# Performance: Consider list comprehension for "
|
|
1078
|
+
f"{indent}# Performance: Consider list[t.Any] comprehension for "
|
|
1154
1079
|
f"20-30% improvement"
|
|
1155
1080
|
)
|
|
1156
1081
|
lines.insert(line_idx, comment)
|
|
@@ -1163,7 +1088,6 @@ class PerformanceAgent(SubAgent):
|
|
|
1163
1088
|
lines: list[str],
|
|
1164
1089
|
issue: dict[str, t.Any],
|
|
1165
1090
|
) -> tuple[list[str], bool]:
|
|
1166
|
-
"""Add comments about caching builtin function calls."""
|
|
1167
1091
|
modified = False
|
|
1168
1092
|
|
|
1169
1093
|
instances = issue.get("instances", [])
|
|
@@ -1210,16 +1134,13 @@ class PerformanceAgent(SubAgent):
|
|
|
1210
1134
|
for instance in instances:
|
|
1211
1135
|
line_idx = instance["line_number"] - 1
|
|
1212
1136
|
if line_idx < len(lines):
|
|
1213
|
-
original_line =
|
|
1137
|
+
original_line = lines[line_idx]
|
|
1214
1138
|
|
|
1215
|
-
# Use safe pattern to test and transform
|
|
1216
1139
|
if list_pattern.test(original_line):
|
|
1217
|
-
# Apply the performance optimization using safe pattern
|
|
1218
1140
|
optimized_line = list_pattern.apply(original_line)
|
|
1219
1141
|
lines[line_idx] = optimized_line
|
|
1220
1142
|
modified = True
|
|
1221
1143
|
|
|
1222
|
-
# Extract indent from the original line for comment
|
|
1223
1144
|
indent = original_line[
|
|
1224
1145
|
: len(original_line) - len(original_line.lstrip())
|
|
1225
1146
|
]
|
|
@@ -1264,12 +1185,10 @@ class PerformanceAgent(SubAgent):
|
|
|
1264
1185
|
if line_idx >= len(lines):
|
|
1265
1186
|
return None
|
|
1266
1187
|
|
|
1267
|
-
original_line =
|
|
1188
|
+
original_line = lines[line_idx]
|
|
1268
1189
|
|
|
1269
|
-
# Use safe pattern for string concatenation parsing
|
|
1270
1190
|
concat_pattern = SAFE_PATTERNS["string_concatenation_pattern"]
|
|
1271
1191
|
if concat_pattern.test(original_line):
|
|
1272
|
-
# Extract parts using the safe pattern's compiled pattern
|
|
1273
1192
|
compiled = concat_pattern._get_compiled_pattern()
|
|
1274
1193
|
match = compiled.match(original_line)
|
|
1275
1194
|
if match:
|
|
@@ -1362,7 +1281,7 @@ class PerformanceAgent(SubAgent):
|
|
|
1362
1281
|
indent: str,
|
|
1363
1282
|
) -> None:
|
|
1364
1283
|
lines[init_line_idx] = (
|
|
1365
|
-
f"{indent}{var_name}_parts = [] # Performance: Use list for string building"
|
|
1284
|
+
f"{indent}{var_name}_parts = [] # Performance: Use list[t.Any] for string building"
|
|
1366
1285
|
)
|
|
1367
1286
|
|
|
1368
1287
|
@staticmethod
|
|
@@ -1387,7 +1306,7 @@ class PerformanceAgent(SubAgent):
|
|
|
1387
1306
|
loop_end = self._find_loop_end(lines, loop_start)
|
|
1388
1307
|
if loop_end is not None:
|
|
1389
1308
|
join_line = (
|
|
1390
|
-
f"{indent}{var_name} = ''.join({var_name}_parts) # Performance:"
|
|
1309
|
+
f"{indent}{var_name} = ''.join({var_name}_parts) # Performance: "
|
|
1391
1310
|
f" Join string parts"
|
|
1392
1311
|
)
|
|
1393
1312
|
lines.insert(loop_end + 1, join_line)
|
|
@@ -1420,7 +1339,7 @@ class PerformanceAgent(SubAgent):
|
|
|
1420
1339
|
for instance in issue["instances"]:
|
|
1421
1340
|
line_idx = instance["line_number"] - 1
|
|
1422
1341
|
if line_idx < len(lines):
|
|
1423
|
-
original_line =
|
|
1342
|
+
original_line = lines[line_idx]
|
|
1424
1343
|
indent_level = len(original_line) - len(original_line.lstrip())
|
|
1425
1344
|
indent_str = " " * indent_level
|
|
1426
1345
|
|