Merge #5814
5814: Add SelfParam to code_model
r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
e8d266fa6d
@ -666,23 +666,11 @@ pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
db.function_data(self.id).name.clone()
|
||||
}
|
||||
|
||||
pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
|
||||
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 {
|
||||
pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
|
||||
if !db.function_data(self.id).has_self_param {
|
||||
return None;
|
||||
}
|
||||
|
||||
func_data.params.first().and_then(|param| {
|
||||
if let TypeRef::Reference(_, mutability) = param {
|
||||
Some(*mutability)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
Some(SelfParam { func: self.id })
|
||||
}
|
||||
|
||||
pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeRef> {
|
||||
@ -698,6 +686,41 @@ pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let function_data = db.function_data(self.id);
|
||||
|
@ -32,10 +32,10 @@
|
||||
|
||||
pub use crate::{
|
||||
code_model::{
|
||||
Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
|
||||
Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
|
||||
GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
|
||||
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
||||
Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind,
|
||||
Const, Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource,
|
||||
Function, GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef,
|
||||
ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
||||
},
|
||||
has_source::HasSource,
|
||||
semantics::{original_range, PathResolution, SelfKind, Semantics, SemanticsScope},
|
||||
|
@ -21,13 +21,13 @@
|
||||
};
|
||||
|
||||
use crate::{
|
||||
code_model::Access,
|
||||
db::HirDatabase,
|
||||
diagnostics::Diagnostic,
|
||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
|
||||
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
|
||||
VariantDef,
|
||||
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -627,9 +627,11 @@ fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool
|
||||
}
|
||||
|
||||
let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
|
||||
let is_unsafe = func.has_self_param(self.db)
|
||||
&& matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
|
||||
Some(is_unsafe)
|
||||
let res = match func.self_param(self.db)?.access(self.db) {
|
||||
Access::Shared | Access::Exclusive => true,
|
||||
Access::Owned => false,
|
||||
};
|
||||
Some(res)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
|
||||
let mut seen_methods = FxHashSet::default();
|
||||
let traits_in_scope = ctx.scope.traits_in_scope();
|
||||
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))
|
||||
&& seen_methods.insert(func.name(ctx.db))
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ fn add_function_impl(
|
||||
.lookup_by(fn_name)
|
||||
.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
|
||||
} else {
|
||||
CompletionItemKind::Function
|
||||
|
@ -191,14 +191,12 @@ pub(crate) fn add_function(
|
||||
func: hir::Function,
|
||||
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 ast_node = func.source(ctx.db).value;
|
||||
|
||||
let mut builder =
|
||||
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
|
||||
} else {
|
||||
CompletionItemKind::Function
|
||||
|
@ -4,7 +4,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use hir::{Mutability, Name, SelfKind, Semantics, VariantDef};
|
||||
use hir::{Name, SelfKind, Semantics, VariantDef};
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
|
||||
RootDatabase,
|
||||
@ -761,17 +761,13 @@ fn highlight_name(
|
||||
h |= HighlightModifier::Unsafe;
|
||||
}
|
||||
|
||||
return if func.has_self_param(db) {
|
||||
match func.mutability_of_self_param(db) {
|
||||
Some(mutability) => match mutability {
|
||||
Mutability::Mut => h | HighlightModifier::Mutable,
|
||||
Mutability::Shared => h,
|
||||
},
|
||||
None => h,
|
||||
}
|
||||
} else {
|
||||
h
|
||||
};
|
||||
match func.self_param(db) {
|
||||
None => h,
|
||||
Some(self_param) => match self_param.access(db) {
|
||||
hir::Access::Exclusive => h | HighlightModifier::Mutable,
|
||||
hir::Access::Shared | hir::Access::Owned => h,
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
|
||||
|
@ -545,7 +545,7 @@ fn attempt_match_ufcs_to_method_call(
|
||||
// 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
|
||||
// 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()) {
|
||||
let deref_count = self.check_expr_type(pattern_type, expr)?;
|
||||
let pattern_receiver = pattern_args.next();
|
||||
|
@ -165,7 +165,7 @@ fn path_contains_placeholder(&self, path: &ast::Path) -> bool {
|
||||
fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool {
|
||||
match resolution {
|
||||
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
|
||||
// calls. e.g. `Foo::bar($s)` should match `x.bar()`.
|
||||
true
|
||||
|
Loading…
Reference in New Issue
Block a user