Merge #5643
5643: Add new consuming modifier, apply consuming and mutable to methods r=matklad a=Nashenas88 This adds a new `consuming` semantic modifier for syntax highlighters. This also emits `mutable` and `consuming` in two cases: - When a method takes `&mut self`, then it now has `function.mutable` emitted. - When a method takes `self`, and the type of `Self` is not `Copy`, then `function.consuming` is emitted. CC @flodiebold Co-authored-by: Paul Daniel Faria <Nashenas88@users.noreply.github.com>
This commit is contained in:
@@ -670,6 +670,21 @@ impl Function {
|
||||
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;
|
||||
}
|
||||
|
||||
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> {
|
||||
db.function_data(self.id).params.clone()
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub use crate::{
|
||||
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
|
||||
},
|
||||
has_source::HasSource,
|
||||
semantics::{original_range, PathResolution, Semantics, SemanticsScope},
|
||||
semantics::{original_range, PathResolution, SelfKind, Semantics, SemanticsScope},
|
||||
};
|
||||
|
||||
pub use hir_def::{
|
||||
|
||||
@@ -6,8 +6,10 @@ use std::{cell::RefCell, fmt, iter::successors};
|
||||
|
||||
use base_db::{FileId, FileRange};
|
||||
use hir_def::{
|
||||
lang_item::LangItemTarget,
|
||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||
AsMacroCall, FunctionId, TraitId, VariantId,
|
||||
src::HasSource,
|
||||
AsMacroCall, FunctionId, Lookup, TraitId, VariantId,
|
||||
};
|
||||
use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo};
|
||||
use hir_ty::associated_type_shorthand_candidates;
|
||||
@@ -15,7 +17,7 @@ use itertools::Itertools;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::{
|
||||
algo::{find_node_at_offset, skip_trivia_token},
|
||||
ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
||||
ast, AstNode, Direction, SmolStr, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -79,6 +81,13 @@ impl PathResolution {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SelfKind {
|
||||
Shared,
|
||||
Mutable,
|
||||
Consuming,
|
||||
Copied,
|
||||
}
|
||||
|
||||
/// Primary API to get semantic information, like types, from syntax trees.
|
||||
pub struct Semantics<'db, DB> {
|
||||
pub db: &'db DB,
|
||||
@@ -188,6 +197,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||
self.imp.type_of_self(param)
|
||||
}
|
||||
|
||||
pub fn method_reciever_kind(&self, call: &ast::MethodCallExpr) -> Option<SelfKind> {
|
||||
self.imp.method_receiver_kind(call)
|
||||
}
|
||||
|
||||
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
|
||||
self.imp.resolve_method_call(call).map(Function::from)
|
||||
}
|
||||
@@ -267,7 +280,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||
self.imp.assert_contains_node(node)
|
||||
}
|
||||
|
||||
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
|
||||
pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
|
||||
self.imp.is_unsafe_method_call(method_call_expr)
|
||||
}
|
||||
|
||||
@@ -410,6 +423,35 @@ impl<'db> SemanticsImpl<'db> {
|
||||
self.analyze(param.syntax()).type_of_self(self.db, ¶m)
|
||||
}
|
||||
|
||||
fn method_receiver_kind(&self, call: &ast::MethodCallExpr) -> Option<SelfKind> {
|
||||
self.resolve_method_call(call).and_then(|func| {
|
||||
let lookup = func.lookup(self.db.upcast());
|
||||
let src = lookup.source(self.db.upcast());
|
||||
let param_list = src.value.param_list()?;
|
||||
let self_param = param_list.self_param()?;
|
||||
if self_param.amp_token().is_some() {
|
||||
return Some(if self_param.mut_token().is_some() {
|
||||
SelfKind::Mutable
|
||||
} else {
|
||||
SelfKind::Shared
|
||||
});
|
||||
}
|
||||
|
||||
let ty = self.type_of_expr(&call.expr()?)?;
|
||||
let krate = Function::from(func).krate(self.db)?;
|
||||
let lang_item = self.db.lang_item(krate.id, SmolStr::new("copy"));
|
||||
let copy_trait = match lang_item? {
|
||||
LangItemTarget::TraitId(copy_trait) => Trait::from(copy_trait),
|
||||
_ => return None,
|
||||
};
|
||||
Some(if ty.impls_trait(self.db, copy_trait, &[]) {
|
||||
SelfKind::Copied
|
||||
} else {
|
||||
SelfKind::Consuming
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
|
||||
self.analyze(call.syntax()).resolve_method_call(self.db, call)
|
||||
}
|
||||
@@ -571,7 +613,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||
InFile::new(file_id, node)
|
||||
}
|
||||
|
||||
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
|
||||
pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
|
||||
method_call_expr
|
||||
.expr()
|
||||
.and_then(|expr| {
|
||||
|
||||
Reference in New Issue
Block a user