This commit is contained in:
Lukas Wirth 2022-01-02 17:34:28 +01:00
parent aeb5d64912
commit 44b0fe8ec7
2 changed files with 46 additions and 29 deletions

View file

@ -5,6 +5,7 @@ mod source_to_def;
use std::{cell::RefCell, fmt}; use std::{cell::RefCell, fmt};
use base_db::{FileId, FileRange}; use base_db::{FileId, FileRange};
use either::Either;
use hir_def::{ use hir_def::{
body, body,
resolver::{self, HasResolver, Resolver, TypeNs}, resolver::{self, HasResolver, Resolver, TypeNs},
@ -909,42 +910,54 @@ impl<'db> SemanticsImpl<'db> {
return None; return None;
} }
let attr_def = let file = self.find_file(attr.syntax());
ast::Attr::to_def(self, self.find_file(attr.syntax()).with_value(attr.clone()))?; let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
let mut derive_paths = attr_def.parse_path_comma_token_tree()?; let res = self.with_ctx(|ctx| {
let derives = self.resolve_derive_macro(&attr)?; let attr_def = ctx.attr_to_def(file.with_value(attr.clone()))?;
let derives = ctx
.attr_to_derive_macro_call(file.with_value(&adt), file.with_value(attr.clone()))?;
let derive_idx = tt let mut derive_paths = attr_def.parse_path_comma_token_tree()?;
.syntax()
.children_with_tokens()
.filter_map(SyntaxElement::into_token)
.take_while(|tok| tok != syntax)
.filter(|t| t.kind() == T![,])
.count();
let path_segment_idx = syntax
.siblings_with_tokens(Direction::Prev)
.filter_map(SyntaxElement::into_token)
.take_while(|tok| matches!(tok.kind(), T![:] | T![ident]))
.filter(|tok| tok.kind() == T![ident])
.count();
let mut mod_path = derive_paths.nth(derive_idx)?; let derive_idx = tt
.syntax()
.children_with_tokens()
.filter_map(SyntaxElement::into_token)
.take_while(|tok| tok != syntax)
.filter(|t| t.kind() == T![,])
.count();
let path_segment_idx = syntax
.siblings_with_tokens(Direction::Prev)
.filter_map(SyntaxElement::into_token)
.take_while(|tok| matches!(tok.kind(), T![:] | T![ident]))
.filter(|tok| tok.kind() == T![ident])
.count();
if path_segment_idx < mod_path.len() { let mut mod_path = derive_paths.nth(derive_idx)?;
// the path for the given ident is a qualifier, resolve to module if possible
while path_segment_idx < mod_path.len() { if path_segment_idx < mod_path.len() {
mod_path.pop_segment(); // the path for the given ident is a qualifier, resolve to module if possible
while path_segment_idx < mod_path.len() {
mod_path.pop_segment();
}
Some(Either::Left(mod_path))
} else {
// otherwise fetch the derive
Some(Either::Right(derives[derive_idx]))
} }
resolve_hir_path( })?;
match res {
Either::Left(path) => resolve_hir_path(
self.db, self.db,
&self.scope(attr.syntax()).resolver, &self.scope(attr.syntax()).resolver,
&Path::from_known_path(mod_path, []), &Path::from_known_path(path, []),
) )
.filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))) .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
} else { Either::Right(derive) => derive
// otherwise fetch the derive .map(|call| MacroDef { id: self.db.lookup_intern_macro_call(call).def })
derives.get(derive_idx)?.map(PathResolution::Macro) .map(PathResolution::Macro),
} }
} }

View file

@ -746,7 +746,11 @@ impl Attr {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
return Some(paths.into_iter()); Some(paths.into_iter())
}
pub fn path(&self) -> &ModPath {
&self.path
} }
pub fn string_value(&self) -> Option<&SmolStr> { pub fn string_value(&self) -> Option<&SmolStr> {