Repository: rust-analyzer/rust-analyzer
Pull request #2384 (2019-11-24 13:05:08)

Nicer API for attrs


Patch:
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 36ea8d8bf0..905bb5bcba 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -734,7 +734,7 @@ pub struct Static {
 
 impl Static {
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.module(db) }
+        Module { id: self.id.lookup(db).module(db) }
     }
 
     pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 59cda2e896..b9d21bdd72 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -88,7 +88,7 @@ impl HasSource for Const {
 impl HasSource for Static {
     type Ast = ast::StaticDef;
     fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
-        self.id.source(db)
+        self.id.lookup(db).source(db)
     }
 }
 impl HasSource for Trait {
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index c3c3b05ed3..f506bba705 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -104,10 +104,21 @@ impl FromSource for Const {
 impl FromSource for Static {
     type Ast = ast::StaticDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
-        let id = from_source(db, src)?;
-        Some(Static { id })
+        let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
+            Container::Module(it) => it,
+            Container::Trait(_) | Container::ImplBlock(_) => return None,
+        };
+        module
+            .declarations(db)
+            .into_iter()
+            .filter_map(|it| match it {
+                ModuleDef::Static(it) => Some(it),
+                _ => None,
+            })
+            .find(|it| same_source(&it.source(db), &src))
     }
 }
+
 impl FromSource for TypeAlias {
     type Ast = ast::TypeAliasDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
@@ -271,7 +282,9 @@ where
     let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
     let module = Module::from_definition(db, Source::new(src.file_id, module_src))?;
     let ctx = LocationCtx::new(db, module.id, src.file_id);
-    Some(DEF::from_ast(ctx, &src.value))
+    let items = db.ast_id_map(src.file_id);
+    let item_id = items.ast_id(&src.value);
+    Some(DEF::from_ast_id(ctx, item_id))
 }
 
 enum Container {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 0a836c9130..cfc4bd3260 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -11,7 +11,7 @@ use hir_def::{
     expr::{ExprId, PatId},
     path::known,
     resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
-    DefWithBodyId, LocationCtx,
+    DefWithBodyId,
 };
 use hir_expand::{
     name::AsName, AstId, HirFileId, MacroCallId, MacroCallLoc, MacroFileKind, Source,
@@ -28,8 +28,8 @@ use crate::{
     expr::{BodySourceMap, ExprScopes, ScopeId},
     ty::method_resolution::{self, implements_trait},
     Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
-    GenericParam, HasBody, Local, MacroDef, Module, Name, Path, ScopeDef, Static, Struct, Trait,
-    Ty, TypeAlias,
+    GenericParam, HasBody, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty,
+    TypeAlias,
 };
 
 fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> {
@@ -68,16 +68,12 @@ fn def_with_body_from_child_node(
     db: &impl HirDatabase,
     child: Source<&SyntaxNode>,
 ) -> Option<DefWithBody> {
-    let module_source = crate::ModuleSource::from_child_node(db, child);
-    let module = Module::from_definition(db, Source::new(child.file_id, module_source))?;
-    let ctx = LocationCtx::new(db, module.id, child.file_id);
-
     child.value.ancestors().find_map(|node| {
         match_ast! {
             match node {
                 ast::FnDef(def)  => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); },
                 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); },
-                ast::StaticDef(def) => { Some(Static { id: ctx.to_def(&def) }.into()) },
+                ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); },
                 _ => { None },
             }
         }
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 48ce8cd936..53456fc085 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,9 +2,8 @@
 
 use std::{ops, sync::Arc};
 
-use hir_expand::{either::Either, hygiene::Hygiene, AstId};
+use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source};
 use mbe::ast_to_token_tree;
-use ra_cfg::CfgOptions;
 use ra_syntax::{
     ast::{self, AstNode, AttrsOwner},
     SmolStr,
@@ -40,50 +39,53 @@ impl Attrs {
                     Some(it) => it,
                     None => return Attrs::default(),
                 };
-                let hygiene = Hygiene::new(db, src.file_id);
-                Attr::from_attrs_owner(&src.value, &hygiene)
+                Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
             }
             AttrDefId::StructFieldId(it) => {
                 let src = it.parent.child_source(db);
                 match &src.value[it.local_id] {
                     Either::A(_tuple) => Attrs::default(),
-                    Either::B(record) => {
-                        let hygiene = Hygiene::new(db, src.file_id);
-                        Attr::from_attrs_owner(record, &hygiene)
-                    }
+                    Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                 }
             }
-            AttrDefId::EnumVariantId(it) => {
-                let src = it.parent.child_source(db);
-                let hygiene = Hygiene::new(db, src.file_id);
-                Attr::from_attrs_owner(&src.value[it.local_id], &hygiene)
+            AttrDefId::EnumVariantId(var_id) => {
+                let src = var_id.parent.child_source(db);
+                let src = src.as_ref().map(|it| &it[var_id.local_id]);
+                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
             }
             AttrDefId::AdtId(it) => match it {
                 AdtId::StructId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
                 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
                 AdtId::UnionId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
             },
-            AttrDefId::StaticId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db),
             AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
+            AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db),
             AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
             AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db),
         }
     }
 
-    pub fn has_atom(&self, atom: &str) -> bool {
-        self.iter().any(|it| it.is_simple_atom(atom))
+    fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs {
+        let hygiene = Hygiene::new(db, owner.file_id);
+        Attrs::new(owner.value, &hygiene)
     }
 
-    pub fn find_string_value(&self, key: &str) -> Option<SmolStr> {
-        self.iter().filter(|attr| attr.is_simple_atom(key)).find_map(|attr| {
-            match attr.input.as_ref()? {
-                AttrInput::Literal(it) => Some(it.clone()),
-                _ => None,
-            }
-        })
+    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
+        let mut attrs = owner.attrs().peekable();
+        let entries = if attrs.peek().is_none() {
+            // Avoid heap allocation
+            None
+        } else {
+            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
+        };
+        Attrs { entries }
+    }
+
+    pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
+        AttrQuery { attrs: self, key }
     }
 }
 
@@ -100,7 +102,7 @@ pub enum AttrInput {
 }
 
 impl Attr {
-    pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
+    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
         let path = Path::from_src(ast.path()?, hygiene)?;
         let input = match ast.input() {
             None => None,
@@ -116,46 +118,37 @@ impl Attr {
 
         Some(Attr { path, input })
     }
+}
 
-    pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
-        let mut attrs = owner.attrs().peekable();
-        let entries = if attrs.peek().is_none() {
-            // Avoid heap allocation
-            None
-        } else {
-            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
-        };
-        Attrs { entries }
-    }
+pub struct AttrQuery<'a> {
+    attrs: &'a Attrs,
+    key: &'static str,
+}
 
-    pub fn is_simple_atom(&self, name: &str) -> bool {
-        // FIXME: Avoid cloning
-        self.path.as_ident().map_or(false, |s| s.to_string() == name)
+impl<'a> AttrQuery<'a> {
+    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
+        self.attrs().filter_map(|attr| match attr.input.as_ref()? {
+            AttrInput::TokenTree(it) => Some(it),
+            _ => None,
+        })
     }
 
-    // FIXME: handle cfg_attr :-)
-    pub fn as_cfg(&self) -> Option<&Subtree> {
-        if !self.is_simple_atom("cfg") {
-            return None;
-        }
-        match &self.input {
-            Some(AttrInput::TokenTree(subtree)) => Some(subtree),
+    pub fn string_value(self) -> Option<&'a SmolStr> {
+        self.attrs().find_map(|attr| match attr.input.as_ref()? {
+            AttrInput::Literal(it) => Some(it),
             _ => None,
-        }
+        })
     }
 
-    pub fn as_path(&self) -> Option<&SmolStr> {
-        if !self.is_simple_atom("path") {
-            return None;
-        }
-        match &self.input {
-            Some(AttrInput::Literal(it)) => Some(it),
-            _ => None,
-        }
+    pub fn exists(self) -> bool {
+        self.attrs().next().is_some()
     }
 
-    pub fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> {
-        cfg_options.is_cfg_enabled(self.as_cfg()?)
+    fn attrs(self) -> impl Iterator<Item = &'a Attr> {
+        let key = self.key;
+        self.attrs
+            .iter()
+            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
     }
 }
 
@@ -164,8 +157,8 @@ where
     N: ast::AttrsOwner,
     D: DefDatabase,
 {
-    let hygiene = Hygiene::new(db, src.file_id());
-    Attr::from_attrs_owner(&src.to_node(db), &hygiene)
+    let src = Source::new(src.file_id(), src.to_node(db));
+    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
 }
 
 fn attrs_from_loc<T, D>(node: T, db: &D) -> Attrs
@@ -175,6 +168,5 @@ where
     D: DefDatabase,
 {
     let src = node.source(db);
-    let hygiene = Hygiene::new(db, src.file_id);
-    Attr::from_attrs_owner(&src.value, &hygiene)
+    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
 }
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 225638b422..1589085b53 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -17,7 +17,7 @@ use crate::{
     expr::{Expr, ExprId, Pat, PatId},
     nameres::CrateDefMap,
     path::Path,
-    AstItemDef, DefWithBodyId, HasModule, HasSource, Lookup, ModuleId,
+    DefWithBodyId, HasModule, HasSource, Lookup, ModuleId,
 };
 
 pub struct Expander {
@@ -160,6 +160,7 @@ impl Body {
                 (src.file_id, c.module(db), src.value.body())
             }
             DefWithBodyId::StaticId(s) => {
+                let s = s.lookup(db);
                 let src = s.source(db);
                 (src.file_id, s.module(db), src.value.body())
             }
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index f0b3e198a3..81a8ec18db 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -204,7 +204,7 @@ impl ConstData {
     }
 
     pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> {
-        let node = konst.source(db).value;
+        let node = konst.lookup(db).source(db).value;
         const_data_for(&node)
     }
 }
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 7fec2e8c01..32adb11bdc 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -18,7 +18,8 @@ use crate::{
         CrateDefMap,
     },
     AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
-    ImplId, ItemLoc, ModuleId, StaticId, StructOrUnionId, TraitId, TypeAliasId, TypeAliasLoc,
+    ImplId, ItemLoc, ModuleId, StaticId, StaticLoc, StructOrUnionId, TraitId, TypeAliasId,
+    TypeAliasLoc,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -32,7 +33,7 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_const(&self, loc: ConstLoc) -> ConstId;
     #[salsa::interned]
-    fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> StaticId;
+    fn intern_static(&self, loc: StaticLoc) -> StaticId;
     #[salsa::interned]
     fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId;
     #[salsa::interned]
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs
index 69846fd1b2..2255114288 100644
--- a/crates/ra_hir_def/src/docs.rs
+++ b/crates/ra_hir_def/src/docs.rs
@@ -52,10 +52,10 @@ impl Documentation {
                 let src = it.parent.child_source(db);
                 docs_from_ast(&src.value[it.local_id])
             }
-            AttrDefId::StaticId(it) => docs_from_ast(&it.source(db).value),
             AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value),
             AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)),
             AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value),
+            AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value),
             AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
             AttrDefId::TypeAliasId(it) => docs_from_ast(&it.lookup(db).source(db).value),
             AttrDefId::ImplId(_) => None,
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index df951c5330..3b9fb03285 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -113,8 +113,8 @@ impl LangItems {
         T: Into<AttrDefId> + Copy,
     {
         let attrs = db.attrs(item.into());
-        if let Some(lang_item_name) = attrs.find_string_value("lang") {
-            self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
+        if let Some(lang_item_name) = attrs.by_key("lang").string_value() {
+            self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item));
         }
     }
 }
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index b063530c27..f60feb5fa9 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -94,25 +94,10 @@ impl<'a, DB> LocationCtx<&'a DB> {
     }
 }
 
-impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
-    pub fn to_def<N, DEF>(self, ast: &N) -> DEF
-    where
-        N: AstNode,
-        DEF: AstItemDef<N>,
-    {
-        DEF::from_ast(self, ast)
-    }
-}
-
 pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
     fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
     fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
 
-    fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
-        let items = ctx.db.ast_id_map(ctx.file_id);
-        let item_id = items.ast_id(ast);
-        Self::from_ast_id(ctx, item_id)
-    }
     fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
         let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
         Self::intern(ctx.db, loc)
@@ -245,12 +230,24 @@ impl Lookup for ConstId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StaticId(salsa::InternId);
 impl_intern_key!(StaticId);
-impl AstItemDef<ast::StaticDef> for StaticId {
-    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
-        db.intern_static(loc)
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct StaticLoc {
+    pub container: ModuleId,
+    pub ast_id: AstId<ast::StaticDef>,
+}
+
+impl Intern for StaticLoc {
+    type ID = StaticId;
+    fn intern(self, db: &impl db::DefDatabase) -> StaticId {
+        db.intern_static(self)
     }
-    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
-        db.lookup_intern_static(self)
+}
+
+impl Lookup for StaticId {
+    type Data = StaticLoc;
+    fn lookup(&self, db: &impl db::DefDatabase) -> StaticLoc {
+        db.lookup_intern_static(*self)
     }
 }
 
@@ -481,6 +478,12 @@ impl HasModule for ConstLoc {
     }
 }
 
+impl HasModule for StaticLoc {
+    fn module(&self, _db: &impl db::DefDatabase) -> ModuleId {
+        self.container
+    }
+}
+
 pub trait HasSource {
     type Value;
     fn source(&self, db: &impl db::DefDatabase) -> Source<Self::Value>;
@@ -513,6 +516,15 @@ impl HasSource for ConstLoc {
     }
 }
 
+impl HasSource for StaticLoc {
+    type Value = ast::StaticDef;
+
+    fn source(&self, db: &impl db::DefDatabase) -> Source<ast::StaticDef> {
+        let node = self.ast_id.to_node(db);
+        Source::new(self.ast_id.file_id(), node)
+    }
+}
+
 pub trait HasChildSource {
     type ChildId;
     type Value;
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 1d004b6a60..7a5f903279 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -7,7 +7,7 @@ use hir_expand::{
 };
 use ra_cfg::CfgOptions;
 use ra_db::{CrateId, FileId};
-use ra_syntax::{ast, SmolStr};
+use ra_syntax::ast;
 use rustc_hash::{FxHashMap, FxHashSet};
 use test_utils::tested_by;
 
@@ -21,7 +21,7 @@ use crate::{
     path::{Path, PathKind},
     per_ns::PerNs,
     AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId,
-    Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticId, StructId,
+    Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId,
     StructOrUnionId, TraitId, TypeAliasLoc, UnionId,
 };
 
@@ -599,8 +599,8 @@ where
     }
 
     fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) {
-        let path_attr = self.path_attr(attrs);
-        let is_macro_use = attrs.has_atom("macro_use");
+        let path_attr = attrs.by_key("path").string_value();
+        let is_macro_use = attrs.by_key("macro_use").exists();
         match module {
             // inline module, just recurse
             raw::ModuleData::Definition { name, items, ast_id } => {
@@ -715,7 +715,10 @@ where
                 PerNs::values(def.into())
             }
             raw::DefKind::Static(ast_id) => {
-                PerNs::values(StaticId::from_ast_id(ctx, ast_id).into())
+                let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
+                    .intern(self.def_collector.db);
+
+                PerNs::values(def.into())
             }
             raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()),
             raw::DefKind::TypeAlias(ast_id) => {
@@ -793,11 +796,11 @@ where
     }
 
     fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
-        attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
-    }
-
-    fn path_attr<'a>(&self, attrs: &'a Attrs) -> Option<&'a SmolStr> {
-        attrs.iter().find_map(|attr| attr.as_path())
+        // FIXME: handle cfg_attr :-)
+        attrs
+            .by_key("cfg")
+            .tt_values()
+            .all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false))
     }
 }
 
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 552cbe5448..1985787538 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -17,10 +17,7 @@ use ra_syntax::{
 use test_utils::tested_by;
 
 use crate::{
-    attr::{Attr, Attrs},
-    db::DefDatabase,
-    path::Path,
-    FileAstId, HirFileId, LocalImportId, Source,
+    attr::Attrs, db::DefDatabase, path::Path, FileAstId, HirFileId, LocalImportId, Source,
 };
 
 /// `RawItems` is a set of top-level items in a file (except for impls).
@@ -407,6 +404,6 @@ impl RawItemsCollector {
     }
 
     fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
-        Attr::from_attrs_owner(item, &self.hygiene)
+        Attrs::new(item, &self.hygiene)
     }
 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index b56de44dd7..4ff0a091b8 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -540,7 +540,7 @@ impl HasResolver for ConstId {
 
 impl HasResolver for StaticId {
     fn resolver(self, db: &impl DefDatabase) -> Resolver {
-        self.module(db).resolver(db)
+        self.lookup(db).container.resolver(db)
     }
 }
 
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 896ad15173..bac3f7582f 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -288,7 +288,7 @@ impl Completions {
 }
 
 fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool {
-    node.attrs(db).has_atom("deprecated")
+    node.attrs(db).by_key("deprecated").exists()
 }
 
 fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 17a50cf741..3209c66bd0 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2550,8 +2550,6 @@ fn test() {
     [233; 246) 'GLOBAL_STATIC': u32
     [256; 257) 'w': u32
     [260; 277) 'GLOBAL...IC_MUT': u32
-    [118; 120) '99': u32
-    [161; 163) '99': u32
     "###
     );
 }