mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Fix NameRef::classify
path resolution inside attributes
This commit is contained in:
parent
9ef62b0ccd
commit
9957220dfe
4 changed files with 48 additions and 42 deletions
|
@ -11,7 +11,10 @@ use ide_db::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, T};
|
use syntax::{
|
||||||
|
algo, ast, display::fn_as_proc_macro_label, match_ast, AstNode, AstToken, Direction,
|
||||||
|
SyntaxKind::*, SyntaxToken, T,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::{macro_label, TryToNav},
|
display::{macro_label, TryToNav},
|
||||||
|
@ -166,6 +169,7 @@ pub(crate) fn hover(
|
||||||
|
|
||||||
let node = token
|
let node = token
|
||||||
.ancestors()
|
.ancestors()
|
||||||
|
.take_while(|it| !ast::Item::can_cast(it.kind()))
|
||||||
.find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
|
.find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
|
||||||
|
|
||||||
let ty = match_ast! {
|
let ty = match_ast! {
|
||||||
|
@ -409,16 +413,13 @@ fn hover_for_definition(
|
||||||
) -> Option<Markup> {
|
) -> Option<Markup> {
|
||||||
let mod_path = definition_mod_path(db, &def);
|
let mod_path = definition_mod_path(db, &def);
|
||||||
let (label, docs) = match def {
|
let (label, docs) = match def {
|
||||||
Definition::Macro(it) => match &it.source(db)?.value {
|
Definition::Macro(it) => (
|
||||||
Either::Left(mac) => {
|
match &it.source(db)?.value {
|
||||||
let label = macro_label(mac);
|
Either::Left(mac) => macro_label(mac),
|
||||||
(label, it.attrs(db).docs())
|
Either::Right(mac_fn) => fn_as_proc_macro_label(mac_fn),
|
||||||
}
|
|
||||||
Either::Right(_) => {
|
|
||||||
// FIXME
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
it.attrs(db).docs(),
|
||||||
|
),
|
||||||
Definition::Field(def) => label_and_docs(db, def),
|
Definition::Field(def) => label_and_docs(db, def),
|
||||||
Definition::ModuleDef(it) => match it {
|
Definition::ModuleDef(it) => match it {
|
||||||
hir::ModuleDef::Module(it) => label_and_docs(db, it),
|
hir::ModuleDef::Module(it) => label_and_docs(db, it),
|
||||||
|
|
|
@ -1308,24 +1308,6 @@ fn test$0() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_attr_matches_proc_macro_fn() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
fn my_proc_macro() {}
|
|
||||||
|
|
||||||
#[my_proc_macro$0]
|
|
||||||
fn test() {}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
my_proc_macro Function FileId(0) 0..45 27..40
|
|
||||||
|
|
||||||
FileId(0) 49..62
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_const_in_pattern() {
|
fn test_const_in_pattern() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
|
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
db::HirDatabase, Crate, Field, GenericParam, HasAttrs, HasVisibility, Impl, Label, Local,
|
db::HirDatabase, Crate, Field, GenericParam, HasVisibility, Impl, Label, Local, MacroDef,
|
||||||
MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, Visibility,
|
Module, ModuleDef, Name, PathResolution, Semantics, Visibility,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, PathSegmentKind},
|
ast::{self, AstNode, PathSegmentKind},
|
||||||
|
@ -385,15 +385,22 @@ impl NameRefClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(resolved) = sema.resolve_path(&path) {
|
if let Some(resolved) = sema.resolve_path(&path) {
|
||||||
if path.syntax().ancestors().find_map(ast::Attr::cast).is_some() {
|
return if path.syntax().ancestors().find_map(ast::Attr::cast).is_some() {
|
||||||
if let PathResolution::Def(ModuleDef::Function(func)) = resolved {
|
match resolved {
|
||||||
if func.attrs(sema.db).by_key("proc_macro_attribute").exists() {
|
// Don't wanna collide with builtin attributes here like `test` hence guard
|
||||||
return Some(NameRefClass::Definition(resolved.into()));
|
PathResolution::Def(module @ ModuleDef::Module(_))
|
||||||
|
if path.parent_path().is_some() =>
|
||||||
|
{
|
||||||
|
Some(NameRefClass::Definition(Definition::ModuleDef(module)))
|
||||||
}
|
}
|
||||||
|
PathResolution::Macro(mac) if mac.kind() == hir::MacroKind::Attr => {
|
||||||
|
Some(NameRefClass::Definition(Definition::Macro(mac)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Some(NameRefClass::Definition(resolved.into()));
|
Some(NameRefClass::Definition(resolved.into()))
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,19 +77,35 @@ pub fn type_label(node: &ast::TypeAlias) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macro_label(node: &ast::Macro) -> String {
|
pub fn macro_label(node: &ast::Macro) -> String {
|
||||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
let name = node.name();
|
||||||
|
let mut s = String::new();
|
||||||
match node {
|
match node {
|
||||||
ast::Macro::MacroRules(node) => {
|
ast::Macro::MacroRules(node) => {
|
||||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export] " } else { "" };
|
let vis = if node.has_atom_attr("macro_export") { "#[macro_export] " } else { "" };
|
||||||
format!("{}macro_rules! {}", vis, name)
|
format_to!(s, "{}macro_rules!", vis);
|
||||||
}
|
}
|
||||||
ast::Macro::MacroDef(node) => {
|
ast::Macro::MacroDef(node) => {
|
||||||
|
if let Some(vis) = node.visibility() {
|
||||||
|
format_to!(s, "{} ", vis);
|
||||||
|
}
|
||||||
|
format_to!(s, "macro");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(name) = name {
|
||||||
|
format_to!(s, " {}", name);
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fn_as_proc_macro_label(node: &ast::Fn) -> String {
|
||||||
|
let name = node.name();
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
if let Some(vis) = node.visibility() {
|
if let Some(vis) = node.visibility() {
|
||||||
format_to!(s, "{} ", vis);
|
format_to!(s, "{} ", vis);
|
||||||
}
|
}
|
||||||
format_to!(s, "macro {}", name);
|
format_to!(s, "macro");
|
||||||
|
if let Some(name) = name {
|
||||||
|
format_to!(s, " {}", name);
|
||||||
|
}
|
||||||
s
|
s
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue