mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Improve autocompletion by looking on the type and name
Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
This commit is contained in:
parent
c1317d6923
commit
d42346fed6
6 changed files with 194 additions and 30 deletions
|
@ -1,6 +1,6 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
|
|
||||||
use hir::{HasVisibility, Type};
|
use hir::{HasVisibility, HirDisplay, Type};
|
||||||
|
|
||||||
use crate::completion::completion_item::CompletionKind;
|
use crate::completion::completion_item::CompletionKind;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
};
|
};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
/// Complete dot accesses, i.e. fields or methods (and .await syntax).
|
/// Complete dot accesses, i.e. fields or methods (and .await syntax).
|
||||||
pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
|
@ -37,7 +38,31 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
|
|
||||||
fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
|
fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
|
||||||
for receiver in receiver.autoderef(ctx.db) {
|
for receiver in receiver.autoderef(ctx.db) {
|
||||||
for (field, ty) in receiver.fields(ctx.db) {
|
let mut fields = receiver.fields(ctx.db);
|
||||||
|
if let Some(call_info) = &ctx.call_info {
|
||||||
|
if let Some(active_parameter_type) = call_info.active_parameter_type() {
|
||||||
|
let active_parameter_name = call_info.active_parameter_name().unwrap();
|
||||||
|
fields.sort_by(|a, b| {
|
||||||
|
// For the same type
|
||||||
|
if active_parameter_type == a.1.display(ctx.db).to_string() {
|
||||||
|
// If same type + same name then go top position
|
||||||
|
if active_parameter_name == a.0.name(ctx.db).to_string() {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
if active_parameter_type == b.1.display(ctx.db).to_string() {
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
Ordering::Less
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (field, ty) in fields {
|
||||||
if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
|
if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
|
||||||
// Skip private field. FIXME: If the definition location of the
|
// Skip private field. FIXME: If the definition location of the
|
||||||
// field is editable, we should show the completion
|
// field is editable, we should show the completion
|
||||||
|
@ -47,6 +72,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
|
||||||
}
|
}
|
||||||
for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
|
for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
|
||||||
// FIXME: Handle visibility
|
// FIXME: Handle visibility
|
||||||
|
// TODO: add the same behavior with type ?
|
||||||
acc.add_tuple_field(ctx, i, &ty);
|
acc.add_tuple_field(ctx, i, &ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,13 +96,20 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
|
use crate::completion::{
|
||||||
|
test_utils::{do_completion, do_completion_without_sort},
|
||||||
|
CompletionItem, CompletionKind,
|
||||||
|
};
|
||||||
use insta::assert_debug_snapshot;
|
use insta::assert_debug_snapshot;
|
||||||
|
|
||||||
fn do_ref_completion(code: &str) -> Vec<CompletionItem> {
|
fn do_ref_completion(code: &str) -> Vec<CompletionItem> {
|
||||||
do_completion(code, CompletionKind::Reference)
|
do_completion(code, CompletionKind::Reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_ref_completion_without_sort(code: &str) -> Vec<CompletionItem> {
|
||||||
|
do_completion_without_sort(code, CompletionKind::Reference)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_struct_field_completion() {
|
fn test_struct_field_completion() {
|
||||||
assert_debug_snapshot!(
|
assert_debug_snapshot!(
|
||||||
|
@ -103,6 +136,92 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_struct_field_completion_in_func_call() {
|
||||||
|
assert_debug_snapshot!(
|
||||||
|
do_ref_completion_without_sort(
|
||||||
|
r"
|
||||||
|
struct A { another_field: i64, the_field: u32, my_string: String }
|
||||||
|
fn test(my_param: u32) -> u32 { my_param }
|
||||||
|
fn foo(a: A) {
|
||||||
|
test(a.<|>)
|
||||||
|
}
|
||||||
|
",
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "the_field",
|
||||||
|
source_range: [201; 201),
|
||||||
|
delete: [201; 201),
|
||||||
|
insert: "the_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "another_field",
|
||||||
|
source_range: [201; 201),
|
||||||
|
delete: [201; 201),
|
||||||
|
insert: "another_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "i64",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "my_string",
|
||||||
|
source_range: [201; 201),
|
||||||
|
delete: [201; 201),
|
||||||
|
insert: "my_string",
|
||||||
|
kind: Field,
|
||||||
|
detail: "{unknown}",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_struct_field_completion_in_func_call_with_type_and_name() {
|
||||||
|
assert_debug_snapshot!(
|
||||||
|
do_ref_completion_without_sort(
|
||||||
|
r"
|
||||||
|
struct A { another_field: i64, another_good_type: u32, the_field: u32 }
|
||||||
|
fn test(the_field: u32) -> u32 { the_field }
|
||||||
|
fn foo(a: A) {
|
||||||
|
test(a.<|>)
|
||||||
|
}
|
||||||
|
",
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "the_field",
|
||||||
|
source_range: [208; 208),
|
||||||
|
delete: [208; 208),
|
||||||
|
insert: "the_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "another_good_type",
|
||||||
|
source_range: [208; 208),
|
||||||
|
delete: [208; 208),
|
||||||
|
insert: "another_good_type",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "another_field",
|
||||||
|
source_range: [208; 208),
|
||||||
|
delete: [208; 208),
|
||||||
|
insert: "another_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "i64",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_struct_field_completion_self() {
|
fn test_struct_field_completion_self() {
|
||||||
assert_debug_snapshot!(
|
assert_debug_snapshot!(
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
|
|
||||||
use hir::{Semantics, SemanticsScope};
|
use hir::{db::HirDatabase, Semantics, SemanticsScope};
|
||||||
use ra_db::SourceDatabase;
|
use ra_db::SourceDatabase;
|
||||||
use ra_ide_db::RootDatabase;
|
use ra_ide_db::RootDatabase;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::{find_covering_element, find_node_at_offset},
|
algo::{find_covering_element, find_node_at_offset},
|
||||||
ast, AstNode,
|
ast,
|
||||||
|
ast::ArgListOwner,
|
||||||
|
AstNode,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextUnit,
|
SyntaxNode, SyntaxToken, TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
use ra_text_edit::AtomTextEdit;
|
use ra_text_edit::AtomTextEdit;
|
||||||
|
|
||||||
use crate::{completion::CompletionConfig, FilePosition};
|
use crate::{call_info::call_info, completion::CompletionConfig, CallInfo, FilePosition};
|
||||||
|
|
||||||
/// `CompletionContext` is created early during completion to figure out, where
|
/// `CompletionContext` is created early during completion to figure out, where
|
||||||
/// exactly is the cursor, syntax-wise.
|
/// exactly is the cursor, syntax-wise.
|
||||||
|
@ -21,6 +23,7 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
pub(super) db: &'a RootDatabase,
|
pub(super) db: &'a RootDatabase,
|
||||||
pub(super) config: &'a CompletionConfig,
|
pub(super) config: &'a CompletionConfig,
|
||||||
pub(super) offset: TextUnit,
|
pub(super) offset: TextUnit,
|
||||||
|
pub(super) file_position: FilePosition,
|
||||||
/// The token before the cursor, in the original file.
|
/// The token before the cursor, in the original file.
|
||||||
pub(super) original_token: SyntaxToken,
|
pub(super) original_token: SyntaxToken,
|
||||||
/// The token before the cursor, in the macro-expanded file.
|
/// The token before the cursor, in the macro-expanded file.
|
||||||
|
@ -32,6 +35,7 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
pub(super) record_lit_syntax: Option<ast::RecordLit>,
|
pub(super) record_lit_syntax: Option<ast::RecordLit>,
|
||||||
pub(super) record_lit_pat: Option<ast::RecordPat>,
|
pub(super) record_lit_pat: Option<ast::RecordPat>,
|
||||||
pub(super) impl_def: Option<ast::ImplDef>,
|
pub(super) impl_def: Option<ast::ImplDef>,
|
||||||
|
pub(super) call_info: Option<CallInfo>,
|
||||||
pub(super) is_param: bool,
|
pub(super) is_param: bool,
|
||||||
/// If a name-binding or reference to a const in a pattern.
|
/// If a name-binding or reference to a const in a pattern.
|
||||||
/// Irrefutable patterns (like let) are excluded.
|
/// Irrefutable patterns (like let) are excluded.
|
||||||
|
@ -88,9 +92,11 @@ impl<'a> CompletionContext<'a> {
|
||||||
original_token,
|
original_token,
|
||||||
token,
|
token,
|
||||||
offset: position.offset,
|
offset: position.offset,
|
||||||
|
file_position: position,
|
||||||
krate,
|
krate,
|
||||||
name_ref_syntax: None,
|
name_ref_syntax: None,
|
||||||
function_syntax: None,
|
function_syntax: None,
|
||||||
|
call_info: None,
|
||||||
use_item_syntax: None,
|
use_item_syntax: None,
|
||||||
record_lit_syntax: None,
|
record_lit_syntax: None,
|
||||||
record_lit_pat: None,
|
record_lit_pat: None,
|
||||||
|
@ -253,6 +259,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
self.use_item_syntax =
|
self.use_item_syntax =
|
||||||
self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);
|
self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);
|
||||||
|
|
||||||
|
self.call_info = call_info(self.db, self.file_position);
|
||||||
|
|
||||||
self.function_syntax = self
|
self.function_syntax = self
|
||||||
.sema
|
.sema
|
||||||
.ancestors_with_macros(self.token.parent())
|
.ancestors_with_macros(self.token.parent())
|
||||||
|
|
|
@ -367,7 +367,7 @@ mod tests {
|
||||||
ra_fixture: &str,
|
ra_fixture: &str,
|
||||||
options: CompletionConfig,
|
options: CompletionConfig,
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
do_completion_with_options(ra_fixture, CompletionKind::Reference, &options)
|
do_completion_with_options(ra_fixture, CompletionKind::Reference, &options, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -7,13 +7,18 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
|
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
|
||||||
do_completion_with_options(code, kind, &CompletionConfig::default())
|
do_completion_with_options(code, kind, &CompletionConfig::default(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn do_completion_without_sort(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
|
||||||
|
do_completion_with_options(code, kind, &CompletionConfig::default(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn do_completion_with_options(
|
pub(crate) fn do_completion_with_options(
|
||||||
code: &str,
|
code: &str,
|
||||||
kind: CompletionKind,
|
kind: CompletionKind,
|
||||||
options: &CompletionConfig,
|
options: &CompletionConfig,
|
||||||
|
sort_by_key: bool,
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
let (analysis, position) = if code.contains("//-") {
|
let (analysis, position) = if code.contains("//-") {
|
||||||
analysis_and_position(code)
|
analysis_and_position(code)
|
||||||
|
@ -24,6 +29,8 @@ pub(crate) fn do_completion_with_options(
|
||||||
let completion_items: Vec<CompletionItem> = completions.into();
|
let completion_items: Vec<CompletionItem> = completions.into();
|
||||||
let mut kind_completions: Vec<CompletionItem> =
|
let mut kind_completions: Vec<CompletionItem> =
|
||||||
completion_items.into_iter().filter(|c| c.completion_kind == kind).collect();
|
completion_items.into_iter().filter(|c| c.completion_kind == kind).collect();
|
||||||
kind_completions.sort_by_key(|c| c.label().to_owned());
|
if sort_by_key {
|
||||||
|
kind_completions.sort_by_key(|c| c.label().to_owned());
|
||||||
|
}
|
||||||
kind_completions
|
kind_completions
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ pub struct FunctionSignature {
|
||||||
pub parameters: Vec<String>,
|
pub parameters: Vec<String>,
|
||||||
/// Parameter names of the function
|
/// Parameter names of the function
|
||||||
pub parameter_names: Vec<String>,
|
pub parameter_names: Vec<String>,
|
||||||
|
/// Parameter types of the function
|
||||||
|
pub parameter_types: Vec<String>,
|
||||||
/// Optional return type
|
/// Optional return type
|
||||||
pub ret_type: Option<String>,
|
pub ret_type: Option<String>,
|
||||||
/// Where predicates
|
/// Where predicates
|
||||||
|
@ -62,14 +64,14 @@ impl FunctionSignature {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let params = st
|
let mut params = vec![];
|
||||||
.fields(db)
|
let mut parameter_types = vec![];
|
||||||
.into_iter()
|
for field in st.fields(db).into_iter() {
|
||||||
.map(|field: hir::StructField| {
|
let ty = field.signature_ty(db);
|
||||||
let ty = field.signature_ty(db);
|
let raw_param = format!("{}", ty.display(db));
|
||||||
format!("{}", ty.display(db))
|
parameter_types.push(raw_param.split(':').nth(1).unwrap()[1..].to_string());
|
||||||
})
|
params.push(raw_param);
|
||||||
.collect();
|
}
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
FunctionSignature {
|
FunctionSignature {
|
||||||
|
@ -79,6 +81,7 @@ impl FunctionSignature {
|
||||||
ret_type: node.name().map(|n| n.text().to_string()),
|
ret_type: node.name().map(|n| n.text().to_string()),
|
||||||
parameters: params,
|
parameters: params,
|
||||||
parameter_names: vec![],
|
parameter_names: vec![],
|
||||||
|
parameter_types,
|
||||||
generic_parameters: generic_parameters(&node),
|
generic_parameters: generic_parameters(&node),
|
||||||
where_predicates: where_predicates(&node),
|
where_predicates: where_predicates(&node),
|
||||||
doc: None,
|
doc: None,
|
||||||
|
@ -99,15 +102,14 @@ impl FunctionSignature {
|
||||||
|
|
||||||
let name = format!("{}::{}", parent_name, variant.name(db));
|
let name = format!("{}::{}", parent_name, variant.name(db));
|
||||||
|
|
||||||
let params = variant
|
let mut params = vec![];
|
||||||
.fields(db)
|
let mut parameter_types = vec![];
|
||||||
.into_iter()
|
for field in variant.fields(db).into_iter() {
|
||||||
.map(|field: hir::StructField| {
|
let ty = field.signature_ty(db);
|
||||||
let name = field.name(db);
|
let raw_param = format!("{}", ty.display(db));
|
||||||
let ty = field.signature_ty(db);
|
parameter_types.push(raw_param.split(':').nth(1).unwrap()[1..].to_string());
|
||||||
format!("{}: {}", name, ty.display(db))
|
params.push(raw_param);
|
||||||
})
|
}
|
||||||
.collect();
|
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
FunctionSignature {
|
FunctionSignature {
|
||||||
|
@ -117,6 +119,7 @@ impl FunctionSignature {
|
||||||
ret_type: None,
|
ret_type: None,
|
||||||
parameters: params,
|
parameters: params,
|
||||||
parameter_names: vec![],
|
parameter_names: vec![],
|
||||||
|
parameter_types,
|
||||||
generic_parameters: vec![],
|
generic_parameters: vec![],
|
||||||
where_predicates: vec![],
|
where_predicates: vec![],
|
||||||
doc: None,
|
doc: None,
|
||||||
|
@ -139,6 +142,7 @@ impl FunctionSignature {
|
||||||
ret_type: None,
|
ret_type: None,
|
||||||
parameters: params,
|
parameters: params,
|
||||||
parameter_names: vec![],
|
parameter_names: vec![],
|
||||||
|
parameter_types: vec![],
|
||||||
generic_parameters: vec![],
|
generic_parameters: vec![],
|
||||||
where_predicates: vec![],
|
where_predicates: vec![],
|
||||||
doc: None,
|
doc: None,
|
||||||
|
@ -151,18 +155,28 @@ impl FunctionSignature {
|
||||||
|
|
||||||
impl From<&'_ ast::FnDef> for FunctionSignature {
|
impl From<&'_ ast::FnDef> for FunctionSignature {
|
||||||
fn from(node: &ast::FnDef) -> FunctionSignature {
|
fn from(node: &ast::FnDef) -> FunctionSignature {
|
||||||
fn param_list(node: &ast::FnDef) -> (bool, Vec<String>) {
|
fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
|
let mut res_types = vec![];
|
||||||
let mut has_self_param = false;
|
let mut has_self_param = false;
|
||||||
if let Some(param_list) = node.param_list() {
|
if let Some(param_list) = node.param_list() {
|
||||||
if let Some(self_param) = param_list.self_param() {
|
if let Some(self_param) = param_list.self_param() {
|
||||||
has_self_param = true;
|
has_self_param = true;
|
||||||
res.push(self_param.syntax().text().to_string())
|
let raw_param = self_param.syntax().text().to_string();
|
||||||
|
|
||||||
|
// TODO: better solution ?
|
||||||
|
res_types.push(
|
||||||
|
raw_param.split(':').nth(1).unwrap_or_else(|| " Self")[1..].to_string(),
|
||||||
|
);
|
||||||
|
res.push(raw_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
|
res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
|
||||||
|
res_types.extend(param_list.params().map(|param| {
|
||||||
|
param.syntax().text().to_string().split(':').nth(1).unwrap()[1..].to_string()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
(has_self_param, res)
|
(has_self_param, res, res_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_name_list(node: &ast::FnDef) -> Vec<String> {
|
fn param_name_list(node: &ast::FnDef) -> Vec<String> {
|
||||||
|
@ -192,7 +206,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
let (has_self_param, parameters) = param_list(node);
|
let (has_self_param, parameters, parameter_types) = param_list(node);
|
||||||
|
|
||||||
FunctionSignature {
|
FunctionSignature {
|
||||||
kind: CallableKind::Function,
|
kind: CallableKind::Function,
|
||||||
|
@ -204,6 +218,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
|
||||||
.map(|n| n.syntax().text().to_string()),
|
.map(|n| n.syntax().text().to_string()),
|
||||||
parameters,
|
parameters,
|
||||||
parameter_names: param_name_list(node),
|
parameter_names: param_name_list(node),
|
||||||
|
parameter_types,
|
||||||
generic_parameters: generic_parameters(node),
|
generic_parameters: generic_parameters(node),
|
||||||
where_predicates: where_predicates(node),
|
where_predicates: where_predicates(node),
|
||||||
// docs are processed separately
|
// docs are processed separately
|
||||||
|
|
|
@ -127,6 +127,21 @@ pub struct CallInfo {
|
||||||
pub active_parameter: Option<usize>,
|
pub active_parameter: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CallInfo {
|
||||||
|
pub fn active_parameter_type(&self) -> Option<String> {
|
||||||
|
if let Some(id) = self.active_parameter {
|
||||||
|
return self.signature.parameter_types.get(id).map(|param_ty| param_ty.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub fn active_parameter_name(&self) -> Option<String> {
|
||||||
|
if let Some(id) = self.active_parameter {
|
||||||
|
return self.signature.parameter_names.get(id).map(|param_ty| param_ty.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `AnalysisHost` stores the current state of the world.
|
/// `AnalysisHost` stores the current state of the world.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnalysisHost {
|
pub struct AnalysisHost {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue