Land upstream #1686 (maxmilian + bompus kernel/CG-28 follow-ups) onto current main. tree-sitter-typescript interface members (method_signature / property_signature) were never listed in the TS extractor, so platform .d.ts APIs had no declaration nodes for call edges. Mirrors on the Rust kernel path; keeps CG-28 damping for pure-interface declaration files; filters damped files from the explore RWR seed set. Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
This commit is contained in:
co-authored by
Colby McHenry
parent
8c047342cd
commit
ee83636acb
@@ -302,8 +302,33 @@ impl<'t> Walker<'t> {
|
||||
let name = self.text(name_node).to_string();
|
||||
|
||||
// TS/JS field definitions carry an explicit `type` field; the generic
|
||||
// scan is for other languages (#808).
|
||||
let type_text = node.child_by_field_name("type").map(|t| {
|
||||
// scan is for other languages (#808). A `property_signature` (an
|
||||
// interface member, #1638) carries a `type` field and no value, so it
|
||||
// reads the type field too: the generic scan's exclusion list covers
|
||||
// `identifier` but not the `property_identifier` an interface member is
|
||||
// named with, so it would stop on the name and make the signature repeat
|
||||
// it (`counts counts`) instead of naming the type. Mirrors
|
||||
// extractProperty's isTsJsField.
|
||||
let is_ts_js_field = matches!(
|
||||
node.kind(),
|
||||
"public_field_definition" | "field_definition" | "property_signature"
|
||||
);
|
||||
let type_node = if is_ts_js_field {
|
||||
node.child_by_field_name("type")
|
||||
} else {
|
||||
(0..node.named_child_count()).filter_map(|i| node.named_child(i)).find(|c| {
|
||||
!matches!(
|
||||
c.kind(),
|
||||
"modifier"
|
||||
| "modifiers"
|
||||
| "identifier"
|
||||
| "accessor_list"
|
||||
| "accessors"
|
||||
| "equals_value_clause"
|
||||
)
|
||||
})
|
||||
};
|
||||
let type_text = type_node.map(|t| {
|
||||
let raw = self.text(t);
|
||||
raw.strip_prefix(':').unwrap_or(raw).trim_start().to_string()
|
||||
});
|
||||
|
||||
@@ -55,10 +55,32 @@ impl Variant {
|
||||
/// typescriptExtractor.methodTypes / javascriptExtractor.methodTypes.
|
||||
fn is_method_type(v: Variant, kind: &str) -> bool {
|
||||
kind == "method_definition"
|
||||
|| (v.is_ts() && kind == "public_field_definition")
|
||||
|| (v.is_ts() && matches!(kind, "public_field_definition" | "method_signature"))
|
||||
|| (!v.is_ts() && kind == "field_definition")
|
||||
}
|
||||
|
||||
/// typescriptExtractor.propertyTypes. The interface counterpart of
|
||||
/// `public_field_definition`: it carries no value, so it is always a property
|
||||
/// and never goes through classify_ts_class_member (#1638).
|
||||
fn is_property_type(v: Variant, kind: &str) -> bool {
|
||||
v.is_ts() && kind == "property_signature"
|
||||
}
|
||||
|
||||
/// Method node types that spell a SIGNATURE — a declaration with no body (#1638).
|
||||
///
|
||||
/// They are a method of whatever type declares them and nothing on their own, so
|
||||
/// they must not take `extract_method`'s "no class-like parent, so treat it as a
|
||||
/// free function" fallback. The other method types can: a `method_definition`
|
||||
/// outside a class really is a function. This one appears outside a class only
|
||||
/// inside a type literal (`type Handle = { stop(): void }`), whose members
|
||||
/// `extract_ts_type_alias_members` already extracts and attaches to the alias
|
||||
/// (#359) — take the fallback and the file gains a phantom top-level
|
||||
/// `function stop` beside the real `Handle::stop`. Mirrors the TS extractor's
|
||||
/// SIGNATURE_METHOD_NODE_TYPES (extraction/tree-sitter.ts).
|
||||
fn is_signature_method_type(kind: &str) -> bool {
|
||||
kind == "method_signature"
|
||||
}
|
||||
|
||||
fn is_function_type(kind: &str) -> bool {
|
||||
matches!(kind, "function_declaration" | "generator_function_declaration" | "arrow_function" | "function_expression" | "generator_function")
|
||||
}
|
||||
@@ -622,7 +644,9 @@ impl<'t> Walker<'t> {
|
||||
} else if is_class_type(self.variant, kind) {
|
||||
self.extract_class(node);
|
||||
skip_children = true;
|
||||
} else if is_method_type(self.variant, kind) {
|
||||
} else if is_method_type(self.variant, kind)
|
||||
&& (!is_signature_method_type(kind) || self.inside_class_like())
|
||||
{
|
||||
if classify_ts_class_member(node) == Member::Property {
|
||||
let prop = self.extract_property(node);
|
||||
if let (Some((row, name)), Some(value)) = (prop, node.child_by_field_name("value")) {
|
||||
@@ -664,12 +688,22 @@ impl<'t> Walker<'t> {
|
||||
self.extract_call(node);
|
||||
} else if kind == "new_expression" {
|
||||
self.extract_instantiation(node);
|
||||
} else if self.variant.is_ts()
|
||||
&& matches!(kind, "property_signature" | "method_signature")
|
||||
&& self.inside_class_like()
|
||||
{
|
||||
let parent = self.top_row();
|
||||
self.extract_type_annotations(node, parent);
|
||||
} else if is_property_type(self.variant, kind) && self.inside_class_like() {
|
||||
// NOTE: `property_signature` / `method_signature` used to be handled
|
||||
// here together, hanging their type annotations off the ENCLOSING
|
||||
// INTERFACE — the only anchor available while the members themselves
|
||||
// went unextracted. Since #1638 `method_signature` is a method type
|
||||
// and `property_signature` a property type, so the method branch
|
||||
// above claims the first (under the same inside_class_like guard
|
||||
// this branch had) and this one extracts the second as a real node.
|
||||
// The `references` edges survive — extract_method and
|
||||
// extract_property each call extract_type_annotations — but now hang
|
||||
// off the member, the more precise anchor: `Api::fetch → PageId`
|
||||
// says which member wants the type, where `Api → PageId` only said
|
||||
// the file did.
|
||||
self.extract_property(node);
|
||||
self.scan_fn_ref_subtree(node, 0);
|
||||
skip_children = true;
|
||||
}
|
||||
|
||||
if !skip_children {
|
||||
|
||||
Reference in New Issue
Block a user