]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/data.rs
Support `#[cfg]` on all associated items
[rust.git] / crates / hir_def / src / data.rs
index 6190906da9856f2210605ff98feb7a8442dc09dd..2c70b3bc0e6cdc666f5e859d3401f78c0943efd5 100644 (file)
@@ -9,7 +9,7 @@
     attr::Attrs,
     body::Expander,
     db::DefDatabase,
-    item_tree::{AssocItem, ItemTreeId, ModItem},
+    item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
     type_ref::{TypeBound, TypeRef},
     visibility::RawVisibility,
     AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -25,7 +25,9 @@ pub struct FunctionData {
     /// True if the first param is `self`. This is relevant to decide whether this
     /// can be called as a method.
     pub has_self_param: bool,
-    pub is_unsafe: bool,
+    pub has_body: bool,
+    pub qualifier: FunctionQualifier,
+    pub is_in_extern_block: bool,
     pub is_varargs: bool,
     pub visibility: RawVisibility,
 }
@@ -33,17 +35,39 @@ pub struct FunctionData {
 impl FunctionData {
     pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
         let loc = func.lookup(db);
+        let krate = loc.container.module(db).krate;
+        let crate_graph = db.crate_graph();
+        let cfg_options = &crate_graph[krate].cfg_options;
         let item_tree = db.item_tree(loc.id.file_id);
         let func = &item_tree[loc.id.value];
 
+        let enabled_params = func
+            .params
+            .clone()
+            .filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));
+
+        // If last cfg-enabled param is a `...` param, it's a varargs function.
+        let is_varargs = enabled_params
+            .clone()
+            .next_back()
+            .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
+
         Arc::new(FunctionData {
             name: func.name.clone(),
-            params: func.params.to_vec(),
-            ret_type: func.ret_type.clone(),
-            attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
+            params: enabled_params
+                .clone()
+                .filter_map(|id| match &item_tree[id] {
+                    Param::Normal(ty) => Some(item_tree[*ty].clone()),
+                    Param::Varargs => None,
+                })
+                .collect(),
+            ret_type: item_tree[func.ret_type].clone(),
+            attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             has_self_param: func.has_self_param,
-            is_unsafe: func.is_unsafe,
-            is_varargs: func.is_varargs,
+            has_body: func.has_body,
+            qualifier: func.qualifier.clone(),
+            is_in_extern_block: func.is_in_extern_block,
+            is_varargs,
             visibility: item_tree[func.visibility].clone(),
         })
     }
@@ -70,7 +94,7 @@ pub(crate) fn type_alias_data_query(
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
-            type_ref: typ.type_ref.clone(),
+            type_ref: typ.type_ref.map(|id| item_tree[id].clone()),
             visibility: item_tree[typ.visibility].clone(),
             is_extern: typ.is_extern,
             bounds: typ.bounds.to_vec(),
@@ -82,7 +106,10 @@ pub(crate) fn type_alias_data_query(
 pub struct TraitData {
     pub name: Name,
     pub items: Vec<(Name, AssocItemId)>,
-    pub auto: bool,
+    pub is_auto: bool,
+    pub is_unsafe: bool,
+    pub visibility: RawVisibility,
+    pub bounds: Box<[TypeBound]>,
 }
 
 impl TraitData {
@@ -91,10 +118,13 @@ pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitDa
         let item_tree = db.item_tree(tr_loc.id.file_id);
         let tr_def = &item_tree[tr_loc.id.value];
         let name = tr_def.name.clone();
-        let auto = tr_def.auto;
-        let module_id = tr_loc.container.module(db);
+        let is_auto = tr_def.is_auto;
+        let is_unsafe = tr_def.is_unsafe;
+        let module_id = tr_loc.container;
         let container = AssocContainerId::TraitId(tr);
         let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
+        let visibility = item_tree[tr_def.visibility].clone();
+        let bounds = tr_def.bounds.clone();
 
         let items = collect_items(
             db,
@@ -106,7 +136,7 @@ pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitDa
             100,
         );
 
-        Arc::new(TraitData { name, items, auto })
+        Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds })
     }
 
     pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
@@ -139,10 +169,10 @@ pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData>
 
         let item_tree = db.item_tree(impl_loc.id.file_id);
         let impl_def = &item_tree[impl_loc.id.value];
-        let target_trait = impl_def.target_trait.clone();
-        let target_type = impl_def.target_type.clone();
+        let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
+        let target_type = item_tree[impl_def.target_type].clone();
         let is_negative = impl_def.is_negative;
-        let module_id = impl_loc.container.module(db);
+        let module_id = impl_loc.container;
         let container = AssocContainerId::ImplId(id);
         let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
 
@@ -177,7 +207,7 @@ pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<Cons
 
         Arc::new(ConstData {
             name: konst.name.clone(),
-            type_ref: konst.type_ref.clone(),
+            type_ref: item_tree[konst.type_ref].clone(),
             visibility: item_tree[konst.visibility].clone(),
         })
     }
@@ -189,6 +219,7 @@ pub struct StaticData {
     pub type_ref: TypeRef,
     pub visibility: RawVisibility,
     pub mutable: bool,
+    pub is_extern: bool,
 }
 
 impl StaticData {
@@ -199,9 +230,10 @@ pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<St
 
         Arc::new(StaticData {
             name: Some(statik.name.clone()),
-            type_ref: statik.type_ref.clone(),
+            type_ref: item_tree[statik.type_ref].clone(),
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
+            is_extern: statik.is_extern,
         })
     }
 }
@@ -224,17 +256,17 @@ fn collect_items(
 
     let mut items = Vec::new();
     for item in assoc_items {
+        let attrs = item_tree.attrs(db, module.krate, ModItem::from(item).into());
+        if !attrs.is_cfg_enabled(&cfg_options) {
+            continue;
+        }
+
         match item {
             AssocItem::Function(id) => {
                 let item = &item_tree[id];
-                let attrs = item_tree.attrs(ModItem::from(id).into());
-                if !attrs.is_cfg_enabled(&cfg_options) {
-                    continue;
-                }
                 let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                 items.push((item.name.clone(), def.into()));
             }
-            // FIXME: cfg?
             AssocItem::Const(id) => {
                 let item = &item_tree[id];
                 let name = match item.name.clone() {
@@ -254,23 +286,26 @@ fn collect_items(
                 let ast_id_map = db.ast_id_map(file_id);
                 let root = db.parse_or_expand(file_id).unwrap();
                 let call = ast_id_map.get(call.ast_id).to_node(&root);
-
-                if let Some((mark, mac)) = expander.enter_expand(db, None, call) {
-                    let src: InFile<ast::MacroItems> = expander.to_source(mac);
-                    let item_tree = db.item_tree(src.file_id);
-                    let iter =
-                        item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
-                    items.extend(collect_items(
-                        db,
-                        module,
-                        expander,
-                        iter,
-                        src.file_id,
-                        container,
-                        limit - 1,
-                    ));
-
-                    expander.exit(db, mark);
+                let res = expander.enter_expand(db, call);
+
+                if let Ok(res) = res {
+                    if let Some((mark, mac)) = res.value {
+                        let src: InFile<ast::MacroItems> = expander.to_source(mac);
+                        let item_tree = db.item_tree(src.file_id);
+                        let iter =
+                            item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
+                        items.extend(collect_items(
+                            db,
+                            module,
+                            expander,
+                            iter,
+                            src.file_id,
+                            container,
+                            limit - 1,
+                        ));
+
+                        expander.exit(db, mark);
+                    }
                 }
             }
         }