]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/lib.rs
Map attribute input tokens correctly
[rust.git] / crates / hir_def / src / lib.rs
index be9a5e1a0e7e61d62f5f94ad648d4a1ebf586d32..3c9cf0e38dca8b254ce43bcd081d0dce04ef6ce7 100644 (file)
@@ -19,7 +19,6 @@ macro_rules! eprintln {
 pub mod type_ref;
 pub mod builtin_type;
 pub mod builtin_attr;
-pub mod diagnostics;
 pub mod per_ns;
 pub mod item_scope;
 
@@ -56,23 +55,29 @@ macro_rules! eprintln {
     sync::Arc,
 };
 
+use attr::Attr;
 use base_db::{impl_intern_key, salsa, CrateId};
 use hir_expand::{
     ast_id_map::FileAstId,
     eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
     hygiene::Hygiene,
-    AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
+    AstId, FragmentKind, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
 use la_arena::Idx;
 use nameres::DefMap;
+use path::ModPath;
+use stdx::impl_from;
 use syntax::ast;
 
-use crate::builtin_type::BuiltinType;
-use item_tree::{
-    Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
-    TypeAlias, Union,
+use crate::{
+    adt::VariantData,
+    attr::AttrId,
+    builtin_type::BuiltinType,
+    item_tree::{
+        Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
+        TypeAlias, Union,
+    },
 };
-use stdx::impl_from;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ModuleId {
@@ -106,6 +111,10 @@ pub fn krate(&self) -> CrateId {
     pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
         self.def_map(db).containing_module(self.local_id)
     }
+
+    pub fn containing_block(&self) -> Option<BlockId> {
+        self.block
+    }
 }
 
 /// An ID of a module, **local** to a specific crate
@@ -434,6 +443,16 @@ pub enum AttrDefId {
     for AttrDefId
 );
 
+impl From<AssocContainerId> for AttrDefId {
+    fn from(acid: AssocContainerId) -> Self {
+        match acid {
+            AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
+            AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
+            AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum VariantId {
     EnumVariantId(EnumVariantId),
@@ -442,6 +461,34 @@ pub enum VariantId {
 }
 impl_from!(EnumVariantId, StructId, UnionId for VariantId);
 
+impl VariantId {
+    pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
+        match self {
+            VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
+            VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
+            VariantId::EnumVariantId(it) => {
+                db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
+            }
+        }
+    }
+
+    pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
+        match self {
+            VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
+            VariantId::StructId(it) => it.lookup(db).id.file_id(),
+            VariantId::UnionId(it) => it.lookup(db).id.file_id(),
+        }
+    }
+
+    pub fn adt_id(self) -> AdtId {
+        match self {
+            VariantId::EnumVariantId(it) => it.parent.into(),
+            VariantId::StructId(it) => it.into(),
+            VariantId::UnionId(it) => it.into(),
+        }
+    }
+}
+
 trait Intern {
     type ID;
     fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
@@ -526,6 +573,18 @@ fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
     }
 }
 
+impl HasModule for TypeAliasId {
+    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
+        self.lookup(db).module(db)
+    }
+}
+
+impl HasModule for TraitId {
+    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
+        self.lookup(db).container
+    }
+}
+
 impl HasModule for StaticLoc {
     fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
         self.container
@@ -608,9 +667,10 @@ fn as_call_id_with_errors(
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
         mut error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
+        let fragment = hir_expand::to_fragment_kind(self.value);
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let h = Hygiene::new(db.upcast(), self.file_id);
-        let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
+        let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
 
         let path = match error_sink
             .option(path, || mbe::ExpandError::Other("malformed macro invocation".into()))
@@ -623,6 +683,7 @@ fn as_call_id_with_errors(
 
         macro_call_as_call_id(
             &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
+            fragment,
             db,
             krate,
             resolver,
@@ -644,16 +705,21 @@ fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWi
     }
 }
 
-pub struct UnresolvedMacro;
+#[derive(Debug)]
+pub struct UnresolvedMacro {
+    pub path: ModPath,
+}
 
 fn macro_call_as_call_id(
     call: &AstIdWithPath<ast::MacroCall>,
+    fragment: FragmentKind,
     db: &dyn db::DefDatabase,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     error_sink: &mut dyn FnMut(mbe::ExpandError),
 ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
-    let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?;
+    let def: MacroDefId =
+        resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
 
     let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
         let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
@@ -664,30 +730,79 @@ fn macro_call_as_call_id(
             krate,
             macro_call,
             def,
-            &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
+            &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?),
             error_sink,
         )
         .map(MacroCallId::from)
     } else {
-        Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into())
+        Ok(def.as_lazy_macro(
+            db.upcast(),
+            krate,
+            MacroCallKind::FnLike { ast_id: call.ast_id, fragment },
+        ))
     };
     Ok(res)
 }
 
 fn derive_macro_as_call_id(
     item_attr: &AstIdWithPath<ast::Item>,
+    derive_attr: AttrId,
     db: &dyn db::DefDatabase,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 ) -> Result<MacroCallId, UnresolvedMacro> {
-    let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?;
-    let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?;
-    let res = def
-        .as_lazy_macro(
-            db.upcast(),
-            krate,
-            MacroCallKind::Derive(item_attr.ast_id, last_segment.to_string()),
-        )
-        .into();
+    let def: MacroDefId = resolver(item_attr.path.clone())
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+    let last_segment = item_attr
+        .path
+        .segments()
+        .last()
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+    let res = def.as_lazy_macro(
+        db.upcast(),
+        krate,
+        MacroCallKind::Derive {
+            ast_id: item_attr.ast_id,
+            derive_name: last_segment.to_string(),
+            derive_attr_index: derive_attr.ast_index,
+        },
+    );
+    Ok(res)
+}
+
+fn attr_macro_as_call_id(
+    item_attr: &AstIdWithPath<ast::Item>,
+    macro_attr: &Attr,
+    db: &dyn db::DefDatabase,
+    krate: CrateId,
+    resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+) -> Result<MacroCallId, UnresolvedMacro> {
+    let def: MacroDefId = resolver(item_attr.path.clone())
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+    let last_segment = item_attr
+        .path
+        .segments()
+        .last()
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+    let mut arg = match &macro_attr.input {
+        Some(input) => match &**input {
+            attr::AttrInput::Literal(_) => Default::default(),
+            attr::AttrInput::TokenTree(tt) => tt.clone(),
+        },
+        None => Default::default(),
+    };
+    // The parentheses are always disposed here.
+    arg.tree.delimiter = None;
+
+    let res = def.as_lazy_macro(
+        db.upcast(),
+        krate,
+        MacroCallKind::Attr {
+            ast_id: item_attr.ast_id,
+            attr_name: last_segment.to_string(),
+            attr_args: arg,
+            invoc_attr_index: macro_attr.id.ast_index,
+        },
+    );
     Ok(res)
 }