diff options
author | Aleksey Kladov <[email protected]> | 2020-08-19 16:02:50 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-08-19 16:02:50 +0100 |
commit | 61754678fb4923738c91f2702bba6628230dff6e (patch) | |
tree | 1affb36a509f8f6460bf35a53a7f7937338ae805 | |
parent | 73f4fcbd0fa033947421f827e073bceee86e6447 (diff) |
Better API factoring around self access modes
-rw-r--r-- | crates/hir/src/code_model.rs | 12 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 46 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 26 |
4 files changed, 30 insertions, 56 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 68ccedc60..3d92d0c0d 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -12,6 +12,7 @@ use hir_def::{ | |||
12 | docs::Documentation, | 12 | docs::Documentation, |
13 | expr::{BindingAnnotation, Pat, PatId}, | 13 | expr::{BindingAnnotation, Pat, PatId}, |
14 | import_map, | 14 | import_map, |
15 | lang_item::LangItemTarget, | ||
15 | path::ModPath, | 16 | path::ModPath, |
16 | per_ns::PerNs, | 17 | per_ns::PerNs, |
17 | resolver::{HasResolver, Resolver}, | 18 | resolver::{HasResolver, Resolver}, |
@@ -36,7 +37,7 @@ use rustc_hash::FxHashSet; | |||
36 | use stdx::impl_from; | 37 | use stdx::impl_from; |
37 | use syntax::{ | 38 | use syntax::{ |
38 | ast::{self, AttrsOwner, NameOwner}, | 39 | ast::{self, AttrsOwner, NameOwner}, |
39 | AstNode, | 40 | AstNode, SmolStr, |
40 | }; | 41 | }; |
41 | 42 | ||
42 | use crate::{ | 43 | use crate::{ |
@@ -1287,6 +1288,15 @@ impl Type { | |||
1287 | db.trait_solve(self.krate, goal).is_some() | 1288 | db.trait_solve(self.krate, goal).is_some() |
1288 | } | 1289 | } |
1289 | 1290 | ||
1291 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | ||
1292 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); | ||
1293 | let copy_trait = match lang_item { | ||
1294 | Some(LangItemTarget::TraitId(it)) => it, | ||
1295 | _ => return false, | ||
1296 | }; | ||
1297 | self.impls_trait(db, copy_trait.into(), &[]) | ||
1298 | } | ||
1299 | |||
1290 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { | 1300 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { |
1291 | let def = match self.ty.value { | 1301 | let def = match self.ty.value { |
1292 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def), | 1302 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def), |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 447e60698..78d8651cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -38,7 +38,7 @@ pub use crate::{ | |||
38 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, | 38 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, |
39 | }, | 39 | }, |
40 | has_source::HasSource, | 40 | has_source::HasSource, |
41 | semantics::{original_range, PathResolution, SelfKind, Semantics, SemanticsScope}, | 41 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | pub use hir_def::{ | 44 | pub use hir_def::{ |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index cabeaaf98..8c5f2ff98 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -6,10 +6,8 @@ use std::{cell::RefCell, fmt, iter::successors}; | |||
6 | 6 | ||
7 | use base_db::{FileId, FileRange}; | 7 | use base_db::{FileId, FileRange}; |
8 | use hir_def::{ | 8 | use hir_def::{ |
9 | lang_item::LangItemTarget, | ||
10 | resolver::{self, HasResolver, Resolver, TypeNs}, | 9 | resolver::{self, HasResolver, Resolver, TypeNs}, |
11 | src::HasSource, | 10 | AsMacroCall, FunctionId, TraitId, VariantId, |
12 | AsMacroCall, FunctionId, Lookup, TraitId, VariantId, | ||
13 | }; | 11 | }; |
14 | use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; | 12 | use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; |
15 | use hir_ty::associated_type_shorthand_candidates; | 13 | use hir_ty::associated_type_shorthand_candidates; |
@@ -17,7 +15,7 @@ use itertools::Itertools; | |||
17 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::{FxHashMap, FxHashSet}; |
18 | use syntax::{ | 16 | use syntax::{ |
19 | algo::{find_node_at_offset, skip_trivia_token}, | 17 | algo::{find_node_at_offset, skip_trivia_token}, |
20 | ast, AstNode, Direction, SmolStr, SyntaxNode, SyntaxToken, TextRange, TextSize, | 18 | ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, |
21 | }; | 19 | }; |
22 | 20 | ||
23 | use crate::{ | 21 | use crate::{ |
@@ -81,13 +79,6 @@ impl PathResolution { | |||
81 | } | 79 | } |
82 | } | 80 | } |
83 | 81 | ||
84 | pub enum SelfKind { | ||
85 | Shared, | ||
86 | Mutable, | ||
87 | Consuming, | ||
88 | Copied, | ||
89 | } | ||
90 | |||
91 | /// Primary API to get semantic information, like types, from syntax trees. | 82 | /// Primary API to get semantic information, like types, from syntax trees. |
92 | pub struct Semantics<'db, DB> { | 83 | pub struct Semantics<'db, DB> { |
93 | pub db: &'db DB, | 84 | pub db: &'db DB, |
@@ -197,10 +188,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
197 | self.imp.type_of_self(param) | 188 | self.imp.type_of_self(param) |
198 | } | 189 | } |
199 | 190 | ||
200 | pub fn method_reciever_kind(&self, call: &ast::MethodCallExpr) -> Option<SelfKind> { | ||
201 | self.imp.method_receiver_kind(call) | ||
202 | } | ||
203 | |||
204 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 191 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
205 | self.imp.resolve_method_call(call).map(Function::from) | 192 | self.imp.resolve_method_call(call).map(Function::from) |
206 | } | 193 | } |
@@ -423,35 +410,6 @@ impl<'db> SemanticsImpl<'db> { | |||
423 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) | 410 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) |
424 | } | 411 | } |
425 | 412 | ||
426 | fn method_receiver_kind(&self, call: &ast::MethodCallExpr) -> Option<SelfKind> { | ||
427 | self.resolve_method_call(call).and_then(|func| { | ||
428 | let lookup = func.lookup(self.db.upcast()); | ||
429 | let src = lookup.source(self.db.upcast()); | ||
430 | let param_list = src.value.param_list()?; | ||
431 | let self_param = param_list.self_param()?; | ||
432 | if self_param.amp_token().is_some() { | ||
433 | return Some(if self_param.mut_token().is_some() { | ||
434 | SelfKind::Mutable | ||
435 | } else { | ||
436 | SelfKind::Shared | ||
437 | }); | ||
438 | } | ||
439 | |||
440 | let ty = self.type_of_expr(&call.expr()?)?; | ||
441 | let krate = Function::from(func).krate(self.db)?; | ||
442 | let lang_item = self.db.lang_item(krate.id, SmolStr::new("copy")); | ||
443 | let copy_trait = match lang_item? { | ||
444 | LangItemTarget::TraitId(copy_trait) => Trait::from(copy_trait), | ||
445 | _ => return None, | ||
446 | }; | ||
447 | Some(if ty.impls_trait(self.db, copy_trait, &[]) { | ||
448 | SelfKind::Copied | ||
449 | } else { | ||
450 | SelfKind::Consuming | ||
451 | }) | ||
452 | }) | ||
453 | } | ||
454 | |||
455 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { | 413 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { |
456 | self.analyze(call.syntax()).resolve_method_call(self.db, call) | 414 | self.analyze(call.syntax()).resolve_method_call(self.db, call) |
457 | } | 415 | } |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index fc4f56550..5521fd2b1 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -4,7 +4,7 @@ mod injection; | |||
4 | #[cfg(test)] | 4 | #[cfg(test)] |
5 | mod tests; | 5 | mod tests; |
6 | 6 | ||
7 | use hir::{Name, SelfKind, Semantics, VariantDef}; | 7 | use hir::{Name, Semantics, VariantDef}; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, | 9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, |
10 | RootDatabase, | 10 | RootDatabase, |
@@ -720,15 +720,21 @@ fn highlight_method_call( | |||
720 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | 720 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { |
721 | h |= HighlightModifier::Unsafe; | 721 | h |= HighlightModifier::Unsafe; |
722 | } | 722 | } |
723 | 723 | if let Some(self_param) = func.self_param(sema.db) { | |
724 | sema.method_reciever_kind(&method_call) | 724 | match self_param.access(sema.db) { |
725 | .map(|self_kind| match self_kind { | 725 | hir::Access::Shared => (), |
726 | SelfKind::Shared => h, | 726 | hir::Access::Exclusive => h |= HighlightModifier::Mutable, |
727 | SelfKind::Mutable => h | HighlightModifier::Mutable, | 727 | hir::Access::Owned => { |
728 | SelfKind::Consuming => h | HighlightModifier::Consuming, | 728 | if let Some(receiver_ty) = method_call.expr().and_then(|it| sema.type_of_expr(&it)) |
729 | SelfKind::Copied => h, | 729 | { |
730 | }) | 730 | if !receiver_ty.is_copy(sema.db) { |
731 | .or_else(|| Some(h)) | 731 | h |= HighlightModifier::Consuming |
732 | } | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | } | ||
737 | Some(h) | ||
732 | } | 738 | } |
733 | 739 | ||
734 | fn highlight_name( | 740 | fn highlight_name( |