2807: Use attr location for builtin derive in goto-implementation r=matklad a=edwin0cheng

This PR is use attribute location for builtin derive in `ImplBlock`'s NavigationTarget such that the goto-implementation will goto to a correct position. 

Related to #2531

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2020-01-12 11:33:31 +00:00 committed by GitHub
commit 8bb2a50ce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 2 deletions

View File

@ -26,10 +26,11 @@ use hir_ty::{
}; };
use ra_db::{CrateId, Edition, FileId}; use ra_db::{CrateId, Edition, FileId};
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::ast; use ra_syntax::ast::{self, AttrsOwner};
use crate::{ use crate::{
db::{DefDatabase, HirDatabase}, db::{DefDatabase, HirDatabase},
has_source::HasSource,
CallableDef, HirDisplay, InFile, Name, CallableDef, HirDisplay, InFile, Name,
}; };
@ -805,6 +806,27 @@ impl ImplBlock {
pub fn krate(&self, db: &impl DefDatabase) -> Crate { pub fn krate(&self, db: &impl DefDatabase) -> Crate {
Crate { id: self.module(db).id.krate } Crate { id: self.module(db).id.krate }
} }
pub fn is_builtin_derive(&self, db: &impl DefDatabase) -> Option<InFile<ast::Attr>> {
let src = self.source(db);
let item = src.file_id.is_builtin_derive(db)?;
let hygenic = hir_expand::hygiene::Hygiene::new(db, item.file_id);
let attr = item
.value
.attrs()
.filter_map(|it| {
let path = hir_def::path::ModPath::from_src(it.path()?, &hygenic)?;
if path.as_ident()?.to_string() == "derive" {
Some(it)
} else {
None
}
})
.last()?;
Some(item.with_value(attr))
}
} }
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]

View File

@ -112,6 +112,21 @@ impl HirFileId {
} }
} }
} }
/// Indicate it is macro file generated for builtin derive
pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::ModuleItem>> {
match self.0 {
HirFileIdRepr::FileId(_) => None,
HirFileIdRepr::MacroFile(macro_file) => {
let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
let item = match loc.def.kind {
MacroDefKind::BuiltInDerive(_) => loc.kind.node(db),
_ => return None,
};
Some(item.with_value(ast::ModuleItem::cast(item.value.clone())?))
}
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View File

@ -251,7 +251,11 @@ impl ToNav for hir::Module {
impl ToNav for hir::ImplBlock { impl ToNav for hir::ImplBlock {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
let src = self.source(db); let src = self.source(db);
let frange = original_range(db, src.as_ref().map(|it| it.syntax())); let frange = if let Some(item) = self.is_builtin_derive(db) {
original_range(db, item.syntax())
} else {
original_range(db, src.as_ref().map(|it| it.syntax()))
};
NavigationTarget::from_syntax( NavigationTarget::from_syntax(
frange.file_id, frange.file_id,

View File

@ -203,4 +203,16 @@ mod tests {
], ],
); );
} }
#[test]
fn goto_implementation_to_builtin_derive() {
check_goto(
"
//- /lib.rs
#[derive(Copy)]
struct Foo<|>;
",
&["impl IMPL_BLOCK FileId(1) [0; 15)"],
);
}
} }