Repository navigation
Implement codesmell as a new linter - #9
hungpham10 wants to merge 10 commits into
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (67.96%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #9 +/- ##
==========================================
- Coverage 80.05% 79.70% -0.36%
==========================================
Files 97 109 +12
Lines 28765 30629 +1864
==========================================
+ Hits 23029 24414 +1385
- Misses 5736 6215 +479 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 12.28%2 warnings
Performance Changes
Tip Curious why performance improved? Comment Comparing |
9d45800 to
4477abd
Compare
…eaning magic features (#51) * Implement dynamic dispatch flag + fan-out * Enrich Go semantics: method-set matching, function values, imports, concurrency markers - Method-set matching cho implicit interface: receiver_fn hook lưu receiver base type vào Symbol.type_name (`func (f *File) Write` → "File"); khai báo method trong interface body là node `method_elem` (không phải method_declaration) — giờ được extract với scope đúng vào interface symbol. build_go_method_sets tính structural typing: T implements I ⟺ method names(I) ⊆ method names(T); w.Write() fan-out chỉ tới các type thỏa thay vì naive CHA (fallback giữ nguyên khi method-set chưa đủ dữ liệu). - Function value tracking: go_fn_ptr_assign bắt `handler := process` / `handler = process` → PointerAssign fan-out (dùng chung machinery C). - Package/import: FileDeps { package, imports } mới trong ParseResult; go_file_deps đọc package_clause + import_spec (alias→path); alias_qualified_name resolve `orders.Get` qua import alias cho in-repo packages (match segment cuối path). - Concurrency markers: MARKER_GO/MARKER_DEFER (Marker::Go/Defer) vào chain cho `go f()`/`defer f()`; select_statement wired vào switch machinery (communication_case); EffectType::Panic cho panic/log.Fatal/os.Exit. Tests: 5 extractor (receiver type, interface method scope, fn value, file deps, markers) + 2 e2e graph (method-set precision, import alias). Clippy sạch, fmt xong. * Go method-set: match signature, không chỉ tên + gom LangSpec thành nhóm - Symbol.sig_key: signature key chuẩn hóa `(param_types)(result_types)` (bỏ tên param) qua sig_key_fn hook; go_signature_key dùng chung cho method_declaration/method_elem/function_declaration. build_go_method_sets thỏa interface ⟺ (name, sig_key) khớp — `Wrong.Read(string) string` không còn bị coi là implement `Reader.Read([]byte) (int, error)`. Thiếu key nào → fallback name-only (lenient); interface 0 method → skip. - LangSpec refactor: gom 3 nhóm base / hooks (HookSpec — các Option<fn>, HookSpec::none()) / markers (MarkerSpec — control-flow kinds + field names, MarkerSpec::dflt()); LangSpec::dflt() const + FRU hợp lệ trong static. 14 language spec chỉ khai field KHÁC default — thêm hook mới không còn phải sửa 14 file. * Rust semantic enrichment: field/param typing, use indexing, cross-file impl linking, sig_key - decls += field_declaration/parameter/let_declaration: struct field, tham số và local giờ là symbol có type_name (từ field `type`) — tie-break field_declared_type resolve `db.query()` theo type của `db`. Parameter lấy tên từ field `pattern` TRƯỚC name_type_fallback (tránh lấy nhầm tên kiểu). - rust_file_deps: extract `use` (alias = `as` alias hoặc segment cuối); import_alias_candidates hỗ trợ `Type::method` — `use crate::storage::Database` + `Database::new()` resolve về method của class Database (Alias). - link_impls_globally: impl linking chuyển lên global ingest — `impl Worker` khác file với `struct Worker` vẫn nối (type_ref → def, re-parent methods). - rust_signature_key: `(params)(return)` cho method/fn (self → "self") — nguyên liệu trait matching theo signature. * Python semantic enrichment + persist dynamic indexes qua reopen Python (theo review gaps): - param_container_kinds: `parameters` container → Parameter symbols (identifier / typed_parameter / default_parameter, type từ type hint) — field/param typing cho tie-break resolution. - field_from_self_attr: `self.attr = Database()` → Field symbol scope vào class, type từ callee text — instance-attr typing. - py_file_deps: import/import-as/from-import → FileDeps (alias→path), ăn vào import_alias_candidates sẵn có. - py_superclasses: `class File(Writer)` → impl_trait "Writer" — inheritance fan-out qua machinery impl_index (giống C++ base class). Persistence (fix: dynamic indexes chỉ ở RAM, MCP restart là mất): - Storage trait + sqlite (sg_file_deps/sg_fn_ptr_assigns) + in_memory: persist ĐẦU VÀO thô FileDeps + FnPtrAssigns theo file path. - rebuild() khi open: rebuild file_imports/fn_ptr_index từ blob + link_impls_globally/impl_index/go_impls từ sg_symbols — resolution quality giữ nguyên sau restart. E2e: dynamic_indexes_survive_reopen. * Rust config review fixes: trait-declared methods + macro invocations Review bằng fixture "thật" (trait + impl + macro + closure + async) phát hiện: - function_signature_item (method KHAI BÁO trong trait) không được extract — không có symbol scope vào Interface nên fan-out Rust không bao giờ fire trên code thật (các test trước dùng synthetic symbols). Thêm vào decls → trigger Interface như Go method_elem. - macro_invocation không phải call (println!/vec! mất hoàn toàn) — thêm CallRule với rust_macro_call_name (`println!`). - E2E extraction thật: trait Repo{ping} + 2 impl → r.ping() fan-out cả hai (HierarchyFanOut) — chứng minh path thật chạy, không chỉ synthetic. - Cập nhật chain expectation test cũ: cg_t!/cg_d! giờ là call thật. Còn lại (defer): closure/callable tracking (cb()), generic instantiation, associated type semantics, UFCS. * Persist file_deps/fn_ptr_assigns cho MỌI storage backend Trước đó chỉ sqlite + in_memory implement — lmdb/postgres/mysql/redis rơi về no-op default = mất dynamic indexes khi reopen trên các backend đó. - lmdb: 2 named DBI (sg_file_deps/sg_fn_ptr_assigns) + set/all (cursor iter) + clear_entities. - postgres/mysql: bảng sg_file_deps/sg_fn_ptr_assigns (repo_id, path) PK, CREATE TABLE IF NOT EXISTS idempotent khi mở repo (không cần migration tay); mysql dùng ON DUPLICATE KEY UPDATE; clear_entities thêm 2 bảng. - redis: 2 hash keys (filedeps/fnptpassigns) + DEL trong clear_entities. - cached.rs: forward 4 methods xuống inner storage (trước đây rơi về default no-op → bypass backend thật!). - Test roundtrip in_memory (set/all/clear); build + test --all-features. * callers()/impact xuyên dyn-trait: fan-out fire theo receiver_text + dyn_callers index Review qua MCP index thật (codegraph-rs tự index chính nó) phát hiện: - `callers(set_file_deps)` trả rỗng dù ingest_with_progress gọi nó qua `dyn Storage` — call qua trait object bị resolve Single vì is_method_dispatch check `call_name.contains('.')` nhưng extractor đã rút call_name còn bare, trong khi receiver_text vẫn giữ receiver. - Fix 1: is_method_dispatch = receiver_text.is_some() || call_name.contains('.') → fan-out fire cho dyn-trait call. - Fix 2: dyn_callers (callee → callers) build từ call_meta khi ingest, scan call records khi rebuild; callers_resumable merge vào pending (dedup qua visited) → callers()/impact() thấy caller xuyên dyn-trait/interface/fn-ptr. - E2E: callers() của từng impl method thấy dyn caller (trước đây rỗng). Note vận hành: MCP server đang chạy bị MDB_BAD_RSLOT sau re-index in-process — reader locktable stale, cần restart MCP server (issue riêng, chưa xử lý). * Java + JavaScript/TypeScript semantic enrichment Review setup vs machinery Go/Rust/Python đã có — lấp các gap: Java (typing đã tốt nhất: field/param/local + annotations + implements): - java_supers: gộp extends (superclass) + implements vào impl_trait — inheritance fan-out qua machinery C++-base (superclass đứng trước). - java_signature_key: (params)(return) — tên param bỏ. - java_file_deps: import (bỏ static/wildcard) → FileDeps; strip keyword "extends" khỏi superclass text. JavaScript/TypeScript: - param_container_kinds formal_parameters: js identifier/rest_pattern, ts required/optional_parameter (name từ field pattern, type từ type_annotation — strip ':' + '?'). Trước đây params KHÔNG được extract. - js_file_deps (share TS): import default/named-as/namespace → FileDeps. Bug kèm theo: class_type_name cũ không bao giờ match JS thuần (class_heritage không có extends_clause — chỉ TS có); js_extends xử lý cả 2 grammar. - js_extends → impl_trait: inheritance fan-out cho class extends. - js_fn_value_assign: `handler = process` / `const h = process` (identifier thuần) → PointerAssign machinery. Tests: 3 fixture mới (java supers/sig/imports; js params/imports/extends/ fn-value; ts typed params + interface method scope). 20/21 suite (Redis env). * PHP/Ruby/Lua/Scala semantic enrichment — hoàn thiện fan-out toàn ngôn ngữ PHP (typing đã tốt: params/property/variable): - php_supers: base_clause (extends) + class_interface_clause (implements) — LÀ NODE KIND không phải field name (child_by_field_name trả None!) — inheritance fan-out. - php_signature_key + php_use_deps (namespace_use_declaration, bỏ function/const/wildcard). Ruby (mỏng nhất — params chưa từng extract): - param_container_kinds method_parameters: identifier/optional_parameter/ keyword_parameter/splat_parameter. - ruby_superclass → impl_trait (bỏ dynamic superclass `< Struct.new(..)`). - ruby_require_deps: require/require_relative → FileDeps. Lua: - param_container_kinds "parameters" (kind thật, không phải parameter_list). - lua_require_deps: `local mod = require('mod')` ghép variable_list với expression_list theo vị trí. - lua_fn_value_assign: `handler = process` → PointerAssign. Scala: - scala_supers: field "extend" (extends_clause là node kind, field tên "extend") — extends B with T → "B,T". - scala_signature_key + scala_file_deps (import_declaration, selector `.{a, b => c}`); token keyword "import" có cùng kind — guard child_count. Bài học chung: field name vs node kind khác nhau từng grammar — luôn dump AST trước khi wire hook. * Swift/C# semantic enrichment — đủ 14/14 ngôn ngữ Swift (trước đây gần trống — không hooks): - decls += protocol_function_declaration: method KHAI BÁO trong protocol scope vào Interface → fan-out (đúng bug Rust từng mắc). - swift_supers: inheritance_specifier (`class FileRepo: BaseRepo, Repo`) → impl_trait — protocol conformance đi cùng cơ chế fan-out. - swift_signature_key: Swift dùng TRÙNG tên field "name" cho tên param VÀ type (lấy field "name" cuối); match cả protocol_function_declaration; return = user_type sau token "->". - swift_import_deps: import_declaration → FileDeps. C# (typing/annotations sẵn tốt): - csharp_bases: base_list (node kind, unnamed child) → impl_trait (base class + interfaces, strip generic). - csharp_signature_key: return field là "returns" (không phải "type"). - csharp_using_deps: `using App.Repos` + alias form `using Db = App.Data`. Tests: 2 fixture mới (swift protocol/supers/sig/imports; csharp bases/sig/ using). 25/25 dynamic_dispatch, 20/21 workspace (Redis env-only). * FunctionValue + member assignment + MARKER_AWAIT (priority 1/3/6) A. FunctionValue cho 4 ngôn ngữ còn thiếu: - Python: `handler = process` (identifier=identifier) + `self.handler = process` (member, var = "self.handler"). - Ruby: CHỈ `handler = method(:process)` — plain `x = process` là LỜI GỌI trong Ruby, không track. - Java: `Runnable r = this::run` — method_reference, target = identifier cuối (không phụ thuộc field name grammar). - C#: `Action handler = Process` — value là identifier UNNAMED (không có field "value") — lấy identifier con cuối khác name. B. Member fn assignment `obj.handler = fn`: - Mở guard fn_ptr_index (bỏ `!contains('.')`) — lookup theo call_name bare lẫn dotted. - js/ts: member_expression left → key full dotted text (`Foo.prototype.run`). - lua: text chứa '.' → full text; bracket `handlers["read"]` skip. - python: self.attr. C. MARKER_AWAIT (Marker::Await = 27): MarkerSpec.await_kinds — python "await", js/ts/csharp/swift "await_expression" (dump AST xác nhận); walk_chain push AWAIT trước call như GO/DEFER → edge mang ngữ cảnh async boundary. E2E: member_fn_assignment_resolves_dotted_call — `obj.handler = process` + `obj.handler()` → PointerAssign (trước đây guard chặn). 25/25 dynamic_dispatch (2 test mới), 20/21 workspace (Redis env-only). * C/C++ enrichment batch 1-4: include graph, fn-ptr mở rộng, sig_key, virtual precision 1. c_include_deps: #include "foo.h" / <openssl/ssl.h> → FileDeps (path nguyên văn, alias = tên file không extension) — include graph qua machinery file_imports; C + C++ share. 2. c_fn_ptr_assign mở rộng: LHS field_expression (`obj.handler` — dotted key, ăn guard fn_ptr_index mới) + pointer_expression (`*handler` → "handler"); RHS `&f` address-of + `&ns::cb` qualified. 3. cpp_signature_key: params từ function_declarator (function_definition 1 tầng declarator; method inline field_declaration cũng 1 tầng — dump mới thấy, không phải 2); return field "type". 4. Virtual precision trong collect_fanout (C++ path): nếu CÓ candidate mang keyword virtual/override (signature chứa — extractor lưu dòng khai báo) → chỉ giữ virtual candidates + base decl; không keyword nào → giữ hết (soundness fallback). Loại non-virtual cùng tên trong hierarchy. E2E: cpp_virtual_filter_prefers_override_candidates (D2 non-virtual bị loại). Tests: 26/26 dynamic_dispatch (2 mới), 121/121 graph lib, 20/21 workspace (Redis env-only). * Web UI: dynamic-dispatch badges, Call sites/Pattern/Trace tabs, search pagination + annotation Explore UI (SvelteKit + GraphQL) lộ đầy đủ query surface mới: - Flow tab: mỗi call hiện badge resolvedVia ([dyn]/[fn-ptr]/[unresolved]/…) + candidate chips click-to-navigate (searchExact). GraphQL enum là SCREAMING_SNAKE_CASE — smoke query bắt được bug casing lowercase ban đầu. - Tab Call sites (references): tìm callers theo call name — thấy cả unresolved/library + dynamic calls; prefill theo symbol name. - Tab Pattern (searchFlow): tìm hàm theo chain pattern (markers/tên/id). - Tab Trace (traceFullFlow — targetId arg): debug-style paths caller → target, indent theo stackDepth, icon theo action (CALL/RETURN/THROW/BRANCH/LOOP), màu theo PathEnding; chọn caller depth. - SymbolSearch: Load more (offset pagination), "continue" khi timed_out (resumable cursor), source by name | by annotation (graphcodeSearchByAnnotation). Smoke qua server thật: flow(ingest_with_progress) có 11 HIERARCHY_FAN_OUT calls với 7 candidates (dyn Storage backends), trace 3 paths, annotation "derive" 196 kết quả, references set_file_deps 2 callers. svelte-check 0 errors, build-web assets embed, workspace tests 20/21 (Redis env-only). * C/C++ batch #6 + #8: declaration–definition linking + namespace-qualified call #6 link_cpp_decl_def (global, chạy cả ingest lẫn rebuild): - `void Service::run() {}` trong .cpp (definition, có chain) nối với method khai báo trong .hpp (declaration, không chain): cùng tên + cùng sig_key (khi cả hai có) + khác file → def re-parent về scope của decl (class/ namespace) + reclassify theo kind của decl; decl.type_ref → def. - Hiệu ứng: fan-out/hierarchy thấy definition (có body/flow), class_info theo type_ref tới nơi có chain. #8 qualified call `orders::run()`: - Short-name fallback split cả '::' (rsplit ['.', ':'] bỏ segment rỗng) — trước đây "::" không split → qualified call unresolved hoàn toàn. - Namespace preference: prefix trước '::' lọc candidate theo tổ tiên Module (namespace) cùng tên hoặc file chứa prefix — `foo::run` không còn nhầm `bar::run`; không subset khớp → giữ tất cả (soundness). E2E: cpp_decl_def_linked_across_files (link đúng, pick_best ưu tiên def has-chain); cpp_qualified_call_prefers_namespace (orders::run chọn đúng namespace, không chọn bar). 123/123 graph lib, 20/21 workspace (Redis env). * C/C++ batch cuối: lambda có tên (#5), macro theo thiết kế ghi-nhận (#9-lite), typedef signature (#4-lite) #5 C++ lambda thành Function symbol: - decls/func_kinds += lambda_expression → chain riêng cho calls trong lambda body (attribution chính xác, không gộp vào enclosing fn). - anonymous_name_fn cpp_lambda_name: `auto f = [](){}` mượn tên biến — LƯU Ý init_declarator đặt tên ở field `declarator`, không phải `name` như JS variable_declarator (grammar khác nhau). #9-lite macro THEO THIẾT KẾ GHI-NHẬN (không resolve): - preproc_function_def + preproc_def → Constant symbol, signature = định nghĩa nguyên văn (`CALL(x) x()`, `MAX 10`) — macro KHÔNG phải function, invocation giữ raw call → usage tra qua call-name index (references). - Hành vi semantic do config khai báo ("LLM tự định nghĩa"): `[[effect_rules]]` trong .codegraph/config.toml (matcher + EffectType, xét trước bảng default) — test chứng minh rule Contains "CALL" → Panic (exception-like). - Không làm (đúng defer): macro expansion, conditional compilation. #4-lite typedef signature: - HookSpec thêm typedef_sig_fn; c_typedef_sig (C + C++ share): typedef + macro → signature = text định nghĩa (strip typedef/#define + ;). Hook ƯU TIÊN extract_signature (nó trả full text trước khiến hook không chạy). - fn-ptr typedef giờ giữ underlying type: `int (*handler_t)(int)` thay vì chỉ `int` từ field type. Tests: cpp_lambda_macro_typedef_batch (lambda symbol + chain + calls, macro Constant + signature + raw invocation + effect-rule config, typedef sig). 20/21 workspace (Redis env-only), clippy sạch. * MCP + GraphQL tool cấu hình effect rules runtime (LLM tự định nghĩa macro semantics) Trước đây `[[effect_rules]]` chỉ đọc được từ .codegraph/config.toml — LLM phải sửa file ngoài band rồi re-index. Giờ có tool chính tắc: - config.rs CRUD API: list_effect_rules (raw — kể cả rule lỗi) / add_effect_rule (validate matcher + EffectType, toml_edit preserve mọi section khác) / remove_effect_rule (theo index). Sau ghi: install_current cho thread hiện tại; orchestrator reload config mỗi index nên rule áp dụng từ lần re-index kế tiếp (re-classify call records). - MCP tool `codegraph_config_effects`: op list|add|remove; mô tả tool kèm ví dụ macro exception-like (contains CHECK → panic) + ghi chú áp dụng. - GraphQL mutation `configEffects(op, matcher, text, effect, index)` mirror cho web UI. Test: effect_rule_crud_roundtrip — add 2 rules → list đúng, classifier load từ file classify CHECK_OK → Panic / db.Query → SqlQuery, effect sai bị chặn (file không đổi), remove theo index, section khác (storage) nguyên vẹn. Fix bug bắt được bởi test: or_insert tạo ArrayOfTables với table rỗng dummy → rule rỗng đầu danh sách. * Bump version to v2.2.11 * Dọn debug eprintln sót (DBG by_name/DBG/DBG3/PHPDBG/SCALADBG) sau các batch debug
…te maintainable code
- Resolve rebase conflicts keeping main's newer storage/extract/MCP surfaces; merged docs (README, configuration, MCP instructions) and CI (web + sonar). - codesmell: adapt to new GraphIndex::ingest signature and Symbol fields. - LruCache: close data races between get/remove/put-update and clear by touching node key/value only under the owning shard lock; re-validate the mapping entry and node key under the lock to avoid returning values from reused slots and to avoid a cross-lock cycle between DashMap and shard mutex.
028a798 to
bdfc17c
Compare
- [testing.coverage] in policy.toml: test_paths/layers/selectors (same semantics as testing.missing_test) plus an optional percent threshold; a below-threshold run adds one testing.coverage violation in codesmell check. - New src/coverage.rs measures the estimate; reports percent + uncovered functions (human/json), exits non-zero below the threshold; results also ride on check's JSON report. - Starter policy (codesmell init) ships a coverage block; docs/codesmell.md and spec 11 updated; new dedicated guide docs/codesmell-coverage.md covers the heuristic, its limits (macros, depth-1 callers) and CI usage.
No description provided.