about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-07-16 10:36:59 +0200
committerLukas Wirth <lukastw97@gmail.com>2024-07-16 10:41:42 +0200
commit9ce066e6faa1bfcec7792a0fae4231a5bd7a5a56 (patch)
tree6cbe4f66336136e54853ddb88b7080ecf40d2d01
parent7f8a54bbee4fec4a6885c7554a2864a62bf40638 (diff)
downloadrust-9ce066e6faa1bfcec7792a0fae4231a5bd7a5a56.tar.gz
rust-9ce066e6faa1bfcec7792a0fae4231a5bd7a5a56.zip
Use symbol in cfg
-rw-r--r--src/tools/rust-analyzer/Cargo.lock4
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/cfg/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs39
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/dnf.rs19
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/tests.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs4
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol.rs8
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs29
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cfg.rs7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs21
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs3
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs4
22 files changed, 147 insertions, 92 deletions
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 241392edb1e..c9542ead790 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -146,10 +146,10 @@ dependencies = [
  "arbitrary",
  "derive_arbitrary",
  "expect-test",
+ "intern",
  "mbe",
  "oorandom",
  "rustc-hash",
- "smol_str",
  "syntax",
  "tt",
 ]
@@ -1416,6 +1416,7 @@ dependencies = [
  "cargo_metadata",
  "cfg",
  "expect-test",
+ "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "paths",
@@ -1656,6 +1657,7 @@ dependencies = [
  "ide",
  "ide-db",
  "ide-ssr",
+ "intern",
  "itertools",
  "load-cargo",
  "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index d4c3b7a3bfb..428d11ad60d 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -50,7 +50,7 @@ debug = 2
 [workspace.dependencies]
 # local crates
 base-db = { path = "./crates/base-db", version = "0.0.0" }
-cfg = { path = "./crates/cfg", version = "0.0.0" }
+cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] }
 flycheck = { path = "./crates/flycheck", version = "0.0.0" }
 hir = { path = "./crates/hir", version = "0.0.0" }
 hir-def = { path = "./crates/hir-def", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index 784e86649d1..faf93f62c6a 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -15,8 +15,8 @@ doctest = false
 rustc-hash.workspace = true
 
 # locals deps
-tt.workspace = true
-smol_str.workspace = true
+tt = { workspace = true, optional = true }
+intern.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.1"
diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
index 9c95f0e4e4b..e4c2a28fb06 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
@@ -2,20 +2,20 @@
 //!
 //! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation>
 
-use std::{fmt, slice::Iter as SliceIter};
+use std::fmt;
 
-use smol_str::SmolStr;
+use intern::Symbol;
 
 /// A simple configuration value passed in from the outside.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum CfgAtom {
     /// eg. `#[cfg(test)]`
-    Flag(SmolStr),
+    Flag(Symbol),
     /// eg. `#[cfg(target_os = "linux")]`
     ///
     /// Note that a key can have multiple values that are all considered "active" at the same time.
     /// For example, `#[cfg(target_feature = "sse")]` and `#[cfg(target_feature = "sse2")]`.
-    KeyValue { key: SmolStr, value: SmolStr },
+    KeyValue { key: Symbol, value: Symbol },
 }
 
 impl fmt::Display for CfgAtom {
@@ -44,6 +44,7 @@ impl From<CfgAtom> for CfgExpr {
 }
 
 impl CfgExpr {
+    #[cfg(feature = "tt")]
     pub fn parse<S>(tt: &tt::Subtree<S>) -> CfgExpr {
         next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
     }
@@ -63,7 +64,11 @@ impl CfgExpr {
         }
     }
 }
-fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr> {
+
+#[cfg(feature = "tt")]
+fn next_cfg_expr<S>(it: &mut std::slice::Iter<'_, tt::TokenTree<S>>) -> Option<CfgExpr> {
+    use intern::sym;
+
     let name = match it.next() {
         None => return None,
         Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.sym.clone(),
@@ -77,9 +82,7 @@ fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr>
                 Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => {
                     it.next();
                     it.next();
-                    // FIXME: escape?
-                    let value = literal.symbol.as_str().into();
-                    CfgAtom::KeyValue { key: name.as_str().into(), value }.into()
+                    CfgAtom::KeyValue { key: name, value: literal.symbol.clone() }.into()
                 }
                 _ => return Some(CfgExpr::Invalid),
             }
@@ -88,14 +91,16 @@ fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr>
             it.next();
             let mut sub_it = subtree.token_trees.iter();
             let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect();
-            match name.as_str() {
-                "all" => CfgExpr::All(subs),
-                "any" => CfgExpr::Any(subs),
-                "not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))),
+            match &name {
+                s if *s == sym::all => CfgExpr::All(subs),
+                s if *s == sym::any => CfgExpr::Any(subs),
+                s if *s == sym::not => {
+                    CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid)))
+                }
                 _ => CfgExpr::Invalid,
             }
         }
-        _ => CfgAtom::Flag(name.as_str().into()).into(),
+        _ => CfgAtom::Flag(name).into(),
     };
 
     // Eat comma separator
@@ -111,11 +116,11 @@ fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr>
 impl arbitrary::Arbitrary<'_> for CfgAtom {
     fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
         if u.arbitrary()? {
-            Ok(CfgAtom::Flag(String::arbitrary(u)?.into()))
+            Ok(CfgAtom::Flag(Symbol::intern(<_>::arbitrary(u)?)))
         } else {
             Ok(CfgAtom::KeyValue {
-                key: String::arbitrary(u)?.into(),
-                value: String::arbitrary(u)?.into(),
+                key: Symbol::intern(<_>::arbitrary(u)?),
+                value: Symbol::intern(<_>::arbitrary(u)?),
             })
         }
     }
diff --git a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
index fd80e1ebe68..58a250829d4 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
@@ -66,9 +66,9 @@ impl DnfExpr {
             }
         }
 
-        res.enabled.sort_unstable();
+        res.enabled.sort_unstable_by(compare);
         res.enabled.dedup();
-        res.disabled.sort_unstable();
+        res.disabled.sort_unstable_by(compare);
         res.disabled.dedup();
         Some(res)
     }
@@ -114,14 +114,25 @@ impl DnfExpr {
             };
 
             // Undo the FxHashMap randomization for consistent output.
-            diff.enable.sort_unstable();
-            diff.disable.sort_unstable();
+            diff.enable.sort_unstable_by(compare);
+            diff.disable.sort_unstable_by(compare);
 
             Some(diff)
         })
     }
 }
 
+fn compare(a: &CfgAtom, b: &CfgAtom) -> std::cmp::Ordering {
+    match (a, b) {
+        (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
+        (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less,
+        (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater,
+        (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => {
+            key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str()))
+        }
+    }
+}
+
 impl fmt::Display for DnfExpr {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.conjunctions.len() != 1 {
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index 5ef7a104dda..6d46dfb9994 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -9,9 +9,10 @@ use std::fmt;
 
 use rustc_hash::FxHashSet;
 
+use intern::Symbol;
+
 pub use cfg_expr::{CfgAtom, CfgExpr};
 pub use dnf::DnfExpr;
-use smol_str::SmolStr;
 
 /// Configuration options used for conditional compilation on items with `cfg` attributes.
 /// We have two kind of options in different namespaces: atomic options like `unix`, and
@@ -48,11 +49,11 @@ impl CfgOptions {
         cfg.fold(&|atom| self.enabled.contains(atom))
     }
 
-    pub fn insert_atom(&mut self, key: SmolStr) {
+    pub fn insert_atom(&mut self, key: Symbol) {
         self.enabled.insert(CfgAtom::Flag(key));
     }
 
-    pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) {
+    pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
         self.enabled.insert(CfgAtom::KeyValue { key, value });
     }
 
@@ -66,19 +67,16 @@ impl CfgOptions {
         }
     }
 
-    pub fn get_cfg_keys(&self) -> impl Iterator<Item = &SmolStr> {
+    pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
         self.enabled.iter().map(|it| match it {
             CfgAtom::Flag(key) => key,
             CfgAtom::KeyValue { key, .. } => key,
         })
     }
 
-    pub fn get_cfg_values<'a>(
-        &'a self,
-        cfg_key: &'a str,
-    ) -> impl Iterator<Item = &'a SmolStr> + 'a {
+    pub fn get_cfg_values<'a>(&'a self, cfg_key: &'a str) -> impl Iterator<Item = &'a Symbol> + 'a {
         self.enabled.iter().filter_map(move |it| match it {
-            CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
+            CfgAtom::KeyValue { key, value } if cfg_key == key.as_str() => Some(value),
             _ => None,
         })
     }
diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
index dddaf2cce18..278e5f61de2 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
@@ -1,5 +1,6 @@
 use arbitrary::{Arbitrary, Unstructured};
 use expect_test::{expect, Expect};
+use intern::Symbol;
 use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
 use syntax::{ast, AstNode, Edition};
 
@@ -65,22 +66,25 @@ fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) {
 
 #[test]
 fn test_cfg_expr_parser() {
-    assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into());
-    assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into());
+    assert_parse_result("#![cfg(foo)]", CfgAtom::Flag(Symbol::intern("foo")).into());
+    assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag(Symbol::intern("foo")).into());
     assert_parse_result(
         "#![cfg(not(foo))]",
-        CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())),
+        CfgExpr::Not(Box::new(CfgAtom::Flag(Symbol::intern("foo")).into())),
     );
     assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid);
 
     // Only take the first
-    assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into());
+    assert_parse_result(
+        r#"#![cfg(foo, bar = "baz")]"#,
+        CfgAtom::Flag(Symbol::intern("foo")).into(),
+    );
 
     assert_parse_result(
         r#"#![cfg(all(foo, bar = "baz"))]"#,
         CfgExpr::All(vec![
-            CfgAtom::Flag("foo".into()).into(),
-            CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(),
+            CfgAtom::Flag(Symbol::intern("foo")).into(),
+            CfgAtom::KeyValue { key: Symbol::intern("bar"), value: Symbol::intern("baz") }.into(),
         ]),
     );
 
@@ -90,7 +94,7 @@ fn test_cfg_expr_parser() {
             CfgExpr::Not(Box::new(CfgExpr::Invalid)),
             CfgExpr::All(vec![]),
             CfgExpr::Invalid,
-            CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(),
+            CfgAtom::KeyValue { key: Symbol::intern("bar"), value: Symbol::intern("baz") }.into(),
         ]),
     );
 }
@@ -167,7 +171,7 @@ fn hints() {
 
     check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]);
 
-    opts.insert_atom("test".into());
+    opts.insert_atom(Symbol::intern("test"));
 
     check_enable_hints("#![cfg(test)]", &opts, &[]);
     check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]);
@@ -180,7 +184,7 @@ fn hints_impossible() {
 
     check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]);
 
-    opts.insert_atom("test".into());
+    opts.insert_atom(Symbol::intern("test"));
 
     check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]);
 }
@@ -188,8 +192,8 @@ fn hints_impossible() {
 #[test]
 fn why_inactive() {
     let mut opts = CfgOptions::default();
-    opts.insert_atom("test".into());
-    opts.insert_atom("test2".into());
+    opts.insert_atom(Symbol::intern("test"));
+    opts.insert_atom(Symbol::intern("test2"));
 
     check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]);
     check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]);
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 4b1a3d69728..e3290f53432 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -563,7 +563,12 @@ fn concat_bytes_expand(
     };
     for (i, t) in tt.token_trees.iter().enumerate() {
         match t {
-            tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, kind, suffix: _ })) => {
+            tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+                symbol: text,
+                span,
+                kind,
+                suffix: _,
+            })) => {
                 record_span(*span);
                 match kind {
                     tt::LitKind::Byte => {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
index 5f038cfe687..9f927184193 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs
@@ -3,6 +3,7 @@ use std::iter::Peekable;
 
 use base_db::CrateId;
 use cfg::{CfgAtom, CfgExpr};
+use intern::{sym, Symbol};
 use rustc_hash::FxHashSet;
 use syntax::{
     ast::{self, Attr, HasAttrs, Meta, VariantList},
@@ -262,13 +263,13 @@ where
     let name = match iter.next() {
         None => return None,
         Some(NodeOrToken::Token(element)) => match element.kind() {
-            syntax::T![ident] => element.text().to_owned(),
+            syntax::T![ident] => Symbol::intern(element.text()),
             _ => return Some(CfgExpr::Invalid),
         },
         Some(_) => return Some(CfgExpr::Invalid),
     };
-    let result = match name.as_str() {
-        "all" | "any" | "not" => {
+    let result = match &name {
+        s if [&sym::all, &sym::any, &sym::not].contains(&s) => {
             let mut preds = Vec::new();
             let Some(NodeOrToken::Node(tree)) = iter.next() else {
                 return Some(CfgExpr::Invalid);
@@ -285,10 +286,12 @@ where
                     preds.push(pred);
                 }
             }
-            let group = match name.as_str() {
-                "all" => CfgExpr::All(preds),
-                "any" => CfgExpr::Any(preds),
-                "not" => CfgExpr::Not(Box::new(preds.pop().unwrap_or(CfgExpr::Invalid))),
+            let group = match &name {
+                s if *s == sym::all => CfgExpr::All(preds),
+                s if *s == sym::any => CfgExpr::Any(preds),
+                s if *s == sym::not => {
+                    CfgExpr::Not(Box::new(preds.pop().unwrap_or(CfgExpr::Invalid)))
+                }
                 _ => unreachable!(),
             };
             Some(group)
@@ -301,13 +304,15 @@ where
                         if (value_token.kind() == syntax::SyntaxKind::STRING) =>
                     {
                         let value = value_token.text();
-                        let value = value.trim_matches('"').into();
-                        Some(CfgExpr::Atom(CfgAtom::KeyValue { key: name.into(), value }))
+                        Some(CfgExpr::Atom(CfgAtom::KeyValue {
+                            key: name,
+                            value: Symbol::intern(value.trim_matches('"')),
+                        }))
                     }
                     _ => None,
                 }
             }
-            _ => Some(CfgExpr::Atom(CfgAtom::Flag(name.into()))),
+            _ => Some(CfgExpr::Atom(CfgAtom::Flag(name))),
         },
     };
     if let Some(NodeOrToken::Token(element)) = iter.peek() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
index 87a286778e6..6e7d50ede06 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -39,6 +39,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
             "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion),
             "target_endian" => ["little", "big"].into_iter().for_each(add_completion),
             name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
+                let s = s.as_str();
                 let insert_text = format!(r#""{s}""#);
                 let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
                 item.insert_text(insert_text);
@@ -47,6 +48,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
             }),
         },
         None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
+            let s = s.as_str();
             let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
             acc.add(item.build(ctx.db));
         }),
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index f0b35903f38..a7073f7062e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@ use std::panic::UnwindSafe;
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::ChangeWithProcMacros;
+use hir::{sym, ChangeWithProcMacros};
 use ide_db::{
     base_db::{
         salsa::{self, ParallelDatabase},
@@ -248,7 +248,7 @@ impl Analysis {
         // FIXME: cfg options
         // Default to enable test for single file.
         let mut cfg_options = CfgOptions::default();
-        cfg_options.insert_atom("test".into());
+        cfg_options.insert_atom(sym::test.clone());
         crate_graph.add_crate_root(
             file_id,
             Edition::CURRENT,
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index a68ee4f8671..362d3238a9a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
 use hir::{
-    db::HirDatabase, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics,
+    db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
@@ -403,7 +403,7 @@ pub(crate) fn runnable_impl(
 }
 
 fn has_cfg_test(attrs: AttrsWithOwner) -> bool {
-    attrs.cfgs().any(|cfg| matches!(cfg, CfgExpr::Atom(CfgAtom::Flag(s)) if s == "test"))
+    attrs.cfgs().any(|cfg| matches!(&cfg, CfgExpr::Atom(CfgAtom::Flag(s)) if *s == sym::test))
 }
 
 /// Creates a test mod runnable for outline modules at the top of their definition.
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
index 9e3f6d842f3..ef76192ba83 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -139,11 +139,17 @@ impl TaggedArcPtr {
     }
 }
 
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash)]
 pub struct Symbol {
     repr: TaggedArcPtr,
 }
 
+impl fmt::Debug for Symbol {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
+
 const _: () = assert!(std::mem::size_of::<Symbol>() == std::mem::size_of::<NonNull<()>>());
 const _: () = assert!(std::mem::align_of::<Symbol>() == std::mem::align_of::<NonNull<()>>());
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 61b9d099e06..04c70e4fae1 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -93,20 +93,20 @@ define_symbols! {
     __ra_fixup,
     add_assign,
     add,
-    attributes,
     align_offset,
+    align,
+    all,
     alloc_layout,
     alloc,
+    any,
     as_str,
     asm,
     assert,
+    attributes,
     begin_panic,
     bench,
     bitand_assign,
     bitand,
-    notable_trait,
-    hidden,
-    local_inner_macros,
     bitor_assign,
     bitor,
     bitxor_assign,
@@ -118,6 +118,7 @@ define_symbols! {
     branch,
     Break,
     c_void,
+    C,
     call_mut,
     call_once,
     call,
@@ -146,8 +147,10 @@ define_symbols! {
     core,
     coroutine_state,
     coroutine,
+    count,
     crate_type,
     CStr,
+    debug_assertions,
     Debug,
     default,
     Default,
@@ -172,6 +175,7 @@ define_symbols! {
     Eq,
     Err,
     exchange_malloc,
+    exhaustive_patterns,
     f128,
     f16,
     f32,
@@ -208,11 +212,13 @@ define_symbols! {
     global_asm,
     gt,
     Hash,
+    hidden,
     i128,
     i16,
     i32,
     i64,
     i8,
+    ignore,
     Implied,
     include_bytes,
     include_str,
@@ -237,14 +243,15 @@ define_symbols! {
     len,
     line,
     llvm_asm,
+    local_inner_macros,
     log_syntax,
     lt,
     macro_rules,
-    ignore,
-    count,
     manually_drop,
     maybe_uninit,
     metadata_type,
+    min_exhaustive_patterns,
+    miri,
     missing,
     module_path,
     mul_assign,
@@ -271,6 +278,7 @@ define_symbols! {
     None,
     not,
     Not,
+    notable_trait,
     Ok,
     opaque,
     ops,
@@ -280,6 +288,7 @@ define_symbols! {
     Ord,
     Output,
     owned_box,
+    packed,
     panic_2015,
     panic_2021,
     panic_bounds_check,
@@ -328,6 +337,7 @@ define_symbols! {
     rust_2018,
     rust_2021,
     rust_2024,
+    rust_analyzer,
     rustc_coherence_is_core,
     rustc_macro_transparency,
     semitransparent,
@@ -335,6 +345,7 @@ define_symbols! {
     shl,
     shr_assign,
     shr,
+    simd,
     sized,
     slice_len_fn,
     Some,
@@ -367,10 +378,6 @@ define_symbols! {
     u8,
     Unknown,
     unpin,
-    simd,
-    C,
-    align,
-    packed,
     unreachable_2015,
     unreachable_2021,
     unreachable,
@@ -378,7 +385,5 @@ define_symbols! {
     unsize,
     usize,
     v1,
-    exhaustive_patterns,
-    min_exhaustive_patterns,
     va_list
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 097ee1f75cd..8b34bd3fad1 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -25,6 +25,7 @@ itertools.workspace = true
 
 # local deps
 base-db.workspace = true
+intern.workspace = true
 span.workspace = true
 cfg.workspace = true
 paths = { workspace = true, features = ["serde1"] }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/cfg.rs
index b409bc1ce7a..e921e3de722 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cfg.rs
@@ -4,6 +4,7 @@
 use std::{fmt, str::FromStr};
 
 use cfg::{CfgDiff, CfgOptions};
+use intern::Symbol;
 use rustc_hash::FxHashMap;
 use serde::Serialize;
 
@@ -44,8 +45,10 @@ impl Extend<CfgFlag> for CfgOptions {
     fn extend<T: IntoIterator<Item = CfgFlag>>(&mut self, iter: T) {
         for cfg_flag in iter {
             match cfg_flag {
-                CfgFlag::Atom(it) => self.insert_atom(it.into()),
-                CfgFlag::KeyValue { key, value } => self.insert_key_value(key.into(), value.into()),
+                CfgFlag::Atom(it) => self.insert_atom(Symbol::intern(&it)),
+                CfgFlag::KeyValue { key, value } => {
+                    self.insert_key_value(Symbol::intern(&key), Symbol::intern(&value))
+                }
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 2762de5997a..8d50d4bdfe2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -4,6 +4,7 @@ use base_db::{CrateGraph, FileId, ProcMacroPaths};
 use cargo_metadata::Metadata;
 use cfg::{CfgAtom, CfgDiff};
 use expect_test::{expect_file, ExpectFile};
+use intern::sym;
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::de::DeserializeOwned;
@@ -180,7 +181,7 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) {
 #[test]
 fn cargo_hello_world_project_model_with_wildcard_overrides() {
     let cfg_overrides = CfgOverrides {
-        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
+        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
         selective: Default::default(),
     };
     let (crate_graph, _proc_macros) =
@@ -199,7 +200,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
         global: Default::default(),
         selective: std::iter::once((
             "libc".to_owned(),
-            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
+            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
         ))
         .collect(),
     };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 5e27ce29873..e006b70362e 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -10,6 +10,7 @@ use base_db::{
     LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
+use intern::{sym, Symbol};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
@@ -977,8 +978,8 @@ fn cargo_to_crate_graph(
 
             if cargo[pkg].is_local {
                 // Add test cfg for local crates
-                cfg_options.insert_atom("test".into());
-                cfg_options.insert_atom("rust_analyzer".into());
+                cfg_options.insert_atom(sym::test.clone());
+                cfg_options.insert_atom(sym::rust_analyzer.clone());
             }
 
             override_cfg.apply(&mut cfg_options, &cargo[pkg].name);
@@ -1144,8 +1145,8 @@ fn detached_file_to_crate_graph(
         sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
 
     let mut cfg_options = CfgOptions::from_iter(rustc_cfg);
-    cfg_options.insert_atom("test".into());
-    cfg_options.insert_atom("rust_analyzer".into());
+    cfg_options.insert_atom(sym::test.clone());
+    cfg_options.insert_atom(sym::rust_analyzer.clone());
     override_cfg.apply(&mut cfg_options, "");
     let cfg_options = Arc::new(cfg_options);
 
@@ -1307,7 +1308,7 @@ fn add_target_crate_root(
     let cfg_options = {
         let mut opts = cfg_options;
         for feature in pkg.active_features.iter() {
-            opts.insert_key_value("feature".into(), feature.into());
+            opts.insert_key_value(sym::feature.clone(), Symbol::intern(feature));
         }
         if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
             opts.extend(cfgs.iter().cloned());
@@ -1381,8 +1382,8 @@ fn sysroot_to_crate_graph(
                 &CfgOverrides {
                     global: CfgDiff::new(
                         vec![
-                            CfgAtom::Flag("debug_assertions".into()),
-                            CfgAtom::Flag("miri".into()),
+                            CfgAtom::Flag(sym::debug_assertions.clone()),
+                            CfgAtom::Flag(sym::miri.clone()),
                         ],
                         vec![],
                     )
@@ -1394,7 +1395,7 @@ fn sysroot_to_crate_graph(
 
             let mut pub_deps = vec![];
             let mut libproc_macro = None;
-            let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap();
+            let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]).unwrap();
             for (cid, c) in cg.iter_mut() {
                 // uninject `test` flag so `core` keeps working.
                 Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
@@ -1449,8 +1450,8 @@ fn sysroot_to_crate_graph(
             let cfg_options = Arc::new({
                 let mut cfg_options = CfgOptions::default();
                 cfg_options.extend(rustc_cfg);
-                cfg_options.insert_atom("debug_assertions".into());
-                cfg_options.insert_atom("miri".into());
+                cfg_options.insert_atom(sym::debug_assertions.clone());
+                cfg_options.insert_atom(sym::miri.clone());
                 cfg_options
             });
             let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = stitched
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 93fb55ede8e..bc1b13a6497 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -54,6 +54,7 @@ hir-def.workspace = true
 hir-ty.workspace = true
 hir.workspace = true
 ide-db.workspace = true
+intern.workspace = true
 # This should only be used in CLI
 ide-ssr.workspace = true
 ide.workspace = true
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 91cde4dc0ad..a0ec3920e6e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -8,6 +8,7 @@ use std::{fmt, iter, ops::Not, sync::OnceLock};
 use cfg::{CfgAtom, CfgDiff};
 use dirs::config_dir;
 use flycheck::{CargoOptions, FlycheckConfig};
+use hir::Symbol;
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
     GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
@@ -1691,8 +1692,11 @@ impl Config {
                     self.cargo_cfgs()
                         .iter()
                         .map(|(key, val)| match val {
-                            Some(val) => CfgAtom::KeyValue { key: key.into(), value: val.into() },
-                            None => CfgAtom::Flag(key.into()),
+                            Some(val) => CfgAtom::KeyValue {
+                                key: Symbol::intern(key),
+                                value: Symbol::intern(val),
+                            },
+                            None => CfgAtom::Flag(Symbol::intern(key)),
                         })
                         .collect(),
                     vec![],
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 863ff064399..045b9e4198a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -3,6 +3,7 @@
 use std::mem;
 
 use cfg::{CfgAtom, CfgExpr};
+use hir::sym;
 use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId};
 use project_model::project_json::Runnable;
 use project_model::{CargoFeatures, ManifestPath, TargetKind};
@@ -237,7 +238,7 @@ impl CargoTargetSpec {
 /// Fill minimal features needed
 fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) {
     match cfg_expr {
-        CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if key == "feature" => {
+        CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if *key == sym::feature => {
             features.push(value.to_string())
         }
         CfgExpr::All(preds) => {
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 7a0c474b750..e910094c772 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -481,9 +481,9 @@ impl FileMeta {
         let mut cfg = CfgOptions::default();
         for (k, v) in f.cfgs {
             if let Some(v) = v {
-                cfg.insert_key_value(k.into(), v.into());
+                cfg.insert_key_value(Symbol::intern(&k), Symbol::intern(&v));
             } else {
-                cfg.insert_atom(k.into());
+                cfg.insert_atom(Symbol::intern(&k));
             }
         }