MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / extract_arrow_subject

Function extract_arrow_subject

src/subject_extraction.rs:291–487  ·  view source on GitHub ↗

Extract the subject expression before an arrow operator (`->`). `chars` is the line as a char slice. `arrow_pos` is the index of the `-` character (i.e. `chars[arrow_pos] == '-'` and `chars[arrow_pos + 1] == '>'`). Handles: - `$this->`, `$var->` (simple variable) - `$this->prop->` (property chain) - `$this?->prop->` (nullsafe property chain) - `app()->` (function call) - `$this->getService()->`

(chars: &[char], arrow_pos: usize)

Source from the content-addressed store, hash-verified

289/// - `Status::Active->` (enum case access)
290/// - `tryFrom($int)?->` (nullsafe after call)
291fn extract_arrow_subject(chars: &[char], arrow_pos: usize) -> String {
292 // Position just before the `->`
293 let mut end = arrow_pos;
294
295 // Skip whitespace
296 let mut i = end;
297 while i > 0 && chars[i - 1] == ' ' {
298 i -= 1;
299 }
300
301 // Skip the `?` of the nullsafe `?->` operator so that the rest
302 // of the extraction logic sees the expression before the `?`
303 // (e.g. the `)` of a call expression like `tryFrom($int)?->`,
304 // or a simple variable like `$var?->`).
305 if i > 0 && chars[i - 1] == '?' {
306 i -= 1;
307 }
308
309 // Update `end` so the fallback `extract_simple_variable` at the
310 // bottom of this function also starts from the correct position
311 // (past any `?` and whitespace).
312 end = i;
313
314 // ── Array access: detect `]` ──
315 // e.g. `$admins[0]->`, `$admins[$key]->`, `$config['key']->`
316 // Also handles chained access: `$response['items'][0]->`
317 //
318 // Walk backward through one or more balanced `[…]` pairs, collecting
319 // each bracket segment. The segments are stored innermost-first and
320 // reversed at the end so the final subject reads left-to-right.
321 if i > 0 && chars[i - 1] == ']' {
322 let mut segments: Vec<String> = Vec::new();
323 // Track the raw bracket ranges so we can reconstruct the
324 // array literal base when there is no `$var` prefix.
325 let mut bracket_ranges: Vec<(usize, usize)> = Vec::new();
326 let mut pos = i;
327
328 while pos > 0
329 && chars[pos - 1] == ']'
330 && let Some(bracket_open) = skip_balanced_brackets_back(chars, pos)
331 {
332 let inner: String = chars[bracket_open + 1..pos - 1].iter().collect();
333 let inner_trimmed = inner.trim();
334 // Quoted string key → preserve it so the resolver can look
335 // up the specific key in an array shape type annotation.
336 if (inner_trimmed.starts_with('\'') && inner_trimmed.ends_with('\''))
337 || (inner_trimmed.starts_with('"') && inner_trimmed.ends_with('"'))
338 {
339 segments.push(format!("[{}]", inner_trimmed));
340 } else {
341 // Generic / numeric index → strip to `[]`.
342 segments.push("[]".to_string());
343 }
344 bracket_ranges.push((bracket_open, pos));
345 pos = bracket_open;
346 }
347
348 if !segments.is_empty() {

Calls 7

extract_simple_variableFunction · 0.85
extract_call_subjectFunction · 0.85
iterMethod · 0.80
pushMethod · 0.80
is_emptyMethod · 0.45