mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Merge commit 'aa9bc86125
' into sync-from-ra
This commit is contained in:
parent
1570299af4
commit
c48062fe2a
598 changed files with 57696 additions and 17615 deletions
|
@ -4,7 +4,6 @@ use hir_def::{
|
|||
attr::{AttrsWithOwner, Documentation},
|
||||
item_scope::ItemInNs,
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
resolver::HasResolver,
|
||||
AttrDefId, GenericParamId, ModuleDefId,
|
||||
};
|
||||
|
@ -41,7 +40,7 @@ macro_rules! impl_has_attrs {
|
|||
impl HasAttrs for $def {
|
||||
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
|
||||
let def = AttrDefId::$def_id(self.into());
|
||||
db.attrs(def)
|
||||
db.attrs_with_owner(def)
|
||||
}
|
||||
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
|
||||
let def = AttrDefId::$def_id(self.into());
|
||||
|
@ -121,6 +120,7 @@ impl HasAttrs for AssocItem {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resolves the item `link` points to in the scope of `def`.
|
||||
fn resolve_doc_path(
|
||||
db: &dyn HirDatabase,
|
||||
def: AttrDefId,
|
||||
|
@ -155,14 +155,14 @@ fn resolve_doc_path(
|
|||
.syntax_node()
|
||||
.descendants()
|
||||
.find_map(ast::Path::cast)?;
|
||||
if ast_path.to_string() != link {
|
||||
if ast_path.syntax().text() != link {
|
||||
return None;
|
||||
}
|
||||
ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())?
|
||||
};
|
||||
|
||||
let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
|
||||
let resolved = if resolved == PerNs::none() {
|
||||
let resolved = if resolved.is_none() {
|
||||
resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
|
||||
} else {
|
||||
resolved
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
pub use hir_def::db::*;
|
||||
pub use hir_expand::db::{
|
||||
AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery,
|
||||
InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery,
|
||||
MacroExpandQuery, ParseMacroExpansionQuery,
|
||||
InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery,
|
||||
ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery,
|
||||
};
|
||||
pub use hir_ty::db::*;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use cfg::{CfgExpr, CfgOptions};
|
|||
use either::Either;
|
||||
use hir_def::path::ModPath;
|
||||
use hir_expand::{name::Name, HirFileId, InFile};
|
||||
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
|
||||
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
|
||||
|
||||
use crate::{AssocItem, Field, Local, MacroKind, Type};
|
||||
|
||||
|
@ -38,19 +38,25 @@ diagnostics![
|
|||
IncorrectCase,
|
||||
InvalidDeriveTarget,
|
||||
IncoherentImpl,
|
||||
MacroDefError,
|
||||
MacroError,
|
||||
MacroExpansionParseError,
|
||||
MalformedDerive,
|
||||
MismatchedArgCount,
|
||||
MissingFields,
|
||||
MissingMatchArms,
|
||||
MissingUnsafe,
|
||||
MovedOutOfRef,
|
||||
NeedMut,
|
||||
NoSuchField,
|
||||
PrivateAssocItem,
|
||||
PrivateField,
|
||||
ReplaceFilterMapNextWithFindMap,
|
||||
TypedHole,
|
||||
TypeMismatch,
|
||||
UndeclaredLabel,
|
||||
UnimplementedBuiltinMacro,
|
||||
UnreachableLabel,
|
||||
UnresolvedExternCrate,
|
||||
UnresolvedField,
|
||||
UnresolvedImport,
|
||||
|
@ -61,6 +67,19 @@ diagnostics![
|
|||
UnusedMut,
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BreakOutsideOfLoop {
|
||||
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||
pub is_break: bool,
|
||||
pub bad_value_break: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypedHole {
|
||||
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||
pub expected: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnresolvedModule {
|
||||
pub decl: InFile<AstPtr<ast::Module>>,
|
||||
|
@ -84,6 +103,17 @@ pub struct UnresolvedMacroCall {
|
|||
pub path: ModPath,
|
||||
pub is_bang: bool,
|
||||
}
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct UnreachableLabel {
|
||||
pub node: InFile<AstPtr<ast::Lifetime>>,
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct UndeclaredLabel {
|
||||
pub node: InFile<AstPtr<ast::Lifetime>>,
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct InactiveCode {
|
||||
|
@ -111,6 +141,20 @@ pub struct MacroError {
|
|||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct MacroExpansionParseError {
|
||||
pub node: InFile<SyntaxNodePtr>,
|
||||
pub precise_location: Option<TextRange>,
|
||||
pub errors: Box<[SyntaxError]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct MacroDefError {
|
||||
pub node: InFile<AstPtr<ast::Macro>>,
|
||||
pub message: String,
|
||||
pub name: Option<TextRange>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnimplementedBuiltinMacro {
|
||||
pub node: InFile<SyntaxNodePtr>,
|
||||
|
@ -166,13 +210,6 @@ pub struct PrivateField {
|
|||
pub field: Field,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BreakOutsideOfLoop {
|
||||
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||
pub is_break: bool,
|
||||
pub bad_value_break: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MissingUnsafe {
|
||||
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||
|
@ -223,3 +260,9 @@ pub struct NeedMut {
|
|||
pub struct UnusedMut {
|
||||
pub local: Local,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MovedOutOfRef {
|
||||
pub ty: Type,
|
||||
pub span: InFile<SyntaxNodePtr>,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! HirDisplay implementations for various hir types.
|
||||
use hir_def::{
|
||||
adt::VariantData,
|
||||
data::adt::VariantData,
|
||||
generics::{
|
||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||
},
|
||||
|
@ -8,6 +8,7 @@ use hir_def::{
|
|||
type_ref::{TypeBound, TypeRef},
|
||||
AdtId, GenericDefId,
|
||||
};
|
||||
use hir_expand::name;
|
||||
use hir_ty::{
|
||||
display::{
|
||||
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
|
||||
|
@ -50,7 +51,7 @@ impl HirDisplay for Function {
|
|||
// FIXME: String escape?
|
||||
write!(f, "extern \"{}\" ", &**abi)?;
|
||||
}
|
||||
write!(f, "fn {}", data.name)?;
|
||||
write!(f, "fn {}", data.name.display(f.db.upcast()))?;
|
||||
|
||||
write_generic_params(GenericDefId::FunctionId(self.id), f)?;
|
||||
|
||||
|
@ -62,7 +63,7 @@ impl HirDisplay for Function {
|
|||
{
|
||||
f.write_char('&')?;
|
||||
if let Some(lifetime) = lifetime {
|
||||
write!(f, "{} ", lifetime.name)?;
|
||||
write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
|
||||
}
|
||||
if let hir_def::type_ref::Mutability::Mut = mut_ {
|
||||
f.write_str("mut ")?;
|
||||
|
@ -76,22 +77,22 @@ impl HirDisplay for Function {
|
|||
};
|
||||
|
||||
let mut first = true;
|
||||
for (name, type_ref) in &data.params {
|
||||
// FIXME: Use resolved `param.ty` once we no longer discard lifetimes
|
||||
for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)) {
|
||||
let local = param.as_local(db).map(|it| it.name(db));
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
if data.has_self_param() {
|
||||
if local == Some(name!(self)) {
|
||||
write_self_param(type_ref, f)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match name {
|
||||
Some(name) => write!(f, "{name}: ")?,
|
||||
match local {
|
||||
Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?,
|
||||
None => f.write_str("_: ")?,
|
||||
}
|
||||
// FIXME: Use resolved `param.ty` or raw `type_ref`?
|
||||
// The former will ignore lifetime arguments currently.
|
||||
type_ref.hir_fmt(f)?;
|
||||
}
|
||||
|
||||
|
@ -150,7 +151,7 @@ impl HirDisplay for Struct {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
f.write_str("struct ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
|
@ -162,7 +163,7 @@ impl HirDisplay for Enum {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
f.write_str("enum ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
|
@ -174,7 +175,7 @@ impl HirDisplay for Union {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
f.write_str("union ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
|
@ -185,14 +186,14 @@ impl HirDisplay for Union {
|
|||
impl HirDisplay for Field {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
|
||||
write!(f, "{}: ", self.name(f.db))?;
|
||||
write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?;
|
||||
self.ty(f.db).hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Variant {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
|
||||
let data = self.variant_data(f.db);
|
||||
match &*data {
|
||||
VariantData::Unit => {}
|
||||
|
@ -221,7 +222,7 @@ impl HirDisplay for Variant {
|
|||
f.write_str(", ")?;
|
||||
}
|
||||
// Enum variant fields must be pub.
|
||||
write!(f, "{}: ", field.name)?;
|
||||
write!(f, "{}: ", field.name.display(f.db.upcast()))?;
|
||||
field.type_ref.hir_fmt(f)?;
|
||||
}
|
||||
f.write_str(" }")?;
|
||||
|
@ -258,7 +259,7 @@ impl HirDisplay for TypeOrConstParam {
|
|||
|
||||
impl HirDisplay for TypeParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
|
||||
if f.omit_verbose_types() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -285,13 +286,13 @@ impl HirDisplay for TypeParam {
|
|||
|
||||
impl HirDisplay for LifetimeParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for ConstParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "const {}: ", self.name(f.db))?;
|
||||
write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?;
|
||||
self.ty(f.db).hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +325,7 @@ fn write_generic_params(
|
|||
};
|
||||
for (_, lifetime) in params.lifetimes.iter() {
|
||||
delim(f)?;
|
||||
write!(f, "{}", lifetime.name)?;
|
||||
write!(f, "{}", lifetime.name.display(f.db.upcast()))?;
|
||||
}
|
||||
for (_, ty) in params.type_or_consts.iter() {
|
||||
if let Some(name) = &ty.name() {
|
||||
|
@ -334,7 +335,7 @@ fn write_generic_params(
|
|||
continue;
|
||||
}
|
||||
delim(f)?;
|
||||
write!(f, "{name}")?;
|
||||
write!(f, "{}", name.display(f.db.upcast()))?;
|
||||
if let Some(default) = &ty.default {
|
||||
f.write_str(" = ")?;
|
||||
default.hir_fmt(f)?;
|
||||
|
@ -342,7 +343,7 @@ fn write_generic_params(
|
|||
}
|
||||
TypeOrConstParamData::ConstParamData(c) => {
|
||||
delim(f)?;
|
||||
write!(f, "const {name}: ")?;
|
||||
write!(f, "const {}: ", name.display(f.db.upcast()))?;
|
||||
c.ty.hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +380,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(),
|
|||
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
||||
match ¶ms.type_or_consts[*id].name() {
|
||||
Some(name) => write!(f, "{name}"),
|
||||
Some(name) => write!(f, "{}", name.display(f.db.upcast())),
|
||||
None => f.write_str("{unnamed}"),
|
||||
}
|
||||
}
|
||||
|
@ -411,10 +412,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(),
|
|||
WherePredicate::Lifetime { target, bound } => {
|
||||
if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
|
||||
{
|
||||
write!(f, " + {}", bound.name)?;
|
||||
write!(f, " + {}", bound.name.display(f.db.upcast()))?;
|
||||
} else {
|
||||
new_predicate(f)?;
|
||||
write!(f, "{}: {}", target.name, bound.name)?;
|
||||
write!(
|
||||
f,
|
||||
"{}: {}",
|
||||
target.name.display(f.db.upcast()),
|
||||
bound.name.display(f.db.upcast())
|
||||
)?;
|
||||
}
|
||||
}
|
||||
WherePredicate::ForLifetime { lifetimes, target, bound } => {
|
||||
|
@ -431,7 +437,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(),
|
|||
if idx != 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
write!(f, "{lifetime}")?;
|
||||
write!(f, "{}", lifetime.display(f.db.upcast()))?;
|
||||
}
|
||||
f.write_str("> ")?;
|
||||
write_target(target, f)?;
|
||||
|
@ -461,7 +467,7 @@ impl HirDisplay for Const {
|
|||
let data = db.const_data(self.id);
|
||||
f.write_str("const ")?;
|
||||
match &data.name {
|
||||
Some(name) => write!(f, "{name}: ")?,
|
||||
Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?,
|
||||
None => f.write_str("_: ")?,
|
||||
}
|
||||
data.type_ref.hir_fmt(f)?;
|
||||
|
@ -477,7 +483,7 @@ impl HirDisplay for Static {
|
|||
if data.mutable {
|
||||
f.write_str("mut ")?;
|
||||
}
|
||||
write!(f, "{}: ", &data.name)?;
|
||||
write!(f, "{}: ", data.name.display(f.db.upcast()))?;
|
||||
data.type_ref.hir_fmt(f)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -493,7 +499,7 @@ impl HirDisplay for Trait {
|
|||
if data.is_auto {
|
||||
f.write_str("auto ")?;
|
||||
}
|
||||
write!(f, "trait {}", data.name)?;
|
||||
write!(f, "trait {}", data.name.display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::TraitId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
|
@ -505,7 +511,7 @@ impl HirDisplay for TraitAlias {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.trait_alias_data(self.id);
|
||||
write!(f, "trait {}", data.name)?;
|
||||
write!(f, "trait {}", data.name.display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::TraitAliasId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
f.write_str(" = ")?;
|
||||
|
@ -521,7 +527,7 @@ impl HirDisplay for TypeAlias {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.type_alias_data(self.id);
|
||||
write!(f, "type {}", data.name)?;
|
||||
write!(f, "type {}", data.name.display(f.db.upcast()))?;
|
||||
let def_id = GenericDefId::TypeAliasId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
|
@ -541,8 +547,8 @@ impl HirDisplay for Module {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
// FIXME: Module doesn't have visibility saved in data.
|
||||
match self.name(f.db) {
|
||||
Some(name) => write!(f, "mod {name}"),
|
||||
None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) {
|
||||
Some(name) => write!(f, "mod {}", name.display(f.db.upcast())),
|
||||
None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) {
|
||||
Some(name) => write!(f, "extern crate {name}"),
|
||||
None => f.write_str("extern crate {unknown}"),
|
||||
},
|
||||
|
@ -558,6 +564,6 @@ impl HirDisplay for Macro {
|
|||
hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
|
||||
hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"),
|
||||
}?;
|
||||
write!(f, " {}", self.name(f.db))
|
||||
write!(f, " {}", self.name(f.db).display(f.db.upcast()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! are splitting the hir.
|
||||
|
||||
use hir_def::{
|
||||
expr::{BindingId, LabelId},
|
||||
hir::{BindingId, LabelId},
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId,
|
||||
ModuleDefId, VariantId,
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,9 +7,10 @@ use std::{cell::RefCell, fmt, iter, mem, ops};
|
|||
use base_db::{FileId, FileRange};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
body,
|
||||
expr::Expr,
|
||||
hir::Expr,
|
||||
lower::LowerCtx,
|
||||
macro_id_to_def_id,
|
||||
nameres::MacroSubNs,
|
||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||
type_ref::Mutability,
|
||||
AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
|
||||
|
@ -140,7 +141,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.imp.parse(file_id)
|
||||
}
|
||||
|
||||
pub fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
|
||||
pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
|
||||
self.imp.parse_or_expand(file_id)
|
||||
}
|
||||
|
||||
|
@ -350,6 +351,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.imp.type_of_pat(pat)
|
||||
}
|
||||
|
||||
/// It also includes the changes that binding mode makes in the type. For example in
|
||||
/// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
|
||||
/// of this function is `&mut Option<T>`
|
||||
pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
|
||||
self.imp.type_of_binding_in_pat(pat)
|
||||
}
|
||||
|
||||
pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
|
||||
self.imp.type_of_self(param)
|
||||
}
|
||||
|
@ -518,23 +526,23 @@ impl<'db> SemanticsImpl<'db> {
|
|||
tree
|
||||
}
|
||||
|
||||
fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
|
||||
let node = self.db.parse_or_expand(file_id)?;
|
||||
fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
|
||||
let node = self.db.parse_or_expand(file_id);
|
||||
self.cache(node.clone(), file_id);
|
||||
Some(node)
|
||||
node
|
||||
}
|
||||
|
||||
fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
|
||||
let sa = self.analyze_no_infer(macro_call.syntax())?;
|
||||
let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
|
||||
let node = self.parse_or_expand(file_id)?;
|
||||
let node = self.parse_or_expand(file_id);
|
||||
Some(node)
|
||||
}
|
||||
|
||||
fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
|
||||
let src = self.wrap_node_infile(item.clone());
|
||||
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
|
||||
self.parse_or_expand(macro_call_id.as_file())
|
||||
Some(self.parse_or_expand(macro_call_id.as_file()))
|
||||
}
|
||||
|
||||
fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
|
||||
|
@ -543,7 +551,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
let call_id = self.with_ctx(|ctx| {
|
||||
ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
|
||||
})?;
|
||||
self.parse_or_expand(call_id.as_file())
|
||||
Some(self.parse_or_expand(call_id.as_file()))
|
||||
}
|
||||
|
||||
fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
|
||||
|
@ -566,7 +574,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
.into_iter()
|
||||
.flat_map(|call| {
|
||||
let file_id = call?.as_file();
|
||||
let node = self.db.parse_or_expand(file_id)?;
|
||||
let node = self.db.parse_or_expand(file_id);
|
||||
self.cache(node.clone(), file_id);
|
||||
Some(node)
|
||||
})
|
||||
|
@ -609,7 +617,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
let krate = resolver.krate();
|
||||
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
|
||||
resolver
|
||||
.resolve_path_as_macro(self.db.upcast(), &path)
|
||||
.resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||
.map(|it| macro_id_to_def_id(self.db.upcast(), it))
|
||||
})?;
|
||||
hir_expand::db::expand_speculative(
|
||||
|
@ -990,7 +998,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
||||
let root = self.parse_or_expand(src.file_id).unwrap();
|
||||
let root = self.parse_or_expand(src.file_id);
|
||||
let node = src.map(|it| it.to_node(&root));
|
||||
node.as_ref().original_file_range(self.db.upcast())
|
||||
}
|
||||
|
@ -1065,7 +1073,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
|
||||
fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
|
||||
let analyze = self.analyze(ty.syntax())?;
|
||||
let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id);
|
||||
let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id);
|
||||
let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver)
|
||||
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
|
||||
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
|
||||
|
@ -1074,12 +1082,9 @@ impl<'db> SemanticsImpl<'db> {
|
|||
fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
|
||||
let analyze = self.analyze(path.syntax())?;
|
||||
let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
|
||||
let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
|
||||
let ctx = LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
|
||||
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
||||
match analyze
|
||||
.resolver
|
||||
.resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
|
||||
{
|
||||
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
|
||||
TypeNs::TraitId(id) => Some(Trait { id }),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -1141,6 +1146,10 @@ impl<'db> SemanticsImpl<'db> {
|
|||
.map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
|
||||
}
|
||||
|
||||
fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
|
||||
self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
|
||||
}
|
||||
|
||||
fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
|
||||
self.analyze(param.syntax())?.type_of_self(self.db, param)
|
||||
}
|
||||
|
@ -1647,6 +1656,7 @@ impl<'a> SemanticsScope<'a> {
|
|||
VisibleTraits(resolver.traits_in_scope(self.db.upcast()))
|
||||
}
|
||||
|
||||
/// Calls the passed closure `f` on all names in scope.
|
||||
pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||
let scope = self.resolver.names_in_scope(self.db.upcast());
|
||||
for (name, entries) in scope {
|
||||
|
@ -1674,7 +1684,7 @@ impl<'a> SemanticsScope<'a> {
|
|||
/// Resolve a path as-if it was written at the given scope. This is
|
||||
/// necessary a heuristic, as it doesn't take hygiene into account.
|
||||
pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
|
||||
let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id);
|
||||
let ctx = LowerCtx::with_file_id(self.db.upcast(), self.file_id);
|
||||
let path = Path::from_src(path.clone(), &ctx)?;
|
||||
resolve_hir_path(self.db, &self.resolver, &path)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
//! expression, an item definition.
|
||||
//!
|
||||
//! Knowing only the syntax gives us relatively little info. For example,
|
||||
//! looking at the syntax of the function we can realise that it is a part of an
|
||||
//! looking at the syntax of the function we can realize that it is a part of an
|
||||
//! `impl` block, but we won't be able to tell what trait function the current
|
||||
//! function overrides, and whether it does that correctly. For that, we need to
|
||||
//! go from [`ast::Fn`] to [`crate::Function`], and that's exactly what this
|
||||
|
@ -88,9 +88,11 @@
|
|||
use base_db::FileId;
|
||||
use hir_def::{
|
||||
child_by_source::ChildBySource,
|
||||
dyn_map::DynMap,
|
||||
expr::{BindingId, LabelId},
|
||||
keys::{self, Key},
|
||||
dyn_map::{
|
||||
keys::{self, Key},
|
||||
DynMap,
|
||||
},
|
||||
hir::{BindingId, LabelId},
|
||||
AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId,
|
||||
GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId,
|
||||
TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
|
||||
|
|
|
@ -5,21 +5,19 @@
|
|||
//!
|
||||
//! So, this modules should not be used during hir construction, it exists
|
||||
//! purely for "IDE needs".
|
||||
use std::{
|
||||
iter::{self, once},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::iter::{self, once};
|
||||
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
body::{
|
||||
self,
|
||||
scope::{ExprScopes, ScopeId},
|
||||
Body, BodySourceMap,
|
||||
},
|
||||
expr::{ExprId, Pat, PatId},
|
||||
hir::{BindingId, ExprId, Pat, PatId},
|
||||
lang_item::LangItem,
|
||||
lower::LowerCtx,
|
||||
macro_id_to_def_id,
|
||||
nameres::MacroSubNs,
|
||||
path::{ModPath, Path, PathKind},
|
||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
type_ref::Mutability,
|
||||
|
@ -39,7 +37,8 @@ use hir_ty::{
|
|||
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
|
||||
UnsafeExpr,
|
||||
},
|
||||
method_resolution::{self, lang_items_for_bin_op},
|
||||
lang_items::lang_items_for_bin_op,
|
||||
method_resolution::{self},
|
||||
Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
@ -48,6 +47,7 @@ use syntax::{
|
|||
ast::{self, AstNode},
|
||||
SyntaxKind, SyntaxNode, TextRange, TextSize,
|
||||
};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
|
||||
|
@ -134,13 +134,22 @@ impl SourceAnalyzer {
|
|||
self.body_source_map()?.node_pat(src)
|
||||
}
|
||||
|
||||
fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {
|
||||
let pat_id = self.pat_id(&pat.clone().into())?;
|
||||
if let Pat::Bind { id, .. } = self.body()?.pats[pat_id] {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
expr: InFile<ast::MacroCall>,
|
||||
) -> Option<InFile<ast::Expr>> {
|
||||
let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
|
||||
let expanded = db.parse_or_expand(macro_file)?;
|
||||
let expanded = db.parse_or_expand(macro_file);
|
||||
let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
|
||||
match stmts.expr()? {
|
||||
ast::Expr::MacroExpr(mac) => {
|
||||
|
@ -199,6 +208,18 @@ impl SourceAnalyzer {
|
|||
Some((mk_ty(ty), coerced.map(mk_ty)))
|
||||
}
|
||||
|
||||
pub(crate) fn type_of_binding_in_pat(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
pat: &ast::IdentPat,
|
||||
) -> Option<Type> {
|
||||
let binding_id = self.binding_id_of_pat(pat)?;
|
||||
let infer = self.infer.as_ref()?;
|
||||
let ty = infer[binding_id].clone();
|
||||
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
|
||||
Some(mk_ty(ty))
|
||||
}
|
||||
|
||||
pub(crate) fn type_of_self(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
|
@ -215,9 +236,9 @@ impl SourceAnalyzer {
|
|||
_db: &dyn HirDatabase,
|
||||
pat: &ast::IdentPat,
|
||||
) -> Option<BindingMode> {
|
||||
let pat_id = self.pat_id(&pat.clone().into())?;
|
||||
let binding_id = self.binding_id_of_pat(pat)?;
|
||||
let infer = self.infer.as_ref()?;
|
||||
infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
|
||||
infer.binding_modes.get(binding_id).map(|bm| match bm {
|
||||
hir_ty::BindingMode::Move => BindingMode::Move,
|
||||
hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
|
||||
hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
|
||||
|
@ -420,7 +441,10 @@ impl SourceAnalyzer {
|
|||
None
|
||||
} else {
|
||||
// Shorthand syntax, resolve to the local
|
||||
let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
|
||||
let path = Path::from_known_path_with_no_generic(ModPath::from_segments(
|
||||
PathKind::Plain,
|
||||
once(local_name.clone()),
|
||||
));
|
||||
match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
|
||||
Some(ValueNs::LocalBinding(binding_id)) => {
|
||||
Some(Local { binding_id, parent: self.resolver.body_owner()? })
|
||||
|
@ -459,9 +483,11 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
macro_call: InFile<&ast::MacroCall>,
|
||||
) -> Option<Macro> {
|
||||
let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
|
||||
let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
|
||||
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
|
||||
self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
|
||||
self.resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
|
||||
.map(|it| it.into())
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_bind_pat_to_const(
|
||||
|
@ -571,7 +597,7 @@ impl SourceAnalyzer {
|
|||
|
||||
// This must be a normal source file rather than macro file.
|
||||
let hygiene = Hygiene::new(db.upcast(), self.file_id);
|
||||
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
|
||||
let ctx = LowerCtx::with_hygiene(db.upcast(), &hygiene);
|
||||
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
||||
|
||||
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
|
||||
|
@ -655,7 +681,7 @@ impl SourceAnalyzer {
|
|||
}
|
||||
}
|
||||
}
|
||||
return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
|
||||
return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {
|
||||
Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
|
||||
// this labels any path that starts with a tool module as the tool itself, this is technically wrong
|
||||
// but there is no benefit in differentiating these two cases for the time being
|
||||
|
@ -733,7 +759,7 @@ impl SourceAnalyzer {
|
|||
let krate = self.resolver.krate();
|
||||
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
|
||||
self.resolver
|
||||
.resolve_path_as_macro(db.upcast(), &path)
|
||||
.resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||
.map(|it| macro_id_to_def_id(db.upcast(), it))
|
||||
})?;
|
||||
Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
|
||||
|
@ -801,15 +827,11 @@ impl SourceAnalyzer {
|
|||
func: FunctionId,
|
||||
substs: Substitution,
|
||||
) -> FunctionId {
|
||||
let krate = self.resolver.krate();
|
||||
let owner = match self.resolver.body_owner() {
|
||||
Some(it) => it,
|
||||
None => return func,
|
||||
};
|
||||
let env = owner.as_generic_def_id().map_or_else(
|
||||
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
|
||||
|d| db.trait_environment(d),
|
||||
);
|
||||
let env = db.trait_environment_for_body(owner);
|
||||
method_resolution::lookup_impl_method(db, env, func, substs).0
|
||||
}
|
||||
|
||||
|
@ -819,15 +841,11 @@ impl SourceAnalyzer {
|
|||
const_id: ConstId,
|
||||
subs: Substitution,
|
||||
) -> ConstId {
|
||||
let krate = self.resolver.krate();
|
||||
let owner = match self.resolver.body_owner() {
|
||||
Some(it) => it,
|
||||
None => return const_id,
|
||||
};
|
||||
let env = owner.as_generic_def_id().map_or_else(
|
||||
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
|
||||
|d| db.trait_environment(d),
|
||||
);
|
||||
let env = db.trait_environment_for_body(owner);
|
||||
method_resolution::lookup_impl_const(db, env, const_id, subs).0
|
||||
}
|
||||
|
||||
|
@ -941,12 +959,14 @@ pub(crate) fn resolve_hir_path(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn resolve_hir_path_as_macro(
|
||||
pub(crate) fn resolve_hir_path_as_attr_macro(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
path: &Path,
|
||||
) -> Option<Macro> {
|
||||
resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
|
||||
resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn resolve_hir_path_(
|
||||
|
@ -962,8 +982,7 @@ fn resolve_hir_path_(
|
|||
res.map(|ty_ns| (ty_ns, path.segments().first()))
|
||||
}
|
||||
None => {
|
||||
let (ty, remaining_idx) =
|
||||
resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
|
||||
let (ty, remaining_idx) = resolver.resolve_path_in_type_ns(db.upcast(), path)?;
|
||||
match remaining_idx {
|
||||
Some(remaining_idx) => {
|
||||
if remaining_idx + 1 == path.segments().len() {
|
||||
|
@ -1019,7 +1038,7 @@ fn resolve_hir_path_(
|
|||
|
||||
let body_owner = resolver.body_owner();
|
||||
let values = || {
|
||||
resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
|
||||
resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| {
|
||||
let res = match val {
|
||||
ValueNs::LocalBinding(binding_id) => {
|
||||
let var = Local { parent: body_owner?, binding_id };
|
||||
|
@ -1039,14 +1058,14 @@ fn resolve_hir_path_(
|
|||
|
||||
let items = || {
|
||||
resolver
|
||||
.resolve_module_path_in_items(db.upcast(), path.mod_path())
|
||||
.resolve_module_path_in_items(db.upcast(), path.mod_path()?)
|
||||
.take_types()
|
||||
.map(|it| PathResolution::Def(it.into()))
|
||||
};
|
||||
|
||||
let macros = || {
|
||||
resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path())
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, None)
|
||||
.map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
|
||||
};
|
||||
|
||||
|
@ -1074,7 +1093,7 @@ fn resolve_hir_path_qualifier(
|
|||
path: &Path,
|
||||
) -> Option<PathResolution> {
|
||||
resolver
|
||||
.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
|
||||
.resolve_path_in_type_ns_fully(db.upcast(), &path)
|
||||
.map(|ty| match ty {
|
||||
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
|
||||
TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
|
||||
|
@ -1089,7 +1108,7 @@ fn resolve_hir_path_qualifier(
|
|||
})
|
||||
.or_else(|| {
|
||||
resolver
|
||||
.resolve_module_path_in_items(db.upcast(), path.mod_path())
|
||||
.resolve_module_path_in_items(db.upcast(), path.mod_path()?)
|
||||
.take_types()
|
||||
.map(|it| PathResolution::Def(it.into()))
|
||||
})
|
||||
|
|
|
@ -2,23 +2,25 @@
|
|||
|
||||
use base_db::FileRange;
|
||||
use hir_def::{
|
||||
item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId,
|
||||
HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId,
|
||||
src::HasSource, AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId,
|
||||
ModuleDefId, ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::{HirFileId, InFile};
|
||||
use hir_ty::db::HirDatabase;
|
||||
use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr};
|
||||
|
||||
use crate::{Module, Semantics};
|
||||
use crate::{Module, ModuleDef, Semantics};
|
||||
|
||||
/// The actual data that is stored in the index. It should be as compact as
|
||||
/// possible.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FileSymbol {
|
||||
// even though name can be derived from the def, we store it for efficiency
|
||||
pub name: SmolStr,
|
||||
pub def: ModuleDef,
|
||||
pub loc: DeclarationLocation,
|
||||
pub kind: FileSymbolKind,
|
||||
pub container_name: Option<SmolStr>,
|
||||
pub is_alias: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -32,18 +34,26 @@ pub struct DeclarationLocation {
|
|||
}
|
||||
|
||||
impl DeclarationLocation {
|
||||
pub fn syntax<DB: HirDatabase>(&self, sema: &Semantics<'_, DB>) -> Option<SyntaxNode> {
|
||||
let root = sema.parse_or_expand(self.hir_file_id)?;
|
||||
Some(self.ptr.to_node(&root))
|
||||
pub fn syntax<DB: HirDatabase>(&self, sema: &Semantics<'_, DB>) -> SyntaxNode {
|
||||
let root = sema.parse_or_expand(self.hir_file_id);
|
||||
self.ptr.to_node(&root)
|
||||
}
|
||||
|
||||
pub fn original_range(&self, db: &dyn HirDatabase) -> Option<FileRange> {
|
||||
let node = resolve_node(db, self.hir_file_id, &self.ptr)?;
|
||||
Some(node.as_ref().original_file_range(db.upcast()))
|
||||
pub fn original_range(&self, db: &dyn HirDatabase) -> FileRange {
|
||||
if let Some(file_id) = self.hir_file_id.file_id() {
|
||||
// fast path to prevent parsing
|
||||
return FileRange { file_id, range: self.ptr.text_range() };
|
||||
}
|
||||
let node = resolve_node(db, self.hir_file_id, &self.ptr);
|
||||
node.as_ref().original_file_range(db.upcast())
|
||||
}
|
||||
|
||||
pub fn original_name_range(&self, db: &dyn HirDatabase) -> Option<FileRange> {
|
||||
let node = resolve_node(db, self.hir_file_id, &self.name_ptr)?;
|
||||
if let Some(file_id) = self.hir_file_id.file_id() {
|
||||
// fast path to prevent parsing
|
||||
return Some(FileRange { file_id, range: self.name_ptr.text_range() });
|
||||
}
|
||||
let node = resolve_node(db, self.hir_file_id, &self.name_ptr);
|
||||
node.as_ref().original_file_range_opt(db.upcast())
|
||||
}
|
||||
}
|
||||
|
@ -52,38 +62,10 @@ fn resolve_node(
|
|||
db: &dyn HirDatabase,
|
||||
file_id: HirFileId,
|
||||
ptr: &SyntaxNodePtr,
|
||||
) -> Option<InFile<SyntaxNode>> {
|
||||
let root = db.parse_or_expand(file_id)?;
|
||||
) -> InFile<SyntaxNode> {
|
||||
let root = db.parse_or_expand(file_id);
|
||||
let node = ptr.to_node(&root);
|
||||
Some(InFile::new(file_id, node))
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
||||
pub enum FileSymbolKind {
|
||||
Const,
|
||||
Enum,
|
||||
Function,
|
||||
Macro,
|
||||
Module,
|
||||
Static,
|
||||
Struct,
|
||||
Trait,
|
||||
TraitAlias,
|
||||
TypeAlias,
|
||||
Union,
|
||||
}
|
||||
|
||||
impl FileSymbolKind {
|
||||
pub fn is_type(self: FileSymbolKind) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
FileSymbolKind::Struct
|
||||
| FileSymbolKind::Enum
|
||||
| FileSymbolKind::Trait
|
||||
| FileSymbolKind::TypeAlias
|
||||
| FileSymbolKind::Union
|
||||
)
|
||||
}
|
||||
InFile::new(file_id, node)
|
||||
}
|
||||
|
||||
/// Represents an outstanding module that the symbol collector must collect symbols from.
|
||||
|
@ -102,21 +84,33 @@ pub struct SymbolCollector<'a> {
|
|||
/// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect
|
||||
/// all symbols that should be indexed for the given module.
|
||||
impl<'a> SymbolCollector<'a> {
|
||||
pub fn collect(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> {
|
||||
let mut symbol_collector = SymbolCollector {
|
||||
pub fn new(db: &'a dyn HirDatabase) -> Self {
|
||||
SymbolCollector {
|
||||
db,
|
||||
symbols: Default::default(),
|
||||
work: Default::default(),
|
||||
current_container_name: None,
|
||||
// The initial work is the root module we're collecting, additional work will
|
||||
// be populated as we traverse the module's definitions.
|
||||
work: vec![SymbolCollectorWork { module_id: module.into(), parent: None }],
|
||||
};
|
||||
|
||||
while let Some(work) = symbol_collector.work.pop() {
|
||||
symbol_collector.do_work(work);
|
||||
}
|
||||
}
|
||||
|
||||
symbol_collector.symbols
|
||||
pub fn collect(&mut self, module: Module) {
|
||||
// The initial work is the root module we're collecting, additional work will
|
||||
// be populated as we traverse the module's definitions.
|
||||
self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None });
|
||||
|
||||
while let Some(work) = self.work.pop() {
|
||||
self.do_work(work);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Vec<FileSymbol> {
|
||||
self.symbols
|
||||
}
|
||||
|
||||
pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> {
|
||||
let mut symbol_collector = SymbolCollector::new(db);
|
||||
symbol_collector.collect(module);
|
||||
symbol_collector.finish()
|
||||
}
|
||||
|
||||
fn do_work(&mut self, work: SymbolCollectorWork) {
|
||||
|
@ -134,36 +128,34 @@ impl<'a> SymbolCollector<'a> {
|
|||
match module_def_id {
|
||||
ModuleDefId::ModuleId(id) => self.push_module(id),
|
||||
ModuleDefId::FunctionId(id) => {
|
||||
self.push_decl_assoc(id, FileSymbolKind::Function);
|
||||
self.push_decl(id);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::AdtId(AdtId::StructId(id)) => {
|
||||
self.push_decl(id, FileSymbolKind::Struct)
|
||||
}
|
||||
ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, FileSymbolKind::Enum),
|
||||
ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, FileSymbolKind::Union),
|
||||
ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id),
|
||||
ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id),
|
||||
ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id),
|
||||
ModuleDefId::ConstId(id) => {
|
||||
self.push_decl_assoc(id, FileSymbolKind::Const);
|
||||
self.push_decl(id);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::StaticId(id) => {
|
||||
self.push_decl_assoc(id, FileSymbolKind::Static);
|
||||
self.push_decl(id);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::TraitId(id) => {
|
||||
self.push_decl(id, FileSymbolKind::Trait);
|
||||
self.push_decl(id);
|
||||
self.collect_from_trait(id);
|
||||
}
|
||||
ModuleDefId::TraitAliasId(id) => {
|
||||
self.push_decl(id, FileSymbolKind::TraitAlias);
|
||||
self.push_decl(id);
|
||||
}
|
||||
ModuleDefId::TypeAliasId(id) => {
|
||||
self.push_decl_assoc(id, FileSymbolKind::TypeAlias);
|
||||
self.push_decl(id);
|
||||
}
|
||||
ModuleDefId::MacroId(id) => match id {
|
||||
MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::Macro2Id(id) => self.push_decl(id),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id),
|
||||
},
|
||||
// Don't index these.
|
||||
ModuleDefId::BuiltinType(_) => {}
|
||||
|
@ -183,9 +175,9 @@ impl<'a> SymbolCollector<'a> {
|
|||
for &id in id {
|
||||
if id.module(self.db.upcast()) == module_id {
|
||||
match id {
|
||||
MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro),
|
||||
MacroId::Macro2Id(id) => self.push_decl(id),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,124 +225,94 @@ impl<'a> SymbolCollector<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn current_container_name(&self) -> Option<SmolStr> {
|
||||
self.current_container_name.clone()
|
||||
}
|
||||
|
||||
fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
|
||||
match body_id {
|
||||
DefWithBodyId::FunctionId(id) => Some(
|
||||
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
||||
),
|
||||
DefWithBodyId::StaticId(id) => Some(
|
||||
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
||||
),
|
||||
DefWithBodyId::ConstId(id) => Some(
|
||||
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
||||
),
|
||||
DefWithBodyId::VariantId(id) => Some({
|
||||
let db = self.db.upcast();
|
||||
id.parent.lookup(db).source(db).value.name()?.text().into()
|
||||
}),
|
||||
DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()),
|
||||
DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()),
|
||||
DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()),
|
||||
DefWithBodyId::VariantId(id) => {
|
||||
Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) {
|
||||
match assoc_item_id {
|
||||
AssocItemId::FunctionId(id) => self.push_decl_assoc(id, FileSymbolKind::Function),
|
||||
AssocItemId::ConstId(id) => self.push_decl_assoc(id, FileSymbolKind::Const),
|
||||
AssocItemId::TypeAliasId(id) => self.push_decl_assoc(id, FileSymbolKind::TypeAlias),
|
||||
AssocItemId::FunctionId(id) => self.push_decl(id),
|
||||
AssocItemId::ConstId(id) => self.push_decl(id),
|
||||
AssocItemId::TypeAliasId(id) => self.push_decl(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_decl_assoc<L, T>(&mut self, id: L, kind: FileSymbolKind)
|
||||
fn push_decl<L>(&mut self, id: L)
|
||||
where
|
||||
L: Lookup<Data = AssocItemLoc<T>>,
|
||||
T: ItemTreeNode,
|
||||
<T as ItemTreeNode>::Source: HasName,
|
||||
{
|
||||
fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> {
|
||||
match container {
|
||||
ItemContainerId::ModuleId(module_id) => {
|
||||
let module = Module::from(module_id);
|
||||
module.name(db).and_then(|name| name.as_text())
|
||||
}
|
||||
ItemContainerId::TraitId(trait_id) => {
|
||||
let trait_data = db.trait_data(trait_id);
|
||||
trait_data.name.as_text()
|
||||
}
|
||||
ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
self.push_file_symbol(|s| {
|
||||
let loc = id.lookup(s.db.upcast());
|
||||
let source = loc.source(s.db.upcast());
|
||||
let name_node = source.value.name()?;
|
||||
let container_name =
|
||||
container_name(s.db, loc.container).or_else(|| s.current_container_name());
|
||||
|
||||
Some(FileSymbol {
|
||||
name: name_node.text().into(),
|
||||
kind,
|
||||
container_name,
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: source.file_id,
|
||||
ptr: SyntaxNodePtr::new(source.value.syntax()),
|
||||
name_ptr: SyntaxNodePtr::new(name_node.syntax()),
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn push_decl<L>(&mut self, id: L, kind: FileSymbolKind)
|
||||
where
|
||||
L: Lookup,
|
||||
L: Lookup + Into<ModuleDefId>,
|
||||
<L as Lookup>::Data: HasSource,
|
||||
<<L as Lookup>::Data as HasSource>::Value: HasName,
|
||||
{
|
||||
self.push_file_symbol(|s| {
|
||||
let loc = id.lookup(s.db.upcast());
|
||||
let source = loc.source(s.db.upcast());
|
||||
let name_node = source.value.name()?;
|
||||
let loc = id.lookup(self.db.upcast());
|
||||
let source = loc.source(self.db.upcast());
|
||||
let Some(name_node) = source.value.name() else { return };
|
||||
let def = ModuleDef::from(id.into());
|
||||
let dec_loc = DeclarationLocation {
|
||||
hir_file_id: source.file_id,
|
||||
ptr: SyntaxNodePtr::new(source.value.syntax()),
|
||||
name_ptr: SyntaxNodePtr::new(name_node.syntax()),
|
||||
};
|
||||
|
||||
Some(FileSymbol {
|
||||
name: name_node.text().into(),
|
||||
kind,
|
||||
container_name: s.current_container_name(),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: source.file_id,
|
||||
ptr: SyntaxNodePtr::new(source.value.syntax()),
|
||||
name_ptr: SyntaxNodePtr::new(name_node.syntax()),
|
||||
},
|
||||
})
|
||||
})
|
||||
if let Some(attrs) = def.attrs(self.db) {
|
||||
for alias in attrs.doc_aliases() {
|
||||
self.symbols.push(FileSymbol {
|
||||
name: alias,
|
||||
def,
|
||||
loc: dec_loc.clone(),
|
||||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.symbols.push(FileSymbol {
|
||||
name: name_node.text().into(),
|
||||
def,
|
||||
container_name: self.current_container_name.clone(),
|
||||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
});
|
||||
}
|
||||
|
||||
fn push_module(&mut self, module_id: ModuleId) {
|
||||
self.push_file_symbol(|s| {
|
||||
let def_map = module_id.def_map(s.db.upcast());
|
||||
let module_data = &def_map[module_id.local_id];
|
||||
let declaration = module_data.origin.declaration()?;
|
||||
let module = declaration.to_node(s.db.upcast());
|
||||
let name_node = module.name()?;
|
||||
let def_map = module_id.def_map(self.db.upcast());
|
||||
let module_data = &def_map[module_id.local_id];
|
||||
let Some(declaration) = module_data.origin.declaration() else { return };
|
||||
let module = declaration.to_node(self.db.upcast());
|
||||
let Some(name_node) = module.name() else { return };
|
||||
let dec_loc = DeclarationLocation {
|
||||
hir_file_id: declaration.file_id,
|
||||
ptr: SyntaxNodePtr::new(module.syntax()),
|
||||
name_ptr: SyntaxNodePtr::new(name_node.syntax()),
|
||||
};
|
||||
|
||||
Some(FileSymbol {
|
||||
name: name_node.text().into(),
|
||||
kind: FileSymbolKind::Module,
|
||||
container_name: s.current_container_name(),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: declaration.file_id,
|
||||
ptr: SyntaxNodePtr::new(module.syntax()),
|
||||
name_ptr: SyntaxNodePtr::new(name_node.syntax()),
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
let def = ModuleDef::Module(module_id.into());
|
||||
|
||||
fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option<FileSymbol>) {
|
||||
if let Some(file_symbol) = f(self) {
|
||||
self.symbols.push(file_symbol);
|
||||
if let Some(attrs) = def.attrs(self.db) {
|
||||
for alias in attrs.doc_aliases() {
|
||||
self.symbols.push(FileSymbol {
|
||||
name: alias,
|
||||
def,
|
||||
loc: dec_loc.clone(),
|
||||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.symbols.push(FileSymbol {
|
||||
name: name_node.text().into(),
|
||||
def: ModuleDef::Module(module_id.into()),
|
||||
container_name: self.current_container_name.clone(),
|
||||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue