analyzer: Update ra_ap_syntax and fix completions

This commit is contained in:
davidsemakula 2025-10-21 21:46:24 +03:00
parent ce8857f9e2
commit 4655d53ab0
6 changed files with 46 additions and 25 deletions

View file

@ -657,8 +657,9 @@ pub fn entity_completions(
item_at_offset.parent_ast_item()
};
// Bail if focused token is part of an item that spans multiple lines,
// except if the next token is an error as that likely just indicates an intermittent join
// of the current incomplete item to the next one by the parser.
// except if the next token is an error (as that likely just indicates an intermittent join
// of the current incomplete item to the next one by the parser)
// or the focused token is fully enclosed by a `mod` or `impl` parent.
let is_multi_line_focused_item = focused_item.as_ref().is_some_and(|focused_item| {
focused_item.syntax().text_range().end()
> last_line_sibling
@ -667,7 +668,21 @@ pub fn entity_completions(
.unwrap_or_else(|| focused_token.text_range())
.end()
});
if is_multi_line_focused_item && !is_next_node_error() {
let is_parent_mod_or_impl = || {
focused_item.as_ref().is_some_and(|focused_item| {
matches!(
focused_item.syntax().kind(),
SyntaxKind::MODULE | SyntaxKind::IMPL
) && utils::ast_item_declaration_range(focused_item)
.as_ref()
.is_some_and(|decl_range| {
let focus_range = focused_token.text_range();
focus_range.start() > decl_range.end()
&& focus_range.end() < focused_item.syntax().text_range().end()
})
})
};
if is_multi_line_focused_item && (!is_next_node_error() && !is_parent_mod_or_impl()) {
return;
}
@ -676,6 +691,8 @@ pub fn entity_completions(
// Completion context "parent item" for record fields (e.g. `struct` fields) and
// whitespace-only lines is the direct parent item.
item_at_offset.parent_ast_item()
} else if is_parent_mod_or_impl() {
focused_item
} else {
// Otherwise, the completion context "parent item" is the parent of the "focused" item.
focused_item

View file

@ -1,7 +1,10 @@
//! ink! extension/function diagnostics.
use ink_analyzer_ir::syntax::{AstNode, SyntaxNode};
use ink_analyzer_ir::{ast, InkArgKind, InkAttributeKind, IsChainExtensionFn};
use ink_analyzer_ir::{
ast::{self, HasGenericArgs},
syntax::{AstNode, SyntaxNode},
InkArgKind, InkAttributeKind, IsChainExtensionFn,
};
use itertools::Itertools;
use crate::analysis::diagnostics::common;

View file

@ -3,11 +3,11 @@
use std::collections::{HashMap, HashSet};
use std::iter;
use ink_analyzer_ir::ast::{AstNode, HasName, HasVisibility, Trait};
use ink_analyzer_ir::syntax::{SyntaxNode, TextRange};
use ink_analyzer_ir::{
ast, HasInkImplParent, InkArg, InkArgKind, InkArgValueKind, InkAttributeKind, InkEntity,
InkImpl, IsInkFn, IsInkTrait, Message,
ast::{self, AstNode, HasGenericArgs, HasName, HasVisibility, Trait},
syntax::{SyntaxNode, TextRange},
HasInkImplParent, InkArg, InkArgKind, InkArgValueKind, InkAttributeKind, InkEntity, InkImpl,
IsInkFn, IsInkTrait, Message,
};
use itertools::Itertools;

View file

@ -1,6 +1,6 @@
//! Utilities for ink! 5.0 migration.
use ink_analyzer_ir::ast;
use ink_analyzer_ir::ast::{self, HasGenericArgs};
use ink_analyzer_ir::syntax::SyntaxNode;
use crate::resolution;

View file

@ -412,8 +412,8 @@ fn match_path_to_external_crate_in_scope(
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::parse_first_ast_node_of_type;
use ink_analyzer_ir::ast::{HasName, SourceFile};
use crate::test_utils::{parse_first_ast_node_of_type, parse_source};
use ink_analyzer_ir::ast::HasName;
use ink_analyzer_ir::{InkEntity, InkFile};
use quote::quote;
use test_utils::quote_as_str;
@ -602,16 +602,12 @@ mod tests {
] {
let file = InkFile::parse(code);
let path: ast::Path = parse_first_ast_node_of_type(path_str);
let ref_module_option = SourceFile::parse(code)
.tree()
.syntax()
.descendants()
.find_map(|node| {
ast::Module::cast(node).filter(|item| {
item.name()
.is_some_and(|name| name.to_string() == ref_name.to_string())
})
});
let ref_module_option = parse_source(code).syntax().descendants().find_map(|node| {
ast::Module::cast(node).filter(|item| {
item.name()
.is_some_and(|name| name.to_string() == ref_name.to_string())
})
});
assert!(
is_external_crate_item(

View file

@ -2,7 +2,7 @@
#![cfg(test)]
use ink_analyzer_ir::syntax::{AstNode, SourceFile, TextRange, TextSize};
use ink_analyzer_ir::syntax::{AstNode, Edition, SourceFile, TextRange, TextSize};
use ink_analyzer_ir::{InkEntity, InkFile};
use test_utils::{parse_offset_at, PartialMatchStr, TestResultAction};
@ -55,8 +55,7 @@ pub fn parse_first_ast_node_of_type<T>(code: &str) -> T
where
T: AstNode,
{
SourceFile::parse(code)
.tree()
parse_source(code)
.syntax()
.descendants()
.find_map(T::cast)
@ -105,3 +104,9 @@ pub fn text_edits_from_fixtures(
})
.collect()
}
/// Returns the `SourceFile` for the code snippet.
pub fn parse_source(code: &str) -> SourceFile {
// TODO: Do we need an edition args?
SourceFile::parse(code, Edition::Edition2021).tree()
}