mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Add SelfParam to code_model
This commit is contained in:
parent
a3b0a3aeb8
commit
b9b4693ce3
@ -666,23 +666,11 @@ impl Function {
|
|||||||
db.function_data(self.id).name.clone()
|
db.function_data(self.id).name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
|
pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
|
||||||
db.function_data(self.id).has_self_param
|
if !db.function_data(self.id).has_self_param {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mutability_of_self_param(self, db: &dyn HirDatabase) -> Option<Mutability> {
|
|
||||||
let func_data = db.function_data(self.id);
|
|
||||||
if !func_data.has_self_param {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
Some(SelfParam { func: self.id })
|
||||||
func_data.params.first().and_then(|param| {
|
|
||||||
if let TypeRef::Reference(_, mutability) = param {
|
|
||||||
Some(*mutability)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeRef> {
|
pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeRef> {
|
||||||
@ -698,6 +686,41 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
|
||||||
|
pub enum Access {
|
||||||
|
Shared,
|
||||||
|
Exclusive,
|
||||||
|
Owned,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Mutability> for Access {
|
||||||
|
fn from(mutability: Mutability) -> Access {
|
||||||
|
match mutability {
|
||||||
|
Mutability::Shared => Access::Shared,
|
||||||
|
Mutability::Mut => Access::Exclusive,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SelfParam {
|
||||||
|
func: FunctionId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelfParam {
|
||||||
|
pub fn access(self, db: &dyn HirDatabase) -> Access {
|
||||||
|
let func_data = db.function_data(self.func);
|
||||||
|
func_data
|
||||||
|
.params
|
||||||
|
.first()
|
||||||
|
.map(|param| match *param {
|
||||||
|
TypeRef::Reference(_, mutability) => mutability.into(),
|
||||||
|
_ => Access::Owned,
|
||||||
|
})
|
||||||
|
.unwrap_or(Access::Owned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HasVisibility for Function {
|
impl HasVisibility for Function {
|
||||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||||
let function_data = db.function_data(self.id);
|
let function_data = db.function_data(self.id);
|
||||||
|
@ -32,10 +32,10 @@ mod has_source;
|
|||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
code_model::{
|
code_model::{
|
||||||
Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
|
Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind,
|
||||||
Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
|
Const, Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource,
|
||||||
GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
|
Function, GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef,
|
||||||
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
||||||
},
|
},
|
||||||
has_source::HasSource,
|
has_source::HasSource,
|
||||||
semantics::{original_range, PathResolution, SelfKind, Semantics, SemanticsScope},
|
semantics::{original_range, PathResolution, SelfKind, Semantics, SemanticsScope},
|
||||||
|
@ -21,13 +21,13 @@ use syntax::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
code_model::Access,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
diagnostics::Diagnostic,
|
diagnostics::Diagnostic,
|
||||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||||
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
|
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
|
||||||
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
|
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||||
VariantDef,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -627,9 +627,11 @@ impl<'db> SemanticsImpl<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
|
let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
|
||||||
let is_unsafe = func.has_self_param(self.db)
|
let res = match func.self_param(self.db)?.access(self.db) {
|
||||||
&& matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
|
Access::Shared | Access::Exclusive => true,
|
||||||
Some(is_unsafe)
|
Access::Owned => false,
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
|
|||||||
let mut seen_methods = FxHashSet::default();
|
let mut seen_methods = FxHashSet::default();
|
||||||
let traits_in_scope = ctx.scope.traits_in_scope();
|
let traits_in_scope = ctx.scope.traits_in_scope();
|
||||||
receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
|
receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
|
||||||
if func.has_self_param(ctx.db)
|
if func.self_param(ctx.db).is_some()
|
||||||
&& ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
|
&& ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
|
||||||
&& seen_methods.insert(func.name(ctx.db))
|
&& seen_methods.insert(func.name(ctx.db))
|
||||||
{
|
{
|
||||||
|
@ -136,7 +136,7 @@ fn add_function_impl(
|
|||||||
.lookup_by(fn_name)
|
.lookup_by(fn_name)
|
||||||
.set_documentation(func.docs(ctx.db));
|
.set_documentation(func.docs(ctx.db));
|
||||||
|
|
||||||
let completion_kind = if func.has_self_param(ctx.db) {
|
let completion_kind = if func.self_param(ctx.db).is_some() {
|
||||||
CompletionItemKind::Method
|
CompletionItemKind::Method
|
||||||
} else {
|
} else {
|
||||||
CompletionItemKind::Function
|
CompletionItemKind::Function
|
||||||
|
@ -191,14 +191,12 @@ impl Completions {
|
|||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
local_name: Option<String>,
|
local_name: Option<String>,
|
||||||
) {
|
) {
|
||||||
let has_self_param = func.has_self_param(ctx.db);
|
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
|
let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
|
||||||
let ast_node = func.source(ctx.db).value;
|
let ast_node = func.source(ctx.db).value;
|
||||||
|
|
||||||
let mut builder =
|
let mut builder =
|
||||||
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
|
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
|
||||||
.kind(if has_self_param {
|
.kind(if func.self_param(ctx.db).is_some() {
|
||||||
CompletionItemKind::Method
|
CompletionItemKind::Method
|
||||||
} else {
|
} else {
|
||||||
CompletionItemKind::Function
|
CompletionItemKind::Function
|
||||||
|
@ -4,7 +4,7 @@ mod injection;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use hir::{Mutability, Name, SelfKind, Semantics, VariantDef};
|
use hir::{Name, SelfKind, Semantics, VariantDef};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
|
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
@ -761,17 +761,13 @@ fn highlight_name(
|
|||||||
h |= HighlightModifier::Unsafe;
|
h |= HighlightModifier::Unsafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
return if func.has_self_param(db) {
|
match func.self_param(db) {
|
||||||
match func.mutability_of_self_param(db) {
|
None => h,
|
||||||
Some(mutability) => match mutability {
|
Some(self_param) => match self_param.access(db) {
|
||||||
Mutability::Mut => h | HighlightModifier::Mutable,
|
hir::Access::Exclusive => h | HighlightModifier::Mutable,
|
||||||
Mutability::Shared => h,
|
hir::Access::Shared | hir::Access::Owned => h,
|
||||||
},
|
},
|
||||||
None => h,
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
|
hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
|
||||||
|
@ -545,7 +545,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
|
|||||||
// If the function we're calling takes a self parameter, then we store additional
|
// If the function we're calling takes a self parameter, then we store additional
|
||||||
// information on the placeholder match about autoderef and autoref. This allows us to use
|
// information on the placeholder match about autoderef and autoref. This allows us to use
|
||||||
// the placeholder in a context where autoderef and autoref don't apply.
|
// the placeholder in a context where autoderef and autoref don't apply.
|
||||||
if code_resolved_function.has_self_param(self.sema.db) {
|
if code_resolved_function.self_param(self.sema.db).is_some() {
|
||||||
if let (Some(pattern_type), Some(expr)) = (&pattern_ufcs.qualifier_type, &code.expr()) {
|
if let (Some(pattern_type), Some(expr)) = (&pattern_ufcs.qualifier_type, &code.expr()) {
|
||||||
let deref_count = self.check_expr_type(pattern_type, expr)?;
|
let deref_count = self.check_expr_type(pattern_type, expr)?;
|
||||||
let pattern_receiver = pattern_args.next();
|
let pattern_receiver = pattern_args.next();
|
||||||
|
@ -165,7 +165,7 @@ impl Resolver<'_, '_> {
|
|||||||
fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool {
|
fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool {
|
||||||
match resolution {
|
match resolution {
|
||||||
hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) => {
|
hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) => {
|
||||||
if function.has_self_param(self.resolution_scope.scope.db) {
|
if function.self_param(self.resolution_scope.scope.db).is_some() {
|
||||||
// If we don't use this path resolution, then we won't be able to match method
|
// If we don't use this path resolution, then we won't be able to match method
|
||||||
// calls. e.g. `Foo::bar($s)` should match `x.bar()`.
|
// calls. e.g. `Foo::bar($s)` should match `x.bar()`.
|
||||||
true
|
true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user