Skip to content

Commit

Permalink
Fix definition lookups for let a =-style bindings
Browse files Browse the repository at this point in the history
commit-id:02fe336d
  • Loading branch information
mkaput committed Dec 19, 2024
1 parent f470be1 commit 45edd55
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 33 deletions.
98 changes: 65 additions & 33 deletions src/lang/inspect/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use cairo_lang_semantic::items::imp::ImplLongId;
use cairo_lang_semantic::lookup_item::LookupItemEx;
use cairo_lang_semantic::resolve::{ResolvedConcreteItem, ResolvedGenericItem};
use cairo_lang_semantic::{Binding, Expr, Mutability, TypeLongId};
use cairo_lang_syntax::node::ast::{Param, PatternIdentifier, PatternPtr, TerminalIdentifier};
use cairo_lang_syntax::node::ast::{ExprPath, Param, PatternIdentifier, TerminalIdentifier};
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_syntax::node::utils::is_grandparent_of_kind;
use cairo_lang_syntax::node::utils::{is_grandparent_of_kind, is_parent_of_kind};
use cairo_lang_syntax::node::{SyntaxNode, Terminal, TypedStablePtr, TypedSyntaxNode, ast};
use cairo_lang_utils::{Intern, LookupIntern, Upcast};
use itertools::Itertools;
Expand Down Expand Up @@ -179,20 +179,25 @@ impl VariableDef {
fn new(db: &AnalysisDatabase, definition_node: SyntaxNode) -> Option<Self> {
match definition_node.kind(db.upcast()) {
SyntaxKind::TerminalIdentifier => {
let definition_node = definition_node.parent()?;
match definition_node.kind(db.upcast()) {
SyntaxKind::PatternIdentifier => {
let pattern_identifier =
PatternIdentifier::from_syntax_node(db.upcast(), definition_node);
Self::new_pattern_identifier(db, pattern_identifier)
}
kind => {
error!(
"variable definition node parent is not an pattern identifier: \
{kind:?}"
);
None
}
let pattern_node = definition_node.parent()?;
let kind = pattern_node.kind(db.upcast());
if let SyntaxKind::PatternIdentifier = kind {
let pattern_identifier =
PatternIdentifier::from_syntax_node(db.upcast(), pattern_node);
Self::new_pattern_identifier(db, pattern_identifier)
} else if is_parent_of_kind(db, &pattern_node, SyntaxKind::ExprPath) {
let expr_path = ExprPath::from_syntax_node(
db.upcast(),
pattern_node.parent().expect("Grandparent already exists"),
);
let terminal_identifier =
TerminalIdentifier::from_syntax_node(db.upcast(), definition_node);
Self::new_expr_path(db, expr_path, terminal_identifier)
} else {
error!(
"variable definition node parent is not an pattern identifier: {kind:?}"
);
None
}
}

Expand All @@ -215,24 +220,22 @@ impl VariableDef {
) -> Option<Self> {
let name = pattern_identifier.name(db.upcast()).text(db.upcast());

// Get the function which contains the variable/parameter.
let function_id =
db.find_lookup_item(&pattern_identifier.as_syntax_node())?.function_with_body()?;

// Get the semantic model for the pattern.
let pattern = {
let pattern_ptr = PatternPtr::from(pattern_identifier.stable_ptr());
let id = db.lookup_pattern_by_ptr(function_id, pattern_ptr).ok()?;
db.pattern_semantic(function_id, id)
};
let var =
lookup_binding_for_pattern(db, ast::Pattern::Identifier(pattern_identifier), &name)?;

// Extract variable semantic from the found pattern.
let var = pattern
.variables(&QueryPatternVariablesFromDb(db.upcast(), function_id))
.into_iter()
.find(|pv| pv.name == name)?
.var
.into();
Some(Self { name, var })
}

/// Constructs a new [`VariableDef`] instance for a [`TerminalIdentifier`]
/// that is a segment of an [`ExprPath`].
fn new_expr_path(
db: &AnalysisDatabase,
expr_path: ExprPath,
terminal_identifier: TerminalIdentifier,
) -> Option<Self> {
let name = terminal_identifier.text(db.upcast());

let var = lookup_binding_for_pattern(db, ast::Pattern::Path(expr_path), &name)?;

Some(Self { name, var })
}
Expand Down Expand Up @@ -563,3 +566,32 @@ fn resolved_generic_item_def(
ResolvedGenericItem::Variable(var) => var.untyped_stable_ptr(defs_db),
})
}

/// Extracts variable semantic (a binding) from the given pattern syntax node.
///
/// The `name` has to be the name of the variable (which is always known in advance when calling
/// this function but hard to reverse lookup).
fn lookup_binding_for_pattern(
db: &AnalysisDatabase,
pattern: ast::Pattern,
name: &str,
) -> Option<Binding> {
// Get the function which contains the variable/parameter.
let function_id = db.find_lookup_item(&pattern.as_syntax_node())?.function_with_body()?;

// Get the semantic model for the pattern.
let pattern = db.pattern_semantic(
function_id,
db.lookup_pattern_by_ptr(function_id, pattern.stable_ptr()).ok()?,
);

// Extract the binding from the found pattern.
let binding = pattern
.variables(&QueryPatternVariablesFromDb(db.upcast(), function_id))
.into_iter()
.find(|pv| pv.name == name)?
.var
.into();

Some(binding)
}
1 change: 1 addition & 0 deletions tests/e2e/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cairo_lang_test_utils::test_file_test!(
literals: "literals.txt",
structs: "structs.txt",
paths: "paths.txt",
variables: "variables.txt",
},
test_hover
);
Expand Down
54 changes: 54 additions & 0 deletions tests/test_data/hover/variables.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! > Hover for variables

//! > test_runner_name
test_hover

//! > cairo_project.toml
[crate_roots]
hello = "src"

[config.global]
edition = "2023_11"

//! > cairo_code
fn main() {
let ab<caret>c: felt252 = 0;
let mut de<caret>f = ab<caret>c * 2;
let _ = de<caret>f * 2;
}

//! > hover #0
// = source context
let ab<caret>c: felt252 = 0;
// = highlight
No highlight information.
// = popover
Type: `core::felt252`

//! > hover #1
// = source context
let mut de<caret>f = abc * 2;
// = highlight
No highlight information.
// = popover
Type: `core::felt252`

//! > hover #2
// = source context
let mut def = ab<caret>c * 2;
// = highlight
let mut def = <sel>abc</sel> * 2;
// = popover
```cairo
let abc: core::felt252
```

//! > hover #3
// = source context
let _ = de<caret>f * 2;
// = highlight
let _ = <sel>def</sel> * 2;
// = popover
```cairo
let mut def: core::felt252
```

0 comments on commit 45edd55

Please sign in to comment.