Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
| -rw-r--r-- | crates/hir/src/lib.rs | 267 |
1 files changed, 176 insertions, 91 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1b24aad103..9418903123 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -45,12 +45,11 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, - DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - GenericParamId, HasModule, ImplId, InternedModuleId, ItemContainerId, LifetimeParamId, + AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, + CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, + FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, - attrs::AttrFlags, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, @@ -64,12 +63,13 @@ use hir_def::{ }, per_ns::PerNs, resolver::{HasResolver, Resolver}, - signatures::{EnumSignature, ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, + signatures::{ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, src::HasSource as _, visibility::visibility_from_ast, }; use hir_expand::{ - AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind, + AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, + proc_macro::ProcMacroKind, }; use hir_ty::{ TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, @@ -98,8 +98,8 @@ use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never}; use syntax::{ - AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, - ast::{self, HasName, HasVisibility as _}, + AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, + ast::{self, HasAttrs as _, HasName, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -107,7 +107,7 @@ use triomphe::{Arc, ThinArc}; use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ - attrs::{AttrsWithOwner, HasAttrs, resolve_doc_path_on}, + attrs::{HasAttrs, resolve_doc_path_on}, diagnostics::*, has_source::HasSource, semantics::{ @@ -130,7 +130,7 @@ pub use { hir_def::{ Complete, FindPathConfig, - attrs::{Docs, IsInnerDoc}, + attr::{AttrSourceMap, Attrs, AttrsWithOwner}, find_path::PrefixKind, import_map, lang_item::LangItem, @@ -144,6 +144,7 @@ pub use { }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, + attrs::{Attr, AttrId}, change::ChangeWithProcMacros, files::{ FilePosition, FilePositionWrapper, FileRange, FileRangeWrapper, HirFilePosition, @@ -290,10 +291,11 @@ impl Crate { } /// Try to get the root URL of the documentation of a crate. - pub fn get_html_root_url(self, db: &dyn HirDatabase) -> Option<String> { + pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { // Look for #![doc(html_root_url = "...")] - let doc_url = AttrFlags::doc_html_root_url(db, self.id); - doc_url.as_ref().map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") + let attrs = db.attrs(AttrDefId::ModuleId(self.root_module().into())); + let doc_url = attrs.by_key(sym::doc).find_string_value_in_tt(sym::html_root_url); + doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") } pub fn cfg<'db>(&self, db: &'db dyn HirDatabase) -> &'db CfgOptions { @@ -638,7 +640,7 @@ impl Module { // FIXME: This is accidentally quadratic. continue; } - emit_def_diagnostic(db, acc, diag, edition, def_map.krate()); + emit_def_diagnostic(db, acc, diag, edition); } if !self.id.is_block_module() { @@ -657,9 +659,8 @@ impl Module { acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Trait(t) => { - let krate = t.krate(db); for diag in TraitItems::query_with_diagnostics(db, t.id).1.iter() { - emit_def_diagnostic(db, acc, diag, edition, krate.id); + emit_def_diagnostic(db, acc, diag, edition); } for item in t.items(db) { @@ -777,7 +778,7 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { - emit_def_diagnostic(db, acc, diag, edition, loc.container.krate()); + emit_def_diagnostic(db, acc, diag, edition); } if inherent_impls.invalid_impls().contains(&impl_def.id) { @@ -808,10 +809,21 @@ impl Module { return None; } let parent = impl_def.id.into(); - let (lifetimes_attrs, type_and_consts_attrs) = - AttrFlags::query_generic_params(db, parent); - let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE)) - || type_and_consts_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE)); + let generic_params = db.generic_params(parent); + let lifetime_params = generic_params.iter_lt().map(|(local_id, _)| { + GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }) + }); + let type_params = generic_params + .iter_type_or_consts() + .filter(|(_, it)| it.type_param().is_some()) + .map(|(local_id, _)| { + GenericParamId::TypeParamId(TypeParamId::from_unchecked( + TypeOrConstParamId { parent, local_id }, + )) + }); + let res = type_params.chain(lifetime_params).any(|p| { + db.attrs(AttrDefId::GenericParamId(p)).by_key(sym::may_dangle).exists() + }); Some(res) })() .unwrap_or(false); @@ -972,17 +984,6 @@ impl Module { ) -> Option<ModPath> { hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg) } - - #[inline] - pub fn doc_keyword(self, db: &dyn HirDatabase) -> Option<Symbol> { - AttrFlags::doc_keyword(db, InternedModuleId::new(db, self.id)) - } - - /// Whether it has `#[path = "..."]` attribute. - #[inline] - pub fn has_path(&self, db: &dyn HirDatabase) -> bool { - self.attrs(db).attrs.contains(AttrFlags::HAS_PATH) - } } fn macro_call_diagnostics<'db>( @@ -997,19 +998,31 @@ fn macro_call_diagnostics<'db>( if let Some(err) = err { let loc = db.lookup_intern_macro_call(macro_call_id); let file_id = loc.kind.file_id(); - let mut range = precise_macro_call_location(&loc.kind, db, loc.krate); + let node = + InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id())); let RenderedExpandError { message, error, kind } = err.render_to_string(db); - if Some(err.span().anchor.file_id) == file_id.file_id().map(|it| it.editioned_file_id(db)) { - range.value = err.span().range - + db.ast_id_map(file_id).get_erased(err.span().anchor.ast_id).text_range().start(); - } - acc.push(MacroError { range, message, error, kind }.into()); + let editioned_file_id = EditionedFileId::from_span(db, err.span().anchor.file_id); + let precise_location = if editioned_file_id == file_id { + Some( + err.span().range + + db.ast_id_map(editioned_file_id.into()) + .get_erased(err.span().anchor.ast_id) + .text_range() + .start(), + ) + } else { + None + }; + acc.push(MacroError { node, precise_location, message, error, kind }.into()); } if !parse_errors.is_empty() { let loc = db.lookup_intern_macro_call(macro_call_id); - let range = precise_macro_call_location(&loc.kind, db, loc.krate); - acc.push(MacroExpansionParseError { range, errors: parse_errors.clone() }.into()) + let (node, precise_location) = precise_macro_call_location(&loc.kind, db); + acc.push( + MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() } + .into(), + ) } } @@ -1033,7 +1046,6 @@ fn emit_macro_def_diagnostics<'db>( acc, &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, edition, - m.krate(db).id, ); } } @@ -1043,9 +1055,8 @@ fn emit_def_diagnostic<'db>( acc: &mut Vec<AnyDiagnostic<'db>>, diag: &DefDiagnostic, edition: Edition, - krate: base_db::Crate, ) { - emit_def_diagnostic_(db, acc, &diag.kind, edition, krate) + emit_def_diagnostic_(db, acc, &diag.kind, edition) } fn emit_def_diagnostic_<'db>( @@ -1053,7 +1064,6 @@ fn emit_def_diagnostic_<'db>( acc: &mut Vec<AnyDiagnostic<'db>>, diag: &DefDiagnosticKind, edition: Edition, - krate: base_db::Crate, ) { match diag { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { @@ -1076,7 +1086,8 @@ fn emit_def_diagnostic_<'db>( let RenderedExpandError { message, error, kind } = err.render_to_string(db); acc.push( MacroError { - range: InFile::new(ast.file_id, item.text_range()), + node: InFile::new(ast.file_id, item.syntax_node_ptr()), + precise_location: None, message: format!("{}: {message}", path.display(db, edition)), error, kind, @@ -1106,10 +1117,11 @@ fn emit_def_diagnostic_<'db>( ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { - let location = precise_macro_call_location(ast, db, krate); + let (node, precise_location) = precise_macro_call_location(ast, db); acc.push( UnresolvedMacroCall { - range: location, + macro_call: node, + precise_location, path: path.clone(), is_bang: matches!(ast, MacroCallKind::FnLike { .. }), } @@ -1128,12 +1140,34 @@ fn emit_def_diagnostic_<'db>( ); } DefDiagnosticKind::InvalidDeriveTarget { ast, id } => { - let derive = id.find_attr_range(db, krate, *ast).3.path_range(); - acc.push(InvalidDeriveTarget { range: ast.with_value(derive) }.into()); + let node = ast.to_node(db); + let derive = node.attrs().nth(*id); + match derive { + Some(derive) => { + acc.push( + InvalidDeriveTarget { + node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), + } + .into(), + ); + } + None => stdx::never!("derive diagnostic on item without derive attribute"), + } } DefDiagnosticKind::MalformedDerive { ast, id } => { - let derive = id.find_attr_range(db, krate, *ast).2; - acc.push(MalformedDerive { range: ast.with_value(derive) }.into()); + let node = ast.to_node(db); + let derive = node.attrs().nth(*id); + match derive { + Some(derive) => { + acc.push( + MalformedDerive { + node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), + } + .into(), + ); + } + None => stdx::never!("derive diagnostic on item without derive attribute"), + } } DefDiagnosticKind::MacroDefError { ast, message } => { let node = ast.to_node(db); @@ -1152,28 +1186,61 @@ fn emit_def_diagnostic_<'db>( fn precise_macro_call_location( ast: &MacroCallKind, db: &dyn HirDatabase, - krate: base_db::Crate, -) -> InFile<TextRange> { +) -> (InFile<SyntaxNodePtr>, Option<TextRange>) { // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics // - e.g. the full attribute for macro errors, but only the name for name resolution match ast { MacroCallKind::FnLike { ast_id, .. } => { let node = ast_id.to_node(db); - let range = node - .path() - .and_then(|it| it.segment()) - .and_then(|it| it.name_ref()) - .map(|it| it.syntax().text_range()); - let range = range.unwrap_or_else(|| node.syntax().text_range()); - ast_id.with_value(range) + ( + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), + node.path() + .and_then(|it| it.segment()) + .and_then(|it| it.name_ref()) + .map(|it| it.syntax().text_range()), + ) } MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { - let range = derive_attr_index.find_derive_range(db, krate, *ast_id, *derive_index); - ast_id.with_value(range) + let node = ast_id.to_node(db); + // Compute the precise location of the macro name's token in the derive + // list. + let token = (|| { + let derive_attr = collect_attrs(&node) + .nth(derive_attr_index.ast_index()) + .and_then(|x| Either::left(x.1))?; + let token_tree = derive_attr.meta()?.token_tree()?; + let chunk_by = token_tree + .syntax() + .children_with_tokens() + .filter_map(|elem| match elem { + syntax::NodeOrToken::Token(tok) => Some(tok), + _ => None, + }) + .chunk_by(|t| t.kind() == T![,]); + let (_, mut group) = chunk_by + .into_iter() + .filter(|&(comma, _)| !comma) + .nth(*derive_index as usize)?; + group.find(|t| t.kind() == T![ident]) + })(); + ( + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), + token.as_ref().map(|tok| tok.text_range()), + ) } - MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => { - let attr_range = attr_ids.invoc_attr().find_attr_range(db, krate, *ast_id).2; - ast_id.with_value(attr_range) + MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { + let node = ast_id.to_node(db); + let attr = collect_attrs(&node) + .nth(invoc_attr_index.ast_index()) + .and_then(|x| Either::left(x.1)) + .unwrap_or_else(|| { + panic!("cannot find attribute #{}", invoc_attr_index.ast_index()) + }); + + ( + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), + Some(attr.syntax().text_range()), + ) } } } @@ -1371,7 +1438,7 @@ impl Struct { } pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { - AttrFlags::repr(db, self.id.into()) + db.struct_signature(self.id).repr } pub fn kind(self, db: &dyn HirDatabase) -> StructKind { @@ -1387,7 +1454,7 @@ impl Struct { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + db.attrs(self.id.into()).is_unstable() } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> { @@ -1476,7 +1543,7 @@ impl Union { .collect() } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + db.attrs(self.id.into()).is_unstable() } } @@ -1511,7 +1578,7 @@ impl Enum { } pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { - AttrFlags::repr(db, self.id.into()) + db.enum_signature(self.id).repr } pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { @@ -1527,7 +1594,7 @@ impl Enum { let interner = DbInterner::new_with(db, None, None); Type::new_for_crate( self.id.lookup(db).container.krate(), - match EnumSignature::variant_body_type(db, self.id) { + match db.enum_signature(self.id).variant_body_type() { layout::IntegerType::Pointer(sign) => match sign { true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), false => Ty::new_uint(interner, rustc_type_ir::UintTy::Usize), @@ -1568,7 +1635,7 @@ impl Enum { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + db.attrs(self.id.into()).is_unstable() } } @@ -1669,7 +1736,7 @@ impl Variant { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + db.attrs(self.id.into()).is_unstable() } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> { @@ -2154,7 +2221,8 @@ fn expr_store_diagnostics<'db>( InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into() } ExpressionStoreDiagnostics::UnresolvedMacroCall { node, path } => UnresolvedMacroCall { - range: node.map(|ptr| ptr.text_range()), + macro_call: (*node).map(|ast_ptr| ast_ptr.into()), + precise_location: None, path: path.clone(), is_bang: true, } @@ -2379,33 +2447,33 @@ impl Function { /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { - self.attrs(db).is_test() + db.attrs(self.id.into()).is_test() } /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { - self.exported_main(db) + db.attrs(self.id.into()).export_name() == Some(&sym::main) || self.module(db).is_crate_root() && db.function_signature(self.id).name == sym::main } /// Is this a function with an `export_name` of `main`? pub fn exported_main(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_EXPORT_NAME_MAIN) + db.attrs(self.id.into()).export_name() == Some(&sym::main) } /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_IGNORE) + db.attrs(self.id.into()).is_ignore() } /// Does this function have `#[bench]` attribute? pub fn is_bench(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_BENCH) + db.attrs(self.id.into()).is_bench() } /// Is this function marked as unstable with `#[feature]` attribute? pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) + db.attrs(self.id.into()).is_unstable() } pub fn is_unsafe_to_call( @@ -2416,7 +2484,8 @@ impl Function { ) -> bool { let (target_features, target_feature_is_safe_in_target) = caller .map(|caller| { - let target_features = hir_ty::TargetFeatures::from_fn(db, caller.id); + let target_features = + hir_ty::TargetFeatures::from_attrs(&db.attrs(caller.id.into())); let target_feature_is_safe_in_target = match &caller.krate(db).id.workspace_data(db).target { Ok(target) => hir_ty::target_feature_is_safe_in_target(target), @@ -2447,6 +2516,14 @@ impl Function { } pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> { + let attrs = db.attrs(self.id.into()); + // FIXME: Store this in FunctionData flags? + if !(attrs.is_proc_macro() + || attrs.is_proc_macro_attribute() + || attrs.is_proc_macro_derive()) + { + return None; + } let def_map = crate_def_map(db, HasModule::krate(&self.id, db)); def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) } @@ -2899,7 +2976,7 @@ impl Trait { /// `#[rust_analyzer::completions(...)]` mode. pub fn complete(self, db: &dyn HirDatabase) -> Complete { - Complete::extract(true, self.attrs(db).attrs) + Complete::extract(true, &self.attrs(db)) } } @@ -3070,10 +3147,10 @@ impl Macro { let loc = id.lookup(db); let source = loc.source(db); match loc.kind { - ProcMacroKind::CustomDerive => AttrFlags::derive_info(db, self.id).map_or_else( - || as_name_opt(source.value.name()), - |info| Name::new_symbol_root(info.trait_name.clone()), - ), + ProcMacroKind::CustomDerive => db + .attrs(id.into()) + .parse_proc_macro_derive() + .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), } } @@ -3081,7 +3158,7 @@ impl Macro { } pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool { - matches!(self.id, MacroId::MacroRulesId(_) if AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_MACRO_EXPORT)) + matches!(self.id, MacroId::MacroRulesId(_) if db.attrs(self.id.into()).by_key(sym::macro_export).exists()) } pub fn is_proc_macro(self) -> bool { @@ -3905,10 +3982,18 @@ impl DeriveHelper { } pub fn name(&self, db: &dyn HirDatabase) -> Name { - AttrFlags::derive_info(db, self.derive) - .and_then(|it| it.helpers.get(self.idx as usize)) - .map(|helper| Name::new_symbol_root(helper.clone())) - .unwrap_or_else(Name::missing) + match self.derive { + makro @ MacroId::Macro2Id(_) => db + .attrs(makro.into()) + .parse_rustc_builtin_macro() + .and_then(|(_, helpers)| helpers.get(self.idx as usize).cloned()), + MacroId::MacroRulesId(_) => None, + makro @ MacroId::ProcMacroId(_) => db + .attrs(makro.into()) + .parse_proc_macro_derive() + .and_then(|(_, helpers)| helpers.get(self.idx as usize).cloned()), + } + .unwrap_or_else(Name::missing) } } @@ -4129,7 +4214,7 @@ impl TypeParam { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - self.attrs(db).is_unstable() + db.attrs(GenericParamId::from(self.id).into()).is_unstable() } } |