Skip to content

Commit 7343775

Browse files
committed
Type hint completion in definitions
1 parent 581da7e commit 7343775

5 files changed

Lines changed: 1562 additions & 0 deletions

File tree

example.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,32 @@ function handleIntersection(User&Loggable $entity): void {
353353
$r = new Response(200); // → Response(${1:$statusCode})
354354

355355

356+
// ── Type Hint Completion in Definitions ─────────────────────────────────────
357+
// When typing a type hint inside a function/method definition, return type,
358+
// or property declaration, PHPantomLSP offers PHP native scalar types
359+
// (string, int, float, bool, …) alongside class-name completions.
360+
// Constants and standalone functions are excluded since they're invalid
361+
// in type positions.
362+
363+
// Try triggering completion after the `(` or `,` in these signatures:
364+
function typeHintDemo(User $user, string $name): User { return $user; }
365+
// ↑ type hint ↑ scalar ↑ return type
366+
367+
// Union types, nullable types, and intersection types also work:
368+
function unionDemo(string|int $value, ?User $maybe): User|null { return $maybe; }
369+
// ↑ after | ↑ after ? ↑ after |
370+
371+
// Property type hints after visibility modifiers:
372+
// (see Model class below — `public readonly string $uuid`)
373+
374+
// Promoted constructor parameters with modifiers:
375+
// (see Customer class below — `private readonly string $email`)
376+
377+
// Closures and arrow functions:
378+
$typedClosure = function(User $u): string { return $u->getName(); };
379+
$typedArrow = fn(int $x): float => $x * 1.5;
380+
381+
356382
// ── parent:: Completion ─────────────────────────────────────────────────────
357383
// Open AdminUser's constructor and toArray() in scaffolding below for
358384
// parent:: examples (inherited methods, overridden methods, constants).

src/completion/handler.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,57 @@ impl Backend {
219219
}
220220
}
221221

222+
// ── Type hint completion in definitions ─────────────────
223+
// When the cursor is at a type-hint position inside a
224+
// function/method parameter list, return type, or property
225+
// declaration, offer PHP native scalar types alongside
226+
// class-name completions (but NOT constants or standalone
227+
// functions, which are invalid in type positions).
228+
//
229+
// This check MUST run before named-argument detection so
230+
// that typing inside a function *definition* like
231+
// `function foo(Us|)` offers type completions rather than
232+
// named-argument suggestions for a same-named function.
233+
if let Some(th_ctx) = crate::completion::type_hint_completion::detect_type_hint_context(
234+
&content, position,
235+
) {
236+
let partial_lower = th_ctx.partial.to_lowercase();
237+
let mut items: Vec<CompletionItem> =
238+
crate::completion::type_hint_completion::PHP_NATIVE_TYPES
239+
.iter()
240+
.filter(|t| t.to_lowercase().starts_with(&partial_lower))
241+
.enumerate()
242+
.map(|(idx, t)| CompletionItem {
243+
label: t.to_string(),
244+
kind: Some(CompletionItemKind::KEYWORD),
245+
detail: Some("PHP built-in type".to_string()),
246+
insert_text: Some(t.to_string()),
247+
filter_text: Some(t.to_string()),
248+
sort_text: Some(format!("0_{:03}", idx)),
249+
..CompletionItem::default()
250+
})
251+
.collect();
252+
253+
let (class_items, class_incomplete) = self.build_class_name_completions(
254+
&file_use_map,
255+
&file_namespace,
256+
&th_ctx.partial,
257+
&content,
258+
false, // not a `new` context
259+
);
260+
items.extend(class_items);
261+
262+
if !items.is_empty() {
263+
return Ok(Some(CompletionResponse::List(CompletionList {
264+
is_incomplete: class_incomplete,
265+
items,
266+
})));
267+
}
268+
// Even when empty, return early so we don't fall through
269+
// to named-arg or class+constant+function completion.
270+
return Ok(None);
271+
}
272+
222273
// ── Named argument completion ───────────────────────────
223274
// When the cursor is inside the parentheses of a function or
224275
// method call, offer parameter names as `name:` completions.

src/completion/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
/// - **catch_completion**: Smart exception type completion inside `catch()` clauses
1515
/// - **conditional_resolution**: PHPStan conditional return type resolution at call sites
1616
/// - **type_narrowing**: instanceof / assert / custom type guard narrowing
17+
/// - **type_hint_completion**: Type completion inside function/method parameter lists,
18+
/// return types, and property declarations (offers native PHP types + class names)
1719
/// - **variable_resolution**: Variable type resolution via assignment scanning
1820
/// - **closure_resolution**: Closure and arrow-function parameter resolution
1921
///
@@ -31,6 +33,7 @@ pub mod named_args;
3133
pub mod phpdoc;
3234
pub mod resolver;
3335
pub mod target;
36+
pub(crate) mod type_hint_completion;
3437
pub mod type_narrowing;
3538
pub mod use_edit;
3639
pub mod variable_completion;

0 commit comments

Comments
 (0)