Refine search for const and function assoc items
This commit is contained in:
parent
f32f64bffc
commit
bb4e272d8a
@ -712,17 +712,17 @@ fn lookup_impl_assoc_item_for_trait_ref(
|
||||
let table = InferenceTable::new(db, env);
|
||||
|
||||
let impl_data = find_matching_impl(impls, table, trait_ref)?;
|
||||
impl_data.items.iter().find_map(|it| match it {
|
||||
impl_data.items.iter().find_map(|&it| match it {
|
||||
AssocItemId::FunctionId(f) => {
|
||||
(db.function_data(*f).name == *name).then_some(AssocItemId::FunctionId(*f))
|
||||
(db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f))
|
||||
}
|
||||
AssocItemId::ConstId(c) => db
|
||||
.const_data(*c)
|
||||
.const_data(c)
|
||||
.name
|
||||
.as_ref()
|
||||
.map(|n| *n == *name)
|
||||
.and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }),
|
||||
_ => None,
|
||||
.map(|n| n == name)
|
||||
.and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }),
|
||||
AssocItemId::TypeAliasId(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2129,7 +2129,7 @@ pub enum AssocItem {
|
||||
Const(Const),
|
||||
TypeAlias(TypeAlias),
|
||||
}
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AssocItemContainer {
|
||||
Trait(Trait),
|
||||
Impl(Impl),
|
||||
|
@ -504,7 +504,7 @@ impl SourceAnalyzer {
|
||||
AssocItemId::ConstId(const_id) => {
|
||||
self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
|
||||
}
|
||||
_ => assoc,
|
||||
assoc => assoc,
|
||||
};
|
||||
|
||||
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
|
||||
@ -517,7 +517,13 @@ impl SourceAnalyzer {
|
||||
prefer_value_ns = true;
|
||||
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
|
||||
let pat_id = self.pat_id(&path_pat.into())?;
|
||||
if let Some((assoc, _)) = infer.assoc_resolutions_for_pat(pat_id) {
|
||||
if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) {
|
||||
let assoc = match assoc {
|
||||
AssocItemId::ConstId(const_id) => {
|
||||
self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
|
||||
}
|
||||
assoc => assoc,
|
||||
};
|
||||
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
|
||||
}
|
||||
if let Some(VariantId::EnumVariantId(variant)) =
|
||||
|
@ -7,7 +7,9 @@
|
||||
use std::{mem, sync::Arc};
|
||||
|
||||
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
||||
use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
|
||||
use hir::{
|
||||
AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility,
|
||||
};
|
||||
use memchr::memmem::Finder;
|
||||
use once_cell::unsync::Lazy;
|
||||
use parser::SyntaxKind;
|
||||
@ -311,15 +313,15 @@ impl Definition {
|
||||
|
||||
pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
|
||||
FindUsages {
|
||||
def: self,
|
||||
assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)),
|
||||
sema,
|
||||
scope: None,
|
||||
include_self_kw_refs: None,
|
||||
local_repr: match self {
|
||||
Definition::Local(local) => Some(local.representative(sema.db)),
|
||||
_ => None,
|
||||
},
|
||||
def: self,
|
||||
trait_assoc_def: as_trait_assoc_def(sema.db, self),
|
||||
sema,
|
||||
scope: None,
|
||||
include_self_kw_refs: None,
|
||||
search_self_mod: false,
|
||||
}
|
||||
}
|
||||
@ -328,8 +330,7 @@ impl Definition {
|
||||
#[derive(Clone)]
|
||||
pub struct FindUsages<'a> {
|
||||
def: Definition,
|
||||
/// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition
|
||||
trait_assoc_def: Option<Definition>,
|
||||
assoc_item_container: Option<hir::AssocItemContainer>,
|
||||
sema: &'a Semantics<'a, RootDatabase>,
|
||||
scope: Option<SearchScope>,
|
||||
include_self_kw_refs: Option<hir::Type>,
|
||||
@ -380,7 +381,9 @@ impl<'a> FindUsages<'a> {
|
||||
let sema = self.sema;
|
||||
|
||||
let search_scope = {
|
||||
let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db);
|
||||
// FIXME: Is the trait scope needed for trait impl assoc items?
|
||||
let base =
|
||||
as_trait_assoc_def(sema.db, self.def).unwrap_or(self.def).search_scope(sema.db);
|
||||
match &self.scope {
|
||||
None => base,
|
||||
Some(scope) => base.intersection(scope),
|
||||
@ -651,13 +654,26 @@ impl<'a> FindUsages<'a> {
|
||||
sink(file_id, reference)
|
||||
}
|
||||
Some(NameRefClass::Definition(def))
|
||||
if match self.trait_assoc_def {
|
||||
Some(trait_assoc_def) => {
|
||||
// we have a trait assoc item, so force resolve all assoc items to their trait version
|
||||
convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
|
||||
}
|
||||
None => self.def == def,
|
||||
} =>
|
||||
if self.def == def
|
||||
// is our def a trait assoc item? then we want to find everything
|
||||
|| matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_)))
|
||||
&& convert_to_def_in_trait(self.sema.db, def) == self.def =>
|
||||
{
|
||||
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
|
||||
let reference = FileReference {
|
||||
range,
|
||||
name: ast::NameLike::NameRef(name_ref.clone()),
|
||||
category: ReferenceCategory::new(&def, name_ref),
|
||||
};
|
||||
sink(file_id, reference)
|
||||
}
|
||||
// FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions
|
||||
// so we always resolve all assoc type aliases to both their trait def and impl defs
|
||||
Some(NameRefClass::Definition(def))
|
||||
if self.assoc_item_container.is_some()
|
||||
&& matches!(self.def, Definition::TypeAlias(_))
|
||||
&& convert_to_def_in_trait(self.sema.db, def)
|
||||
== convert_to_def_in_trait(self.sema.db, self.def) =>
|
||||
{
|
||||
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
|
||||
let reference = FileReference {
|
||||
@ -748,12 +764,14 @@ impl<'a> FindUsages<'a> {
|
||||
false
|
||||
}
|
||||
Some(NameClass::Definition(def)) if def != self.def => {
|
||||
// if the def we are looking for is a trait (impl) assoc item, we'll have to resolve the items to trait definition assoc item
|
||||
if !matches!(
|
||||
self.trait_assoc_def,
|
||||
Some(trait_assoc_def)
|
||||
if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
|
||||
) {
|
||||
// only when looking for trait assoc items, we want to find other assoc items
|
||||
if !matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_)))
|
||||
// FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions
|
||||
// so we always resolve all assoc type aliases to both their trait def and impl defs
|
||||
&& !(matches!(self.def, Definition::TypeAlias(_))
|
||||
&& convert_to_def_in_trait(self.sema.db, def)
|
||||
== convert_to_def_in_trait(self.sema.db, self.def))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
|
||||
|
@ -1356,7 +1356,6 @@ fn main() {
|
||||
r#"
|
||||
trait Trait {
|
||||
fn func(self) {}
|
||||
//^^^^
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
@ -1376,7 +1375,6 @@ fn main() {
|
||||
r#"
|
||||
trait Trait {
|
||||
fn func(self) {}
|
||||
//^^^^
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
|
@ -1636,4 +1636,265 @@ pub fn deri$0ve(_stream: TokenStream) -> TokenStream {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assoc_items_trait_def() {
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
const CONST$0: usize;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
const CONST: usize = 0;
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
const CONST: usize = 0;
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::CONST;
|
||||
|
||||
let _ = T::CONST;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
CONST Const FileId(0) 18..37 24..29
|
||||
|
||||
FileId(0) 71..76
|
||||
FileId(0) 125..130
|
||||
FileId(0) 183..188
|
||||
FileId(0) 206..211
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
type TypeAlias$0;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type TypeAlias = ();
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
type TypeAlias = ();
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _: <() as Trait>::TypeAlias;
|
||||
|
||||
let _: T::TypeAlias;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
TypeAlias TypeAlias FileId(0) 18..33 23..32
|
||||
|
||||
FileId(0) 66..75
|
||||
FileId(0) 117..126
|
||||
FileId(0) 181..190
|
||||
FileId(0) 207..216
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
fn function$0() {}
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::function;
|
||||
|
||||
let _ = T::function;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
function Function FileId(0) 18..34 21..29
|
||||
|
||||
FileId(0) 65..73
|
||||
FileId(0) 112..120
|
||||
FileId(0) 166..174
|
||||
FileId(0) 192..200
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assoc_items_trait_impl_def() {
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
const CONST: usize;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
const CONST$0: usize = 0;
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
const CONST: usize = 0;
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::CONST;
|
||||
|
||||
let _ = T::CONST;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
CONST Const FileId(0) 65..88 71..76
|
||||
|
||||
FileId(0) 183..188
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
type TypeAlias;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type TypeAlias$0 = ();
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
type TypeAlias = ();
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _: <() as Trait>::TypeAlias;
|
||||
|
||||
let _: T::TypeAlias;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
TypeAlias TypeAlias FileId(0) 61..81 66..75
|
||||
|
||||
FileId(0) 23..32
|
||||
FileId(0) 117..126
|
||||
FileId(0) 181..190
|
||||
FileId(0) 207..216
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
fn function$0() {}
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::function;
|
||||
|
||||
let _ = T::function;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
function Function FileId(0) 62..78 65..73
|
||||
|
||||
FileId(0) 166..174
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assoc_items_ref() {
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
const CONST: usize;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
const CONST: usize = 0;
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
const CONST: usize = 0;
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::CONST$0;
|
||||
|
||||
let _ = T::CONST;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
CONST Const FileId(0) 65..88 71..76
|
||||
|
||||
FileId(0) 183..188
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
type TypeAlias;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type TypeAlias = ();
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
type TypeAlias = ();
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _: <() as Trait>::TypeAlias$0;
|
||||
|
||||
let _: T::TypeAlias;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
TypeAlias TypeAlias FileId(0) 18..33 23..32
|
||||
|
||||
FileId(0) 66..75
|
||||
FileId(0) 117..126
|
||||
FileId(0) 181..190
|
||||
FileId(0) 207..216
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
trait Trait {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
impl Trait for ((),) {
|
||||
fn function() {}
|
||||
}
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = <()>::function$0;
|
||||
|
||||
let _ = T::function;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
function Function FileId(0) 62..78 65..73
|
||||
|
||||
FileId(0) 166..174
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1044,7 +1044,7 @@ impl Config {
|
||||
&self.data.cargo_extraEnv
|
||||
}
|
||||
|
||||
pub fn check_on_save_extra_env(&self) -> FxHashMap<String, String> {
|
||||
pub fn check_extra_env(&self) -> FxHashMap<String, String> {
|
||||
let mut extra_env = self.data.cargo_extraEnv.clone();
|
||||
extra_env.extend(self.data.check_extraEnv.clone());
|
||||
extra_env
|
||||
@ -1165,7 +1165,7 @@ impl Config {
|
||||
FlycheckConfig::CustomCommand {
|
||||
command,
|
||||
args,
|
||||
extra_env: self.check_on_save_extra_env(),
|
||||
extra_env: self.check_extra_env(),
|
||||
invocation_strategy: match self.data.check_invocationStrategy {
|
||||
InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
|
||||
InvocationStrategy::PerWorkspace => {
|
||||
@ -1210,7 +1210,7 @@ impl Config {
|
||||
CargoFeaturesDef::Selected(it) => it,
|
||||
},
|
||||
extra_args: self.data.check_extraArgs.clone(),
|
||||
extra_env: self.check_on_save_extra_env(),
|
||||
extra_env: self.check_extra_env(),
|
||||
ansi_color_output: self.color_diagnostic_output(),
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user