Skip to content

Commit 6dc0a3f

Browse files
committed
Resolve Foo::class parameter defaults to FQN in extract_parameters
1 parent 5e4a597 commit 6dc0a3f

3 files changed

Lines changed: 60 additions & 4 deletions

File tree

src/parser/ast_update.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,21 @@ impl Backend {
246246
// like `if (! function_exists('...'))`) using the shared helper
247247
// which recurses into if/block statements.
248248
let mut functions = Vec::new();
249+
// Update doc_ctx with the file's use-map and namespace so that
250+
// parameter default values (e.g. `Application::class`) can be
251+
// resolved to FQNs during extraction.
252+
let func_doc_ctx = DocblockCtx {
253+
trivias: doc_ctx.trivias,
254+
content: doc_ctx.content,
255+
php_version: doc_ctx.php_version,
256+
use_map: use_map.clone(),
257+
namespace: namespace.clone(),
258+
};
249259
Self::extract_functions_from_statements(
250260
program.statements.iter(),
251261
&mut functions,
252262
&namespace,
253-
Some(&doc_ctx),
263+
Some(&func_doc_ctx),
254264
);
255265
if !functions.is_empty() {
256266
// Resolve class-like names in function return types and

src/parser/mod.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,15 @@ pub(crate) fn extract_parameters(
938938
let span = dv.value.span();
939939
let start = span.start.offset as usize;
940940
let end = span.end.offset as usize;
941-
src.get(start..end).map(|s| s.trim().to_string())
941+
let raw = src.get(start..end)?.trim().to_string();
942+
// Resolve `ClassName::class` to its FQN so that
943+
// downstream template substitution can find the class.
944+
if let Some(class_name) = raw.strip_suffix("::class") {
945+
let fqn = resolve_default_class_name(class_name, doc_ctx);
946+
Some(format!("{}::class", fqn))
947+
} else {
948+
Some(raw)
949+
}
942950
});
943951

944952
ParameterInfo {
@@ -956,6 +964,35 @@ pub(crate) fn extract_parameters(
956964
.collect()
957965
}
958966

967+
/// Resolve a class name from a parameter default (`Foo::class`) to its FQN
968+
/// using the file's use-map and namespace from [`DocblockCtx`].
969+
fn resolve_default_class_name(name: &str, doc_ctx: Option<&DocblockCtx<'_>>) -> String {
970+
// Already fully-qualified.
971+
if let Some(stripped) = name.strip_prefix('\\') {
972+
return stripped.to_string();
973+
}
974+
let Some(ctx) = doc_ctx else {
975+
return name.to_string();
976+
};
977+
// Check use-map (handles `use App\Application;` → "Application" → "App\Application").
978+
if let Some(fqn) = ctx.use_map.get(name) {
979+
return fqn.clone();
980+
}
981+
// If the name has a namespace prefix (e.g. `Sub\Foo`), check the first segment.
982+
if let Some(first_seg) = name.split('\\').next()
983+
&& first_seg != name
984+
&& let Some(base) = ctx.use_map.get(first_seg)
985+
{
986+
let rest = &name[first_seg.len() + 1..];
987+
return format!("{}\\{}", base, rest);
988+
}
989+
// Prepend file namespace if present.
990+
if let Some(ref ns) = ctx.namespace {
991+
return format!("{}\\{}", ns, name);
992+
}
993+
name.to_string()
994+
}
995+
959996
/// Extract visibility from a set of modifiers.
960997
/// Defaults to `Public` if no visibility modifier is present.
961998
pub(crate) fn extract_visibility<'a>(

tests/integration/completion_generics.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5019,11 +5019,20 @@ async fn test_method_template_self_class_resolves_to_enclosing_class() {
50195019
backend.did_open(open_params).await;
50205020

50215021
let line = text.lines().position(|l| l.contains("$child->")).unwrap() as u32;
5022-
let col = text.lines().nth(line as usize).unwrap().find("$child->").unwrap() as u32 + 8;
5022+
let col = text
5023+
.lines()
5024+
.nth(line as usize)
5025+
.unwrap()
5026+
.find("$child->")
5027+
.unwrap() as u32
5028+
+ 8;
50235029
let completion_params = CompletionParams {
50245030
text_document_position: TextDocumentPositionParams {
50255031
text_document: TextDocumentIdentifier { uri },
5026-
position: Position { line, character: col },
5032+
position: Position {
5033+
line,
5034+
character: col,
5035+
},
50275036
},
50285037
work_done_progress_params: Default::default(),
50295038
partial_result_params: Default::default(),

0 commit comments

Comments
 (0)