Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 69 additions & 10 deletions tooling/lsp/src/requests/signature_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ use async_lsp::lsp_types::{
};
use fm::FileId;
use noirc_errors::{Location, Span};
use noirc_frontend::ast::AttributeTarget;
use noirc_frontend::node_interner::FuncId;
use noirc_frontend::token::{MetaAttribute, MetaAttributeName, SecondaryAttributeKind};
use noirc_frontend::{
ParsedModule, Type,
ast::{
CallExpression, ConstrainExpression, ConstrainKind, Expression, FunctionReturnType,
MethodCallExpression, Statement, Visitor,
},
hir_def::{function::FuncMeta, stmt::HirPattern},
hir_def::stmt::HirPattern,
node_interner::{NodeInterner, ReferenceId},
parser::Item,
};
Expand Down Expand Up @@ -70,6 +73,7 @@ impl<'a> SignatureFinder<'a> {
arguments_span: Span,
name_span: Span,
has_self: bool,
is_attribute: bool,
) {
if self.signature_help.is_some() {
return;
Expand All @@ -84,11 +88,12 @@ impl<'a> SignatureFinder<'a> {

// Check if the call references a named function
if let Some(ReferenceId::Function(func_id)) = self.interner.find_referenced(location) {
let name = self.interner.function_name(&func_id);
let func_meta = self.interner.function_meta(&func_id);

let signature_information =
self.func_meta_signature_information(func_meta, name, active_parameter, has_self);
let signature_information = self.func_id_signature_information(
func_id,
active_parameter,
has_self,
is_attribute,
);
self.set_signature_help(signature_information);
return;
}
Expand All @@ -111,13 +116,18 @@ impl<'a> SignatureFinder<'a> {
}
}

fn func_meta_signature_information(
fn func_id_signature_information(
&self,
func_meta: &FuncMeta,
name: &str,
func_id: FuncId,
active_parameter: Option<u32>,
has_self: bool,
is_attribute: bool,
) -> SignatureInformation {
let name = self.interner.function_name(&func_id);
let func_meta = self.interner.function_meta(&func_id);
let mut attributes = self.interner.function_attributes(&func_id).secondary.iter();
let is_varargs = attributes.any(|attr| attr.kind == SecondaryAttributeKind::Varargs);

let enum_type_id = match (func_meta.type_id, func_meta.enum_variant_index) {
(Some(type_id), Some(_)) => Some(type_id),
_ => None,
Expand All @@ -126,6 +136,10 @@ impl<'a> SignatureFinder<'a> {
let mut label = String::new();
let mut parameters = Vec::new();

if is_varargs {
label.push_str("#[varargs]\n");
}

if let Some(enum_type_id) = enum_type_id {
label.push_str("enum ");
label.push_str(self.interner.get_type(enum_type_id).borrow().name.as_str());
Expand All @@ -136,7 +150,16 @@ impl<'a> SignatureFinder<'a> {

label.push_str(name);
label.push('(');
for (index, (pattern, typ, _)) in func_meta.parameters.0.iter().enumerate() {

let mut func_parameters = func_meta.parameters.0.iter();

if is_attribute {
// The first argument is `FunctionDefinition`, `TypeDefinition`, etc., and we don't
// want to show that in the signature help.
func_parameters.next();
}

for (index, (pattern, typ, _)) in func_parameters.enumerate() {
if index > 0 {
label.push_str(", ");
}
Expand Down Expand Up @@ -351,12 +374,14 @@ impl Visitor for SignatureFinder<'_> {
let span = call_expression.func.location.span;
let name_span = Span::from(span.end() - 1..span.end());
let has_self = false;
let is_attribute = false;

self.try_compute_signature_help(
&call_expression.arguments,
arguments_span,
name_span,
has_self,
is_attribute,
);

false
Expand All @@ -373,12 +398,14 @@ impl Visitor for SignatureFinder<'_> {
Span::from(method_call_expression.method_name.span().end() + 1..span.end() - 1);
let name_span = method_call_expression.method_name.span();
let has_self = true;
let is_attribute = false;

self.try_compute_signature_help(
&method_call_expression.arguments,
arguments_span,
name_span,
has_self,
is_attribute,
);

false
Expand Down Expand Up @@ -415,4 +442,36 @@ impl Visitor for SignatureFinder<'_> {

false
}

fn visit_meta_attribute(
&mut self,
attribute: &MetaAttribute,
_target: AttributeTarget,
_span: Span,
) -> bool {
let MetaAttributeName::Path(path) = &attribute.name else {
return false;
};

let name_span = path.span();
let arguments_span = if attribute.arguments.is_empty() {
Span::from(name_span.end() + 1..name_span.end() + 2)
} else {
Span::from(
name_span.end() + 1..attribute.arguments.last().unwrap().location.span.end() + 1,
)
};

let has_self = false;
let is_attribute = true;
self.try_compute_signature_help(
&attribute.arguments,
arguments_span,
name_span,
has_self,
is_attribute,
);

false
}
}
51 changes: 51 additions & 0 deletions tooling/lsp/src/requests/signature_help/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,55 @@ mod signature_help_tests {

assert_eq!(signature.active_parameter, Some(0));
}

#[test]
async fn test_signature_help_for_macro_attribute() {
let src = r#"
comptime fn foo(_: FunctionDefinition, x: i32, y: Field) { }

#[foo(>|<1, 2)]
fn bar() {
}
"#;

let signature_help = get_signature_help(src).await;
assert_eq!(signature_help.signatures.len(), 1);

let signature = &signature_help.signatures[0];
assert_eq!(signature.label, "fn foo(x: i32, y: Field)");

let params = signature.parameters.as_ref().unwrap();
assert_eq!(params.len(), 2);

check_label(&signature.label, &params[0].label, "x: i32");
check_label(&signature.label, &params[1].label, "y: Field");

assert_eq!(signature.active_parameter, Some(0));
}

#[test]
async fn test_signature_help_for_varargs_macro_attribute() {
let src = r#"
#[varargs]
comptime fn foo(_: FunctionDefinition, x: i32, y: [Field]) { }

#[foo(>|<1, 2)]
fn bar() {
}
"#;

let signature_help = get_signature_help(src).await;
assert_eq!(signature_help.signatures.len(), 1);

let signature = &signature_help.signatures[0];
assert_eq!(signature.label, "#[varargs]\nfn foo(x: i32, y: [Field])");

let params = signature.parameters.as_ref().unwrap();
assert_eq!(params.len(), 2);

check_label(&signature.label, &params[0].label, "x: i32");
check_label(&signature.label, &params[1].label, "y: [Field]");

assert_eq!(signature.active_parameter, Some(0));
}
}
Loading