Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Find definition for member declarations, fix definition nodes, add SyntaxNodeExt::cast #255

Merged
merged 1 commit into from
Feb 6, 2025
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
28 changes: 25 additions & 3 deletions src/lang/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::iter;
use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::{
GenericTypeId, LanguageElementId, LocalVarLongId, LookupItemId, MemberId, ModuleId,
ModuleItemId, NamedLanguageElementId, SubmoduleLongId, TopLevelLanguageElementId, TraitItemId,
VarId,
ModuleItemId, NamedLanguageElementId, StructLongId, SubmoduleLongId, TopLevelLanguageElementId,
TraitItemId, VarId,
};
use cairo_lang_diagnostics::ToOption;
use cairo_lang_doc::db::DocGroup;
Expand Down Expand Up @@ -445,8 +445,12 @@ fn find_definition(

if let Some(member_id) = try_extract_member(db, identifier, lookup_items)
.or_else(|| try_extract_member_from_constructor(db, identifier, lookup_items))
.or_else(|| try_extract_member_declaration(db, identifier))
{
return Some((ResolvedItem::Member(member_id), member_id.untyped_stable_ptr(db)));
return Some((
ResolvedItem::Member(member_id),
member_id.stable_ptr(db).lookup(db).name(db).stable_ptr().untyped(),
));
}

if let Some(var_id) = try_extract_variable_declaration(db, identifier, lookup_items) {
Expand Down Expand Up @@ -572,6 +576,24 @@ fn try_extract_member(
}
}

/// Extracts [`MemberId`] if the [`TerminalIdentifier`] is a name of member in struct declaration.
fn try_extract_member_declaration(
db: &AnalysisDatabase,
identifier: &ast::TerminalIdentifier,
) -> Option<MemberId> {
let member = identifier.as_syntax_node().parent()?.cast::<ast::Member>(db)?;
mkaput marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(member.name(db), *identifier);
let item_struct = member.as_syntax_node().parent_of_type::<ast::ItemStruct>(db)?;
let struct_id = StructLongId(
db.find_module_file_containing_node(&item_struct.as_syntax_node())?,
item_struct.stable_ptr(),
)
.intern(db);
let struct_members = db.struct_members(struct_id).ok()?;
let member_semantic = struct_members.get(&member.name(db).text(db))?;
Some(member_semantic.id)
}

/// Lookups if the identifier is a declaration of a variable/param in one of the lookup items.
///
/// Declaration identifiers aren't kept in `ResolvedData`, which is searched for by
Expand Down
7 changes: 7 additions & 0 deletions src/lang/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};

pub trait SyntaxNodeExt {
/// Mirror of [`TypedSyntaxNode::cast`].
fn cast<T: TypedSyntaxNode>(self, db: &dyn SyntaxGroup) -> Option<T>;

/// Creates an iterator that yields ancestors of this syntax node.
fn ancestors(&self) -> impl Iterator<Item = SyntaxNode>;

Expand Down Expand Up @@ -40,6 +43,10 @@ pub trait SyntaxNodeExt {
}

impl SyntaxNodeExt for SyntaxNode {
fn cast<T: TypedSyntaxNode>(self, db: &dyn SyntaxGroup) -> Option<T> {
T::cast(db, self)
}

fn ancestors(&self) -> impl Iterator<Item = SyntaxNode> {
// We aren't reusing `ancestors_with_self` here to avoid cloning this node.
iter::successors(self.parent(), SyntaxNode::parent)
Expand Down
11 changes: 5 additions & 6 deletions tests/e2e/find_references/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ fn struct_by_name() {
")
}

// FIXME(#129): The results for this are very off.
#[test]
fn struct_member_via_definition() {
test_transform!(find_references, r#"
Expand All @@ -38,10 +37,10 @@ fn struct_member_via_definition() {
}
"#, @r"
#[derive(Drop)]
struct <sel=declaration>Foo</sel> { width: u64 }
struct Foo { <sel=declaration>width</sel>: u64 }
fn main() {
let foo = <sel>Foo</sel> { width: 0 };
let x = foo.width * 2;
let foo = Foo { <sel>width</sel>: 0 };
let x = foo.<sel>width</sel> * 2;
}
")
}
Expand All @@ -57,7 +56,7 @@ fn struct_member_via_constructor() {
}
"#, @r"
#[derive(Drop)]
struct Foo { <sel=declaration>width: u64</sel> }
struct Foo { <sel=declaration>width</sel>: u64 }
fn main() {
let foo = Foo { <sel>width</sel>: 0 };
let x = foo.<sel>width</sel> * 2;
Expand All @@ -76,7 +75,7 @@ fn struct_member_via_field_access() {
}
"#, @r"
#[derive(Drop)]
struct Foo { <sel=declaration>width: u64</sel> }
struct Foo { <sel=declaration>width</sel>: u64 }
fn main() {
let foo = Foo { <sel>width</sel>: 0 };
let x = foo.<sel>width</sel> * 2;
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/goto_definition/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn struct_member_via_field_access() {
}
", @r"
#[derive(Drop)]
struct Circle { <sel>radius: u64</sel> }
struct Circle { <sel>radius</sel>: u64 }
fn foo(circle: Circle) -> u64 {
circle.radius
}
Expand All @@ -54,7 +54,7 @@ fn struct_member_in_constructor() {
}
", @r"
#[derive(Drop)]
struct Circle { <sel>radius: u64</sel> }
struct Circle { <sel>radius</sel>: u64 }
fn main() {
let circle = Circle { radius: 42 };
}
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/hover/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn member_definition_name() {
}
```
---
Docstring of Struct."""
Docstring of member1."""
"#)
}

Expand Down
Loading