|
@@ -11,10 +11,11 @@
|
|
|
//! - impl blocks push NO scope: members re-dispatch at file scope, so an impl
|
|
//! - impl blocks push NO scope: members re-dispatch at file scope, so an impl
|
|
|
//! associated `const` becomes a FILE-level `variable`, and the method↔owner
|
|
//! associated `const` becomes a FILE-level `variable`, and the method↔owner
|
|
|
//! `contains` edge is a source-order name scan (an impl ABOVE its struct
|
|
//! `contains` edge is a source-order name scan (an impl ABOVE its struct
|
|
|
-//! gets no edge). `impl Trait for Generic<T>`'s receiver resolves to the
|
|
|
|
|
-//! TRAIT (the only direct type_identifier), and methods get QN
|
|
|
|
|
-//! `Trait::method` — preserve, never "fix" via the grammar's trait:/type:
|
|
|
|
|
-//! fields.
|
|
|
|
|
|
|
+//! gets no edge). The receiver (method QN prefix, `contains` owner,
|
|
|
|
|
+//! `implements` source) is the impl_item's `type` field via
|
|
|
|
|
+//! impl_type_name — both sides moved to the grammar's trait:/type: fields
|
|
|
|
|
+//! together in #1588 (the earlier positional scan qualified every
|
|
|
|
|
+//! parameterized impl's methods by the TRAIT).
|
|
|
//! - `const_item`/`static_item` ride the generic extractVariable fallback:
|
|
//! - `const_item`/`static_item` ride the generic extractVariable fallback:
|
|
|
//! kind is always `variable`, no signature, and EVERY direct `identifier`
|
|
//! kind is always `variable`, no signature, and EVERY direct `identifier`
|
|
|
//! child mints a node (`const MAX: u32 = OTHER;` → two nodes, `MAX` + the
|
|
//! child mints a node (`const MAX: u32 = OTHER;` → two nodes, `MAX` + the
|
|
@@ -22,10 +23,12 @@
|
|
|
//! - Unit structs (`struct Unit;`, no body field) mint NO node; `mod_item`
|
|
//! - Unit structs (`struct Unit;`, no body field) mint NO node; `mod_item`
|
|
|
//! mints no module node and adds no QN prefix.
|
|
//! mints no module node and adds no QN prefix.
|
|
|
//! - Chained-call re-encode is scoped_identifier-gated (`Foo::new().bar()` →
|
|
//! - Chained-call re-encode is scoped_identifier-gated (`Foo::new().bar()` →
|
|
|
-//! `Foo::new().bar`); instance chains, parens, `.await`, 2-hop fields, and
|
|
|
|
|
-//! `self` receivers all collapse to the bare method name (`self` is node
|
|
|
|
|
-//! kind `self`, not `identifier`, so it dodges SKIP_RECEIVERS by falling
|
|
|
|
|
-//! through). Turbofish callees keep the raw `helper::<T>` text.
|
|
|
|
|
|
|
+//! `Foo::new().bar`); a call through a field of the enclosing type keeps
|
|
|
|
|
+//! the owner-field shape (`self.inner.run()` → `self.inner.run`, #1585);
|
|
|
|
|
+//! instance chains, parens, `.await`, deeper/non-self field chains, and
|
|
|
|
|
+//! bare `self` receivers all collapse to the bare method name (`self` is
|
|
|
|
|
+//! node kind `self`, not `identifier`, so it dodges SKIP_RECEIVERS by
|
|
|
|
|
+//! falling through). Turbofish callees keep the raw `helper::<T>` text.
|
|
|
//! - `use` emits an import node named by the ROOT module (`crate`/`self`/…),
|
|
//! - `use` emits an import node named by the ROOT module (`crate`/`self`/…),
|
|
|
//! one root `imports` ref, then one FULL-path `imports` ref per binding;
|
|
//! one root `imports` ref, then one FULL-path `imports` ref per binding;
|
|
|
//! `use x::*` (use_wildcard) emits nothing at all.
|
|
//! `use x::*` (use_wildcard) emits nothing at all.
|
|
@@ -399,33 +402,35 @@ impl<'t> Walker<'t> {
|
|
|
Some(if last == "Self" { "self".to_string() } else { last.to_string() })
|
|
Some(if last == "Self" { "self".to_string() } else { last.to_string() })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// rustExtractor.getReceiverType: parent-walk to the nearest impl_item;
|
|
|
|
|
- /// LAST direct type_identifier child wins (for `impl Trait for Generic<T>`
|
|
|
|
|
- /// that's the TRAIT — bug preserved); else the first generic_type's inner
|
|
|
|
|
- /// type_identifier.
|
|
|
|
|
|
|
+ /// rustImplTypeName (languages/rust.ts) — the implementing type's simple
|
|
|
|
|
+ /// name for an impl block, from the grammar's `type` field (#1588):
|
|
|
|
|
+ /// `impl<T> Tr for G<T>` / `impl<'a> Iterator for Parents<'a>` /
|
|
|
|
|
+ /// `impl Tr for &Foo` / `impl Tr for m::Foo` → `G` / `Parents` / `Foo` /
|
|
|
|
|
+ /// `Foo`. Shapes naming no single type (tuple, `dyn Tr`, pointer,
|
|
|
|
|
+ /// primitive, fn type…) → None. Mirrored byte-for-byte — change both.
|
|
|
|
|
+ fn impl_type_name(&self, ty: Option<Node>) -> Option<String> {
|
|
|
|
|
+ let ty = ty?;
|
|
|
|
|
+ match ty.kind() {
|
|
|
|
|
+ "type_identifier" | "identifier" => Some(self.text(ty).to_string()),
|
|
|
|
|
+ "generic_type" => self.impl_type_name(ty.child_by_field_name("type")),
|
|
|
|
|
+ "scoped_type_identifier" | "scoped_identifier" => {
|
|
|
|
|
+ self.impl_type_name(ty.child_by_field_name("name"))
|
|
|
|
|
+ }
|
|
|
|
|
+ "reference_type" => self.impl_type_name(ty.child_by_field_name("type")),
|
|
|
|
|
+ _ => None,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// rustExtractor.getReceiverType: parent-walk to the nearest impl_item and
|
|
|
|
|
+ /// read its `type` field (impl_type_name). The pre-#1588 rule took the
|
|
|
|
|
+ /// LAST direct type_identifier child, which for `impl Trait for Generic<T>`
|
|
|
|
|
+ /// was the TRAIT — so every parameterized impl's methods were qualified by
|
|
|
|
|
+ /// the trait.
|
|
|
fn receiver_type_of(&self, node: Node) -> Option<String> {
|
|
fn receiver_type_of(&self, node: Node) -> Option<String> {
|
|
|
let mut parent = node.parent();
|
|
let mut parent = node.parent();
|
|
|
while let Some(p) = parent {
|
|
while let Some(p) = parent {
|
|
|
if p.kind() == "impl_item" {
|
|
if p.kind() == "impl_item" {
|
|
|
- let type_idents: Vec<Node> = (0..p.named_child_count())
|
|
|
|
|
- .filter_map(|i| p.named_child(i))
|
|
|
|
|
- .filter(|c| c.kind() == "type_identifier")
|
|
|
|
|
- .collect();
|
|
|
|
|
- if let Some(last) = type_idents.last() {
|
|
|
|
|
- return Some(self.text(*last).to_string());
|
|
|
|
|
- }
|
|
|
|
|
- let generic = (0..p.named_child_count())
|
|
|
|
|
- .filter_map(|i| p.named_child(i))
|
|
|
|
|
- .find(|c| c.kind() == "generic_type");
|
|
|
|
|
- if let Some(g) = generic {
|
|
|
|
|
- let inner = (0..g.named_child_count())
|
|
|
|
|
- .filter_map(|i| g.named_child(i))
|
|
|
|
|
- .find(|c| c.kind() == "type_identifier");
|
|
|
|
|
- if let Some(inner) = inner {
|
|
|
|
|
- return Some(self.text(inner).to_string());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return None;
|
|
|
|
|
|
|
+ return self.impl_type_name(p.child_by_field_name("type"));
|
|
|
}
|
|
}
|
|
|
parent = p.parent();
|
|
parent = p.parent();
|
|
|
}
|
|
}
|
|
@@ -435,6 +440,7 @@ impl<'t> Walker<'t> {
|
|
|
// --- visitNode ------------------------------------------------------------
|
|
// --- visitNode ------------------------------------------------------------
|
|
|
|
|
|
|
|
fn visit_node(&mut self, node: Node<'t>) {
|
|
fn visit_node(&mut self, node: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let kind = node.kind();
|
|
let kind = node.kind();
|
|
|
let mut skip_children = false;
|
|
let mut skip_children = false;
|
|
|
|
|
|
|
@@ -498,6 +504,7 @@ impl<'t> Walker<'t> {
|
|
|
/// impl method's body, whose parent walk passes through the outer fn) or
|
|
/// impl method's body, whose parent walk passes through the outer fn) or
|
|
|
/// the stack top is class-like (trait members).
|
|
/// the stack top is class-like (trait members).
|
|
|
fn extract_fn_or_method(&mut self, node: Node<'t>) {
|
|
fn extract_fn_or_method(&mut self, node: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let receiver = self.receiver_type_of(node);
|
|
let receiver = self.receiver_type_of(node);
|
|
|
let as_method = receiver.is_some() || self.inside_class_like();
|
|
let as_method = receiver.is_some() || self.inside_class_like();
|
|
|
|
|
|
|
@@ -564,6 +571,7 @@ impl<'t> Walker<'t> {
|
|
|
/// extractInterface — kind `trait` (interfaceKind), inheritance from
|
|
/// extractInterface — kind `trait` (interfaceKind), inheritance from
|
|
|
/// trait_bounds, body children visited with the trait pushed.
|
|
/// trait_bounds, body children visited with the trait pushed.
|
|
|
fn extract_interface(&mut self, node: Node<'t>) {
|
|
fn extract_interface(&mut self, node: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let name = self.extract_name(node);
|
|
let name = self.extract_name(node);
|
|
|
let extra = Extra {
|
|
let extra = Extra {
|
|
|
docstring: preceding_docstring(node, self.src),
|
|
docstring: preceding_docstring(node, self.src),
|
|
@@ -584,6 +592,7 @@ impl<'t> Walker<'t> {
|
|
|
|
|
|
|
|
/// Extract a Rust struct or union with a body; unit structs remain skipped.
|
|
/// Extract a Rust struct or union with a body; unit structs remain skipped.
|
|
|
fn extract_aggregate(&mut self, node: Node<'t>, kind: &'static str) {
|
|
fn extract_aggregate(&mut self, node: Node<'t>, kind: &'static str) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let Some(body) = node.child_by_field_name("body") else { return };
|
|
let Some(body) = node.child_by_field_name("body") else { return };
|
|
|
let name = self.extract_name(node);
|
|
let name = self.extract_name(node);
|
|
|
let extra = Extra {
|
|
let extra = Extra {
|
|
@@ -606,6 +615,7 @@ impl<'t> Walker<'t> {
|
|
|
/// extractEnum — body required; enum_variant children → enum_member nodes
|
|
/// extractEnum — body required; enum_variant children → enum_member nodes
|
|
|
/// (name field only, payloads never walked); other children re-dispatched.
|
|
/// (name field only, payloads never walked); other children re-dispatched.
|
|
|
fn extract_enum(&mut self, node: Node<'t>) {
|
|
fn extract_enum(&mut self, node: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let Some(body) = node.child_by_field_name("body") else { return };
|
|
let Some(body) = node.child_by_field_name("body") else { return };
|
|
|
let name = self.extract_name(node);
|
|
let name = self.extract_name(node);
|
|
|
let extra = Extra {
|
|
let extra = Extra {
|
|
@@ -700,6 +710,7 @@ impl<'t> Walker<'t> {
|
|
|
|
|
|
|
|
/// getRootModule (languages/rust.ts:124).
|
|
/// getRootModule (languages/rust.ts:124).
|
|
|
fn root_module(&self, n: Node) -> String {
|
|
fn root_module(&self, n: Node) -> String {
|
|
|
|
|
+ stack_guard!();
|
|
|
let Some(first) = n.named_child(0) else {
|
|
let Some(first) = n.named_child(0) else {
|
|
|
return self.text(n).to_string();
|
|
return self.text(n).to_string();
|
|
|
};
|
|
};
|
|
@@ -719,6 +730,7 @@ impl<'t> Walker<'t> {
|
|
|
if prefix.is_empty() { seg.to_string() } else { format!("{prefix}::{seg}") }
|
|
if prefix.is_empty() { seg.to_string() } else { format!("{prefix}::{seg}") }
|
|
|
}
|
|
}
|
|
|
fn collect<'t>(w: &Walker<'t>, n: Node<'t>, prefix: &str, paths: &mut Vec<(String, Node<'t>)>) {
|
|
fn collect<'t>(w: &Walker<'t>, n: Node<'t>, prefix: &str, paths: &mut Vec<(String, Node<'t>)>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
match n.kind() {
|
|
match n.kind() {
|
|
|
"identifier" => paths.push((join(prefix, w.text(n)), n)),
|
|
"identifier" => paths.push((join(prefix, w.text(n)), n)),
|
|
|
"scoped_identifier" => {
|
|
"scoped_identifier" => {
|
|
@@ -835,9 +847,29 @@ impl<'t> Walker<'t> {
|
|
|
callee_name = method_name.to_string();
|
|
callee_name = method_name.to_string();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ "field_expression" => {
|
|
|
|
|
+ // `self.<field>.<method>()` — a call through a
|
|
|
|
|
+ // field of the enclosing type (#1585): keep the
|
|
|
|
|
+ // `self.` prefix so the resolver can type the
|
|
|
|
|
+ // field from the owner struct's declaration
|
|
|
|
|
+ // (or leave it unresolved). Any other
|
|
|
|
|
+ // field_expression receiver — a deeper chain,
|
|
|
|
|
+ // a non-self base — keeps the bare name.
|
|
|
|
|
+ let base = r.child_by_field_name("value");
|
|
|
|
|
+ let field = r.child_by_field_name("field");
|
|
|
|
|
+ match (base, field) {
|
|
|
|
|
+ (Some(b), Some(f))
|
|
|
|
|
+ if b.kind() == "self" && f.kind() == "field_identifier" =>
|
|
|
|
|
+ {
|
|
|
|
|
+ let field_name = self.text(f);
|
|
|
|
|
+ callee_name = format!("self.{field_name}.{method_name}");
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => callee_name = method_name.to_string(),
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
_ => {
|
|
_ => {
|
|
|
- // field_expression 2-hop, parenthesized,
|
|
|
|
|
- // await_expression, `self` — bare method name.
|
|
|
|
|
|
|
+ // parenthesized, await_expression, `self` —
|
|
|
|
|
+ // bare method name.
|
|
|
callee_name = method_name.to_string();
|
|
callee_name = method_name.to_string();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -966,6 +998,7 @@ impl<'t> Walker<'t> {
|
|
|
/// every field has a field_identifier), and the field_declaration_list
|
|
/// every field has a field_identifier), and the field_declaration_list
|
|
|
/// recursion that reaches it.
|
|
/// recursion that reaches it.
|
|
|
fn extract_inheritance(&mut self, node: Node<'t>, class_row: u32) {
|
|
fn extract_inheritance(&mut self, node: Node<'t>, class_row: u32) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let extends_kind = edge_kind_index("extends").unwrap();
|
|
let extends_kind = edge_kind_index("extends").unwrap();
|
|
|
for i in 0..node.named_child_count() {
|
|
for i in 0..node.named_child_count() {
|
|
|
let Some(child) = node.named_child(i) else { continue };
|
|
let Some(child) = node.named_child(i) else { continue };
|
|
@@ -1024,36 +1057,19 @@ impl<'t> Walker<'t> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// extractRustImplItem — `impl Trait for Type` back-reference: positional
|
|
|
|
|
- /// type-node filter (NEVER the grammar's trait:/type: fields), ≥2 needed,
|
|
|
|
|
- /// target found by FIRST earlier node of kind struct/enum/class (never
|
|
|
|
|
- /// trait); ref FROM the type's node, named by the trait's full text.
|
|
|
|
|
|
|
+ /// extractRustImplItem — `impl Trait for Type` back-reference from the
|
|
|
|
|
+ /// grammar's `trait` / `type` fields (#1588; an inherent impl has no
|
|
|
|
|
+ /// `trait` field and emits nothing). Target = FIRST earlier node of kind
|
|
|
|
|
+ /// struct/union/enum/class (never trait) named by impl_type_name; ref FROM
|
|
|
|
|
+ /// the type's node, named by the trait's full text (scoped path / generic
|
|
|
|
|
+ /// args kept), at the trait node's position.
|
|
|
fn extract_rust_impl_item(&mut self, node: Node<'t>) {
|
|
fn extract_rust_impl_item(&mut self, node: Node<'t>) {
|
|
|
- let has_for = (0..node.child_count())
|
|
|
|
|
- .filter_map(|i| node.child(i))
|
|
|
|
|
- .any(|c| c.kind() == "for" && !c.is_named());
|
|
|
|
|
- if !has_for {
|
|
|
|
|
|
|
+ let Some(trait_node) = node.child_by_field_name("trait") else {
|
|
|
return;
|
|
return;
|
|
|
- }
|
|
|
|
|
- let type_idents: Vec<Node> = (0..node.named_child_count())
|
|
|
|
|
- .filter_map(|i| node.named_child(i))
|
|
|
|
|
- .filter(|c| matches!(c.kind(), "type_identifier" | "generic_type" | "scoped_type_identifier"))
|
|
|
|
|
- .collect();
|
|
|
|
|
- if type_idents.len() < 2 {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- let trait_node = type_idents[0];
|
|
|
|
|
- let type_node = type_idents[type_idents.len() - 1];
|
|
|
|
|
-
|
|
|
|
|
|
|
+ };
|
|
|
let trait_name = self.text(trait_node).to_string();
|
|
let trait_name = self.text(trait_node).to_string();
|
|
|
- let type_name = if type_node.kind() == "generic_type" {
|
|
|
|
|
- (0..type_node.named_child_count())
|
|
|
|
|
- .filter_map(|i| type_node.named_child(i))
|
|
|
|
|
- .find(|c| c.kind() == "type_identifier")
|
|
|
|
|
- .map(|c| self.text(c).to_string())
|
|
|
|
|
- .unwrap_or_else(|| self.text(type_node).to_string())
|
|
|
|
|
- } else {
|
|
|
|
|
- self.text(type_node).to_string()
|
|
|
|
|
|
|
+ let Some(type_name) = self.impl_type_name(node.child_by_field_name("type")) else {
|
|
|
|
|
+ return;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
let target_row = self
|
|
let target_row = self
|
|
@@ -1086,6 +1102,7 @@ impl<'t> Walker<'t> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn extract_type_refs_from_subtree(&mut self, node: Node<'t>, from_row: u32) {
|
|
fn extract_type_refs_from_subtree(&mut self, node: Node<'t>, from_row: u32) {
|
|
|
|
|
+ stack_guard!();
|
|
|
if node.kind() == "type_identifier" {
|
|
if node.kind() == "type_identifier" {
|
|
|
let type_name = self.text(node).to_string();
|
|
let type_name = self.text(node).to_string();
|
|
|
if !type_name.is_empty() && !is_builtin_type(&type_name) {
|
|
if !type_name.is_empty() && !is_builtin_type(&type_name) {
|
|
@@ -1103,10 +1120,12 @@ impl<'t> Walker<'t> {
|
|
|
// --- visitFunctionBody -----------------------------------------------------
|
|
// --- visitFunctionBody -----------------------------------------------------
|
|
|
|
|
|
|
|
fn visit_function_body(&mut self, body: Node<'t>) {
|
|
fn visit_function_body(&mut self, body: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
self.visit_for_calls_and_structure(body);
|
|
self.visit_for_calls_and_structure(body);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn visit_for_calls_and_structure(&mut self, node: Node<'t>) {
|
|
fn visit_for_calls_and_structure(&mut self, node: Node<'t>) {
|
|
|
|
|
+ stack_guard!();
|
|
|
let kind = node.kind();
|
|
let kind = node.kind();
|
|
|
self.maybe_capture_fn_refs(node);
|
|
self.maybe_capture_fn_refs(node);
|
|
|
|
|
|
|
@@ -1262,6 +1281,7 @@ impl<'t> Walker<'t> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn scan_fn_ref_subtree(&mut self, node: Node<'t>, depth: u32) {
|
|
fn scan_fn_ref_subtree(&mut self, node: Node<'t>, depth: u32) {
|
|
|
|
|
+ stack_guard!();
|
|
|
if depth > 12 {
|
|
if depth > 12 {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|