Repository: rust-analyzer/rust-analyzer
Pull request #8776 (2021-05-08 23:43:07)

fix: fix unnecessary recomputations due to macros
This computes a macro's fragment kind eagerly (when the calling file is still available in parsed form) and stores it in the `MacroCallLoc`. This means that during expansion we no longer have to reparse the file containing the macro call, avoiding the unnecessary salsa dependencies (https://github.com/rust-analyzer/rust-analyzer/pull/8746#issuecomment-834776349).

Marking as draft until I manage to find a test for this problem, since for some reason `typing_inside_a_function_should_not_invalidate_expansions` does not catch this (which might indicate that I misunderstand the problem).

I've manually confirmed that this fixes the issue described in https://github.com/rust-analyzer/rust-analyzer/pull/8746#issuecomment-834776349:

```
    7ms - parse_query @ FileId(179)
   12ms - SourceBinder::to_module_def
       12ms - crate_def_map:wait
            5ms - item_tree_query (1 calls)
            7ms - ???
```


Patch:
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 8d13c7e047..cad8a7479a 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -18,7 +18,7 @@ use hir_expand::{
     ast_id_map::FileAstId,
     hygiene::Hygiene,
     name::{name, AsName, Name},
-    HirFileId, InFile,
+    FragmentKind, HirFileId, InFile,
 };
 use la_arena::{Arena, Idx, RawIdx};
 use profile::Count;
@@ -656,6 +656,7 @@ pub struct MacroCall {
     /// Path to the called macro.
     pub path: Interned<ModPath>,
     pub ast_id: FileAstId<ast::MacroCall>,
+    pub fragment: FragmentKind,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 5743b33862..fe348091d0 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -624,7 +624,8 @@ impl<'a> Ctx<'a> {
     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
         let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?);
         let ast_id = self.source_ast_id_map.ast_id(m);
-        let res = MacroCall { path, ast_id };
+        let fragment = hir_expand::to_fragment_kind(m);
+        let res = MacroCall { path, ast_id, fragment };
         Some(id(self.data().macro_calls.alloc(res)))
     }
 
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index da46f16f7a..e96ca953ff 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -62,7 +62,8 @@ use hir_expand::{
     ast_id_map::FileAstId,
     eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
     hygiene::Hygiene,
-    AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
+    AstId, AttrId, FragmentKind, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
+    MacroDefKind,
 };
 use la_arena::Idx;
 use nameres::DefMap;
@@ -652,6 +653,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
         mut error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
+        let fragment = hir_expand::to_fragment_kind(self.value);
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let h = Hygiene::new(db.upcast(), self.file_id);
         let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
@@ -667,6 +669,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 
         macro_call_as_call_id(
             &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
+            fragment,
             db,
             krate,
             resolver,
@@ -695,6 +698,7 @@ pub struct UnresolvedMacro {
 
 fn macro_call_as_call_id(
     call: &AstIdWithPath<ast::MacroCall>,
+    fragment: FragmentKind,
     db: &dyn db::DefDatabase,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
@@ -718,7 +722,11 @@ fn macro_call_as_call_id(
         .map(MacroCallId::from)
     } else {
         Ok(def
-            .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id })
+            .as_lazy_macro(
+                db.upcast(),
+                krate,
+                MacroCallKind::FnLike { ast_id: call.ast_id, fragment },
+            )
             .into())
     };
     Ok(res)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 1bc72ec1f0..249af6fc80 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -629,7 +629,7 @@ mod diagnostics {
                 DiagnosticKind::UnresolvedProcMacro { ast } => {
                     let mut precise_location = None;
                     let (file, ast, name) = match ast {
-                        MacroCallKind::FnLike { ast_id } => {
+                        MacroCallKind::FnLike { ast_id, .. } => {
                             let node = ast_id.to_node(db.upcast());
                             (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
                         }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 05ceb1efb6..e89136ed1d 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
     builtin_macro::find_builtin_macro,
     name::{AsName, Name},
     proc_macro::ProcMacroExpander,
-    AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
+    AttrId, FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
 use hir_expand::{InFile, MacroCallLoc};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -215,7 +215,7 @@ struct MacroDirective {
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 enum MacroDirectiveKind {
-    FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
+    FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind },
     Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
 }
 
@@ -807,9 +807,10 @@ impl DefCollector<'_> {
         let mut res = ReachedFixedPoint::Yes;
         macros.retain(|directive| {
             match &directive.kind {
-                MacroDirectiveKind::FnLike { ast_id } => {
+                MacroDirectiveKind::FnLike { ast_id, fragment } => {
                     match macro_call_as_call_id(
                         ast_id,
+                        *fragment,
                         self.db,
                         self.def_map.krate,
                         |path| {
@@ -926,8 +927,9 @@ impl DefCollector<'_> {
 
         for directive in &self.unexpanded_macros {
             match &directive.kind {
-                MacroDirectiveKind::FnLike { ast_id, .. } => match macro_call_as_call_id(
+                MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id(
                     ast_id,
+                    *fragment,
                     self.db,
                     self.def_map.krate,
                     |path| {
@@ -1496,6 +1498,7 @@ impl ModCollector<'_, '_> {
         let mut error = None;
         match macro_call_as_call_id(
             &ast_id,
+            mac.fragment,
             self.def_collector.db,
             self.def_collector.def_map.krate,
             |path| {
@@ -1524,9 +1527,14 @@ impl ModCollector<'_, '_> {
             }
             Ok(Err(_)) => {
                 // Built-in macro failed eager expansion.
+
+                // FIXME: don't parse the file here
+                let fragment = hir_expand::to_fragment_kind(
+                    &ast_id.ast_id.to_node(self.def_collector.db.upcast()),
+                );
                 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
                     self.module_id,
-                    MacroCallKind::FnLike { ast_id: ast_id.ast_id },
+                    MacroCallKind::FnLike { ast_id: ast_id.ast_id, fragment },
                     error.unwrap().to_string(),
                 ));
                 return;
@@ -1543,7 +1551,7 @@ impl ModCollector<'_, '_> {
         self.def_collector.unexpanded_macros.push(MacroDirective {
             module_id: self.module_id,
             depth: self.macro_depth + 1,
-            kind: MacroDirectiveKind::FnLike { ast_id },
+            kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment },
         });
     }
 
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 0142a06ed8..0dd725ec31 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -578,6 +578,7 @@ mod tests {
                     krate,
                     kind: MacroCallKind::FnLike {
                         ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
+                        fragment: FragmentKind::Expr,
                     },
                 };
 
@@ -788,9 +789,9 @@ mod tests {
             r##"
             #[rustc_builtin_macro]
             macro_rules! concat {}
-            concat!("foo", "r", 0, r#"bar"#, "\n", false);
+            concat!("foo", "r", 0, r#"bar"#, false);
             "##,
-            expect![[r#""foor0bar\nfalse""#]],
+            expect![[r#""foor0barfalse""#]],
         );
     }
 }
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index d61f4b31a4..6647e57e7d 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -8,9 +8,7 @@ use parser::FragmentKind;
 use syntax::{
     algo::diff,
     ast::{self, NameOwner},
-    AstNode, GreenNode, Parse,
-    SyntaxKind::*,
-    SyntaxNode, SyntaxToken,
+    AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken,
 };
 
 use crate::{
@@ -160,7 +158,7 @@ pub fn expand_hypothetical(
 
     let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt);
 
-    let fragment_kind = to_fragment_kind(db, actual_macro_call);
+    let fragment_kind = macro_fragment_kind(db, actual_macro_call);
 
     let (node, tmap_2) =
         mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?;
@@ -226,7 +224,7 @@ fn parse_macro_expansion(
         None => return ExpandResult { value: None, err: result.err },
     };
 
-    let fragment_kind = to_fragment_kind(db, macro_file.macro_call_id);
+    let fragment_kind = macro_fragment_kind(db, macro_file.macro_call_id);
 
     log::debug!("expanded = {}", tt.as_debug_string());
     log::debug!("kind = {:?}", fragment_kind);
@@ -427,62 +425,15 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame>
     Arc::new(HygieneFrame::new(db, file_id))
 }
 
-/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
-/// FIXME: Not completed
-fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
-    let lazy_id = match id {
-        MacroCallId::LazyMacro(id) => id,
-        MacroCallId::EagerMacro(id) => {
-            return db.lookup_intern_eager_expansion(id).fragment;
-        }
-    };
-    let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value;
-
-    let parent = match syn.parent() {
-        Some(it) => it,
-        None => return FragmentKind::Statements,
-    };
-
-    match parent.kind() {
-        MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
-        MACRO_STMTS => FragmentKind::Statements,
-        MACRO_PAT => FragmentKind::Pattern,
-        MACRO_TYPE => FragmentKind::Type,
-        ITEM_LIST => FragmentKind::Items,
-        LET_STMT => {
-            // FIXME: Handle LHS Pattern
-            FragmentKind::Expr
+fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
+    match id {
+        MacroCallId::LazyMacro(id) => {
+            let loc: MacroCallLoc = db.lookup_intern_macro(id);
+            loc.kind.fragment_kind()
         }
-        EXPR_STMT => FragmentKind::Statements,
-        BLOCK_EXPR => FragmentKind::Statements,
-        ARG_LIST => FragmentKind::Expr,
-        TRY_EXPR => FragmentKind::Expr,
-        TUPLE_EXPR => FragmentKind::Expr,
-        PAREN_EXPR => FragmentKind::Expr,
-        ARRAY_EXPR => FragmentKind::Expr,
-        FOR_EXPR => FragmentKind::Expr,
-        PATH_EXPR => FragmentKind::Expr,
-        CLOSURE_EXPR => FragmentKind::Expr,
-        CONDITION => FragmentKind::Expr,
-        BREAK_EXPR => FragmentKind::Expr,
-        RETURN_EXPR => FragmentKind::Expr,
-        MATCH_EXPR => FragmentKind::Expr,
-        MATCH_ARM => FragmentKind::Expr,
-        MATCH_GUARD => FragmentKind::Expr,
-        RECORD_EXPR_FIELD => FragmentKind::Expr,
-        CALL_EXPR => FragmentKind::Expr,
-        INDEX_EXPR => FragmentKind::Expr,
-        METHOD_CALL_EXPR => FragmentKind::Expr,
-        FIELD_EXPR => FragmentKind::Expr,
-        AWAIT_EXPR => FragmentKind::Expr,
-        CAST_EXPR => FragmentKind::Expr,
-        REF_EXPR => FragmentKind::Expr,
-        PREFIX_EXPR => FragmentKind::Expr,
-        RANGE_EXPR => FragmentKind::Expr,
-        BIN_EXPR => FragmentKind::Expr,
-        _ => {
-            // Unknown , Just guess it is `Items`
-            FragmentKind::Items
+        MacroCallId::EagerMacro(id) => {
+            let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id);
+            loc.fragment
         }
     }
 }
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index f12132f84b..85491fe8be 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -175,8 +175,13 @@ fn lazy_expand(
 ) -> ExpandResult<Option<InFile<SyntaxNode>>> {
     let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
 
+    let fragment = crate::to_fragment_kind(&macro_call.value);
     let id: MacroCallId = def
-        .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) })
+        .as_lazy_macro(
+            db,
+            krate,
+            MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment },
+        )
         .into();
 
     let err = db.macro_expand_error(id);
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 0402640de3..80ab3aeee7 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -16,7 +16,9 @@ pub mod quote;
 pub mod eager;
 
 use either::Either;
+
 pub use mbe::{ExpandError, ExpandResult};
+pub use parser::FragmentKind;
 
 use std::hash::Hash;
 use std::sync::Arc;
@@ -290,7 +292,7 @@ pub struct MacroCallLoc {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum MacroCallKind {
-    FnLike { ast_id: AstId<ast::MacroCall> },
+    FnLike { ast_id: AstId<ast::MacroCall>, fragment: FragmentKind },
     Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId },
 }
 
@@ -324,6 +326,13 @@ impl MacroCallKind {
             MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
         }
     }
+
+    fn fragment_kind(&self) -> FragmentKind {
+        match self {
+            MacroCallKind::FnLike { fragment, .. } => *fragment,
+            MacroCallKind::Derive { .. } => FragmentKind::Items,
+        }
+    }
 }
 
 impl MacroCallId {
@@ -357,7 +366,6 @@ pub struct ExpansionInfo {
 }
 
 pub use mbe::Origin;
-use parser::FragmentKind;
 
 impl ExpansionInfo {
     pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
@@ -562,3 +570,59 @@ impl<N: AstNode> InFile<N> {
         self.with_value(self.value.syntax())
     }
 }
+
+/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
+/// FIXME: Not completed
+pub fn to_fragment_kind(call: &ast::MacroCall) -> FragmentKind {
+    use syntax::SyntaxKind::*;
+
+    let syn = call.syntax();
+
+    let parent = match syn.parent() {
+        Some(it) => it,
+        None => return FragmentKind::Statements,
+    };
+
+    match parent.kind() {
+        MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
+        MACRO_STMTS => FragmentKind::Statements,
+        MACRO_PAT => FragmentKind::Pattern,
+        MACRO_TYPE => FragmentKind::Type,
+        ITEM_LIST => FragmentKind::Items,
+        LET_STMT => {
+            // FIXME: Handle LHS Pattern
+            FragmentKind::Expr
+        }
+        EXPR_STMT => FragmentKind::Statements,
+        BLOCK_EXPR => FragmentKind::Statements,
+        ARG_LIST => FragmentKind::Expr,
+        TRY_EXPR => FragmentKind::Expr,
+        TUPLE_EXPR => FragmentKind::Expr,
+        PAREN_EXPR => FragmentKind::Expr,
+        ARRAY_EXPR => FragmentKind::Expr,
+        FOR_EXPR => FragmentKind::Expr,
+        PATH_EXPR => FragmentKind::Expr,
+        CLOSURE_EXPR => FragmentKind::Expr,
+        CONDITION => FragmentKind::Expr,
+        BREAK_EXPR => FragmentKind::Expr,
+        RETURN_EXPR => FragmentKind::Expr,
+        MATCH_EXPR => FragmentKind::Expr,
+        MATCH_ARM => FragmentKind::Expr,
+        MATCH_GUARD => FragmentKind::Expr,
+        RECORD_EXPR_FIELD => FragmentKind::Expr,
+        CALL_EXPR => FragmentKind::Expr,
+        INDEX_EXPR => FragmentKind::Expr,
+        METHOD_CALL_EXPR => FragmentKind::Expr,
+        FIELD_EXPR => FragmentKind::Expr,
+        AWAIT_EXPR => FragmentKind::Expr,
+        CAST_EXPR => FragmentKind::Expr,
+        REF_EXPR => FragmentKind::Expr,
+        PREFIX_EXPR => FragmentKind::Expr,
+        RANGE_EXPR => FragmentKind::Expr,
+        BIN_EXPR => FragmentKind::Expr,
+        _ => {
+            // Unknown , Just guess it is `Items`
+            FragmentKind::Items
+        }
+    }
+}
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs
index 230a599641..c82487ef04 100644
--- a/crates/hir_expand/src/quote.rs
+++ b/crates/hir_expand/src/quote.rs
@@ -196,8 +196,8 @@ impl_to_to_tokentrees! {
     tt::Literal => self { self };
     tt::Ident => self { self };
     tt::Punct => self { self };
-    &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}};
-    String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}
+    &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}};
+    String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}
 }
 
 #[cfg(test)]
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 482b23cf5e..fe2a349e63 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -65,15 +65,11 @@ fn remove_newlines(edit: &mut TextEditBuilder, token: &SyntaxToken, range: TextR
 
 fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) {
     if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 {
-        let mut no_space = false;
+        let mut string_open_quote = false;
         if let Some(string) = ast::String::cast(token.clone()) {
             if let Some(range) = string.open_quote_text_range() {
-                cov_mark::hit!(join_string_literal_open_quote);
-                no_space |= range.end() == offset;
-            }
-            if let Some(range) = string.close_quote_text_range() {
-                cov_mark::hit!(join_string_literal_close_quote);
-                no_space |= range.start() == offset + TextSize::of('\n');
+                cov_mark::hit!(join_string_literal);
+                string_open_quote = range.end() == offset;
             }
         }
 
@@ -86,7 +82,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
         };
 
         let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into());
-        let replace_with = if no_space { "" } else { " " };
+        let replace_with = if string_open_quote { "" } else { " " };
         edit.replace(range, replace_with.to_string());
         return;
     }
@@ -801,41 +797,22 @@ fn foo() {
 
     #[test]
     fn join_string_literal() {
-        {
-            cov_mark::check!(join_string_literal_open_quote);
-            check_join_lines(
-                r#"
+        cov_mark::check!(join_string_literal);
+        check_join_lines(
+            r#"
 fn main() {
     $0"
 hello
 ";
 }
 "#,
-                r#"
-fn main() {
-    $0"hello
-";
-}
-"#,
-            );
-        }
-
-        {
-            cov_mark::check!(join_string_literal_close_quote);
-            check_join_lines(
-                r#"
+            r#"
 fn main() {
     $0"hello
 ";
 }
 "#,
-                r#"
-fn main() {
-    $0"hello";
-}
-"#,
-            );
-        }
+        );
 
         check_join_lines(
             r#"
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index b18699b771..bc6e203414 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -201,12 +201,31 @@ impl CargoWorkspace {
         if let Some(parent) = cargo_toml.parent() {
             meta.current_dir(parent.to_path_buf());
         }
-        let target = if let Some(target) = &config.target {
+        let target = if let Some(target) = config.target.as_ref() {
             Some(target.clone())
-        } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
-            stdout
         } else {
-            rustc_discover_host_triple(cargo_toml)
+            // cargo metadata defaults to giving information for _all_ targets.
+            // In the absence of a preference from the user, we use the host platform.
+            let mut rustc = Command::new(toolchain::rustc());
+            rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
+            log::debug!("Discovering host platform by {:?}", rustc);
+            match utf8_stdout(rustc) {
+                Ok(stdout) => {
+                    let field = "host: ";
+                    let target = stdout.lines().find_map(|l| l.strip_prefix(field));
+                    if let Some(target) = target {
+                        Some(target.to_string())
+                    } else {
+                        // If we fail to resolve the host platform, it's not the end of the world.
+                        log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
+                        None
+                    }
+                }
+                Err(e) => {
+                    log::warn!("Failed to discover host platform: {}", e);
+                    None
+                }
+            }
         };
         if let Some(target) = target {
             meta.other_options(vec![String::from("--filter-platform"), target]);
@@ -349,43 +368,3 @@ impl CargoWorkspace {
         self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
     }
 }
-
-fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
-    let mut rustc = Command::new(toolchain::rustc());
-    rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
-    log::debug!("Discovering host platform by {:?}", rustc);
-    match utf8_stdout(rustc) {
-        Ok(stdout) => {
-            let field = "host: ";
-            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
-            if let Some(target) = target {
-                Some(target.to_string())
-            } else {
-                // If we fail to resolve the host platform, it's not the end of the world.
-                log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
-                None
-            }
-        }
-        Err(e) => {
-            log::warn!("Failed to discover host platform: {}", e);
-            None
-        }
-    }
-}
-
-fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
-    let mut cargo_config = Command::new(toolchain::cargo());
-    cargo_config
-        .current_dir(cargo_toml.parent().unwrap())
-        .args(&["-Z", "unstable-options", "config", "get", "build.target"])
-        .env("RUSTC_BOOTSTRAP", "1");
-    // if successful we receive `build.target = "target-triple"`
-    log::debug!("Discovering cargo config target by {:?}", cargo_config);
-    match utf8_stdout(cargo_config) {
-        Ok(stdout) => stdout
-            .strip_prefix("build.target = \"")
-            .and_then(|stdout| stdout.strip_suffix('"'))
-            .map(ToOwned::to_owned),
-        Err(_) => None,
-    }
-}
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs
index 012eab256a..312708575e 100644
--- a/crates/project_model/src/rustc_cfg.rs
+++ b/crates/project_model/src/rustc_cfg.rs
@@ -2,12 +2,9 @@
 
 use std::process::Command;
 
-use anyhow::Result;
-use paths::AbsPath;
-
 use crate::{cfg_flag::CfgFlag, utf8_stdout};
 
-pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> {
+pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
     let _p = profile::span("rustc_cfg::get");
     let mut res = Vec::with_capacity(6 * 2 + 1);
 
@@ -19,39 +16,19 @@ pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<Cfg
         }
     }
 
-    match get_rust_cfgs(cargo_toml, target) {
+    let rustc_cfgs = {
+        let mut cmd = Command::new(toolchain::rustc());
+        cmd.args(&["--print", "cfg", "-O"]);
+        if let Some(target) = target {
+            cmd.args(&["--target", target]);
+        }
+        utf8_stdout(cmd)
+    };
+
+    match rustc_cfgs {
         Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
         Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
     }
 
     res
 }
-
-fn get_rust_cfgs(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Result<String> {
-    let cargo_rust_cfgs = match cargo_toml {
-        Some(cargo_toml) => {
-            let mut cargo_config = Command::new(toolchain::cargo());
-            cargo_config
-                .current_dir(cargo_toml.parent().unwrap())
-                .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
-                .env("RUSTC_BOOTSTRAP", "1");
-            if let Some(target) = target {
-                cargo_config.args(&["--target", target]);
-            }
-            utf8_stdout(cargo_config).ok()
-        }
-        None => None,
-    };
-    match cargo_rust_cfgs {
-        Some(stdout) => Ok(stdout),
-        None => {
-            // using unstable cargo features failed, fall back to using plain rustc
-            let mut cmd = Command::new(toolchain::rustc());
-            cmd.args(&["--print", "cfg", "-O"]);
-            if let Some(target) = target {
-                cmd.args(&["--target", target]);
-            }
-            utf8_stdout(cmd)
-        }
-    }
-}
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 84c702fdf7..2fcd0f8fac 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -143,8 +143,7 @@ impl ProjectWorkspace {
                 } else {
                     None
                 };
-
-                let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
+                let rustc_cfg = rustc_cfg::get(config.target.as_deref());
                 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
             }
         };
@@ -160,7 +159,7 @@ impl ProjectWorkspace {
             Some(path) => Some(Sysroot::load(path)?),
             None => None,
         };
-        let rustc_cfg = rustc_cfg::get(None, target);
+        let rustc_cfg = rustc_cfg::get(target);
         Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
     }
 
@@ -311,7 +310,7 @@ fn project_json_to_crate_graph(
 
             let target_cfgs = match krate.target.as_deref() {
                 Some(target) => {
-                    cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
+                    cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target)))
                 }
                 None => &rustc_cfg,
             };


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs
index 227ecd162f..d884a6eb49 100644
--- a/crates/hir_def/src/nameres/tests/incremental.rs
+++ b/crates/hir_def/src/nameres/tests/incremental.rs
@@ -137,6 +137,9 @@ m!(Z);
         });
         let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
         assert_eq!(n_recalculated_item_trees, 6);
+        let n_reparsed_macros =
+            events.iter().filter(|it| it.contains("parse_macro_expansion")).count();
+        assert_eq!(n_reparsed_macros, 3);
     }
 
     let new_text = r#"
@@ -155,5 +158,8 @@ m!(Z);
         });
         let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
         assert_eq!(n_recalculated_item_trees, 1);
+        let n_reparsed_macros =
+            events.iter().filter(|it| it.contains("parse_macro_expansion")).count();
+        assert_eq!(n_reparsed_macros, 0);
     }
 }