From b9b4693ce3bf0229ea40f09e6404fad3e7823321 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Aug 2020 15:16:24 +0200 Subject: Add SelfParam to code_model --- crates/hir/src/code_model.rs | 53 +++++++++++++++++------- crates/hir/src/lib.rs | 8 ++-- crates/hir/src/semantics.rs | 12 +++--- crates/ide/src/completion/complete_dot.rs | 2 +- crates/ide/src/completion/complete_trait_impl.rs | 2 +- crates/ide/src/completion/presentation.rs | 4 +- crates/ide/src/syntax_highlighting.rs | 20 ++++----- crates/ssr/src/matching.rs | 2 +- crates/ssr/src/resolving.rs | 2 +- 9 files changed, 62 insertions(+), 43 deletions(-) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 31d5276b0..3254f316b 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -666,23 +666,11 @@ impl Function { 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 { - let func_data = db.function_data(self.id); - if !func_data.has_self_param { + pub fn self_param(self, db: &dyn HirDatabase) -> Option { + 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 { @@ -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 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); diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index fc1c1ccd3..447e60698 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -32,10 +32,10 @@ mod has_source; 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}, diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 621ebcbe3..cabeaaf98 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -21,13 +21,13 @@ use syntax::{ }; 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 @@ impl<'db> SemanticsImpl<'db> { } 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) } diff --git a/crates/ide/src/completion/complete_dot.rs b/crates/ide/src/completion/complete_dot.rs index 532665285..5488db43f 100644 --- a/crates/ide/src/completion/complete_dot.rs +++ b/crates/ide/src/completion/complete_dot.rs @@ -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)) { diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/ide/src/completion/complete_trait_impl.rs index d69b6b468..d0d3a9f34 100644 --- a/crates/ide/src/completion/complete_trait_impl.rs +++ b/crates/ide/src/completion/complete_trait_impl.rs @@ -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 diff --git a/crates/ide/src/completion/presentation.rs b/crates/ide/src/completion/presentation.rs index e1b1ea4ce..a73f8ab0b 100644 --- a/crates/ide/src/completion/presentation.rs +++ b/crates/ide/src/completion/presentation.rs @@ -191,14 +191,12 @@ impl Completions { func: hir::Function, local_name: Option, ) { - 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 diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 9827c68af..fc4f56550 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[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, diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index 8bb5ced90..26968c474 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs @@ -545,7 +545,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // 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(); diff --git a/crates/ssr/src/resolving.rs b/crates/ssr/src/resolving.rs index b932132d5..5d2cbec47 100644 --- a/crates/ssr/src/resolving.rs +++ b/crates/ssr/src/resolving.rs @@ -165,7 +165,7 @@ impl Resolver<'_, '_> { 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 -- cgit v1.2.3