Repository: rust-analyzer/rust-analyzer
Pull request #6937 (2020-12-18 20:05:04)

Deduplicate highlight tags and symbol kinds
bors r+
🤖


Patch:
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1b9c64ee55..9cd0b72aa9 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -12,7 +12,6 @@ use syntax::{
     ast::{self, AstNode, AttrsOwner},
     match_ast, AstToken, SmolStr, SyntaxNode,
 };
-use test_utils::mark;
 use tt::Subtree;
 
 use crate::{
@@ -123,69 +122,9 @@ impl RawAttrs {
     }
 
     /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
-    pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
-        let has_cfg_attrs = self.iter().any(|attr| {
-            attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr])
-        });
-        if !has_cfg_attrs {
-            return Attrs(self);
-        }
-
-        let crate_graph = db.crate_graph();
-        let new_attrs = self
-            .iter()
-            .filter_map(|attr| {
-                let attr = attr.clone();
-                let is_cfg_attr =
-                    attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]);
-                if !is_cfg_attr {
-                    return Some(attr);
-                }
-
-                let subtree = match &attr.input {
-                    Some(AttrInput::TokenTree(it)) => it,
-                    _ => return Some(attr),
-                };
-
-                // Input subtree is: `(cfg, attr)`
-                // Split it up into a `cfg` and an `attr` subtree.
-                // FIXME: There should be a common API for this.
-                let mut saw_comma = false;
-                let (mut cfg, attr): (Vec<_>, Vec<_>) =
-                    subtree.clone().token_trees.into_iter().partition(|tree| {
-                        if saw_comma {
-                            return false;
-                        }
-
-                        match tree {
-                            tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
-                                saw_comma = true;
-                            }
-                            _ => {}
-                        }
-
-                        true
-                    });
-                cfg.pop(); // `,` ends up in here
-
-                let attr = Subtree { delimiter: None, token_trees: attr };
-                let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg };
-                let cfg = CfgExpr::parse(&cfg);
-
-                let cfg_options = &crate_graph[krate].cfg_options;
-                if cfg_options.check(&cfg) == Some(false) {
-                    None
-                } else {
-                    mark::hit!(cfg_attr_active);
-
-                    let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?;
-                    let hygiene = Hygiene::new_unhygienic(); // FIXME
-                    Attr::from_src(attr, &hygiene)
-                }
-            })
-            .collect();
-
-        Attrs(RawAttrs { entries: Some(new_attrs) })
+    pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
+        // FIXME actually implement this
+        Attrs(self)
     }
 }
 
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 100dbf5d65..5eb7cae7f0 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -12,7 +12,7 @@ use std::{
 };
 
 use arena::{Arena, Idx, RawId};
-use ast::{AstNode, NameOwner, StructKind};
+use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
 use base_db::CrateId;
 use either::Either;
 use hir_expand::{
@@ -495,6 +495,7 @@ pub struct Import {
     pub alias: Option<ImportAlias>,
     pub visibility: RawVisibilityId,
     pub is_glob: bool,
+    pub is_prelude: bool,
     /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
     /// `Import`s can map to the same `use` item.
     pub ast_id: FileAstId<ast::Use>,
@@ -510,6 +511,8 @@ pub struct ExternCrate {
     pub name: Name,
     pub alias: Option<ImportAlias>,
     pub visibility: RawVisibilityId,
+    /// Whether this is a `#[macro_use] extern crate ...`.
+    pub is_macro_use: bool,
     pub ast_id: FileAstId<ast::ExternCrate>,
 }
 
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 3b206ef85e..c8f090c22c 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -485,6 +485,8 @@ impl Ctx {
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
+        // FIXME: cfg_attr
+        let is_prelude = use_item.has_atom_attr("prelude_import");
         let visibility = self.lower_visibility(use_item);
         let ast_id = self.source_ast_id_map.ast_id(use_item);
 
@@ -500,6 +502,7 @@ impl Ctx {
                     alias,
                     visibility,
                     is_glob,
+                    is_prelude,
                     ast_id,
                     index: imports.len(),
                 })));
@@ -519,8 +522,10 @@ impl Ctx {
         });
         let visibility = self.lower_visibility(extern_crate);
         let ast_id = self.source_ast_id_map.ast_id(extern_crate);
+        // FIXME: cfg_attr
+        let is_macro_use = extern_crate.has_atom_attr("macro_use");
 
-        let res = ExternCrate { name, alias, visibility, ast_id };
+        let res = ExternCrate { name, alias, visibility, is_macro_use, ast_id };
         Some(id(self.data().extern_crates.alloc(res)))
     }
 
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 55228e480a..b114a6fe4a 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -136,35 +136,23 @@ struct Import {
 }
 
 impl Import {
-    fn from_use(
-        db: &dyn DefDatabase,
-        krate: CrateId,
-        tree: &ItemTree,
-        id: ItemTreeId<item_tree::Import>,
-    ) -> Self {
+    fn from_use(tree: &ItemTree, id: ItemTreeId<item_tree::Import>) -> Self {
         let it = &tree[id.value];
-        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
         let visibility = &tree[it.visibility];
         Self {
             path: it.path.clone(),
             alias: it.alias.clone(),
             visibility: visibility.clone(),
             is_glob: it.is_glob,
-            is_prelude: attrs.by_key("prelude_import").exists(),
+            is_prelude: it.is_prelude,
             is_extern_crate: false,
             is_macro_use: false,
             source: ImportSource::Import(id),
         }
     }
 
-    fn from_extern_crate(
-        db: &dyn DefDatabase,
-        krate: CrateId,
-        tree: &ItemTree,
-        id: ItemTreeId<item_tree::ExternCrate>,
-    ) -> Self {
+    fn from_extern_crate(tree: &ItemTree, id: ItemTreeId<item_tree::ExternCrate>) -> Self {
         let it = &tree[id.value];
-        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
         let visibility = &tree[it.visibility];
         Self {
             path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
@@ -173,7 +161,7 @@ impl Import {
             is_glob: false,
             is_prelude: false,
             is_extern_crate: true,
-            is_macro_use: attrs.by_key("macro_use").exists(),
+            is_macro_use: it.is_macro_use,
             source: ImportSource::ExternCrate(id),
         }
     }
@@ -942,12 +930,7 @@ impl ModCollector<'_, '_> {
             if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
                 if let ModItem::ExternCrate(id) = item {
                     let import = self.item_tree[*id].clone();
-                    let attrs = self.item_tree.attrs(
-                        self.def_collector.db,
-                        krate,
-                        ModItem::from(*id).into(),
-                    );
-                    if attrs.by_key("macro_use").exists() {
+                    if import.is_macro_use {
                         self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
                     }
                 }
@@ -973,8 +956,6 @@ impl ModCollector<'_, '_> {
                     self.def_collector.unresolved_imports.push(ImportDirective {
                         module_id: self.module_id,
                         import: Import::from_use(
-                            self.def_collector.db,
-                            krate,
                             &self.item_tree,
                             InFile::new(self.file_id, import_id),
                         ),
@@ -985,8 +966,6 @@ impl ModCollector<'_, '_> {
                     self.def_collector.unresolved_imports.push(ImportDirective {
                         module_id: self.module_id,
                         import: Import::from_extern_crate(
-                            self.def_collector.db,
-                            krate,
                             &self.item_tree,
                             InFile::new(self.file_id, import_id),
                         ),
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 77eeee3fe9..7fb4caea36 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -153,7 +153,6 @@ pub mod known {
         // Special names
         macro_rules,
         doc,
-        cfg_attr,
         // Components of known path (value or mod name)
         std,
         core,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index cbdd4ecc2a..7d0514105b 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -18,13 +18,14 @@ use crate::FileSymbol;
 
 use super::short_label::ShortLabel;
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub enum SymbolKind {
     Module,
     Impl,
     Field,
     TypeParam,
     LifetimeParam,
+    ValueParam,
     SelfParam,
     Local,
     Function,
@@ -406,10 +407,11 @@ impl ToNav for hir::Local {
             Some(it) => it.to_string().into(),
             None => "".into(),
         };
+        let kind = if self.is_param(db) { SymbolKind::ValueParam } else { SymbolKind::Local };
         NavigationTarget {
             file_id: full_range.file_id,
             name,
-            kind: Some(SymbolKind::Local),
+            kind: Some(kind),
             full_range: full_range.range,
             focus_range: None,
             container_name: None,
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 8c00a71058..18ea193052 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -546,7 +546,7 @@ fn bar() {
 fn foo(i : u32) -> u32 { i<|> }
 "#,
             expect![[r#"
-                i Local FileId(0) 7..8 Other
+                i ValueParam FileId(0) 7..8 Other
 
                 FileId(0) 25..26 Other Read
             "#]],
@@ -560,7 +560,7 @@ fn foo(i : u32) -> u32 { i<|> }
 fn foo(i<|> : u32) -> u32 { i }
 "#,
             expect![[r#"
-                i Local FileId(0) 7..8 Other
+                i ValueParam FileId(0) 7..8 Other
 
                 FileId(0) 25..26 Other Read
             "#]],
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 488969f1a1..7f98aa316f 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -23,7 +23,7 @@ use crate::{
     syntax_highlighting::{
         format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight,
     },
-    FileId, HighlightModifier, HighlightTag,
+    FileId, HighlightModifier, HighlightTag, SymbolKind,
 };
 
 pub(crate) use html::highlight_as_html;
@@ -103,7 +103,7 @@ pub(crate) fn highlight(
                 if let Some(range) = macro_call_range(&mc) {
                     stack.add(HighlightedRange {
                         range,
-                        highlight: HighlightTag::Macro.into(),
+                        highlight: HighlightTag::Symbol(SymbolKind::Macro).into(),
                         binding_hash: None,
                     });
                 }
@@ -470,13 +470,13 @@ fn highlight_element(
             };
 
             match name_kind {
-                Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
+                Some(NameClass::ExternCrate(_)) => HighlightTag::Symbol(SymbolKind::Module).into(),
                 Some(NameClass::Definition(def)) => {
                     highlight_def(db, def) | HighlightModifier::Definition
                 }
                 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
                 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
-                    let mut h = HighlightTag::Field.into();
+                    let mut h = HighlightTag::Symbol(SymbolKind::Field).into();
                     if let Definition::Field(field) = field_ref {
                         if let VariantDef::Union(_) = field.parent_def(db) {
                             h |= HighlightModifier::Unsafe;
@@ -493,14 +493,16 @@ fn highlight_element(
         NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
             // even though we track whether we are in an attribute or not we still need this special case
             // as otherwise we would emit unresolved references for name refs inside attributes
-            Highlight::from(HighlightTag::Function)
+            Highlight::from(HighlightTag::Symbol(SymbolKind::Function))
         }
         NAME_REF => {
             let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
             highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
                 match NameRefClass::classify(sema, &name_ref) {
                     Some(name_kind) => match name_kind {
-                        NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
+                        NameRefClass::ExternCrate(_) => {
+                            HighlightTag::Symbol(SymbolKind::Module).into()
+                        }
                         NameRefClass::Definition(def) => {
                             if let Definition::Local(local) = &def {
                                 if let Some(name) = local.name(db) {
@@ -530,7 +532,9 @@ fn highlight_element(
 
                             h
                         }
-                        NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
+                        NameRefClass::FieldShorthand { .. } => {
+                            HighlightTag::Symbol(SymbolKind::Field).into()
+                        }
                     },
                     None if syntactic_name_ref_highlighting => {
                         highlight_name_ref_by_syntax(name_ref, sema)
@@ -556,7 +560,7 @@ fn highlight_element(
         CHAR => HighlightTag::CharLiteral.into(),
         QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow,
         LIFETIME => {
-            let h = Highlight::new(HighlightTag::Lifetime);
+            let h = Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam));
             match element.parent().map(|it| it.kind()) {
                 Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition,
                 _ => h,
@@ -580,7 +584,7 @@ fn highlight_element(
                 HighlightTag::Operator.into()
             }
             T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
-                HighlightTag::Macro.into()
+                HighlightTag::Symbol(SymbolKind::Macro).into()
             }
             T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
                 HighlightTag::BuiltinType.into()
@@ -659,7 +663,7 @@ fn highlight_element(
                         .and_then(SyntaxNode::parent)
                         .and_then(ast::Path::cast)
                         .and_then(|p| sema.resolve_path(&p));
-                    let mut h = HighlightTag::SelfKeyword.into();
+                    let mut h = HighlightTag::Symbol(SymbolKind::SelfParam).into();
                     if self_param_is_mut
                         || matches!(self_path,
                             Some(hir::PathResolution::Local(local))
@@ -756,10 +760,10 @@ fn highlight_method_call(
 
 fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
     match def {
-        Definition::Macro(_) => HighlightTag::Macro,
-        Definition::Field(_) => HighlightTag::Field,
+        Definition::Macro(_) => HighlightTag::Symbol(SymbolKind::Macro),
+        Definition::Field(_) => HighlightTag::Symbol(SymbolKind::Field),
         Definition::ModuleDef(def) => match def {
-            hir::ModuleDef::Module(_) => HighlightTag::Module,
+            hir::ModuleDef::Module(_) => HighlightTag::Symbol(SymbolKind::Module),
             hir::ModuleDef::Function(func) => {
                 let mut h = if func.as_assoc_item(db).is_some() {
                     if func.self_param(db).is_none() {
@@ -768,23 +772,23 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
                         HighlightTag::Method.into()
                     }
                 } else {
-                    HighlightTag::Function.into()
+                    HighlightTag::Symbol(SymbolKind::Function).into()
                 };
                 if func.is_unsafe(db) {
                     h |= HighlightModifier::Unsafe;
                 }
                 return h;
             }
-            hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
-            hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum,
-            hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union,
-            hir::ModuleDef::EnumVariant(_) => HighlightTag::EnumVariant,
-            hir::ModuleDef::Const(_) => HighlightTag::Constant,
-            hir::ModuleDef::Trait(_) => HighlightTag::Trait,
-            hir::ModuleDef::TypeAlias(_) => HighlightTag::TypeAlias,
+            hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Symbol(SymbolKind::Struct),
+            hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Symbol(SymbolKind::Enum),
+            hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Symbol(SymbolKind::Union),
+            hir::ModuleDef::EnumVariant(_) => HighlightTag::Symbol(SymbolKind::Variant),
+            hir::ModuleDef::Const(_) => HighlightTag::Symbol(SymbolKind::Const),
+            hir::ModuleDef::Trait(_) => HighlightTag::Symbol(SymbolKind::Trait),
+            hir::ModuleDef::TypeAlias(_) => HighlightTag::Symbol(SymbolKind::TypeAlias),
             hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType,
             hir::ModuleDef::Static(s) => {
-                let mut h = Highlight::new(HighlightTag::Static);
+                let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Static));
                 if s.is_mut(db) {
                     h |= HighlightModifier::Mutable;
                     h |= HighlightModifier::Unsafe;
@@ -792,11 +796,14 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
                 return h;
             }
         },
-        Definition::SelfType(_) => HighlightTag::SelfType,
-        Definition::TypeParam(_) => HighlightTag::TypeParam,
+        Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl),
+        Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam),
         Definition::Local(local) => {
-            let tag =
-                if local.is_param(db) { HighlightTag::ValueParam } else { HighlightTag::Local };
+            let tag = if local.is_param(db) {
+                HighlightTag::Symbol(SymbolKind::ValueParam)
+            } else {
+                HighlightTag::Symbol(SymbolKind::Local)
+            };
             let mut h = Highlight::new(tag);
             if local.is_mut(db) || local.ty(db).is_mutable_reference() {
                 h |= HighlightModifier::Mutable;
@@ -806,7 +813,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
             }
             return h;
         }
-        Definition::LifetimeParam(_) => HighlightTag::Lifetime,
+        Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam),
     }
     .into()
 }
@@ -820,19 +827,19 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
     };
 
     let tag = match parent.kind() {
-        STRUCT => HighlightTag::Struct,
-        ENUM => HighlightTag::Enum,
-        UNION => HighlightTag::Union,
-        TRAIT => HighlightTag::Trait,
-        TYPE_ALIAS => HighlightTag::TypeAlias,
-        TYPE_PARAM => HighlightTag::TypeParam,
-        RECORD_FIELD => HighlightTag::Field,
-        MODULE => HighlightTag::Module,
-        FN => HighlightTag::Function,
-        CONST => HighlightTag::Constant,
-        STATIC => HighlightTag::Static,
-        VARIANT => HighlightTag::EnumVariant,
-        IDENT_PAT => HighlightTag::Local,
+        STRUCT => HighlightTag::Symbol(SymbolKind::Struct),
+        ENUM => HighlightTag::Symbol(SymbolKind::Enum),
+        VARIANT => HighlightTag::Symbol(SymbolKind::Variant),
+        UNION => HighlightTag::Symbol(SymbolKind::Union),
+        TRAIT => HighlightTag::Symbol(SymbolKind::Trait),
+        TYPE_ALIAS => HighlightTag::Symbol(SymbolKind::TypeAlias),
+        TYPE_PARAM => HighlightTag::Symbol(SymbolKind::TypeParam),
+        RECORD_FIELD => HighlightTag::Symbol(SymbolKind::Field),
+        MODULE => HighlightTag::Symbol(SymbolKind::Module),
+        FN => HighlightTag::Symbol(SymbolKind::Function),
+        CONST => HighlightTag::Symbol(SymbolKind::Const),
+        STATIC => HighlightTag::Symbol(SymbolKind::Static),
+        IDENT_PAT => HighlightTag::Symbol(SymbolKind::Local),
         _ => default,
     };
 
@@ -851,10 +858,10 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
         METHOD_CALL_EXPR => {
             return ast::MethodCallExpr::cast(parent)
                 .and_then(|method_call| highlight_method_call(sema, &method_call))
-                .unwrap_or_else(|| HighlightTag::Function.into());
+                .unwrap_or_else(|| HighlightTag::Symbol(SymbolKind::Function).into());
         }
         FIELD_EXPR => {
-            let h = HighlightTag::Field;
+            let h = HighlightTag::Symbol(SymbolKind::Field);
             let is_union = ast::FieldExpr::cast(parent)
                 .and_then(|field_expr| {
                     let field = sema.resolve_field(&field_expr)?;
@@ -881,9 +888,9 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
                 _ => {
                     // within path, decide whether it is module or adt by checking for uppercase name
                     return if name.text().chars().next().unwrap_or_default().is_uppercase() {
-                        HighlightTag::Struct
+                        HighlightTag::Symbol(SymbolKind::Struct)
                     } else {
-                        HighlightTag::Module
+                        HighlightTag::Symbol(SymbolKind::Module)
                     }
                     .into();
                 }
@@ -894,11 +901,11 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
             };
 
             match parent.kind() {
-                CALL_EXPR => HighlightTag::Function.into(),
+                CALL_EXPR => HighlightTag::Symbol(SymbolKind::Function).into(),
                 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
-                    HighlightTag::Struct.into()
+                    HighlightTag::Symbol(SymbolKind::Struct)
                 } else {
-                    HighlightTag::Constant
+                    HighlightTag::Symbol(SymbolKind::Const)
                 }
                 .into(),
             }
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index 42f27df5d9..26416022b8 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -4,7 +4,9 @@ use syntax::{
     AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
 };
 
-use crate::{syntax_highlighting::HighlightedRangeStack, HighlightTag, HighlightedRange};
+use crate::{
+    syntax_highlighting::HighlightedRangeStack, HighlightTag, HighlightedRange, SymbolKind,
+};
 
 #[derive(Default)]
 pub(super) struct FormatStringHighlighter {
@@ -71,6 +73,6 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> {
         | FormatSpecifier::Asterisk
         | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier,
         FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral,
-        FormatSpecifier::Identifier => HighlightTag::Local,
+        FormatSpecifier::Identifier => HighlightTag::Symbol(SymbolKind::Local),
     })
 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index ffd9588b84..e0117a6b2a 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -3,6 +3,8 @@
 
 use std::{fmt, ops};
 
+use crate::SymbolKind;
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct Highlight {
     pub tag: HighlightTag,
@@ -14,40 +16,26 @@ pub struct HighlightModifiers(u32);
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub enum HighlightTag {
-    Attribute,
+    Symbol(SymbolKind),
+
     BoolLiteral,
     BuiltinType,
     ByteLiteral,
     CharLiteral,
+    NumericLiteral,
+    StringLiteral,
+    Attribute,
     Comment,
-    Constant,
-    Enum,
-    EnumVariant,
     EscapeSequence,
-    Field,
-    Function,
-    Generic,
+    FormatSpecifier,
     Keyword,
-    Lifetime,
-    Macro,
-    Method,
-    Module,
-    NumericLiteral,
     Punctuation,
-    SelfKeyword,
-    SelfType,
-    Static,
-    StringLiteral,
-    Struct,
-    Trait,
-    TypeAlias,
-    TypeParam,
-    Union,
-    ValueParam,
-    Local,
-    UnresolvedReference,
-    FormatSpecifier,
     Operator,
+    UnresolvedReference,
+
+    // FIXME: this two are random and don't fit with the others
+    Method,
+    Generic,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -73,39 +61,41 @@ pub enum HighlightModifier {
 impl HighlightTag {
     fn as_str(self) -> &'static str {
         match self {
+            HighlightTag::Symbol(symbol) => match symbol {
+                SymbolKind::Const => "constant",
+                SymbolKind::Static => "static",
+                SymbolKind::Enum => "enum",
+                SymbolKind::Variant => "enum_variant",
+                SymbolKind::Struct => "struct",
+                SymbolKind::Union => "union",
+                SymbolKind::Field => "field",
+                SymbolKind::Module => "module",
+                SymbolKind::Trait => "trait",
+                SymbolKind::Function => "function",
+                SymbolKind::TypeAlias => "type_alias",
+                SymbolKind::TypeParam => "type_param",
+                SymbolKind::LifetimeParam => "lifetime",
+                SymbolKind::Macro => "macro",
+                SymbolKind::Local => "variable",
+                SymbolKind::ValueParam => "value_param",
+                SymbolKind::SelfParam => "self_keyword",
+                SymbolKind::Impl => "self_type",
+            },
             HighlightTag::Attribute => "attribute",
             HighlightTag::BoolLiteral => "bool_literal",
             HighlightTag::BuiltinType => "builtin_type",
             HighlightTag::ByteLiteral => "byte_literal",
             HighlightTag::CharLiteral => "char_literal",
             HighlightTag::Comment => "comment",
-            HighlightTag::Constant => "constant",
-            HighlightTag::Enum => "enum",
-            HighlightTag::EnumVariant => "enum_variant",
             HighlightTag::EscapeSequence => "escape_sequence",
-            HighlightTag::Field => "field",
             HighlightTag::FormatSpecifier => "format_specifier",
-            HighlightTag::Function => "function",
             HighlightTag::Generic => "generic",
             HighlightTag::Keyword => "keyword",
-            HighlightTag::Lifetime => "lifetime",
             HighlightTag::Punctuation => "punctuation",
-            HighlightTag::Macro => "macro",
             HighlightTag::Method => "method",
-            HighlightTag::Module => "module",
             HighlightTag::NumericLiteral => "numeric_literal",
             HighlightTag::Operator => "operator",
-            HighlightTag::SelfKeyword => "self_keyword",
-            HighlightTag::SelfType => "self_type",
-            HighlightTag::Static => "static",
             HighlightTag::StringLiteral => "string_literal",
-            HighlightTag::Struct => "struct",
-            HighlightTag::Trait => "trait",
-            HighlightTag::TypeAlias => "type_alias",
-            HighlightTag::TypeParam => "type_param",
-            HighlightTag::Union => "union",
-            HighlightTag::ValueParam => "value_param",
-            HighlightTag::Local => "variable",
             HighlightTag::UnresolvedReference => "unresolved_reference",
         }
     }
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 1a078f6b4c..23039eba49 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -133,10 +133,6 @@ pub(crate) mod fragments {
 
         m.complete(p, MACRO_STMTS);
     }
-
-    pub(crate) fn attr(p: &mut Parser) {
-        attributes::outer_attrs(p)
-    }
 }
 
 pub(crate) fn reparser(
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index ab8e4c70e8..41e62116f8 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -99,8 +99,6 @@ pub enum FragmentKind {
     // FIXME: use separate fragment kinds for macro inputs and outputs?
     Items,
     Statements,
-
-    Attr,
 }
 
 pub fn parse_fragment(
@@ -120,7 +118,6 @@ pub fn parse_fragment(
         FragmentKind::Statement => grammar::fragments::stmt,
         FragmentKind::Items => grammar::fragments::macro_items,
         FragmentKind::Statements => grammar::fragments::macro_stmts,
-        FragmentKind::Attr => grammar::fragments::attr,
     };
     parse_from_tokens(token_source, tree_sink, parser)
 }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 6b2302803a..229df47dc6 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -43,9 +43,10 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
         SymbolKind::Static => lsp_types::SymbolKind::Constant,
         SymbolKind::Const => lsp_types::SymbolKind::Constant,
         SymbolKind::Impl => lsp_types::SymbolKind::Object,
-        SymbolKind::Local | SymbolKind::SelfParam | SymbolKind::LifetimeParam => {
-            lsp_types::SymbolKind::Variable
-        }
+        SymbolKind::Local
+        | SymbolKind::SelfParam
+        | SymbolKind::LifetimeParam
+        | SymbolKind::ValueParam => lsp_types::SymbolKind::Variable,
         SymbolKind::Union => lsp_types::SymbolKind::Struct,
     }
 }
@@ -371,34 +372,36 @@ fn semantic_token_type_and_modifiers(
 ) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) {
     let mut mods = semantic_tokens::ModifierSet::default();
     let type_ = match highlight.tag {
-        HighlightTag::Struct => lsp_types::SemanticTokenType::STRUCT,
-        HighlightTag::Enum => lsp_types::SemanticTokenType::ENUM,
-        HighlightTag::Union => semantic_tokens::UNION,
-        HighlightTag::TypeAlias => semantic_tokens::TYPE_ALIAS,
-        HighlightTag::Trait => lsp_types::SemanticTokenType::INTERFACE,
+        HighlightTag::Symbol(symbol) => match symbol {
+            SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
+            SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE,
+            SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
+            SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
+            SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
+            SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
+            SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
+            SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
+            SymbolKind::Function => lsp_types::SemanticTokenType::FUNCTION,
+            SymbolKind::Const => {
+                mods |= semantic_tokens::CONSTANT;
+                mods |= lsp_types::SemanticTokenModifier::STATIC;
+                lsp_types::SemanticTokenType::VARIABLE
+            }
+            SymbolKind::Static => {
+                mods |= lsp_types::SemanticTokenModifier::STATIC;
+                lsp_types::SemanticTokenType::VARIABLE
+            }
+            SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT,
+            SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM,
+            SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER,
+            SymbolKind::Union => semantic_tokens::UNION,
+            SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS,
+            SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
+            SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO,
+        },
         HighlightTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
-        HighlightTag::SelfKeyword => semantic_tokens::SELF_KEYWORD,
-        HighlightTag::SelfType => lsp_types::SemanticTokenType::TYPE,
-        HighlightTag::Field => lsp_types::SemanticTokenType::PROPERTY,
-        HighlightTag::Function => lsp_types::SemanticTokenType::FUNCTION,
         HighlightTag::Generic => semantic_tokens::GENERIC,
-        HighlightTag::Module => lsp_types::SemanticTokenType::NAMESPACE,
         HighlightTag::Method => lsp_types::SemanticTokenType::METHOD,
-        HighlightTag::Constant => {
-            mods |= semantic_tokens::CONSTANT;
-            mods |= lsp_types::SemanticTokenModifier::STATIC;
-            lsp_types::SemanticTokenType::VARIABLE
-        }
-        HighlightTag::Static => {
-            mods |= lsp_types::SemanticTokenModifier::STATIC;
-            lsp_types::SemanticTokenType::VARIABLE
-        }
-        HighlightTag::EnumVariant => lsp_types::SemanticTokenType::ENUM_MEMBER,
-        HighlightTag::Macro => lsp_types::SemanticTokenType::MACRO,
-        HighlightTag::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
-        HighlightTag::Local => lsp_types::SemanticTokenType::VARIABLE,
-        HighlightTag::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
-        HighlightTag::Lifetime => semantic_tokens::LIFETIME,
         HighlightTag::ByteLiteral | HighlightTag::NumericLiteral => {
             lsp_types::SemanticTokenType::NUMBER
         }
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 4d272f367a..e753b11bb8 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -205,13 +205,6 @@ impl ast::Type {
     }
 }
 
-impl ast::Attr {
-    /// Returns `text`, parsed as an attribute, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_fragment(text, parser::FragmentKind::Attr)
-    }
-}
-
 /// Matches a `SyntaxNode` against an `ast` type.
 ///
 /// # Example:


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 58d69d3c6b..1a7b988318 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -1,5 +1,4 @@
 use base_db::fixture::WithFixture;
-use test_utils::mark;
 
 use crate::test_db::TestDB;
 
@@ -120,20 +119,3 @@ fn inactive_item() {
         "#,
     );
 }
-
-/// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
-#[test]
-fn inactive_via_cfg_attr() {
-    mark::check!(cfg_attr_active);
-    check_diagnostics(
-        r#"
-        //- /lib.rs
-          #[cfg_attr(not(never), cfg(no))] fn f() {}
-        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
-
-          #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
-
-          #[cfg_attr(never, cfg(no))] fn g() {}
-        "#,
-    );
-}