[GH-ISSUE #2160] [Feature] Name the declaring type of call-edge and field-access targets in inspect_managed_members #711

Closed
opened 2026-10-15 18:27:37 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @Nelglor on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2160

Note

🤖 Claude Opus 5.5 responding on behalf of Nick

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction (managed static analysis, inspect_managed_members)

Current limitation

call_edges[].target_name gives only the member name for external targets, for example Join, ToJson or WriteAllText. member_refs exposes parent_token, but nothing names the TypeRef or TypeSpec it points to. Three related gaps follow:

  • Callers can't tell which library a call goes to. ToJson could be UnityEngine.JsonUtility or Newtonsoft.Json.JsonConvert.
  • Generic method calls are anonymous. method-spec edges report target_name: null.
  • External field reads are anonymous. Field accesses through a MemberRef report field_name: null.

So "where is BinaryFormatter / CryptoStream / File.WriteAllText used" cannot be answered from REA output.

Use cases

  • Save-format identification. In PEAK's Peak.Quicksave (Unity Mono), the save path is SaveNow -> ToJson, WriteAllText, and the load path is LoadSaveData -> ReadAllText plus one unnamed method-spec call. With declaring types this reads as UnityEngine.JsonUtility.ToJson and System.IO.File.WriteAllText. The unnamed call becomes UnityEngine.JsonUtility.FromJson: plain JSON, no encryption.
  • Finding every caller of a crypto, serialization, networking or P/Invoke-adjacent API across selected types.

Desired outcome and success criteria

  • member_refs[].parent_name, call_edges[].target_declaring_type and field_accesses[].field_declaring_type name the declaring type.
  • Names use the same namespace-qualified form as TypeDef full_name, including the existing bare-name convention for nested types.
  • A generic-instantiation TypeSpec names its generic type, for example System.Collections.Generic.List`1.
  • A method-spec edge reports the name and declaring type of the generic method it instantiates.
  • Other TypeSpec forms, ModuleRef and MethodDef parents, and unreadable rows stay null, meaning unknown.
  • Malformed rows are reported, and self-referential TypeSpecs terminate.
  • Older Evidence without the fields still parses, with the fields reading as null.

Authority boundaries and non-goals

  • Static only.
  • No cross-assembly resolution: AssemblyRef scopes are not followed.
  • No type-forwarding resolution.
  • Nested TypeRef names keep the existing bare-name convention rather than introducing a second naming scheme.

Alternatives considered

A separate type_refs inventory would make callers join two arrays for the common question "what does this call". Naming the target where the edge already sits answers it directly. member_refs.parent_name keeps the inventory self-describing for "every reference to type X".

Possible direction

Name types once per token, covering TypeDef via the existing ranges, TypeRef rows, and GENERICINST TypeSpecs. Then resolve every edge target through one token-keyed member lookup.

I have an implementation with focused tests ready and will open a PR referencing this issue.

References

  • ECMA-335 II.22.38 (TypeRef), II.22.39 (TypeSpec), II.22.29 (MethodSpec), II.23.2.12 (GENERICINST).
Originally created by @Nelglor on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2160 > [!NOTE] > 🤖 **Claude Opus 5.5 responding on behalf of Nick** ### Before submitting - [x] I searched the open and closed issues and pull requests for a related proposal. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction (managed static analysis, `inspect_managed_members`) ### Current limitation `call_edges[].target_name` gives only the member name for external targets, for example `Join`, `ToJson` or `WriteAllText`. `member_refs` exposes `parent_token`, but nothing names the TypeRef or TypeSpec it points to. Three related gaps follow: - **Callers can't tell which library a call goes to.** `ToJson` could be `UnityEngine.JsonUtility` or `Newtonsoft.Json.JsonConvert`. - **Generic method calls are anonymous.** `method-spec` edges report `target_name: null`. - **External field reads are anonymous.** Field accesses through a MemberRef report `field_name: null`. So "where is `BinaryFormatter` / `CryptoStream` / `File.WriteAllText` used" cannot be answered from REA output. ### Use cases - **Save-format identification.** In PEAK's `Peak.Quicksave` (Unity Mono), the save path is `SaveNow -> ToJson`, `WriteAllText`, and the load path is `LoadSaveData -> ReadAllText` plus one unnamed `method-spec` call. With declaring types this reads as `UnityEngine.JsonUtility.ToJson` and `System.IO.File.WriteAllText`. The unnamed call becomes `UnityEngine.JsonUtility.FromJson`: plain JSON, no encryption. - **Finding every caller of a crypto, serialization, networking or P/Invoke-adjacent API** across selected types. ### Desired outcome and success criteria - `member_refs[].parent_name`, `call_edges[].target_declaring_type` and `field_accesses[].field_declaring_type` name the declaring type. - Names use the same namespace-qualified form as TypeDef `full_name`, including the existing bare-name convention for nested types. - A generic-instantiation TypeSpec names its generic type, for example ``System.Collections.Generic.List`1``. - A `method-spec` edge reports the name and declaring type of the generic method it instantiates. - Other TypeSpec forms, ModuleRef and MethodDef parents, and unreadable rows stay `null`, meaning unknown. - Malformed rows are reported, and self-referential TypeSpecs terminate. - Older Evidence without the fields still parses, with the fields reading as `null`. ### Authority boundaries and non-goals - Static only. - No cross-assembly resolution: AssemblyRef scopes are not followed. - No type-forwarding resolution. - Nested TypeRef names keep the existing bare-name convention rather than introducing a second naming scheme. ### Alternatives considered A separate `type_refs` inventory would make callers join two arrays for the common question "what does this call". Naming the target where the edge already sits answers it directly. `member_refs.parent_name` keeps the inventory self-describing for "every reference to type X". ### Possible direction Name types once per token, covering TypeDef via the existing ranges, TypeRef rows, and GENERICINST TypeSpecs. Then resolve every edge target through one token-keyed member lookup. I have an implementation with focused tests ready and will open a PR referencing this issue. ### References - ECMA-335 II.22.38 (TypeRef), II.22.39 (TypeSpec), II.22.29 (MethodSpec), II.23.2.12 (GENERICINST).
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

Design & ECMA-335 Metadata Review

Exposing the declaring type (declaring_type_name or qualified namespace) on call_edges and field_accesses in inspect_managed_members is essential for unambiguous symbol resolution:

  • Metadata Resolution: In ECMA-335 CLI metadata, MemberRef entries (table 0x0A) contain a Class coded index pointing to TypeRef (0x01), TypeSpec (0x1B), or TypeDef (0x02). Resolving this index yields the fully qualified enclosing type name.
  • Contract Schema: Add an optional declaring_type property to call_edges and field_accesses, preserving null only when resolving malformed or truncated metadata tables.
<!-- gh-comment-id:6134430594 --> @matbrgz commented on GitHub (Oct 12, 2026): ### Design & ECMA-335 Metadata Review Exposing the declaring type (`declaring_type_name` or qualified namespace) on `call_edges` and `field_accesses` in `inspect_managed_members` is essential for unambiguous symbol resolution: - **Metadata Resolution:** In ECMA-335 CLI metadata, `MemberRef` entries (table 0x0A) contain a `Class` coded index pointing to `TypeRef` (0x01), `TypeSpec` (0x1B), or `TypeDef` (0x02). Resolving this index yields the fully qualified enclosing type name. - **Contract Schema:** Add an optional `declaring_type` property to `call_edges` and `field_accesses`, preserving `null` only when resolving malformed or truncated metadata tables.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#711
No description provided.