| //! Defines database & queries for name resolution. |
| use base_db::{Crate, RootQueryDb, SourceDatabase}; |
| use either::Either; |
| use hir_expand::{ |
| EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, |
| db::ExpandDatabase, |
| }; |
| use intern::sym; |
| use la_arena::ArenaMap; |
| use syntax::{AstPtr, ast}; |
| use triomphe::Arc; |
| |
| use crate::{ |
| AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, |
| EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, |
| FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, |
| MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, |
| ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, |
| TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, |
| attr::{Attrs, AttrsWithOwner}, |
| expr_store::{ |
| Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, |
| }, |
| hir::generics::GenericParams, |
| import_map::ImportMap, |
| item_tree::{ItemTree, file_item_tree_query}, |
| lang_item::{self, LangItem}, |
| nameres::crate_def_map, |
| signatures::{ |
| ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, |
| StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, |
| }, |
| tt, |
| visibility::{self, Visibility}, |
| }; |
| |
| use salsa::plumbing::AsId; |
| |
| #[query_group::query_group(InternDatabaseStorage)] |
| pub trait InternDatabase: RootQueryDb { |
| // region: items |
| #[salsa::interned] |
| fn intern_use(&self, loc: UseLoc) -> UseId; |
| |
| #[salsa::interned] |
| fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId; |
| |
| #[salsa::interned] |
| fn intern_function(&self, loc: FunctionLoc) -> FunctionId; |
| |
| #[salsa::interned] |
| fn intern_struct(&self, loc: StructLoc) -> StructId; |
| |
| #[salsa::interned] |
| fn intern_union(&self, loc: UnionLoc) -> UnionId; |
| |
| #[salsa::interned] |
| fn intern_enum(&self, loc: EnumLoc) -> EnumId; |
| |
| #[salsa::interned] |
| fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId; |
| |
| #[salsa::interned] |
| fn intern_const(&self, loc: ConstLoc) -> ConstId; |
| |
| #[salsa::interned] |
| fn intern_static(&self, loc: StaticLoc) -> StaticId; |
| |
| #[salsa::interned] |
| fn intern_trait(&self, loc: TraitLoc) -> TraitId; |
| |
| #[salsa::interned] |
| fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; |
| |
| #[salsa::interned] |
| fn intern_impl(&self, loc: ImplLoc) -> ImplId; |
| |
| #[salsa::interned] |
| fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId; |
| |
| #[salsa::interned] |
| fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id; |
| |
| #[salsa::interned] |
| fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; |
| |
| #[salsa::interned] |
| fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; |
| // endregion: items |
| |
| #[salsa::interned] |
| fn intern_block(&self, loc: BlockLoc) -> BlockId; |
| } |
| |
| #[query_group::query_group] |
| pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { |
| /// Whether to expand procedural macros during name resolution. |
| #[salsa::input] |
| fn expand_proc_attr_macros(&self) -> bool; |
| |
| /// Computes an [`ItemTree`] for the given file or macro expansion. |
| #[salsa::invoke(file_item_tree_query)] |
| #[salsa::transparent] |
| fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree; |
| |
| /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. |
| #[salsa::invoke(macro_def)] |
| fn macro_def(&self, m: MacroId) -> MacroDefId; |
| |
| // region:data |
| |
| #[salsa::tracked] |
| fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> { |
| self.trait_signature_with_source_map(trait_).0 |
| } |
| |
| #[salsa::tracked] |
| fn impl_signature(&self, impl_: ImplId) -> Arc<ImplSignature> { |
| self.impl_signature_with_source_map(impl_).0 |
| } |
| |
| #[salsa::tracked] |
| fn struct_signature(&self, struct_: StructId) -> Arc<StructSignature> { |
| self.struct_signature_with_source_map(struct_).0 |
| } |
| |
| #[salsa::tracked] |
| fn union_signature(&self, union_: UnionId) -> Arc<UnionSignature> { |
| self.union_signature_with_source_map(union_).0 |
| } |
| |
| #[salsa::tracked] |
| fn enum_signature(&self, e: EnumId) -> Arc<EnumSignature> { |
| self.enum_signature_with_source_map(e).0 |
| } |
| |
| #[salsa::tracked] |
| fn const_signature(&self, e: ConstId) -> Arc<ConstSignature> { |
| self.const_signature_with_source_map(e).0 |
| } |
| |
| #[salsa::tracked] |
| fn static_signature(&self, e: StaticId) -> Arc<StaticSignature> { |
| self.static_signature_with_source_map(e).0 |
| } |
| |
| #[salsa::tracked] |
| fn function_signature(&self, e: FunctionId) -> Arc<FunctionSignature> { |
| self.function_signature_with_source_map(e).0 |
| } |
| |
| #[salsa::tracked] |
| fn type_alias_signature(&self, e: TypeAliasId) -> Arc<TypeAliasSignature> { |
| self.type_alias_signature_with_source_map(e).0 |
| } |
| |
| #[salsa::invoke(TraitSignature::query)] |
| fn trait_signature_with_source_map( |
| &self, |
| trait_: TraitId, |
| ) -> (Arc<TraitSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(ImplSignature::query)] |
| fn impl_signature_with_source_map( |
| &self, |
| impl_: ImplId, |
| ) -> (Arc<ImplSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(StructSignature::query)] |
| fn struct_signature_with_source_map( |
| &self, |
| struct_: StructId, |
| ) -> (Arc<StructSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(UnionSignature::query)] |
| fn union_signature_with_source_map( |
| &self, |
| union_: UnionId, |
| ) -> (Arc<UnionSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(EnumSignature::query)] |
| fn enum_signature_with_source_map( |
| &self, |
| e: EnumId, |
| ) -> (Arc<EnumSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(ConstSignature::query)] |
| fn const_signature_with_source_map( |
| &self, |
| e: ConstId, |
| ) -> (Arc<ConstSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(StaticSignature::query)] |
| fn static_signature_with_source_map( |
| &self, |
| e: StaticId, |
| ) -> (Arc<StaticSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(FunctionSignature::query)] |
| fn function_signature_with_source_map( |
| &self, |
| e: FunctionId, |
| ) -> (Arc<FunctionSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| #[salsa::invoke(TypeAliasSignature::query)] |
| fn type_alias_signature_with_source_map( |
| &self, |
| e: TypeAliasId, |
| ) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>); |
| |
| // endregion:data |
| |
| #[salsa::invoke(Body::body_with_source_map_query)] |
| #[salsa::lru(512)] |
| fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); |
| |
| #[salsa::invoke(Body::body_query)] |
| fn body(&self, def: DefWithBodyId) -> Arc<Body>; |
| |
| #[salsa::invoke(ExprScopes::expr_scopes_query)] |
| fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; |
| |
| #[salsa::transparent] |
| #[salsa::invoke(GenericParams::new)] |
| fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; |
| |
| #[salsa::transparent] |
| #[salsa::invoke(GenericParams::generic_params_and_store)] |
| fn generic_params_and_store( |
| &self, |
| def: GenericDefId, |
| ) -> (Arc<GenericParams>, Arc<ExpressionStore>); |
| |
| #[salsa::transparent] |
| #[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)] |
| fn generic_params_and_store_and_source_map( |
| &self, |
| def: GenericDefId, |
| ) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>); |
| |
| // region:attrs |
| |
| #[salsa::invoke(Attrs::fields_attrs_query)] |
| fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; |
| |
| // should this really be a query? |
| #[salsa::invoke(crate::attr::fields_attrs_source_map)] |
| fn fields_attrs_source_map( |
| &self, |
| def: VariantId, |
| ) -> Arc<ArenaMap<LocalFieldId, AstPtr<Either<ast::TupleField, ast::RecordField>>>>; |
| |
| // FIXME: Make this a non-interned query. |
| #[salsa::invoke_interned(AttrsWithOwner::attrs_query)] |
| fn attrs(&self, def: AttrDefId) -> Attrs; |
| |
| #[salsa::transparent] |
| #[salsa::invoke(lang_item::lang_attr)] |
| fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>; |
| |
| // endregion:attrs |
| |
| #[salsa::invoke(ImportMap::import_map_query)] |
| fn import_map(&self, krate: Crate) -> Arc<ImportMap>; |
| |
| // region:visibilities |
| |
| #[salsa::invoke(visibility::field_visibilities_query)] |
| fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>; |
| |
| #[salsa::invoke(visibility::assoc_visibility_query)] |
| fn assoc_visibility(&self, def: AssocItemId) -> Visibility; |
| |
| // endregion:visibilities |
| |
| #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] |
| fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>; |
| #[salsa::invoke(crate::lang_item::crate_notable_traits)] |
| fn crate_notable_traits(&self, krate: Crate) -> Option<Arc<[TraitId]>>; |
| |
| #[salsa::invoke(crate_supports_no_std)] |
| fn crate_supports_no_std(&self, crate_id: Crate) -> bool; |
| |
| #[salsa::invoke(include_macro_invoc)] |
| fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>; |
| } |
| |
| // return: macro call id and include file id |
| fn include_macro_invoc( |
| db: &dyn DefDatabase, |
| krate: Crate, |
| ) -> Arc<[(MacroCallId, EditionedFileId)]> { |
| crate_def_map(db, krate) |
| .modules |
| .values() |
| .flat_map(|m| m.scope.iter_macro_invoc()) |
| .filter_map(|invoc| { |
| db.lookup_intern_macro_call(*invoc.1) |
| .include_file_id(db, *invoc.1) |
| .map(|x| (*invoc.1, x)) |
| }) |
| .collect() |
| } |
| |
| fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { |
| let file = crate_id.data(db).root_file_id(db); |
| let item_tree = db.file_item_tree(file.into()); |
| let attrs = item_tree.top_level_raw_attrs(); |
| for attr in &**attrs { |
| match attr.path().as_ident() { |
| Some(ident) if *ident == sym::no_std => return true, |
| Some(ident) if *ident == sym::cfg_attr => {} |
| _ => continue, |
| } |
| |
| // This is a `cfg_attr`; check if it could possibly expand to `no_std`. |
| // Syntax is: `#[cfg_attr(condition(cfg, style), attr0, attr1, <...>)]` |
| let tt = match attr.token_tree_value() { |
| Some(tt) => tt.token_trees(), |
| None => continue, |
| }; |
| |
| let segments = |
| tt.split(|tt| matches!(tt, tt::TtElement::Leaf(tt::Leaf::Punct(p)) if p.char == ',')); |
| for output in segments.skip(1) { |
| match output.flat_tokens() { |
| [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::no_std => { |
| return true; |
| } |
| _ => {} |
| } |
| } |
| } |
| |
| false |
| } |
| |
| fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { |
| let kind = |expander, file_id, m| { |
| let in_file = InFile::new(file_id, m); |
| match expander { |
| MacroExpander::Declarative => MacroDefKind::Declarative(in_file), |
| MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it), |
| MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it), |
| MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it), |
| MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it), |
| } |
| }; |
| |
| match id { |
| MacroId::Macro2Id(it) => { |
| let loc: Macro2Loc = it.lookup(db); |
| |
| MacroDefId { |
| krate: loc.container.krate, |
| kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), |
| local_inner: false, |
| allow_internal_unsafe: loc.allow_internal_unsafe, |
| edition: loc.edition, |
| } |
| } |
| MacroId::MacroRulesId(it) => { |
| let loc: MacroRulesLoc = it.lookup(db); |
| |
| MacroDefId { |
| krate: loc.container.krate, |
| kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), |
| local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), |
| allow_internal_unsafe: loc |
| .flags |
| .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE), |
| edition: loc.edition, |
| } |
| } |
| MacroId::ProcMacroId(it) => { |
| let loc = it.lookup(db); |
| |
| MacroDefId { |
| krate: loc.container.krate, |
| kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), |
| local_inner: false, |
| allow_internal_unsafe: false, |
| edition: loc.edition, |
| } |
| } |
| } |
| } |