Skip to content

Commit 1808fe3

Browse files
lf-facebook-github-bot
authored andcommitted
fix(starlark_lsp): hover should give docs for functions with no docstrings
Summary: I don't know why this was done, but it makes buck2 lsp have largely broken hover on most real code. This area of the code needs tests. I will look into writing a test fixture when I triage more of these bugs. Part of facebook/buck2#899 X-link: facebook/buck2#934 Reviewed By: JakobDegen Differential Revision: D74042714 fbshipit-source-id: 45cb2462c1360a0b31058ec62ccb114b569a85eb
1 parent e868eb5 commit 1808fe3

File tree

4 files changed

+105
-38
lines changed

4 files changed

+105
-38
lines changed

starlark/src/docs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ pub struct DocFunction {
8787
/// they are present.
8888
pub docs: Option<DocString>,
8989
/// The parameters that this function takes. Docs for these parameters should generally be
90-
/// extracted from the main docstring's details.
90+
/// extracted from the main docstring's details, but may be extracted from the definition if the
91+
/// docstring is not present.
9192
pub params: DocParams,
9293
/// Details about what this function returns.
9394
pub ret: DocReturn,

starlark_lsp/src/docs.rs

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use starlark_syntax::syntax::ast::AstStmtP;
3030
use starlark_syntax::syntax::ast::DefP;
3131
use starlark_syntax::syntax::ast::ExprP;
3232
use starlark_syntax::syntax::ast::StmtP;
33+
use starlark_syntax::syntax::def::DefParamKind;
3334
use starlark_syntax::syntax::def::DefParams;
3435

3536
/// Given the AST node for a `def` statement, return a `DocFunction` if the
@@ -38,38 +39,45 @@ pub(crate) fn get_doc_item_for_def<P: AstPayload>(
3839
def: &DefP<P>,
3940
codemap: &CodeMap,
4041
) -> Option<DocFunction> {
41-
if let Some(doc_string) = peek_docstring(&def.body) {
42-
// TODO(nga): do not unwrap.
43-
let def = DefParams::unpack(&def.params, codemap).unwrap();
42+
let raw_docstring = peek_docstring(&def.body);
43+
// TODO(nga): do not unwrap.
44+
let def = DefParams::unpack(&def.params, codemap).unwrap();
4445

45-
let dp = |i: usize| -> DocParam {
46-
let param = &def.params[i];
47-
DocParam {
48-
name: param.ident.ident.clone(),
49-
docs: None,
50-
typ: Ty::any(),
51-
default_value: None,
46+
let dp = |i: usize| -> DocParam {
47+
let param = &def.params[i];
48+
49+
// Just get the default's expr directly out of the source file for now
50+
// TODO(jadel): maybe this should be re-formatted somehow?
51+
let default_value = match param.node.kind {
52+
DefParamKind::Regular(_, Some(default)) => {
53+
Some(codemap.source_span(default.span).to_owned())
5254
}
55+
_ => None,
5356
};
5457

55-
let doc_params = DocParams {
56-
pos_only: def.indices.pos_only().map(dp).collect(),
57-
pos_or_named: def.indices.pos_or_named().map(dp).collect(),
58-
args: def.indices.args.map(|a| a as usize).map(dp),
59-
named_only: def.indices.named_only(def.params.len()).map(dp).collect(),
60-
kwargs: def.indices.kwargs.map(|a| a as usize).map(dp),
61-
};
62-
let doc_function = DocFunction::from_docstring(
63-
DocStringKind::Starlark,
64-
doc_params,
65-
// TODO: Figure out how to get a `Ty` from the `def.return_type`.
66-
Ty::any(),
67-
Some(doc_string),
68-
);
69-
Some(doc_function)
70-
} else {
71-
None
72-
}
58+
DocParam {
59+
name: param.ident.ident.clone(),
60+
docs: None,
61+
typ: Ty::any(),
62+
default_value,
63+
}
64+
};
65+
66+
let doc_params = DocParams {
67+
pos_only: def.indices.pos_only().map(dp).collect(),
68+
pos_or_named: def.indices.pos_or_named().map(dp).collect(),
69+
args: def.indices.args.map(|a| a as usize).map(dp),
70+
named_only: def.indices.named_only(def.params.len()).map(dp).collect(),
71+
kwargs: def.indices.kwargs.map(|a| a as usize).map(dp),
72+
};
73+
let doc_function = DocFunction::from_docstring(
74+
DocStringKind::Starlark,
75+
doc_params,
76+
// TODO: Figure out how to get a `Ty` from the `def.return_type`.
77+
Ty::any(),
78+
raw_docstring,
79+
);
80+
Some(doc_function)
7381
}
7482

7583
pub(crate) fn get_doc_item_for_assign<P: AstPayload>(

starlark_lsp/src/symbols.rs

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,15 @@ pub(crate) fn find_symbols_at_location<P: AstPayload>(
166166
mod tests {
167167
use std::collections::HashMap;
168168

169+
use starlark::docs::DocFunction;
170+
use starlark::docs::DocItem;
171+
use starlark::docs::DocMember;
172+
use starlark::docs::DocParam;
173+
use starlark::docs::DocParams;
174+
use starlark::docs::DocReturn;
169175
use starlark::syntax::AstModule;
170176
use starlark::syntax::Dialect;
177+
use starlark::typing::Ty;
171178
use starlark_syntax::codemap::ResolvedPos;
172179
use starlark_syntax::syntax::module::AstModuleFields;
173180

@@ -181,7 +188,7 @@ mod tests {
181188
"t.star",
182189
r#"load("foo.star", "exported_a", renamed = "exported_b")
183190
184-
def method(param):
191+
def method(param = True):
185192
pass
186193
187194
my_var = True
@@ -191,12 +198,14 @@ my_var = True
191198
)
192199
.unwrap();
193200

201+
let foo = find_symbols_at_location(
202+
ast_module.codemap(),
203+
ast_module.statement(),
204+
ResolvedPos { line: 6, column: 0 },
205+
);
206+
194207
assert_eq!(
195-
find_symbols_at_location(
196-
ast_module.codemap(),
197-
ast_module.statement(),
198-
ResolvedPos { line: 6, column: 0 },
199-
),
208+
foo,
200209
HashMap::from([
201210
(
202211
"exported_a".to_owned(),
@@ -224,7 +233,25 @@ my_var = True
224233
name: "method".to_owned(),
225234
detail: None,
226235
kind: SymbolKind::Method,
227-
doc: None,
236+
doc: Some(DocItem::Member(DocMember::Function(DocFunction {
237+
docs: None,
238+
params: DocParams {
239+
pos_only: vec![],
240+
pos_or_named: vec![DocParam {
241+
name: String::from("param"),
242+
docs: None,
243+
typ: Ty::any(),
244+
default_value: Some(String::from("True"))
245+
}],
246+
args: None,
247+
named_only: vec![],
248+
kwargs: None
249+
},
250+
ret: DocReturn {
251+
docs: None,
252+
typ: Ty::any()
253+
}
254+
}))),
228255
param: None,
229256
},
230257
),
@@ -291,7 +318,25 @@ my_var = True
291318
name: "method".to_owned(),
292319
detail: None,
293320
kind: SymbolKind::Method,
294-
doc: None,
321+
doc: Some(DocItem::Member(DocMember::Function(DocFunction {
322+
docs: None,
323+
params: DocParams {
324+
pos_only: vec![],
325+
pos_or_named: vec![DocParam {
326+
name: String::from("param"),
327+
docs: None,
328+
typ: Ty::any(),
329+
default_value: None
330+
}],
331+
args: None,
332+
named_only: vec![],
333+
kwargs: None
334+
},
335+
ret: DocReturn {
336+
docs: None,
337+
typ: Ty::any()
338+
}
339+
}))),
295340
param: None,
296341
},
297342
),
@@ -302,7 +347,15 @@ my_var = True
302347
detail: None,
303348
kind: SymbolKind::Variable,
304349
doc: None,
305-
param: None,
350+
param: Some((
351+
String::from("param"),
352+
DocParam {
353+
name: String::from("param"),
354+
docs: None,
355+
typ: Ty::any(),
356+
default_value: None
357+
}
358+
)),
306359
}
307360
),
308361
(

starlark_syntax/src/syntax/def.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,14 @@ pub enum DefParamKind<'a, P: AstPayload> {
4949
Kwargs,
5050
}
5151

52+
/// One function parameter.
5253
pub struct DefParam<'a, P: AstPayload> {
54+
/// Name of the parameter.
5355
pub ident: &'a AstAssignIdentP<P>,
56+
/// Whether this is a regular parameter (with optional default) or a varargs construct (*args,
57+
/// **kwargs).
5458
pub kind: DefParamKind<'a, P>,
59+
/// Type of the parameter. This is None when a type is not specified.
5560
pub ty: Option<&'a AstTypeExprP<P>>,
5661
}
5762

0 commit comments

Comments
 (0)