use hir::{AsAssocItem, HasVisibility, Semantics};
use ide_db::{
- defs::{Definition, NameClass, NameRefClass},
- helpers::{try_resolve_derive_input, FamousDefs},
+ defs::{Definition, IdentClass, NameClass, NameRefClass},
+ famous_defs::FamousDefs,
RootDatabase, SymbolKind,
};
use rustc_hash::FxHashMap;
use syntax::{
- ast, match_ast, AstNode, AstToken, NodeOrToken, SyntaxElement,
+ ast, match_ast, AstNode, AstToken, NodeOrToken,
SyntaxKind::{self, *},
SyntaxNode, SyntaxToken, T,
};
Highlight, HlMod, HlTag,
};
-pub(super) fn element(
- sema: &Semantics<RootDatabase>,
- krate: Option<hir::Crate>,
- bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
- syntactic_name_ref_highlighting: bool,
- element: SyntaxElement,
-) -> Option<(Highlight, Option<u64>)> {
- match element {
- NodeOrToken::Node(it) => {
- node(sema, krate, bindings_shadow_count, syntactic_name_ref_highlighting, it)
- }
- NodeOrToken::Token(it) => Some((token(sema, krate, it)?, None)),
- }
-}
-
-fn token(
- sema: &Semantics<RootDatabase>,
- krate: Option<hir::Crate>,
- token: SyntaxToken,
-) -> Option<Highlight> {
- let highlight: Highlight = if let Some(comment) = ast::Comment::cast(token.clone()) {
+pub(super) fn token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Highlight> {
+ if let Some(comment) = ast::Comment::cast(token.clone()) {
let h = HlTag::Comment;
- match comment.kind().doc {
+ return Some(match comment.kind().doc {
Some(_) => h | HlMod::Documentation,
None => h.into(),
- }
- } else {
- match token.kind() {
- STRING | BYTE_STRING => HlTag::StringLiteral.into(),
- INT_NUMBER if token.ancestors().nth(1).map_or(false, |it| it.kind() == FIELD_EXPR) => {
- SymbolKind::Field.into()
- }
- INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
- BYTE => HlTag::ByteLiteral.into(),
- CHAR => HlTag::CharLiteral.into(),
- T![?] => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
- IDENT if parent_matches::<ast::TokenTree>(&token) => {
- if let Some(attr) = token.ancestors().nth(2).and_then(ast::Attr::cast) {
- match try_resolve_derive_input(sema, &attr, &ast::Ident::cast(token).unwrap()) {
- Some(res) => highlight_def(sema, krate, Definition::from(res)),
- None => HlTag::None.into(),
- }
- } else {
- HlTag::None.into()
- }
- }
- p if p.is_punct() => match p {
- T![&] if parent_matches::<ast::BinExpr>(&token) => HlOperator::Bitwise.into(),
- T![&] => {
- let h = HlTag::Operator(HlOperator::Other).into();
- let is_unsafe = token
- .parent()
- .and_then(ast::RefExpr::cast)
- .map_or(false, |ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
- if is_unsafe {
- h | HlMod::Unsafe
- } else {
- h
- }
- }
- T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => {
- HlOperator::Other.into()
- }
- T![!] if parent_matches::<ast::MacroCall>(&token) => SymbolKind::Macro.into(),
- T![!] if parent_matches::<ast::NeverType>(&token) => HlTag::BuiltinType.into(),
- T![!] if parent_matches::<ast::PrefixExpr>(&token) => HlOperator::Logical.into(),
- T![*] if parent_matches::<ast::PtrType>(&token) => HlTag::Keyword.into(),
- T![*] if parent_matches::<ast::PrefixExpr>(&token) => {
- let prefix_expr = token.parent().and_then(ast::PrefixExpr::cast)?;
-
- let expr = prefix_expr.expr()?;
- let ty = sema.type_of_expr(&expr)?.original;
- if ty.is_raw_ptr() {
- HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
- } else if let Some(ast::UnaryOp::Deref) = prefix_expr.op_kind() {
- HlOperator::Other.into()
- } else {
- HlPunct::Other.into()
- }
- }
- T![-] if parent_matches::<ast::PrefixExpr>(&token) => {
- let prefix_expr = token.parent().and_then(ast::PrefixExpr::cast)?;
+ });
+ }
- let expr = prefix_expr.expr()?;
- match expr {
- ast::Expr::Literal(_) => HlTag::NumericLiteral,
- _ => HlTag::Operator(HlOperator::Other),
- }
- .into()
- }
- _ if parent_matches::<ast::PrefixExpr>(&token) => HlOperator::Other.into(),
- T![+] | T![-] | T![*] | T![/] if parent_matches::<ast::BinExpr>(&token) => {
- HlOperator::Arithmetic.into()
- }
- T![+=] | T![-=] | T![*=] | T![/=] if parent_matches::<ast::BinExpr>(&token) => {
- Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable
- }
- T![|] | T![&] | T![!] | T![^] if parent_matches::<ast::BinExpr>(&token) => {
- HlOperator::Bitwise.into()
- }
- T![|=] | T![&=] | T![^=] if parent_matches::<ast::BinExpr>(&token) => {
- Highlight::from(HlOperator::Bitwise) | HlMod::Mutable
- }
- T![&&] | T![||] if parent_matches::<ast::BinExpr>(&token) => {
- HlOperator::Logical.into()
- }
- T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
- if parent_matches::<ast::BinExpr>(&token) =>
- {
- HlOperator::Comparison.into()
- }
- _ if parent_matches::<ast::BinExpr>(&token) => HlOperator::Other.into(),
- _ if parent_matches::<ast::RangeExpr>(&token) => HlOperator::Other.into(),
- _ if parent_matches::<ast::RangePat>(&token) => HlOperator::Other.into(),
- _ if parent_matches::<ast::RestPat>(&token) => HlOperator::Other.into(),
- _ if parent_matches::<ast::Attr>(&token) => HlTag::Attribute.into(),
- kind => match kind {
- T!['['] | T![']'] => HlPunct::Bracket,
- T!['{'] | T!['}'] => HlPunct::Brace,
- T!['('] | T![')'] => HlPunct::Parenthesis,
- T![<] | T![>] => HlPunct::Angle,
- T![,] => HlPunct::Comma,
- T![:] => HlPunct::Colon,
- T![;] => HlPunct::Semi,
- T![.] => HlPunct::Dot,
- _ => HlPunct::Other,
- }
- .into(),
- },
- k if k.is_keyword() => {
- let h = Highlight::new(HlTag::Keyword);
- match k {
- T![await] => h | HlMod::Async | HlMod::ControlFlow,
- T![break]
- | T![continue]
- | T![else]
- | T![if]
- | T![in]
- | T![loop]
- | T![match]
- | T![return]
- | T![while]
- | T![yield] => h | HlMod::ControlFlow,
- T![for] if !is_child_of_impl(&token) => h | HlMod::ControlFlow,
- T![unsafe] => h | HlMod::Unsafe,
- T![true] | T![false] => HlTag::BoolLiteral.into(),
- // crate is handled just as a token if it's in an `extern crate`
- T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
- // self, crate and super are handled as either a Name or NameRef already
- T![self] | T![crate] | T![super] => return None,
- T![ref] => token
- .parent()
- .and_then(ast::IdentPat::cast)
- .and_then(|ident_pat| {
- (sema.is_unsafe_ident_pat(&ident_pat)).then(|| HlMod::Unsafe)
- })
- .map_or(h, |modifier| h | modifier),
- T![async] => h | HlMod::Async,
- _ => h,
- }
- }
- _ => return None,
+ let highlight: Highlight = match token.kind() {
+ STRING | BYTE_STRING => HlTag::StringLiteral.into(),
+ INT_NUMBER if token.ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => {
+ SymbolKind::Field.into()
+ }
+ INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
+ BYTE => HlTag::ByteLiteral.into(),
+ CHAR => HlTag::CharLiteral.into(),
+ IDENT if token.parent().and_then(ast::TokenTree::cast).is_some() => {
+ // from this point on we are inside a token tree, this only happens for identifiers
+ // that were not mapped down into macro invocations
+ HlTag::None.into()
}
+ p if p.is_punct() => punctuation(sema, token, p),
+ k if k.is_keyword() => keyword(sema, token, k)?,
+ _ => return None,
};
Some(highlight)
}
-fn node(
+pub(super) fn name_like(
sema: &Semantics<RootDatabase>,
krate: Option<hir::Crate>,
bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
syntactic_name_ref_highlighting: bool,
- node: SyntaxNode,
+ name_like: ast::NameLike,
) -> Option<(Highlight, Option<u64>)> {
let mut binding_hash = None;
- let highlight = match_ast! {
- match node {
- ast::Fn(__) => {
- bindings_shadow_count.clear();
- return None;
- },
- ast::Attr(__) => {
- HlTag::Attribute.into()
- },
- // Highlight definitions depending on the "type" of the definition.
- ast::Name(name) => {
- highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
- },
- // Highlight references like the definitions they resolve to
- ast::NameRef(name_ref) => {
- highlight_name_ref(
- sema,
- krate,
- bindings_shadow_count,
- &mut binding_hash,
- syntactic_name_ref_highlighting,
- name_ref,
- )
- },
- ast::Lifetime(lifetime) => {
- match NameClass::classify_lifetime(sema, &lifetime) {
- Some(NameClass::Definition(def)) => {
- highlight_def(sema, krate, def) | HlMod::Definition
- }
- None => match NameRefClass::classify_lifetime(sema, &lifetime) {
- Some(NameRefClass::Definition(def)) => highlight_def(sema, krate, def),
- _ => SymbolKind::LifetimeParam.into(),
- },
- _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition,
- }
- },
- _ => return None,
+ let highlight = match name_like {
+ ast::NameLike::NameRef(name_ref) => highlight_name_ref(
+ sema,
+ krate,
+ bindings_shadow_count,
+ &mut binding_hash,
+ syntactic_name_ref_highlighting,
+ name_ref,
+ ),
+ ast::NameLike::Name(name) => {
+ highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
}
+ ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
+ Some(IdentClass::NameClass(NameClass::Definition(def))) => {
+ highlight_def(sema, krate, def) | HlMod::Definition
+ }
+ Some(IdentClass::NameRefClass(NameRefClass::Definition(def))) => {
+ highlight_def(sema, krate, def)
+ }
+ // FIXME: Fallback for 'static and '_, as we do not resolve these yet
+ _ => SymbolKind::LifetimeParam.into(),
+ },
};
Some((highlight, binding_hash))
}
+fn punctuation(sema: &Semantics<RootDatabase>, token: SyntaxToken, kind: SyntaxKind) -> Highlight {
+ let parent = token.parent();
+ let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind);
+ match (kind, parent_kind) {
+ (T![?], _) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
+ (T![&], BIN_EXPR) => HlOperator::Bitwise.into(),
+ (T![&], _) => {
+ let h = HlTag::Operator(HlOperator::Other).into();
+ let is_unsafe = parent
+ .and_then(ast::RefExpr::cast)
+ .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
+ if let Some(true) = is_unsafe {
+ h | HlMod::Unsafe
+ } else {
+ h
+ }
+ }
+ (T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(),
+ (T![!], MACRO_CALL) => HlPunct::MacroBang.into(),
+ (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
+ (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
+ (T![*], PTR_TYPE) => HlTag::Keyword.into(),
+ (T![*], PREFIX_EXPR) => {
+ let is_raw_ptr = (|| {
+ let prefix_expr = parent.and_then(ast::PrefixExpr::cast)?;
+ let expr = prefix_expr.expr()?;
+ sema.type_of_expr(&expr)?.original.is_raw_ptr().then(|| ())
+ })();
+ if let Some(()) = is_raw_ptr {
+ HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
+ } else {
+ HlOperator::Other.into()
+ }
+ }
+ (T![-], PREFIX_EXPR) => {
+ let prefix_expr = parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
+ match prefix_expr {
+ Some(ast::Expr::Literal(_)) => HlTag::NumericLiteral,
+ _ => HlTag::Operator(HlOperator::Other),
+ }
+ .into()
+ }
+ (T![+] | T![-] | T![*] | T![/] | T![%], BIN_EXPR) => HlOperator::Arithmetic.into(),
+ (T![+=] | T![-=] | T![*=] | T![/=] | T![%=], BIN_EXPR) => {
+ Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable
+ }
+ (T![|] | T![&] | T![!] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(),
+ (T![|=] | T![&=] | T![^=] | T![>>=] | T![<<=], BIN_EXPR) => {
+ Highlight::from(HlOperator::Bitwise) | HlMod::Mutable
+ }
+ (T![&&] | T![||], BIN_EXPR) => HlOperator::Logical.into(),
+ (T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=], BIN_EXPR) => {
+ HlOperator::Comparison.into()
+ }
+ (_, PREFIX_EXPR | BIN_EXPR | RANGE_EXPR | RANGE_PAT | REST_PAT) => HlOperator::Other.into(),
+ (_, ATTR) => HlTag::AttributeBracket.into(),
+ (kind, _) => match kind {
+ T!['['] | T![']'] => HlPunct::Bracket,
+ T!['{'] | T!['}'] => HlPunct::Brace,
+ T!['('] | T![')'] => HlPunct::Parenthesis,
+ T![<] | T![>] => HlPunct::Angle,
+ T![,] => HlPunct::Comma,
+ T![:] => HlPunct::Colon,
+ T![;] => HlPunct::Semi,
+ T![.] => HlPunct::Dot,
+ _ => HlPunct::Other,
+ }
+ .into(),
+ }
+}
+
+fn keyword(
+ sema: &Semantics<RootDatabase>,
+ token: SyntaxToken,
+ kind: SyntaxKind,
+) -> Option<Highlight> {
+ let h = Highlight::new(HlTag::Keyword);
+ let h = match kind {
+ T![await] => h | HlMod::Async | HlMod::ControlFlow,
+ T![async] => h | HlMod::Async,
+ T![break]
+ | T![continue]
+ | T![else]
+ | T![if]
+ | T![in]
+ | T![loop]
+ | T![match]
+ | T![return]
+ | T![while]
+ | T![yield] => h | HlMod::ControlFlow,
+ T![for] if parent_matches::<ast::ForExpr>(&token) => h | HlMod::ControlFlow,
+ T![unsafe] => h | HlMod::Unsafe,
+ T![true] | T![false] => HlTag::BoolLiteral.into(),
+ // crate is handled just as a token if it's in an `extern crate`
+ T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
+ // self, crate, super and `Self` are handled as either a Name or NameRef already, unless they
+ // are inside unmapped token trees
+ T![self] | T![crate] | T![super] | T![Self] if parent_matches::<ast::NameRef>(&token) => {
+ return None
+ }
+ T![self] if parent_matches::<ast::Name>(&token) => return None,
+ T![ref] => match token.parent().and_then(ast::IdentPat::cast) {
+ Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe,
+ _ => h,
+ },
+ _ => h,
+ };
+ Some(h)
+}
+
fn highlight_name_ref(
sema: &Semantics<RootDatabase>,
krate: Option<hir::Crate>,
name_ref: ast::NameRef,
) -> Highlight {
let db = sema.db;
- highlight_method_call_by_name_ref(sema, krate, &name_ref).unwrap_or_else(|| {
- let name_class = match NameRefClass::classify(sema, &name_ref) {
- Some(name_kind) => name_kind,
- None => {
- return if syntactic_name_ref_highlighting {
- highlight_name_ref_by_syntax(name_ref, sema, krate)
- } else {
- // FIXME: Workaround for https://github.com/rust-analyzer/rust-analyzer/issues/10708
- //
- // Some popular proc macros (namely async_trait) will rewrite `self` in such a way that it no
- // longer resolves via NameRefClass. If we can't be resolved, but we know we're a self token,
- // within a function with a self param, pretend to still be `self`, rather than
- // an unresolved reference.
- if name_ref.self_token().is_some() && is_in_fn_with_self_param(&name_ref) {
- SymbolKind::SelfParam.into()
- } else {
- HlTag::UnresolvedReference.into()
- }
- };
- }
- };
- let mut h = match name_class {
- NameRefClass::Definition(def) => {
- if let Definition::Local(local) = &def {
- if let Some(name) = local.name(db) {
- let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
- *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
- }
- };
+ if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref) {
+ return res;
+ }
+
+ let name_class = match NameRefClass::classify(sema, &name_ref) {
+ Some(name_kind) => name_kind,
+ None if syntactic_name_ref_highlighting => {
+ return highlight_name_ref_by_syntax(name_ref, sema, krate)
+ }
+ // FIXME: This is required for helper attributes used by proc-macros, as those do not map down
+ // to anything when used.
+ // We can fix this for derive attributes since derive helpers are recorded, but not for
+ // general attributes.
+ None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR) => {
+ return HlTag::Symbol(SymbolKind::Attribute).into();
+ }
+ None => return HlTag::UnresolvedReference.into(),
+ };
+ let mut h = match name_class {
+ NameRefClass::Definition(def) => {
+ if let Definition::Local(local) = &def {
+ let name = local.name(db);
+ let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+ *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+ };
- let mut h = highlight_def(sema, krate, def);
+ let mut h = highlight_def(sema, krate, def);
- match def {
- Definition::Local(local)
- if is_consumed_lvalue(name_ref.syntax(), &local, db) =>
+ match def {
+ Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => {
+ h |= HlMod::Consuming;
+ }
+ Definition::Trait(trait_) if trait_.is_unsafe(db) => {
+ if ast::Impl::for_trait_name_ref(&name_ref)
+ .map_or(false, |impl_| impl_.unsafe_token().is_some())
{
- h |= HlMod::Consuming;
+ h |= HlMod::Unsafe;
}
- Definition::Trait(trait_) if trait_.is_unsafe(db) => {
- if ast::Impl::for_trait_name_ref(&name_ref)
- .map_or(false, |impl_| impl_.unsafe_token().is_some())
- {
- h |= HlMod::Unsafe;
+ }
+ Definition::Field(field) => {
+ if let Some(parent) = name_ref.syntax().parent() {
+ if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
+ if let hir::VariantDef::Union(_) = field.parent_def(db) {
+ h |= HlMod::Unsafe;
+ }
}
}
- Definition::Field(field) => {
- if let Some(parent) = name_ref.syntax().parent() {
- if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
- if let hir::VariantDef::Union(_) = field.parent_def(db) {
- h |= HlMod::Unsafe;
- }
- }
+ }
+ Definition::Macro(_) => {
+ if let Some(macro_call) =
+ ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
+ .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
+ {
+ if sema.is_unsafe_macro_call(¯o_call) {
+ h |= HlMod::Unsafe;
}
}
- _ => (),
}
-
- h
- }
- NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
- };
- if h.tag == HlTag::Symbol(SymbolKind::Module) {
- if name_ref.self_token().is_some() {
- return SymbolKind::SelfParam.into();
- }
- if name_ref.crate_token().is_some() || name_ref.super_token().is_some() {
- h.tag = HlTag::Keyword;
+ _ => (),
}
+
+ h
}
- h
- })
+ NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
+ };
+
+ h.tag = match name_ref.token_kind() {
+ T![Self] => HlTag::Symbol(SymbolKind::SelfType),
+ T![self] => HlTag::Symbol(SymbolKind::SelfParam),
+ T![super] | T![crate] => HlTag::Keyword,
+ _ => h.tag,
+ };
+ h
}
fn highlight_name(
krate: Option<hir::Crate>,
name: ast::Name,
) -> Highlight {
- let db = sema.db;
let name_kind = NameClass::classify(sema, &name);
if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
- if let Some(name) = local.name(db) {
- let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
- *shadow_count += 1;
- *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
- }
+ let name = local.name(sema.db);
+ let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+ *shadow_count += 1;
+ *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
};
match name_kind {
Some(NameClass::Definition(def)) => {
let mut h = highlight_def(sema, krate, def) | HlMod::Definition;
if let Definition::Trait(trait_) = &def {
- if trait_.is_unsafe(db) {
+ if trait_.is_unsafe(sema.db) {
h |= HlMod::Unsafe;
}
}
Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def),
Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
let mut h = HlTag::Symbol(SymbolKind::Field).into();
- if let hir::VariantDef::Union(_) = field_ref.parent_def(db) {
+ if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) {
h |= HlMod::Unsafe;
}
h
) -> Highlight {
let db = sema.db;
let mut h = match def {
- Definition::Macro(_) => Highlight::new(HlTag::Symbol(SymbolKind::Macro)),
+ Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind(sema.db).into())),
Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
Definition::Module(module) => {
let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
}
}
PATH_SEGMENT => {
+ let name_based_fallback = || {
+ if name.text().chars().next().unwrap_or_default().is_uppercase() {
+ SymbolKind::Struct.into()
+ } else {
+ SymbolKind::Module.into()
+ }
+ };
let path = match parent.parent().and_then(ast::Path::cast) {
Some(it) => it,
- _ => return default.into(),
+ _ => return name_based_fallback(),
};
- let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
- Some(it) => it,
- _ => {
- // within path, decide whether it is module or adt by checking for uppercase name
- return if name.text().chars().next().unwrap_or_default().is_uppercase() {
- SymbolKind::Struct
- } else {
- SymbolKind::Module
+ let expr = match path.syntax().parent() {
+ Some(parent) => match_ast! {
+ match parent {
+ ast::PathExpr(path) => path,
+ ast::MacroCall(_) => return SymbolKind::Macro.into(),
+ _ => return name_based_fallback(),
}
- .into();
- }
+ },
+ // within path, decide whether it is module or adt by checking for uppercase name
+ None => return name_based_fallback(),
};
let parent = match expr.syntax().parent() {
Some(it) => it,
kinds.is_empty()
}
-#[inline]
fn parent_matches<N: AstNode>(token: &SyntaxToken) -> bool {
token.parent().map_or(false, |it| N::can_cast(it.kind()))
}
-
-fn is_child_of_impl(token: &SyntaxToken) -> bool {
- match token.parent() {
- Some(e) => e.kind() == IMPL,
- _ => false,
- }
-}
-
-fn is_in_fn_with_self_param<N: AstNode>(node: &N) -> bool {
- node.syntax()
- .ancestors()
- .find_map(ast::Fn::cast)
- .and_then(|s| s.param_list()?.self_param())
- .is_some()
-}