From b4dd4752570d5f1ba24f7ffda69be4b1c935cd04 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 29 Apr 2020 14:49:54 +0200 Subject: More principled approach for finding From trait --- crates/ra_assists/src/utils.rs | 60 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'crates/ra_assists/src/utils.rs') diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 61f8bd1dc..efd988697 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs @@ -3,7 +3,7 @@ pub(crate) mod insert_use; use std::iter; -use hir::{Adt, Semantics, Type}; +use hir::{Adt, Crate, Semantics, Trait, Type}; use ra_ide_db::RootDatabase; use ra_syntax::{ ast::{self, make, NameOwner}, @@ -149,3 +149,61 @@ impl TryEnum { } } } + +/// Helps with finding well-know things inside the standard library. This is +/// somewhat similar to the known paths infra inside hir, but it different; We +/// want to make sure that IDE specific paths don't become interesting inside +/// the compiler itself as well. +pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); + +#[allow(non_snake_case)] +impl FamousDefs<'_, '_> { + #[cfg(test)] + pub(crate) const FIXTURE: &'static str = r#" +//- /libcore.rs crate:core +pub mod convert{ + pub trait From { + fn from(T) -> Self; + } +} + +pub mod prelude { pub use crate::convert::From } +#[prelude_import] +pub use prelude::*; +"#; + + pub(crate) fn core_convert_From(&self) -> Option { + self.find_trait("core:convert:From") + } + + fn find_trait(&self, path: &str) -> Option { + let db = self.0.db; + let mut path = path.split(':'); + let trait_ = path.next_back()?; + let std_crate = path.next()?; + let std_crate = self + .1 + .dependencies(db) + .into_iter() + .find(|dep| &dep.name.to_string() == std_crate)? + .krate; + + let mut module = std_crate.root_module(db)?; + for segment in path { + module = module.children(db).find_map(|child| { + let name = child.name(db)?; + if &name.to_string() == segment { + Some(child) + } else { + None + } + })?; + } + let def = + module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; + match def { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), + _ => None, + } + } +} -- cgit v1.2.3