Skip to content
Open
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
32 changes: 23 additions & 9 deletions src/ide/completion/function/params.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use cairo_lang_semantic::items::function_with_body::FunctionWithBodySemantic;
use cairo_lang_semantic::lookup_item::LookupItemEx;
use cairo_lang_syntax::node::Token;
use cairo_lang_syntax::node::ast::PathSegment;
use cairo_lang_syntax::node::ast::{self, PathSegment};
use cairo_lang_syntax::node::kind::SyntaxKind;
use itertools::Itertools;
use lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails};

Expand All @@ -18,20 +19,33 @@ pub fn params_completions<'db>(
ctx: &AnalysisContext<'db>,
was_node_corrected: bool,
) -> Vec<CompletionItemOrderable> {
let (params, typed_text) = if let Some(path) = expr_selector(db, &ctx.node)
&& dot_expr_rhs(db, &ctx.node, was_node_corrected).is_none()
if dot_expr_rhs(db, &ctx.node, was_node_corrected).is_some() {
return Default::default();
}

let Some(lookup_item_id) = ctx.lookup_item_id else { return Default::default() };
let Some(function_id) = lookup_item_id.function_with_body() else { return Default::default() };
let Ok(signature) = db.function_with_body_signature(function_id) else {
return Default::default();
};

let typed_text = if let Some(path) = expr_selector(db, &ctx.node)
&& let [PathSegment::Simple(segment)] =
path.segments(db).elements(db).take(2).collect_vec().as_slice()
&& let Some(lookup_item_id) = ctx.lookup_item_id
&& let Some(function_id) = lookup_item_id.function_with_body()
&& let Ok(signature) = db.function_with_body_signature(function_id)
{
(signature.params.clone(), segment.ident(db).token(db).text(db).to_string(db))
segment.ident(db).token(db).text(db).to_string(db)
} else if ctx.node.kind(db) == SyntaxKind::ExprBlock
|| ast::Statement::is_variant(ctx.node.kind(db))
|| ctx.node.parent(db).is_some_and(|p| p.kind(db) == SyntaxKind::ExprBlock)
|| ctx.node.parent(db).is_some_and(|p| ast::Statement::is_variant(p.kind(db)))
{
String::new()
} else {
Default::default()
return Default::default();
};

params
signature
.params
.iter()
.filter_map(|param| {
let param_name = param.name.to_string(db);
Expand Down
30 changes: 21 additions & 9 deletions src/ide/completion/function/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cairo_lang_filesystem::ids::FileLongId;
use cairo_lang_semantic::FunctionBody;
use cairo_lang_semantic::items::function_with_body::FunctionWithBodySemantic;
use cairo_lang_semantic::lookup_item::LookupItemEx;
use cairo_lang_syntax::node::ast::{PathSegment, StatementLet};
use cairo_lang_syntax::node::ast::{self, PathSegment, StatementLet};
use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_syntax::node::{Token, TypedSyntaxNode};
use itertools::Itertools;
Expand All @@ -23,18 +23,30 @@ pub fn variables_completions<'db>(
ctx: &AnalysisContext<'db>,
was_node_corrected: bool,
) -> Vec<CompletionItemOrderable> {
if let Some(path) = expr_selector(db, &ctx.node)
&& dot_expr_rhs(db, &ctx.node, was_node_corrected).is_none()
if dot_expr_rhs(db, &ctx.node, was_node_corrected).is_some() {
return Default::default();
}

let Some(lookup_item_id) = ctx.lookup_item_id else { return Default::default() };
let Some(function_id) = lookup_item_id.function_with_body() else { return Default::default() };
let Ok(body) = db.function_body(function_id) else { return Default::default() };

let typed_text = if let Some(path) = expr_selector(db, &ctx.node)
&& let [PathSegment::Simple(segment)] =
path.segments(db).elements(db).take(2).collect_vec().as_slice()
&& let Some(lookup_item_id) = ctx.lookup_item_id
&& let Some(function_id) = lookup_item_id.function_with_body()
&& let Ok(body) = db.function_body(function_id)
{
patterns(body, db, ctx, segment.ident(db).token(db).text(db).to_string(db).as_str())
segment.ident(db).token(db).text(db).to_string(db)
} else if ctx.node.kind(db) == SyntaxKind::ExprBlock
|| ast::Statement::is_variant(ctx.node.kind(db))
|| ctx.node.parent(db).is_some_and(|p| p.kind(db) == SyntaxKind::ExprBlock)
|| ctx.node.parent(db).is_some_and(|p| ast::Statement::is_variant(p.kind(db)))
{
String::new()
} else {
Default::default()
}
return Default::default();
};

patterns(body, db, ctx, typed_text.as_str())
}

fn patterns<'db>(
Expand Down
8 changes: 7 additions & 1 deletion src/ide/completion/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use cairo_lang_semantic::lsp_helpers::LspHelpers;
use cairo_lang_semantic::resolve::{ResolvedConcreteItem, ResolvedGenericItem};
use cairo_lang_semantic::{ConcreteTypeId, TypeLongId};
use cairo_lang_syntax::node::TypedSyntaxNode;
use cairo_lang_syntax::node::ast::{ExprPath, PathSegment};
use cairo_lang_syntax::node::ast::{ExprPath, PathSegment, Statement};
use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_utils::OptionFrom;
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
Expand Down Expand Up @@ -48,8 +48,14 @@ pub fn path_suffix_completions<'db>(
return Default::default();
};

let is_empty_body_context = ctx.node.kind(db) == SyntaxKind::ExprBlock
|| Statement::is_variant(ctx.node.kind(db))
|| ctx.node.parent(db).is_some_and(|p| p.kind(db) == SyntaxKind::ExprBlock)
|| ctx.node.parent(db).is_some_and(|p| Statement::is_variant(p.kind(db)));

let (typed_text, last_typed_segment) = match get_typed_text_and_last_segment(db, ctx) {
(Some(typed_text), Some(last_typed_segment)) => (typed_text, last_typed_segment),
_ if is_empty_body_context => (vec![], SmolStrId::from(db, "")),
_ => return Default::default(),
};

Expand Down
14 changes: 11 additions & 3 deletions src/ide/completion/pattern.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashSet;

use cairo_lang_defs::ids::GenericTypeId;
use cairo_lang_defs::ids::{GenericTypeId, LanguageElementId};
use cairo_lang_semantic::diagnostic::{NotFoundItemType, SemanticDiagnostics};
use cairo_lang_semantic::items::structure::StructSemantic;
use cairo_lang_semantic::resolve::ResolutionContext;
Expand All @@ -16,6 +16,7 @@ use crate::ide::completion::helpers::formatting::format_type_in_node_context;
use crate::ide::completion::{CompletionItemOrderable, CompletionRelevance};
use crate::lang::db::AnalysisDatabase;
use crate::lang::text_matching::text_matches;
use crate::lang::visibility::peek_visible_in_with_edition;
use crate::{
ide::completion::path::path_prefix_completions, lang::analysis_context::AnalysisContext,
};
Expand All @@ -24,7 +25,7 @@ pub fn struct_pattern_completions<'db>(
db: &'db AnalysisDatabase,
ctx: &AnalysisContext<'db>,
) -> Vec<CompletionItemOrderable> {
let (all_members, existing_members, typed) = if let Some(pattern) =
let (all_members, existing_members, typed, struct_parent_module) = if let Some(pattern) =
ctx.node.ancestor_of_type::<PatternStruct>(db)
&& let typed = ctx.node.ancestor_of_type::<PatternIdentifier>(db).filter(|ident| {
ident.as_syntax_node().parent(db).and_then(|p| p.parent(db))
Expand All @@ -39,11 +40,18 @@ pub fn struct_pattern_completions<'db>(
)
&& let Ok(all_members) = db.struct_members(struct_item)
{
(all_members, pattern.params(db).elements(db), typed)
(all_members, pattern.params(db).elements(db), typed, struct_item.parent_module(db))
} else {
return Default::default();
};

// Don't propose fields if any are not visible from the current module.
if !all_members.values().all(|member| {
peek_visible_in_with_edition(db, member.visibility, struct_parent_module, ctx.module_id)
}) {
return Default::default();
}

let existing_members: HashSet<_> = existing_members
.into_iter()
.filter_map(|member| match member {
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/completions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod path;
mod patterns;
mod structs;
mod traits;
mod untyped;
mod uses;
mod vars_and_params;

Expand Down
17 changes: 0 additions & 17 deletions tests/e2e/completions/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,23 +443,6 @@ fn duplicated_completion_without_explicit_path() {
"#);
}

// FIXME(#957)
#[test]
fn no_text_in_function_context() {
test_transform_plain!(Completion, completion_fixture(), "
struct MyStruct {}

fn a() {
<caret>
}
",@r#"
caret = """
<caret>
"""
completions = []
"#);
}

#[test]
fn no_text_last_segment_in_function_context() {
test_transform_plain!(Completion, completion_fixture(), "
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/completions/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ fn struct_unavailable() {
}

fn a() {
let foo:Foo {
let foo::Foo {
qwerty,
<caret>
} = foo:Foo { }
} = foo::Foo { }
}
",@r#"
caret = """
Expand Down
Loading