tree-sitter-analyzer 0.2.0__py3-none-any.whl → 0.4.0__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 tree-sitter-analyzer might be problematic. Click here for more details.
- tree_sitter_analyzer/__init__.py +134 -121
- tree_sitter_analyzer/__main__.py +11 -12
- tree_sitter_analyzer/api.py +533 -539
- tree_sitter_analyzer/cli/__init__.py +39 -39
- tree_sitter_analyzer/cli/__main__.py +12 -13
- tree_sitter_analyzer/cli/commands/__init__.py +26 -27
- tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
- tree_sitter_analyzer/cli/commands/base_command.py +160 -155
- tree_sitter_analyzer/cli/commands/default_command.py +18 -19
- tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -133
- tree_sitter_analyzer/cli/commands/query_command.py +81 -82
- tree_sitter_analyzer/cli/commands/structure_command.py +138 -121
- tree_sitter_analyzer/cli/commands/summary_command.py +101 -93
- tree_sitter_analyzer/cli/commands/table_command.py +235 -233
- tree_sitter_analyzer/cli/info_commands.py +120 -121
- tree_sitter_analyzer/cli_main.py +278 -276
- tree_sitter_analyzer/core/__init__.py +15 -20
- tree_sitter_analyzer/core/analysis_engine.py +555 -574
- tree_sitter_analyzer/core/cache_service.py +320 -330
- tree_sitter_analyzer/core/engine.py +559 -560
- tree_sitter_analyzer/core/parser.py +293 -288
- tree_sitter_analyzer/core/query.py +502 -502
- tree_sitter_analyzer/encoding_utils.py +456 -460
- tree_sitter_analyzer/exceptions.py +337 -340
- tree_sitter_analyzer/file_handler.py +210 -222
- tree_sitter_analyzer/formatters/__init__.py +1 -1
- tree_sitter_analyzer/formatters/base_formatter.py +167 -168
- tree_sitter_analyzer/formatters/formatter_factory.py +78 -74
- tree_sitter_analyzer/formatters/java_formatter.py +291 -270
- tree_sitter_analyzer/formatters/python_formatter.py +259 -235
- tree_sitter_analyzer/interfaces/__init__.py +9 -10
- tree_sitter_analyzer/interfaces/cli.py +528 -557
- tree_sitter_analyzer/interfaces/cli_adapter.py +343 -319
- tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -170
- tree_sitter_analyzer/interfaces/mcp_server.py +405 -416
- tree_sitter_analyzer/java_analyzer.py +187 -219
- tree_sitter_analyzer/language_detector.py +398 -400
- tree_sitter_analyzer/language_loader.py +224 -228
- tree_sitter_analyzer/languages/__init__.py +10 -11
- tree_sitter_analyzer/languages/java_plugin.py +1174 -1113
- tree_sitter_analyzer/{plugins → languages}/javascript_plugin.py +446 -439
- tree_sitter_analyzer/languages/python_plugin.py +747 -712
- tree_sitter_analyzer/mcp/__init__.py +31 -32
- tree_sitter_analyzer/mcp/resources/__init__.py +44 -47
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -213
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +555 -550
- tree_sitter_analyzer/mcp/server.py +333 -345
- tree_sitter_analyzer/mcp/tools/__init__.py +30 -31
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +654 -557
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -245
- tree_sitter_analyzer/mcp/tools/base_tool.py +54 -55
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -302
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -359
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -476
- tree_sitter_analyzer/mcp/utils/__init__.py +107 -106
- tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
- tree_sitter_analyzer/models.py +470 -481
- tree_sitter_analyzer/output_manager.py +255 -264
- tree_sitter_analyzer/plugins/__init__.py +280 -334
- tree_sitter_analyzer/plugins/base.py +496 -446
- tree_sitter_analyzer/plugins/manager.py +379 -355
- tree_sitter_analyzer/queries/__init__.py +26 -27
- tree_sitter_analyzer/queries/java.py +391 -394
- tree_sitter_analyzer/queries/javascript.py +148 -149
- tree_sitter_analyzer/queries/python.py +285 -286
- tree_sitter_analyzer/queries/typescript.py +229 -230
- tree_sitter_analyzer/query_loader.py +257 -260
- tree_sitter_analyzer/table_formatter.py +471 -448
- tree_sitter_analyzer/utils.py +277 -277
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.4.0.dist-info}/METADATA +23 -8
- tree_sitter_analyzer-0.4.0.dist-info/RECORD +73 -0
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.4.0.dist-info}/entry_points.txt +2 -1
- tree_sitter_analyzer/plugins/java_plugin.py +0 -625
- tree_sitter_analyzer/plugins/plugin_loader.py +0 -83
- tree_sitter_analyzer/plugins/python_plugin.py +0 -598
- tree_sitter_analyzer/plugins/registry.py +0 -366
- tree_sitter_analyzer-0.2.0.dist-info/RECORD +0 -77
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.4.0.dist-info}/WHEEL +0 -0
|
@@ -1,574 +1,555 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
統一解析エンジン - CLI・MCP共通解析システム(修正版)
|
|
4
|
-
|
|
5
|
-
このモジュールは、すべての解析処理の中心となる統一エンジンを提供します。
|
|
6
|
-
CLI、MCP、その他のインターフェースから共通して使用されます。
|
|
7
|
-
|
|
8
|
-
Roo Code規約準拠:
|
|
9
|
-
- 型ヒント: 全関数に型ヒント必須
|
|
10
|
-
- MCPログ: 各ステップでログ出力
|
|
11
|
-
- docstring: Google Style docstring
|
|
12
|
-
- パフォーマンス重視: シングルトンパターンとキャッシュ共有
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from
|
|
21
|
-
|
|
22
|
-
from ..
|
|
23
|
-
from
|
|
24
|
-
from
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class UnsupportedLanguageError(Exception):
|
|
28
|
-
"""サポートされていない言語エラー"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
""
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
""
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
stats
|
|
108
|
-
stats["
|
|
109
|
-
stats["
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"""
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
""
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return
|
|
422
|
-
|
|
423
|
-
def
|
|
424
|
-
"""
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
Returns:
|
|
443
|
-
|
|
444
|
-
"""
|
|
445
|
-
return self.
|
|
446
|
-
|
|
447
|
-
def
|
|
448
|
-
"""
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
"""
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
"""
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
"""
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
#
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
imports=[],
|
|
557
|
-
classes=[],
|
|
558
|
-
methods=[],
|
|
559
|
-
fields=[],
|
|
560
|
-
annotations=[],
|
|
561
|
-
analysis_time=0.1,
|
|
562
|
-
success=True,
|
|
563
|
-
error_message=None
|
|
564
|
-
)
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
def get_analysis_engine() -> UnifiedAnalysisEngine:
|
|
568
|
-
"""
|
|
569
|
-
統一解析エンジンのインスタンスを取得
|
|
570
|
-
|
|
571
|
-
Returns:
|
|
572
|
-
統一解析エンジンのシングルトンインスタンス
|
|
573
|
-
"""
|
|
574
|
-
return UnifiedAnalysisEngine()
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
統一解析エンジン - CLI・MCP共通解析システム(修正版)
|
|
4
|
+
|
|
5
|
+
このモジュールは、すべての解析処理の中心となる統一エンジンを提供します。
|
|
6
|
+
CLI、MCP、その他のインターフェースから共通して使用されます。
|
|
7
|
+
|
|
8
|
+
Roo Code規約準拠:
|
|
9
|
+
- 型ヒント: 全関数に型ヒント必須
|
|
10
|
+
- MCPログ: 各ステップでログ出力
|
|
11
|
+
- docstring: Google Style docstring
|
|
12
|
+
- パフォーマンス重視: シングルトンパターンとキャッシュ共有
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import threading
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from typing import Any, Optional, Protocol
|
|
19
|
+
|
|
20
|
+
from ..models import AnalysisResult
|
|
21
|
+
from ..plugins.base import LanguagePlugin as BaseLanguagePlugin
|
|
22
|
+
from ..plugins.manager import PluginManager
|
|
23
|
+
from ..utils import log_debug, log_error, log_info, log_performance
|
|
24
|
+
from .cache_service import CacheService
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class UnsupportedLanguageError(Exception):
|
|
28
|
+
"""サポートされていない言語エラー"""
|
|
29
|
+
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PluginRegistry(Protocol):
|
|
34
|
+
"""プラグイン登録管理のプロトコル"""
|
|
35
|
+
|
|
36
|
+
def get_plugin(self, language: str) -> Optional["LanguagePlugin"]:
|
|
37
|
+
"""言語プラグインを取得"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class LanguagePlugin(Protocol):
|
|
42
|
+
"""言語プラグインのプロトコル"""
|
|
43
|
+
|
|
44
|
+
async def analyze_file(
|
|
45
|
+
self, file_path: str, request: "AnalysisRequest"
|
|
46
|
+
) -> AnalysisResult:
|
|
47
|
+
"""ファイル解析"""
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class PerformanceMonitor:
|
|
52
|
+
"""パフォーマンス監視(簡易版)"""
|
|
53
|
+
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
self._last_duration: float = 0.0
|
|
56
|
+
self._monitoring_active: bool = False
|
|
57
|
+
self._operation_stats: dict[str, Any] = {}
|
|
58
|
+
self._total_operations: int = 0
|
|
59
|
+
|
|
60
|
+
def measure_operation(self, operation_name: str) -> "PerformanceContext":
|
|
61
|
+
"""操作の測定コンテキストを返す"""
|
|
62
|
+
return PerformanceContext(operation_name, self)
|
|
63
|
+
|
|
64
|
+
def get_last_duration(self) -> float:
|
|
65
|
+
"""最後の操作時間を取得"""
|
|
66
|
+
return self._last_duration
|
|
67
|
+
|
|
68
|
+
def _set_duration(self, duration: float) -> None:
|
|
69
|
+
"""操作時間を設定(内部用)"""
|
|
70
|
+
self._last_duration = duration
|
|
71
|
+
|
|
72
|
+
def start_monitoring(self) -> None:
|
|
73
|
+
"""パフォーマンス監視を開始"""
|
|
74
|
+
self._monitoring_active = True
|
|
75
|
+
log_info("Performance monitoring started")
|
|
76
|
+
|
|
77
|
+
def stop_monitoring(self) -> None:
|
|
78
|
+
"""パフォーマンス監視を停止"""
|
|
79
|
+
self._monitoring_active = False
|
|
80
|
+
log_info("Performance monitoring stopped")
|
|
81
|
+
|
|
82
|
+
def get_operation_stats(self) -> dict[str, Any]:
|
|
83
|
+
"""操作統計を取得"""
|
|
84
|
+
return self._operation_stats.copy()
|
|
85
|
+
|
|
86
|
+
def get_performance_summary(self) -> dict[str, Any]:
|
|
87
|
+
"""パフォーマンス要約を取得"""
|
|
88
|
+
return {
|
|
89
|
+
"total_operations": self._total_operations,
|
|
90
|
+
"monitoring_active": self._monitoring_active,
|
|
91
|
+
"last_duration": self._last_duration,
|
|
92
|
+
"operation_count": len(self._operation_stats),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
def record_operation(self, operation_name: str, duration: float) -> None:
|
|
96
|
+
"""操作を記録"""
|
|
97
|
+
if self._monitoring_active:
|
|
98
|
+
if operation_name not in self._operation_stats:
|
|
99
|
+
self._operation_stats[operation_name] = {
|
|
100
|
+
"count": 0,
|
|
101
|
+
"total_time": 0.0,
|
|
102
|
+
"avg_time": 0.0,
|
|
103
|
+
"min_time": float("inf"),
|
|
104
|
+
"max_time": 0.0,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
stats = self._operation_stats[operation_name]
|
|
108
|
+
stats["count"] += 1
|
|
109
|
+
stats["total_time"] += duration
|
|
110
|
+
stats["avg_time"] = stats["total_time"] / stats["count"]
|
|
111
|
+
stats["min_time"] = min(stats["min_time"], duration)
|
|
112
|
+
stats["max_time"] = max(stats["max_time"], duration)
|
|
113
|
+
|
|
114
|
+
self._total_operations += 1
|
|
115
|
+
|
|
116
|
+
def clear_metrics(self) -> None:
|
|
117
|
+
"""メトリクスをクリア"""
|
|
118
|
+
self._operation_stats.clear()
|
|
119
|
+
self._total_operations = 0
|
|
120
|
+
self._last_duration = 0.0
|
|
121
|
+
log_info("Performance metrics cleared")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class PerformanceContext:
|
|
125
|
+
"""パフォーマンス測定コンテキスト"""
|
|
126
|
+
|
|
127
|
+
def __init__(self, operation_name: str, monitor: PerformanceMonitor) -> None:
|
|
128
|
+
self.operation_name = operation_name
|
|
129
|
+
self.monitor = monitor
|
|
130
|
+
self.start_time: float = 0.0
|
|
131
|
+
|
|
132
|
+
def __enter__(self) -> "PerformanceContext":
|
|
133
|
+
import time
|
|
134
|
+
|
|
135
|
+
self.start_time = time.time()
|
|
136
|
+
return self
|
|
137
|
+
|
|
138
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
139
|
+
import time
|
|
140
|
+
|
|
141
|
+
duration = time.time() - self.start_time
|
|
142
|
+
self.monitor._set_duration(duration)
|
|
143
|
+
self.monitor.record_operation(self.operation_name, duration)
|
|
144
|
+
log_performance(self.operation_name, duration, "Operation completed")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass(frozen=True)
|
|
148
|
+
class AnalysisRequest:
|
|
149
|
+
"""
|
|
150
|
+
解析リクエスト
|
|
151
|
+
|
|
152
|
+
Attributes:
|
|
153
|
+
file_path: 解析対象ファイルパス
|
|
154
|
+
language: プログラミング言語(Noneの場合は自動検出)
|
|
155
|
+
include_complexity: 複雑度計算を含むか
|
|
156
|
+
include_details: 詳細情報を含むか
|
|
157
|
+
format_type: 出力フォーマット
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
file_path: str
|
|
161
|
+
language: str | None = None
|
|
162
|
+
include_complexity: bool = True
|
|
163
|
+
include_details: bool = False
|
|
164
|
+
format_type: str = "json"
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def from_mcp_arguments(cls, arguments: dict[str, Any]) -> "AnalysisRequest":
|
|
168
|
+
"""
|
|
169
|
+
MCP引数から解析リクエストを作成
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
arguments: MCP引数辞書
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
解析リクエスト
|
|
176
|
+
"""
|
|
177
|
+
return cls(
|
|
178
|
+
file_path=arguments.get("file_path", ""),
|
|
179
|
+
language=arguments.get("language"),
|
|
180
|
+
include_complexity=arguments.get("include_complexity", True),
|
|
181
|
+
include_details=arguments.get("include_details", False),
|
|
182
|
+
format_type=arguments.get("format_type", "json"),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# SimplePluginRegistry removed - now using PluginManager
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class UnifiedAnalysisEngine:
|
|
190
|
+
"""
|
|
191
|
+
統一解析エンジン(修正版)
|
|
192
|
+
|
|
193
|
+
CLI・MCP・その他のインターフェースから共通して使用される
|
|
194
|
+
中央集権的な解析エンジン。シングルトンパターンで実装し、
|
|
195
|
+
リソースの効率的な利用とキャッシュの共有を実現。
|
|
196
|
+
|
|
197
|
+
修正点:
|
|
198
|
+
- デストラクタでの非同期処理問題を解決
|
|
199
|
+
- 明示的なクリーンアップメソッドを提供
|
|
200
|
+
|
|
201
|
+
Attributes:
|
|
202
|
+
_cache_service: キャッシュサービス
|
|
203
|
+
_plugin_manager: プラグイン管理
|
|
204
|
+
_performance_monitor: パフォーマンス監視
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
_instance: Optional["UnifiedAnalysisEngine"] = None
|
|
208
|
+
_lock: threading.Lock = threading.Lock()
|
|
209
|
+
|
|
210
|
+
def __new__(cls) -> "UnifiedAnalysisEngine":
|
|
211
|
+
"""シングルトンパターンでインスタンス共有"""
|
|
212
|
+
if cls._instance is None:
|
|
213
|
+
with cls._lock:
|
|
214
|
+
if cls._instance is None:
|
|
215
|
+
cls._instance = super().__new__(cls)
|
|
216
|
+
return cls._instance
|
|
217
|
+
|
|
218
|
+
def __init__(self) -> None:
|
|
219
|
+
"""初期化(一度のみ実行)"""
|
|
220
|
+
if hasattr(self, "_initialized"):
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
self._cache_service = CacheService()
|
|
224
|
+
self._plugin_manager = PluginManager()
|
|
225
|
+
self._performance_monitor = PerformanceMonitor()
|
|
226
|
+
|
|
227
|
+
# プラグインを自動ロード
|
|
228
|
+
self._load_plugins()
|
|
229
|
+
|
|
230
|
+
self._initialized = True
|
|
231
|
+
|
|
232
|
+
log_info("UnifiedAnalysisEngine initialized")
|
|
233
|
+
|
|
234
|
+
def _load_plugins(self) -> None:
|
|
235
|
+
"""利用可能なプラグインを自動ロード"""
|
|
236
|
+
log_info("Loading plugins using PluginManager...")
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
# PluginManagerの自動ロード機能を使用
|
|
240
|
+
loaded_plugins = self._plugin_manager.load_plugins()
|
|
241
|
+
|
|
242
|
+
final_languages = [plugin.get_language_name() for plugin in loaded_plugins]
|
|
243
|
+
log_info(
|
|
244
|
+
f"Successfully loaded {len(final_languages)} language plugins: {', '.join(final_languages)}"
|
|
245
|
+
)
|
|
246
|
+
except Exception as e:
|
|
247
|
+
log_error(f"Failed to load plugins: {e}")
|
|
248
|
+
import traceback
|
|
249
|
+
|
|
250
|
+
log_error(f"Plugin loading traceback: {traceback.format_exc()}")
|
|
251
|
+
|
|
252
|
+
async def analyze(self, request: AnalysisRequest) -> AnalysisResult:
|
|
253
|
+
"""
|
|
254
|
+
統一解析メソッド
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
request: 解析リクエスト
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
解析結果
|
|
261
|
+
|
|
262
|
+
Raises:
|
|
263
|
+
UnsupportedLanguageError: サポートされていない言語
|
|
264
|
+
FileNotFoundError: ファイルが見つからない
|
|
265
|
+
"""
|
|
266
|
+
log_info(f"Starting analysis for {request.file_path}")
|
|
267
|
+
|
|
268
|
+
# キャッシュチェック(CLI・MCP間で共有)
|
|
269
|
+
cache_key = self._generate_cache_key(request)
|
|
270
|
+
cached_result = await self._cache_service.get(cache_key)
|
|
271
|
+
if cached_result:
|
|
272
|
+
log_info(f"Cache hit for {request.file_path}")
|
|
273
|
+
return cached_result # type: ignore
|
|
274
|
+
|
|
275
|
+
# 言語検出
|
|
276
|
+
language = request.language or self._detect_language(request.file_path)
|
|
277
|
+
log_debug(f"Detected language: {language}")
|
|
278
|
+
|
|
279
|
+
# デバッグ:登録されているプラグインを確認
|
|
280
|
+
supported_languages = self._plugin_manager.get_supported_languages()
|
|
281
|
+
log_debug(f"Supported languages: {supported_languages}")
|
|
282
|
+
log_debug(f"Looking for plugin for language: {language}")
|
|
283
|
+
|
|
284
|
+
# プラグイン取得
|
|
285
|
+
plugin = self._plugin_manager.get_plugin(language)
|
|
286
|
+
if not plugin:
|
|
287
|
+
error_msg = f"Language {language} not supported"
|
|
288
|
+
log_error(error_msg)
|
|
289
|
+
raise UnsupportedLanguageError(error_msg)
|
|
290
|
+
|
|
291
|
+
log_debug(f"Found plugin for {language}: {type(plugin)}")
|
|
292
|
+
|
|
293
|
+
# 解析実行(パフォーマンス監視付き)
|
|
294
|
+
with self._performance_monitor.measure_operation(f"analyze_{language}"):
|
|
295
|
+
log_debug(f"Calling plugin.analyze_file for {request.file_path}")
|
|
296
|
+
result = await plugin.analyze_file(request.file_path, request)
|
|
297
|
+
log_debug(
|
|
298
|
+
f"Plugin returned result: success={result.success}, elements={len(result.elements) if result.elements else 0}"
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
# 言語情報を確実に設定
|
|
302
|
+
if result.language == "unknown" or not result.language:
|
|
303
|
+
result.language = language
|
|
304
|
+
|
|
305
|
+
# キャッシュ保存
|
|
306
|
+
await self._cache_service.set(cache_key, result)
|
|
307
|
+
|
|
308
|
+
log_performance(
|
|
309
|
+
"unified_analysis",
|
|
310
|
+
self._performance_monitor.get_last_duration(),
|
|
311
|
+
f"Analyzed {request.file_path} ({language})",
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
return result
|
|
315
|
+
|
|
316
|
+
async def analyze_file(self, file_path: str) -> AnalysisResult:
|
|
317
|
+
"""
|
|
318
|
+
Backward compatibility method for analyze_file.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
file_path: Path to the file to analyze
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
Analysis result
|
|
325
|
+
"""
|
|
326
|
+
request = AnalysisRequest(
|
|
327
|
+
file_path=file_path,
|
|
328
|
+
language=None, # Auto-detect
|
|
329
|
+
include_complexity=True,
|
|
330
|
+
include_details=True,
|
|
331
|
+
)
|
|
332
|
+
return await self.analyze(request)
|
|
333
|
+
|
|
334
|
+
def _generate_cache_key(self, request: AnalysisRequest) -> str:
|
|
335
|
+
"""
|
|
336
|
+
キャッシュキーを生成
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
request: 解析リクエスト
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
ハッシュ化されたキャッシュキー
|
|
343
|
+
"""
|
|
344
|
+
# 一意なキーを生成するための文字列を構築
|
|
345
|
+
key_components = [
|
|
346
|
+
request.file_path,
|
|
347
|
+
str(request.language),
|
|
348
|
+
str(request.include_complexity),
|
|
349
|
+
str(request.include_details),
|
|
350
|
+
request.format_type,
|
|
351
|
+
]
|
|
352
|
+
|
|
353
|
+
key_string = ":".join(key_components)
|
|
354
|
+
|
|
355
|
+
# SHA256でハッシュ化
|
|
356
|
+
return hashlib.sha256(key_string.encode("utf-8")).hexdigest()
|
|
357
|
+
|
|
358
|
+
def _detect_language(self, file_path: str) -> str:
|
|
359
|
+
"""
|
|
360
|
+
言語検出
|
|
361
|
+
|
|
362
|
+
Args:
|
|
363
|
+
file_path: ファイルパス
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
検出された言語
|
|
367
|
+
"""
|
|
368
|
+
# 簡易的な拡張子ベース検出
|
|
369
|
+
import os
|
|
370
|
+
|
|
371
|
+
_, ext = os.path.splitext(file_path)
|
|
372
|
+
|
|
373
|
+
language_map = {
|
|
374
|
+
".java": "java",
|
|
375
|
+
".py": "python",
|
|
376
|
+
".js": "javascript",
|
|
377
|
+
".ts": "typescript",
|
|
378
|
+
".c": "c",
|
|
379
|
+
".cpp": "cpp",
|
|
380
|
+
".cc": "cpp",
|
|
381
|
+
".cxx": "cpp",
|
|
382
|
+
".rs": "rust",
|
|
383
|
+
".go": "go",
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
detected = language_map.get(ext.lower(), "unknown")
|
|
387
|
+
log_debug(f"Language detection: {file_path} -> {detected}")
|
|
388
|
+
return detected
|
|
389
|
+
|
|
390
|
+
def clear_cache(self) -> None:
|
|
391
|
+
"""キャッシュクリア(テスト用)"""
|
|
392
|
+
self._cache_service.clear()
|
|
393
|
+
log_info("Analysis engine cache cleared")
|
|
394
|
+
|
|
395
|
+
def register_plugin(self, language: str, plugin: BaseLanguagePlugin) -> None:
|
|
396
|
+
"""
|
|
397
|
+
プラグインを登録
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
language: 言語名(互換性のため保持、実際は使用されない)
|
|
401
|
+
plugin: 言語プラグイン
|
|
402
|
+
"""
|
|
403
|
+
self._plugin_manager.register_plugin(plugin)
|
|
404
|
+
|
|
405
|
+
def get_supported_languages(self) -> list[str]:
|
|
406
|
+
"""
|
|
407
|
+
サポートされている言語一覧を取得
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
サポート言語のリスト
|
|
411
|
+
"""
|
|
412
|
+
return self._plugin_manager.get_supported_languages()
|
|
413
|
+
|
|
414
|
+
def get_cache_stats(self) -> dict[str, Any]:
|
|
415
|
+
"""
|
|
416
|
+
キャッシュ統計を取得
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
キャッシュ統計情報
|
|
420
|
+
"""
|
|
421
|
+
return self._cache_service.get_stats()
|
|
422
|
+
|
|
423
|
+
async def invalidate_cache_pattern(self, pattern: str) -> int:
|
|
424
|
+
"""
|
|
425
|
+
パターンに一致するキャッシュを無効化
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
pattern: 無効化するキーのパターン
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
無効化されたキー数
|
|
432
|
+
"""
|
|
433
|
+
return await self._cache_service.invalidate_pattern(pattern)
|
|
434
|
+
|
|
435
|
+
def measure_operation(self, operation_name: str) -> "PerformanceContext":
|
|
436
|
+
"""
|
|
437
|
+
パフォーマンス計測のためのコンテキストマネージャ
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
operation_name: 操作名
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
パフォーマンス測定コンテキスト
|
|
444
|
+
"""
|
|
445
|
+
return self._performance_monitor.measure_operation(operation_name)
|
|
446
|
+
|
|
447
|
+
def start_monitoring(self) -> None:
|
|
448
|
+
"""パフォーマンス監視を開始"""
|
|
449
|
+
self._performance_monitor.start_monitoring()
|
|
450
|
+
|
|
451
|
+
def stop_monitoring(self) -> None:
|
|
452
|
+
"""パフォーマンス監視を停止"""
|
|
453
|
+
self._performance_monitor.stop_monitoring()
|
|
454
|
+
|
|
455
|
+
def get_operation_stats(self) -> dict[str, Any]:
|
|
456
|
+
"""操作統計を取得"""
|
|
457
|
+
return self._performance_monitor.get_operation_stats()
|
|
458
|
+
|
|
459
|
+
def get_performance_summary(self) -> dict[str, Any]:
|
|
460
|
+
"""パフォーマンス要約を取得"""
|
|
461
|
+
return self._performance_monitor.get_performance_summary()
|
|
462
|
+
|
|
463
|
+
def clear_metrics(self) -> None:
|
|
464
|
+
"""
|
|
465
|
+
収集したパフォーマンスメトリクスをクリア
|
|
466
|
+
|
|
467
|
+
パフォーマンス監視で収集されたメトリクスをリセットします。
|
|
468
|
+
テストやデバッグ時に使用されます。
|
|
469
|
+
"""
|
|
470
|
+
# 新しいパフォーマンスモニターインスタンスを作成してリセット
|
|
471
|
+
self._performance_monitor = PerformanceMonitor()
|
|
472
|
+
log_info("Performance metrics cleared")
|
|
473
|
+
|
|
474
|
+
def cleanup(self) -> None:
|
|
475
|
+
"""
|
|
476
|
+
明示的なリソースクリーンアップ
|
|
477
|
+
|
|
478
|
+
テスト終了時などに明示的に呼び出してリソースをクリーンアップします。
|
|
479
|
+
デストラクタでの非同期処理問題を避けるため、明示的な呼び出しが必要です。
|
|
480
|
+
"""
|
|
481
|
+
try:
|
|
482
|
+
if hasattr(self, "_cache_service"):
|
|
483
|
+
self._cache_service.clear()
|
|
484
|
+
if hasattr(self, "_performance_monitor"):
|
|
485
|
+
self._performance_monitor.clear_metrics()
|
|
486
|
+
log_debug("UnifiedAnalysisEngine cleaned up")
|
|
487
|
+
except Exception as e:
|
|
488
|
+
log_error(f"Error during UnifiedAnalysisEngine cleanup: {e}")
|
|
489
|
+
|
|
490
|
+
def __del__(self) -> None:
|
|
491
|
+
"""
|
|
492
|
+
デストラクタ - 非同期コンテキストでの問題を避けるため最小限の処理
|
|
493
|
+
|
|
494
|
+
デストラクタでは何もしません。これは非同期コンテキストでの
|
|
495
|
+
ガベージコレクション時に発生する問題を避けるためです。
|
|
496
|
+
明示的なクリーンアップはcleanup()メソッドを使用してください。
|
|
497
|
+
"""
|
|
498
|
+
# デストラクタでは何もしない(非同期コンテキストでの問題を避けるため)
|
|
499
|
+
pass
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
# 簡易的なプラグイン実装(テスト用)
|
|
503
|
+
class MockLanguagePlugin:
|
|
504
|
+
"""テスト用のモックプラグイン"""
|
|
505
|
+
|
|
506
|
+
def __init__(self, language: str) -> None:
|
|
507
|
+
self.language = language
|
|
508
|
+
|
|
509
|
+
def get_language_name(self) -> str:
|
|
510
|
+
"""言語名を取得"""
|
|
511
|
+
return self.language
|
|
512
|
+
|
|
513
|
+
def get_file_extensions(self) -> list[str]:
|
|
514
|
+
"""ファイル拡張子を取得"""
|
|
515
|
+
return [f".{self.language}"]
|
|
516
|
+
|
|
517
|
+
def create_extractor(self) -> None:
|
|
518
|
+
"""エクストラクタを作成(モック)"""
|
|
519
|
+
return None
|
|
520
|
+
|
|
521
|
+
async def analyze_file(
|
|
522
|
+
self, file_path: str, request: AnalysisRequest
|
|
523
|
+
) -> AnalysisResult:
|
|
524
|
+
"""モック解析実装"""
|
|
525
|
+
log_info(f"Mock analysis for {file_path} ({self.language})")
|
|
526
|
+
|
|
527
|
+
# 簡易的な解析結果を返す
|
|
528
|
+
return AnalysisResult(
|
|
529
|
+
file_path=file_path,
|
|
530
|
+
line_count=10, # 新しいアーキテクチャ用
|
|
531
|
+
elements=[], # 新しいアーキテクチャ用
|
|
532
|
+
node_count=5, # 新しいアーキテクチャ用
|
|
533
|
+
query_results={}, # 新しいアーキテクチャ用
|
|
534
|
+
source_code="// Mock source code", # 新しいアーキテクチャ用
|
|
535
|
+
language=self.language, # 言語を設定
|
|
536
|
+
package=None,
|
|
537
|
+
imports=[],
|
|
538
|
+
classes=[],
|
|
539
|
+
methods=[],
|
|
540
|
+
fields=[],
|
|
541
|
+
annotations=[],
|
|
542
|
+
analysis_time=0.1,
|
|
543
|
+
success=True,
|
|
544
|
+
error_message=None,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def get_analysis_engine() -> UnifiedAnalysisEngine:
|
|
549
|
+
"""
|
|
550
|
+
統一解析エンジンのインスタンスを取得
|
|
551
|
+
|
|
552
|
+
Returns:
|
|
553
|
+
統一解析エンジンのシングルトンインスタンス
|
|
554
|
+
"""
|
|
555
|
+
return UnifiedAnalysisEngine()
|