Extract a reference from a member expression (property access)
(
&self,
node: &Node,
source: &str,
file_path: &str,
seen: &mut HashSet<(String, u32)>,
)
| 274 | |
| 275 | /// Extract a reference from a member expression (property access) |
| 276 | fn extract_member_reference( |
| 277 | &self, |
| 278 | node: &Node, |
| 279 | source: &str, |
| 280 | file_path: &str, |
| 281 | seen: &mut HashSet<(String, u32)>, |
| 282 | ) -> Option<Reference> { |
| 283 | // Skip if parent is a call expression (we'll handle that separately) |
| 284 | if let Some(parent) = node.parent() { |
| 285 | if parent.kind() == "call_expression" { |
| 286 | return None; |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | let property = node.child_by_field_name("property")?; |
| 291 | let symbol = property.utf8_text(source.as_bytes()).ok()?.to_string(); |
| 292 | let line = node.start_position().row as u32 + 1; |
| 293 | |
| 294 | // Skip common properties |
| 295 | if matches!( |
| 296 | symbol.as_str(), |
| 297 | "length" |
| 298 | | "size" |
| 299 | | "prototype" |
| 300 | | "constructor" |
| 301 | | "name" |
| 302 | | "message" |
| 303 | | "stack" |
| 304 | | "code" |
| 305 | | "data" |
| 306 | | "error" |
| 307 | | "success" |
| 308 | | "result" |
| 309 | | "value" |
| 310 | | "key" |
| 311 | | "id" |
| 312 | | "type" |
| 313 | | "status" |
| 314 | ) { |
| 315 | return None; |
| 316 | } |
| 317 | |
| 318 | let key = (symbol.clone(), line); |
| 319 | if seen.contains(&key) { |
| 320 | return None; |
| 321 | } |
| 322 | seen.insert(key); |
| 323 | |
| 324 | let context = source |
| 325 | .lines() |
| 326 | .nth(node.start_position().row) |
| 327 | .map(|s| s.trim().to_string()); |
| 328 | |
| 329 | Some(Reference { |
| 330 | symbol, |
| 331 | file: file_path.to_string(), |
| 332 | line, |
| 333 | column: Some(property.start_position().column as u32), |