From e92646962a4580799796608f02e4c410b489cb7e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 15:22:39 +0200 Subject: [PATCH 01/11] Move interior mutability into ProcMacroSrvProcess --- crates/proc-macro-api/src/lib.rs | 37 ++++++++-------------------- crates/proc-macro-api/src/process.rs | 37 ++++++++++++++++------------ 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 0de76689ab09..c64ec77487d9 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -15,10 +15,8 @@ use indexmap::IndexSet; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; use span::Span; -use std::{ - fmt, io, - sync::{Arc, Mutex}, -}; +use std::{fmt, io, sync::Arc}; +use tt::SmolStr; use serde::{Deserialize, Serialize}; @@ -48,9 +46,7 @@ pub struct ProcMacroServer { /// /// That means that concurrent salsa requests may block each other when expanding proc macros, /// which is unfortunate, but simple and good enough for the time being. - /// - /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here. - process: Arc>, + process: Arc, path: AbsPathBuf, } @@ -70,9 +66,9 @@ impl MacroDylib { /// we share a single expander process for all macros. #[derive(Debug, Clone)] pub struct ProcMacro { - process: Arc>, + process: Arc, dylib_path: AbsPathBuf, - name: String, + name: SmolStr, kind: ProcMacroKind, } @@ -89,7 +85,6 @@ impl PartialEq for ProcMacro { #[derive(Clone, Debug)] pub struct ServerError { pub message: String, - // io::Error isn't Clone for some reason pub io: Option>, } @@ -104,10 +99,6 @@ impl fmt::Display for ServerError { } } -pub struct MacroPanic { - pub message: String, -} - impl ProcMacroServer { /// Spawns an external process as the proc macro server and returns a client connected to it. pub fn spawn( @@ -115,10 +106,7 @@ impl ProcMacroServer { env: &FxHashMap, ) -> io::Result { let process = ProcMacroProcessSrv::run(process_path, env)?; - Ok(ProcMacroServer { - process: Arc::new(Mutex::new(process)), - path: process_path.to_owned(), - }) + Ok(ProcMacroServer { process: Arc::new(process), path: process_path.to_owned() }) } pub fn path(&self) -> &AbsPath { @@ -127,15 +115,14 @@ impl ProcMacroServer { pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered(); - let macros = - self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; + let macros = self.process.find_proc_macros(&dylib.path)?; match macros { Ok(macros) => Ok(macros .into_iter() .map(|(name, kind)| ProcMacro { process: self.process.clone(), - name, + name: name.into(), kind, dylib_path: dylib.path.clone(), }) @@ -163,7 +150,7 @@ impl ProcMacro { call_site: Span, mixed_site: Span, ) -> Result, PanicMessage>, ServerError> { - let version = self.process.lock().unwrap_or_else(|e| e.into_inner()).version(); + let version = self.process.version(); let current_dir = env.get("CARGO_MANIFEST_DIR"); let mut span_data_table = IndexSet::default(); @@ -190,11 +177,7 @@ impl ProcMacro { }, }; - let response = self - .process - .lock() - .unwrap_or_else(|e| e.into_inner()) - .send_task(msg::Request::ExpandMacro(Box::new(task)))?; + let response = self.process.send_task(msg::Request::ExpandMacro(Box::new(task)))?; match response { msg::Response::ExpandMacro(it) => { diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 718a96dc80fe..1c37082bb29c 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -3,7 +3,7 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, - sync::Arc, + sync::{Arc, Mutex}, }; use paths::AbsPath; @@ -17,13 +17,20 @@ use crate::{ #[derive(Debug)] pub(crate) struct ProcMacroProcessSrv { + /// The state of the proc-macro server process, the protocol is currently strictly sequential + /// hence the lock on the state. + state: Mutex, + version: u32, + mode: SpanMode, +} + +#[derive(Debug)] +struct ProcessSrvState { process: Process, stdin: ChildStdin, stdout: BufReader, /// Populated when the server exits. server_exited: Option, - version: u32, - mode: SpanMode, } impl ProcMacroProcessSrv { @@ -36,10 +43,7 @@ impl ProcMacroProcessSrv { let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { - process, - stdin, - stdout, - server_exited: None, + state: Mutex::new(ProcessSrvState { process, stdin, stdout, server_exited: None }), version: 0, mode: SpanMode::Id, }) @@ -76,7 +80,7 @@ impl ProcMacroProcessSrv { self.version } - pub(crate) fn version_check(&mut self) -> Result { + fn version_check(&self) -> Result { let request = Request::ApiVersionCheck {}; let response = self.send_task(request)?; @@ -86,7 +90,7 @@ impl ProcMacroProcessSrv { } } - fn enable_rust_analyzer_spans(&mut self) -> Result { + fn enable_rust_analyzer_spans(&self) -> Result { let request = Request::SetConfig(crate::msg::ServerConfig { span_mode: crate::msg::SpanMode::RustAnalyzer, }); @@ -99,7 +103,7 @@ impl ProcMacroProcessSrv { } pub(crate) fn find_proc_macros( - &mut self, + &self, dylib_path: &AbsPath, ) -> Result, String>, ServerError> { let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }; @@ -112,20 +116,21 @@ impl ProcMacroProcessSrv { } } - pub(crate) fn send_task(&mut self, req: Request) -> Result { - if let Some(server_error) = &self.server_exited { + pub(crate) fn send_task(&self, req: Request) -> Result { + let state = &mut *self.state.lock().unwrap(); + if let Some(server_error) = &state.server_exited { return Err(server_error.clone()); } let mut buf = String::new(); - send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| { + send_request(&mut state.stdin, &mut state.stdout, req, &mut buf).map_err(|e| { if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { - match self.process.child.try_wait() { + match state.process.child.try_wait() { Ok(None) => e, Ok(Some(status)) => { let mut msg = String::new(); if !status.success() { - if let Some(stderr) = self.process.child.stderr.as_mut() { + if let Some(stderr) = state.process.child.stderr.as_mut() { _ = stderr.read_to_string(&mut msg); } } @@ -133,7 +138,7 @@ impl ProcMacroProcessSrv { message: format!("server exited with {status}: {msg}"), io: None, }; - self.server_exited = Some(server_error.clone()); + state.server_exited = Some(server_error.clone()); server_error } Err(_) => e, From 21a3d01875a71872ff4f1ae7e9b2ef2e14f8eec2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 15:23:54 +0200 Subject: [PATCH 02/11] Remove inline `rust_2018_idioms, unused_lifetimes` lint warn, Cargo.toml already enforces this --- crates/base-db/src/lib.rs | 2 -- crates/cfg/src/lib.rs | 2 -- crates/flycheck/src/lib.rs | 2 -- crates/hir-def/src/lib.rs | 1 - crates/hir-expand/src/lib.rs | 1 - crates/hir-ty/src/lib.rs | 2 +- crates/hir/src/lib.rs | 1 - crates/ide-assists/src/lib.rs | 2 -- crates/ide-completion/src/lib.rs | 2 -- crates/ide-db/src/lib.rs | 2 -- crates/ide-diagnostics/src/lib.rs | 2 -- crates/ide-ssr/src/lib.rs | 2 -- crates/ide/src/lib.rs | 2 +- crates/limit/src/lib.rs | 2 -- crates/mbe/src/lib.rs | 2 -- crates/parser/src/lib.rs | 1 - crates/paths/src/lib.rs | 2 -- crates/proc-macro-api/src/lib.rs | 2 -- crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs | 2 +- crates/proc-macro-srv/proc-macro-test/src/lib.rs | 2 -- crates/proc-macro-srv/src/lib.rs | 1 - crates/profile/src/lib.rs | 2 -- crates/project-model/src/lib.rs | 2 -- crates/rust-analyzer/src/bin/main.rs | 1 - crates/rust-analyzer/src/lib.rs | 2 -- crates/rust-analyzer/tests/slow-tests/main.rs | 1 - crates/sourcegen/src/lib.rs | 2 -- crates/stdx/src/lib.rs | 2 -- crates/syntax/src/lib.rs | 1 - crates/test-utils/src/lib.rs | 1 - crates/text-edit/src/lib.rs | 2 -- crates/toolchain/src/lib.rs | 2 -- crates/tt/src/lib.rs | 2 -- crates/vfs-notify/src/lib.rs | 2 -- crates/vfs/src/lib.rs | 2 -- 35 files changed, 3 insertions(+), 58 deletions(-) diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index f5165ea8a7bb..96fbbc317d48 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -1,7 +1,5 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod change; mod input; diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 9a365889e6a4..8b30286a0a8a 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -1,7 +1,5 @@ //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator -#![warn(rust_2018_idioms, unused_lifetimes)] - mod cfg_expr; mod dnf; #[cfg(test)] diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 4584400e66f0..a257633516ce 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -6,8 +6,6 @@ // addition to `cargo check`. Either split it into 3 crates (one for test, one for check // and one common utilities) or change its name and docs to reflect the current state. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{fmt, io, process::Command, time::Duration}; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 3fa98efbb5ea..211cdd35fd73 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -7,7 +7,6 @@ //! Note that `hir_def` is a work in progress, so not all of the above is //! actually true. -#![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index a7150cf30874..e7c34e51e857 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -4,7 +4,6 @@ //! tree originates not from the text of some `FileId`, but from some macro //! expansion. #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#![warn(rust_2018_idioms, unused_lifetimes)] pub mod attrs; pub mod builtin_attr_macro; diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 07c0cf920f74..bd650869bb38 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -1,6 +1,6 @@ //! The type system. We currently use this to infer types for completion, hover //! information and various assists. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index eea25ac18ae9..a9ae8d564902 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -17,7 +17,6 @@ //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: //! . -#![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index abebdec1d18c..685d230dc6f9 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -58,8 +58,6 @@ //! See also this post: //! -#![warn(rust_2018_idioms, unused_lifetimes)] - mod assist_config; mod assist_context; #[cfg(test)] diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 8323b8f9331d..7150fe3f0176 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -1,7 +1,5 @@ //! `completions` crate provides utilities for generating completions of user input. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod completions; mod config; mod context; diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 357209ceb0b4..8fac5baa57b6 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -2,8 +2,6 @@ //! //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod apply_change; pub mod active_parameter; diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index a419f04bfae6..c696faf270dd 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -23,8 +23,6 @@ //! There are also a couple of ad-hoc diagnostics implemented directly here, we //! don't yet have a great pattern for how to do them properly. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod handlers { pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index b5bf510aeed4..407433ed1923 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -3,8 +3,6 @@ //! Allows searching the AST for code that matches one or more patterns and then replacing that code //! based on a template. -#![warn(rust_2018_idioms, unused_lifetimes)] - // Feature: Structural Search and Replace // // Search and replace with named wildcards that will match any expression, type, path, pattern or item. diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index a2ac62341df9..28ae0dce9878 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -8,7 +8,7 @@ //! in this crate. // For proving that RootDatabase is RefUnwindSafe. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "128"] diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs index 27471db6a341..c1caeed2f872 100644 --- a/crates/limit/src/lib.rs +++ b/crates/limit/src/lib.rs @@ -1,7 +1,5 @@ //! limit defines a struct to enforce limits. -#![warn(rust_2018_idioms, unused_lifetimes)] - #[cfg(feature = "tracking")] use std::sync::atomic::AtomicUsize; diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 5f0598dfe072..b2fd91f6ced7 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -6,8 +6,6 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod expander; mod parser; mod syntax_bridge; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index c2f9ea477286..738ed239a7c9 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -17,7 +17,6 @@ //! //! [`Parser`]: crate::parser::Parser -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(rustdoc::private_intra_doc_links)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index 33c3f83db50f..885f071889ec 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -1,8 +1,6 @@ //! Thin wrappers around `std::path`/`camino::path`, distinguishing between absolute and //! relative paths. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{ borrow::Borrow, ffi::OsStr, diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index c64ec77487d9..039509d87c25 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -5,8 +5,6 @@ //! is used to provide basic infrastructure for communication between two //! processes: Client (RA itself), Server (the external program) -#![warn(rust_2018_idioms, unused_lifetimes)] - pub mod msg; mod process; diff --git a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index 5f8530d08c43..a1707364f3c2 100644 --- a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs @@ -1,6 +1,6 @@ //! Exports a few trivial procedural macros for testing. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![feature(proc_macro_span, proc_macro_def_site)] #![allow(clippy::all)] diff --git a/crates/proc-macro-srv/proc-macro-test/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/src/lib.rs index 739c6ec6f449..2edf23a63440 100644 --- a/crates/proc-macro-srv/proc-macro-test/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/src/lib.rs @@ -1,6 +1,4 @@ //! Exports a few trivial procedural macros for testing. -#![warn(rust_2018_idioms, unused_lifetimes)] - pub static PROC_MACRO_TEST_LOCATION: &str = include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt")); diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 2472c1e3119c..b86dceeb5034 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -13,7 +13,6 @@ #![cfg(any(feature = "sysroot-abi", rust_analyzer))] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unreachable_pub, internal_features)] extern crate proc_macro; diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs index 2ccb1cd06ae4..c1ae0d43d072 100644 --- a/crates/profile/src/lib.rs +++ b/crates/profile/src/lib.rs @@ -1,7 +1,5 @@ //! A collection of tools for profiling rust-analyzer. -#![warn(rust_2018_idioms, unused_lifetimes)] - #[cfg(feature = "cpu_profiler")] mod google_cpu_profiler; mod memory_usage; diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index 35643dcc0284..92bf6a08f870 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -15,8 +15,6 @@ //! procedural macros). //! * Lowering of concrete model to a [`base_db::CrateGraph`] -#![warn(rust_2018_idioms, unused_lifetimes)] - mod build_scripts; mod cargo_workspace; mod cfg; diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 774784f37b00..1985093bc5c3 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -2,7 +2,6 @@ //! //! Based on cli flags, either spawns an LSP server, or runs a batch analysis -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::print_stdout, clippy::print_stderr)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index a398e98f093b..a8e6657c24c5 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -9,8 +9,6 @@ //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. -#![warn(rust_2018_idioms, unused_lifetimes)] - pub mod cli; mod caps; diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index f886df60e681..51b3076b4632 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -8,7 +8,6 @@ //! specific JSON shapes here -- there's little value in such tests, as we can't //! be sure without a real client anyway. -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::disallowed_types)] mod ratoml; diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs index 829b4d5b0ff2..307c214c61d5 100644 --- a/crates/sourcegen/src/lib.rs +++ b/crates/sourcegen/src/lib.rs @@ -6,8 +6,6 @@ //! //! This crate contains utilities to make this kind of source-gen easy. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{ fmt, fs, mem, path::{Path, PathBuf}, diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 54f10df42a85..76dbd42ff6b2 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -1,7 +1,5 @@ //! Missing batteries for standard libraries. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::io as sio; use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index b5d816b0ce1a..177f48b986a9 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -20,7 +20,6 @@ //! [Swift]: #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#![warn(rust_2018_idioms, unused_lifetimes)] #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index 53d4a28bc309..088817b8357c 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -6,7 +6,6 @@ //! * Extracting markup (mainly, `$0` markers) out of fixture strings. //! * marks (see the eponymous module). -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::print_stderr)] mod assert_linear; diff --git a/crates/text-edit/src/lib.rs b/crates/text-edit/src/lib.rs index e2ff373c1baa..3efe0850d88d 100644 --- a/crates/text-edit/src/lib.rs +++ b/crates/text-edit/src/lib.rs @@ -4,8 +4,6 @@ //! so `TextEdit` is the ultimate representation of the work done by //! rust-analyzer. -#![warn(rust_2018_idioms, unused_lifetimes)] - use itertools::Itertools; use std::cmp::max; pub use text_size::{TextRange, TextSize}; diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs index 2591ed16916e..a0603e35a09f 100644 --- a/crates/toolchain/src/lib.rs +++ b/crates/toolchain/src/lib.rs @@ -1,7 +1,5 @@ //! Discovery of `cargo` & `rustc` executables. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{env, iter, path::PathBuf}; use camino::{Utf8Path, Utf8PathBuf}; diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index b2a21b191326..369744d0e96c 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs @@ -2,8 +2,6 @@ //! input and output) of macros. It closely mirrors `proc_macro` crate's //! `TokenTree`. -#![warn(rust_2018_idioms, unused_lifetimes)] - pub mod buffer; pub mod iter; diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 1dbccab370c2..7e0f9af7af89 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -7,8 +7,6 @@ //! Hopefully, one day a reliable file watching/walking crate appears on //! crates.io, and we can reduce this to trivial glue code. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{ fs, path::{Component, Path}, diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 18c8699dd4d7..b3aa6e2fe113 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -38,8 +38,6 @@ //! [`Handle`]: loader::Handle //! [`Entries`]: loader::Entry -#![warn(rust_2018_idioms, unused_lifetimes)] - mod anchored_path; pub mod file_set; pub mod loader; From 23b043a622c17c9c514a5cb1401a95aa52ae315e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 15:28:31 +0200 Subject: [PATCH 03/11] Move proc-macro-srv RUSTC_VERSION fetching from include to env var --- crates/proc-macro-srv/build.rs | 16 ++-------------- crates/proc-macro-srv/src/lib.rs | 3 +-- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/crates/proc-macro-srv/build.rs b/crates/proc-macro-srv/build.rs index 874d1c6cd389..44511d44b35b 100644 --- a/crates/proc-macro-srv/build.rs +++ b/crates/proc-macro-srv/build.rs @@ -4,24 +4,12 @@ use std::{env, fs::File, io::Write, path::PathBuf, process::Command}; fn main() { - println!("cargo:rustc-check-cfg=cfg(rust_analyzer)"); - - let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - path.push("rustc_version.rs"); - let mut f = File::create(&path).unwrap(); + println!("cargo::rustc-check-cfg=cfg(rust_analyzer)"); let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set"); let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run"); let version_string = std::str::from_utf8(&output.stdout[..]) .expect("rustc --version output must be UTF-8") .trim(); - - write!( - f, - " - #[allow(dead_code)] - pub(crate) const RUSTC_VERSION_STRING: &str = {version_string:?}; - " - ) - .unwrap(); + println!("cargo::rustc-env=RUSTC_VERSION={}", version_string); } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index b86dceeb5034..8bc308fce90d 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -48,8 +48,7 @@ use span::Span; use crate::server::TokenStream; -// see `build.rs` -include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); +pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); trait ProcMacroSrvSpan: Copy { type Server: proc_macro::bridge::server::Server>; From 0b88dfc8b17468e4ca542cd90d5decefe7a35af8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 15:34:43 +0200 Subject: [PATCH 04/11] Rename proc-macro-srv::server to server_impl --- crates/proc-macro-srv/src/dylib.rs | 2 +- crates/proc-macro-srv/src/lib.rs | 56 +++++++++---------- crates/proc-macro-srv/src/proc_macros.rs | 9 +-- .../src/{server.rs => server_impl.rs} | 0 .../rust_analyzer_span.rs | 4 +- .../src/{server => server_impl}/symbol.rs | 0 .../src/{server => server_impl}/token_id.rs | 4 +- .../{server => server_impl}/token_stream.rs | 0 crates/proc-macro-srv/src/tests/utils.rs | 8 +-- 9 files changed, 42 insertions(+), 41 deletions(-) rename crates/proc-macro-srv/src/{server.rs => server_impl.rs} (100%) rename crates/proc-macro-srv/src/{server => server_impl}/rust_analyzer_span.rs (99%) rename crates/proc-macro-srv/src/{server => server_impl}/symbol.rs (100%) rename crates/proc-macro-srv/src/{server => server_impl}/token_id.rs (99%) rename crates/proc-macro-srv/src/{server => server_impl}/token_stream.rs (100%) diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 474f00a574fa..7fa560fb85ed 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -2,13 +2,13 @@ mod version; +use proc_macro::bridge; use std::{fmt, fs::File, io}; use libloading::Library; use memmap2::Mmap; use object::Object; use paths::{AbsPath, Utf8Path, Utf8PathBuf}; -use proc_macro::bridge; use proc_macro_api::ProcMacroKind; use crate::ProcMacroSrvSpan; diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 8bc308fce90d..3d309155d5d1 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -26,7 +26,7 @@ extern crate rustc_lexer; mod dylib; mod proc_macros; -mod server; +mod server_impl; use std::{ collections::{hash_map::Entry, HashMap}, @@ -46,36 +46,10 @@ use proc_macro_api::{ }; use span::Span; -use crate::server::TokenStream; +use crate::server_impl::TokenStream; pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); -trait ProcMacroSrvSpan: Copy { - type Server: proc_macro::bridge::server::Server>; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; -} - -impl ProcMacroSrvSpan for TokenId { - type Server = server::token_id::TokenIdServer; - - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { - Self::Server { interner: &server::SYMBOL_INTERNER, call_site, def_site, mixed_site } - } -} -impl ProcMacroSrvSpan for Span { - type Server = server::rust_analyzer_span::RaSpanServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { - Self::Server { - interner: &server::SYMBOL_INTERNER, - call_site, - def_site, - mixed_site, - tracked_env_vars: Default::default(), - tracked_paths: Default::default(), - } - } -} - #[derive(Default)] pub struct ProcMacroSrv { expanders: HashMap<(Utf8PathBuf, SystemTime), dylib::Expander>, @@ -167,6 +141,32 @@ impl ProcMacroSrv { } } +trait ProcMacroSrvSpan: Copy { + type Server: proc_macro::bridge::server::Server>; + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; +} + +impl ProcMacroSrvSpan for TokenId { + type Server = server_impl::token_id::TokenIdServer; + + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + Self::Server { interner: &server_impl::SYMBOL_INTERNER, call_site, def_site, mixed_site } + } +} +impl ProcMacroSrvSpan for Span { + type Server = server_impl::rust_analyzer_span::RaSpanServer; + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + Self::Server { + interner: &server_impl::SYMBOL_INTERNER, + call_site, + def_site, + mixed_site, + tracked_env_vars: Default::default(), + tracked_paths: Default::default(), + } + } +} + fn expand_id( task: msg::ExpandMacro, expander: &dylib::Expander, diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs index b963a8a029f5..c5c3dff9db8e 100644 --- a/crates/proc-macro-srv/src/proc_macros.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -49,11 +49,12 @@ impl ProcMacros { call_site: S, mixed_site: S, ) -> Result, crate::PanicMessage> { - let parsed_body = crate::server::TokenStream::with_subtree(macro_body); + let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body); - let parsed_attributes = attributes.map_or_else(crate::server::TokenStream::new, |attr| { - crate::server::TokenStream::with_subtree(attr) - }); + let parsed_attributes = attributes + .map_or_else(crate::server_impl::TokenStream::new, |attr| { + crate::server_impl::TokenStream::with_subtree(attr) + }); for proc_macro in &self.exported_macros { match proc_macro { diff --git a/crates/proc-macro-srv/src/server.rs b/crates/proc-macro-srv/src/server_impl.rs similarity index 100% rename from crates/proc-macro-srv/src/server.rs rename to crates/proc-macro-srv/src/server_impl.rs diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs similarity index 99% rename from crates/proc-macro-srv/src/server/rust_analyzer_span.rs rename to crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 0350bde41224..bb174ba1b224 100644 --- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -14,7 +14,7 @@ use proc_macro::bridge::{self, server}; use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; -use crate::server::{ +use crate::server_impl::{ delim_to_external, delim_to_internal, literal_with_stringify_parts, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; @@ -29,7 +29,7 @@ mod tt { pub type Ident = ::tt::Ident; } -type TokenStream = crate::server::TokenStream; +type TokenStream = crate::server_impl::TokenStream; #[derive(Clone)] pub struct SourceFile; diff --git a/crates/proc-macro-srv/src/server/symbol.rs b/crates/proc-macro-srv/src/server_impl/symbol.rs similarity index 100% rename from crates/proc-macro-srv/src/server/symbol.rs rename to crates/proc-macro-srv/src/server_impl/symbol.rs diff --git a/crates/proc-macro-srv/src/server/token_id.rs b/crates/proc-macro-srv/src/server_impl/token_id.rs similarity index 99% rename from crates/proc-macro-srv/src/server/token_id.rs rename to crates/proc-macro-srv/src/server_impl/token_id.rs index ad7bd954cf16..12edacbe39dc 100644 --- a/crates/proc-macro-srv/src/server/token_id.rs +++ b/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -7,7 +7,7 @@ use std::{ use proc_macro::bridge::{self, server}; -use crate::server::{ +use crate::server_impl::{ delim_to_external, delim_to_internal, literal_with_stringify_parts, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; @@ -31,7 +31,7 @@ type Spacing = tt::Spacing; #[allow(unused)] type Literal = tt::Literal; type Span = tt::TokenId; -type TokenStream = crate::server::TokenStream; +type TokenStream = crate::server_impl::TokenStream; #[derive(Clone)] pub struct SourceFile; diff --git a/crates/proc-macro-srv/src/server/token_stream.rs b/crates/proc-macro-srv/src/server_impl/token_stream.rs similarity index 100% rename from crates/proc-macro-srv/src/server/token_stream.rs rename to crates/proc-macro-srv/src/server_impl/token_stream.rs diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index 6050bc9e36ec..0579c426d096 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -7,8 +7,8 @@ use tt::TextRange; use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv}; -fn parse_string(call_site: TokenId, src: &str) -> crate::server::TokenStream { - crate::server::TokenStream::with_subtree( +fn parse_string(call_site: TokenId, src: &str) -> crate::server_impl::TokenStream { + crate::server_impl::TokenStream::with_subtree( mbe::parse_to_token_tree_static_span(call_site, src).unwrap(), ) } @@ -17,8 +17,8 @@ fn parse_string_spanned( anchor: SpanAnchor, call_site: SyntaxContextId, src: &str, -) -> crate::server::TokenStream { - crate::server::TokenStream::with_subtree( +) -> crate::server_impl::TokenStream { + crate::server_impl::TokenStream::with_subtree( mbe::parse_to_token_tree(anchor, call_site, src).unwrap(), ) } From 678420e66ac7d30709d3b172cbe201693f4dbc6c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 15:37:00 +0200 Subject: [PATCH 05/11] Move proc-macro-test test path fetching from include to env var --- crates/proc-macro-srv/build.rs | 2 +- crates/proc-macro-srv/proc-macro-test/build.rs | 3 +-- crates/proc-macro-srv/proc-macro-test/src/lib.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/proc-macro-srv/build.rs b/crates/proc-macro-srv/build.rs index 44511d44b35b..9a17cfc9f360 100644 --- a/crates/proc-macro-srv/build.rs +++ b/crates/proc-macro-srv/build.rs @@ -1,7 +1,7 @@ //! Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is //! build with and make it accessible at runtime for ABI selection. -use std::{env, fs::File, io::Write, path::PathBuf, process::Command}; +use std::{env, process::Command}; fn main() { println!("cargo::rustc-check-cfg=cfg(rust_analyzer)"); diff --git a/crates/proc-macro-srv/proc-macro-test/build.rs b/crates/proc-macro-srv/proc-macro-test/build.rs index 6a0ae362d88e..fe1fce3da7eb 100644 --- a/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/crates/proc-macro-srv/proc-macro-test/build.rs @@ -121,6 +121,5 @@ fn main() { // This file is under `target_dir` and is already under `OUT_DIR`. let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found"); - let info_path = out_dir.join("proc_macro_test_location.txt"); - fs::write(info_path, artifact_path.to_str().unwrap()).unwrap(); + println!("cargo::rustc-env=PROC_MACRO_TEST_LOCATION={}", artifact_path.display()); } diff --git a/crates/proc-macro-srv/proc-macro-test/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/src/lib.rs index 2edf23a63440..6464adb2ca7a 100644 --- a/crates/proc-macro-srv/proc-macro-test/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/src/lib.rs @@ -1,4 +1,3 @@ //! Exports a few trivial procedural macros for testing. -pub static PROC_MACRO_TEST_LOCATION: &str = - include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt")); +pub static PROC_MACRO_TEST_LOCATION: &str = env!("PROC_MACRO_TEST_LOCATION"); From 2fb38ceb66d5b0f4a37abd7ed4f9644a16f4dfa5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 16:05:46 +0200 Subject: [PATCH 06/11] Faster env snapshotting in proc-macro-srv --- crates/proc-macro-api/src/lib.rs | 31 ++-- crates/proc-macro-api/src/msg.rs | 44 +++--- crates/proc-macro-srv-cli/src/main.rs | 4 +- crates/proc-macro-srv/src/lib.rs | 177 ++++++++++++----------- crates/proc-macro-srv/src/proc_macros.rs | 3 +- crates/proc-macro-srv/src/tests/utils.rs | 5 +- 6 files changed, 147 insertions(+), 117 deletions(-) diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 039509d87c25..9ba6a09cb738 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -156,23 +156,26 @@ impl ProcMacro { let call_site = span_data_table.insert_full(call_site).0; let mixed_site = span_data_table.insert_full(mixed_site).0; let task = ExpandMacro { - macro_body: FlatTree::new(subtree, version, &mut span_data_table), - macro_name: self.name.to_string(), - attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), + data: msg::ExpandMacroData { + macro_body: FlatTree::new(subtree, version, &mut span_data_table), + macro_name: self.name.to_string(), + attributes: attr + .map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), + has_global_spans: ExpnGlobals { + serialize: version >= HAS_GLOBAL_SPANS, + def_site, + call_site, + mixed_site, + }, + span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT { + serialize_span_data_index_map(&span_data_table) + } else { + Vec::new() + }, + }, lib: self.dylib_path.to_path_buf().into(), env: env.into(), current_dir, - has_global_spans: ExpnGlobals { - serialize: version >= HAS_GLOBAL_SPANS, - def_site, - call_site, - mixed_site, - }, - span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT { - serialize_span_data_index_map(&span_data_table) - } else { - Vec::new() - }, }; let response = self.process.send_task(msg::Request::ExpandMacro(Box::new(task)))?; diff --git a/crates/proc-macro-api/src/msg.rs b/crates/proc-macro-api/src/msg.rs index ad0e1f187b62..49ebedba7ddf 100644 --- a/crates/proc-macro-api/src/msg.rs +++ b/crates/proc-macro-api/src/msg.rs @@ -72,6 +72,16 @@ pub struct PanicMessage(pub String); #[derive(Debug, Serialize, Deserialize)] pub struct ExpandMacro { + pub lib: Utf8PathBuf, + /// Environment variables to set during macro expansion. + pub env: Vec<(String, String)>, + pub current_dir: Option, + #[serde(flatten)] + pub data: ExpandMacroData, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExpandMacroData { /// Argument of macro call. /// /// In custom derive this will be a struct or enum; in attribute-like macro - underlying @@ -86,13 +96,6 @@ pub struct ExpandMacro { /// Possible attributes for the attribute-like macros. pub attributes: Option, - - pub lib: Utf8PathBuf, - - /// Environment variables to set during macro expansion. - pub env: Vec<(String, String)>, - - pub current_dir: Option, /// marker for serde skip stuff #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")] #[serde(default)] @@ -268,25 +271,30 @@ mod tests { let tt = fixture_token_tree(); let mut span_data_table = Default::default(); let task = ExpandMacro { - macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table), - macro_name: Default::default(), - attributes: None, + data: ExpandMacroData { + macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table), + macro_name: Default::default(), + attributes: None, + has_global_spans: ExpnGlobals { + serialize: true, + def_site: 0, + call_site: 0, + mixed_site: 0, + }, + span_data_table: Vec::new(), + }, lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), env: Default::default(), current_dir: Default::default(), - has_global_spans: ExpnGlobals { - serialize: true, - def_site: 0, - call_site: 0, - mixed_site: 0, - }, - span_data_table: Vec::new(), }; let json = serde_json::to_string(&task).unwrap(); // println!("{}", json); let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - assert_eq!(tt, back.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); + assert_eq!( + tt, + back.data.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table) + ); } } diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index df0ae3171f54..f9689712ad63 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -33,12 +33,14 @@ fn run() -> io::Result<()> { #[cfg(any(feature = "sysroot-abi", rust_analyzer))] fn run() -> io::Result<()> { use proc_macro_api::msg::{self, Message}; + use proc_macro_srv::EnvSnapshot; let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); - let mut srv = proc_macro_srv::ProcMacroSrv::default(); + let env = EnvSnapshot::new(); + let mut srv = proc_macro_srv::ProcMacroSrv::new(&env); let mut buf = String::new(); while let Some(req) = read_request(&mut buf)? { diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 3d309155d5d1..34851ee0bee8 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -32,7 +32,9 @@ use std::{ collections::{hash_map::Entry, HashMap}, env, ffi::OsString, - fs, thread, + fs, + path::{Path, PathBuf}, + thread, time::SystemTime, }; @@ -50,15 +52,21 @@ use crate::server_impl::TokenStream; pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); -#[derive(Default)] -pub struct ProcMacroSrv { +pub struct ProcMacroSrv<'env> { expanders: HashMap<(Utf8PathBuf, SystemTime), dylib::Expander>, span_mode: SpanMode, + env: &'env EnvSnapshot, +} + +impl<'env> ProcMacroSrv<'env> { + pub fn new(env: &'env EnvSnapshot) -> Self { + Self { expanders: Default::default(), span_mode: Default::default(), env } + } } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; -impl ProcMacroSrv { +impl<'env> ProcMacroSrv<'env> { pub fn set_span_mode(&mut self, span_mode: SpanMode) { self.span_mode = span_mode; } @@ -69,52 +77,24 @@ impl ProcMacroSrv { pub fn expand( &mut self, - task: msg::ExpandMacro, + msg::ExpandMacro { lib, env, current_dir, data }: msg::ExpandMacro, ) -> Result<(msg::FlatTree, Vec), msg::PanicMessage> { let span_mode = self.span_mode; - let expander = self.expander(task.lib.as_ref()).map_err(|err| { + let snapped_env = self.env; + let expander = self.expander(lib.as_ref()).map_err(|err| { debug_assert!(false, "should list macros before asking to expand"); msg::PanicMessage(format!("failed to load macro: {err}")) })?; - let prev_env = EnvSnapshot::new(); - for (k, v) in &task.env { - env::set_var(k, v); - } - let prev_working_dir = match &task.current_dir { - Some(dir) => { - let prev_working_dir = std::env::current_dir().ok(); - if let Err(err) = std::env::set_current_dir(dir) { - eprintln!("Failed to set the current working dir to {dir}. Error: {err:?}") - } - prev_working_dir - } - None => None, - }; - - let ExpnGlobals { def_site, call_site, mixed_site, .. } = task.has_global_spans; + let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref)); let result = match span_mode { - SpanMode::Id => { - expand_id(task, expander, def_site, call_site, mixed_site).map(|it| (it, vec![])) - } - SpanMode::RustAnalyzer => { - expand_ra_span(task, expander, def_site, call_site, mixed_site) - } + SpanMode::Id => expand_id(data, expander).map(|it| (it, vec![])), + SpanMode::RustAnalyzer => expand_ra_span(data, expander), }; prev_env.rollback(); - if let Some(dir) = prev_working_dir { - if let Err(err) = std::env::set_current_dir(&dir) { - eprintln!( - "Failed to set the current working dir to {}. Error: {:?}", - dir.display(), - err - ) - } - } - result.map_err(msg::PanicMessage) } @@ -168,32 +148,28 @@ impl ProcMacroSrvSpan for Span { } fn expand_id( - task: msg::ExpandMacro, + msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + span_data_table: _, + }: msg::ExpandMacroData, expander: &dylib::Expander, - def_site: usize, - call_site: usize, - mixed_site: usize, ) -> Result { let def_site = TokenId(def_site as u32); let call_site = TokenId(call_site as u32); let mixed_site = TokenId(mixed_site as u32); - let macro_body = task.macro_body.to_subtree_unresolved(CURRENT_API_VERSION); - let attributes = task.attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION)); + let macro_body = macro_body.to_subtree_unresolved(CURRENT_API_VERSION); + let attributes = attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION)); let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) - .name(task.macro_name.clone()) + .name(macro_name.clone()) .spawn_scoped(s, || { expander - .expand( - &task.macro_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - ) + .expand(¯o_name, macro_body, attributes, def_site, call_site, mixed_site) .map(|it| msg::FlatTree::new_raw(&it, CURRENT_API_VERSION)) }); let res = match thread { @@ -210,35 +186,31 @@ fn expand_id( } fn expand_ra_span( - task: msg::ExpandMacro, + msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + span_data_table, + }: msg::ExpandMacroData, expander: &dylib::Expander, - def_site: usize, - call_site: usize, - mixed_site: usize, ) -> Result<(msg::FlatTree, Vec), String> { - let mut span_data_table = deserialize_span_data_index_map(&task.span_data_table); + let mut span_data_table = deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; let call_site = span_data_table[call_site]; let mixed_site = span_data_table[mixed_site]; - let macro_body = task.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table); + let macro_body = macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table); let attributes = - task.attributes.map(|it| it.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); + attributes.map(|it| it.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) - .name(task.macro_name.clone()) + .name(macro_name.clone()) .spawn_scoped(s, || { expander - .expand( - &task.macro_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - ) + .expand(¯o_name, macro_body, attributes, def_site, call_site, mixed_site) .map(|it| { ( msg::FlatTree::new(&it, CURRENT_API_VERSION, &mut span_data_table), @@ -269,31 +241,74 @@ impl PanicMessage { } } -struct EnvSnapshot { +pub struct EnvSnapshot { vars: HashMap, } impl EnvSnapshot { - fn new() -> EnvSnapshot { + pub fn new() -> EnvSnapshot { EnvSnapshot { vars: env::vars_os().collect() } } +} + +struct EnvChange<'snap> { + changed_vars: Vec, + prev_working_dir: Option, + snap: &'snap EnvSnapshot, +} + +impl<'snap> EnvChange<'snap> { + fn apply( + snap: &'snap EnvSnapshot, + new_vars: Vec<(String, String)>, + current_dir: Option<&Path>, + ) -> EnvChange<'snap> { + let prev_working_dir = match current_dir { + Some(dir) => { + let prev_working_dir = std::env::current_dir().ok(); + if let Err(err) = std::env::set_current_dir(dir) { + eprintln!( + "Failed to set the current working dir to {}. Error: {err:?}", + dir.display() + ) + } + prev_working_dir + } + None => None, + }; + EnvChange { + snap, + changed_vars: new_vars + .into_iter() + .map(|(k, v)| { + env::set_var(&k, v); + k + }) + .collect(), + prev_working_dir, + } + } fn rollback(self) {} } -impl Drop for EnvSnapshot { +impl Drop for EnvChange<'_> { fn drop(&mut self) { - for (name, value) in env::vars_os() { - let old_value = self.vars.remove(&name); - if old_value != Some(value) { - match old_value { - None => env::remove_var(name), - Some(old_value) => env::set_var(name, old_value), - } + for name in self.changed_vars.drain(..) { + match self.snap.vars.get::(name.as_ref()) { + Some(prev_val) => env::set_var(name, prev_val), + None => env::remove_var(name), } } - for (name, old_value) in self.vars.drain() { - env::set_var(name, old_value) + + if let Some(dir) = &self.prev_working_dir { + if let Err(err) = std::env::set_current_dir(&dir) { + eprintln!( + "Failed to set the current working dir to {}. Error: {:?}", + dir.display(), + err + ) + } } } } diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs index c5c3dff9db8e..d48c5b30dee6 100644 --- a/crates/proc-macro-srv/src/proc_macros.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -1,9 +1,10 @@ //! Proc macro ABI -use libloading::Library; use proc_macro::bridge; use proc_macro_api::ProcMacroKind; +use libloading::Library; + use crate::{dylib::LoadProcMacroDylibError, ProcMacroSrvSpan}; pub(crate) struct ProcMacros { diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index 0579c426d096..03b1117a5bd3 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -5,7 +5,7 @@ use proc_macro_api::msg::TokenId; use span::{ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId}; use tt::TextRange; -use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv}; +use crate::{dylib, proc_macro_test_dylib_path, EnvSnapshot, ProcMacroSrv}; fn parse_string(call_site: TokenId, src: &str) -> crate::server_impl::TokenStream { crate::server_impl::TokenStream::with_subtree( @@ -96,7 +96,8 @@ fn assert_expand_impl( pub(crate) fn list() -> Vec { let dylib_path = proc_macro_test_dylib_path(); - let mut srv = ProcMacroSrv::default(); + let env = EnvSnapshot::new(); + let mut srv = ProcMacroSrv::new(&env); let res = srv.list_macros(&dylib_path).unwrap(); res.into_iter().map(|(name, kind)| format!("{name} [{kind:?}]")).collect() } From b0c4bc4972e46e22271227893d72e902e78313c6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 16:26:39 +0200 Subject: [PATCH 07/11] Fix proc-macro-test build script --- .../proc-macro-srv/proc-macro-test/build.rs | 3 +-- crates/proc-macro-srv/src/dylib.rs | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/crates/proc-macro-srv/proc-macro-test/build.rs b/crates/proc-macro-srv/proc-macro-test/build.rs index fe1fce3da7eb..dd4709a1f756 100644 --- a/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/crates/proc-macro-srv/proc-macro-test/build.rs @@ -30,8 +30,7 @@ fn main() { if !has_features { println!("proc-macro-test testing only works on nightly toolchains"); - let info_path = out_dir.join("proc_macro_test_location.txt"); - fs::File::create(info_path).unwrap(); + println!("cargo::rustc-env=PROC_MACRO_TEST_LOCATION=\"\""); return; } diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 7fa560fb85ed..c2309cb3d116 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -133,24 +133,32 @@ impl ProcMacroLibraryLibloading { } } -pub struct Expander { +pub(crate) struct Expander { inner: ProcMacroLibraryLibloading, + path: Utf8PathBuf, +} + +impl Drop for Expander { + fn drop(&mut self) { + #[cfg(windows)] + std::fs::remove_file(&self.path).ok(); + } } impl Expander { - pub fn new(lib: &Utf8Path) -> Result { + pub(crate) fn new(lib: &Utf8Path) -> Result { // Some libraries for dynamic loading require canonicalized path even when it is // already absolute let lib = lib.canonicalize_utf8()?; - let lib = ensure_file_with_lock_free_access(&lib)?; + let path = ensure_file_with_lock_free_access(&lib)?; - let library = ProcMacroLibraryLibloading::open(lib.as_ref())?; + let library = ProcMacroLibraryLibloading::open(path.as_ref())?; - Ok(Expander { inner: library }) + Ok(Expander { inner: library, path }) } - pub fn expand( + pub(crate) fn expand( &self, macro_name: &str, macro_body: tt::Subtree, @@ -169,7 +177,7 @@ impl Expander { result.map_err(|e| e.into_string().unwrap_or_default()) } - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { self.inner.proc_macros.list_macros() } } @@ -198,7 +206,7 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result unique_name.push_str(file_name); to.push(unique_name); - std::fs::copy(path, &to).unwrap(); + std::fs::copy(path, &to)?; Ok(to) } From 9d09bc06198d10c5a27f3cb025c85325568e1f86 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 16:33:30 +0200 Subject: [PATCH 08/11] Actual dummy server for the server cli --- crates/proc-macro-srv-cli/src/main.rs | 30 +++++++++++++++++-- .../proc-macro-srv/proc-macro-test/build.rs | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index f9689712ad63..f6f6fdc864b7 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -8,6 +8,8 @@ extern crate rustc_driver as _; use std::io; +use proc_macro_api::msg::ServerConfig; + fn main() -> std::io::Result<()> { let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); match v.as_deref() { @@ -26,8 +28,32 @@ fn main() -> std::io::Result<()> { #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))] fn run() -> io::Result<()> { - eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled"); - std::process::exit(70); + let err = "proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function"; + eprintln!("{err}"); + use proc_macro_api::msg::{self, Message}; + + let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); + + let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); + + let mut buf = String::new(); + + while let Some(req) = read_request(&mut buf)? { + let res = match req { + msg::Request::ListMacros { .. } => msg::Response::ListMacros(Err(err.to_owned())), + msg::Request::ExpandMacro(_) => { + msg::Response::ExpandMacro(Err(msg::PanicMessage(err.to_owned()))) + } + msg::Request::ApiVersionCheck {} => { + msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION) + } + msg::Request::SetConfig(_) => { + msg::Response::SetConfig(ServerConfig { span_mode: msg::SpanMode::Id }) + } + }; + write_response(res)? + } + Ok(()) } #[cfg(any(feature = "sysroot-abi", rust_analyzer))] diff --git a/crates/proc-macro-srv/proc-macro-test/build.rs b/crates/proc-macro-srv/proc-macro-test/build.rs index dd4709a1f756..ff2f5d186391 100644 --- a/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/crates/proc-macro-srv/proc-macro-test/build.rs @@ -8,7 +8,7 @@ //! 1.58) and future ABIs (stage1, nightly) use std::{ - env, fs, + env, path::{Path, PathBuf}, process::Command, }; From 7c7c0cbffb5f5392b5942ea513e70836c15035ea Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 16:41:52 +0200 Subject: [PATCH 09/11] Simplify --- Cargo.lock | 1 - crates/proc-macro-api/Cargo.toml | 1 - crates/proc-macro-api/src/lib.rs | 10 +++++----- crates/proc-macro-api/src/msg/flat.rs | 6 +++--- crates/proc-macro-api/src/process.rs | 10 +++++----- crates/proc-macro-srv-cli/src/main.rs | 6 +++--- crates/rust-analyzer/src/reload.rs | 2 +- 7 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 790bccea1968..56deb1b7a191 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1337,7 +1337,6 @@ dependencies = [ "stdx", "text-size", "tracing", - "triomphe", "tt", ] diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 11fd076a6f68..7f633d91ecc8 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -15,7 +15,6 @@ doctest = false serde.workspace = true serde_json = { workspace = true, features = ["unbounded_depth"] } tracing.workspace = true -triomphe.workspace = true rustc-hash.workspace = true indexmap.workspace = true diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 9ba6a09cb738..f21411bc8143 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -9,9 +9,7 @@ pub mod msg; mod process; use base_db::Env; -use indexmap::IndexSet; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; use span::Span; use std::{fmt, io, sync::Arc}; use tt::SmolStr; @@ -21,7 +19,8 @@ use serde::{Deserialize, Serialize}; use crate::{ msg::{ deserialize_span_data_index_map, flat::serialize_span_data_index_map, ExpandMacro, - ExpnGlobals, FlatTree, PanicMessage, HAS_GLOBAL_SPANS, RUST_ANALYZER_SPAN_SUPPORT, + ExpnGlobals, FlatTree, PanicMessage, SpanDataIndexMap, HAS_GLOBAL_SPANS, + RUST_ANALYZER_SPAN_SUPPORT, }, process::ProcMacroProcessSrv, }; @@ -101,7 +100,8 @@ impl ProcMacroServer { /// Spawns an external process as the proc macro server and returns a client connected to it. pub fn spawn( process_path: &AbsPath, - env: &FxHashMap, + env: impl IntoIterator, impl AsRef)> + + Clone, ) -> io::Result { let process = ProcMacroProcessSrv::run(process_path, env)?; Ok(ProcMacroServer { process: Arc::new(process), path: process_path.to_owned() }) @@ -151,7 +151,7 @@ impl ProcMacro { let version = self.process.version(); let current_dir = env.get("CARGO_MANIFEST_DIR"); - let mut span_data_table = IndexSet::default(); + let mut span_data_table = SpanDataIndexMap::default(); let def_site = span_data_table.insert_full(def_site).0; let call_site = span_data_table.insert_full(call_site).0; let mixed_site = span_data_table.insert_full(mixed_site).0; diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs index 99cdbd930e1c..11fd7596f2b5 100644 --- a/crates/proc-macro-api/src/msg/flat.rs +++ b/crates/proc-macro-api/src/msg/flat.rs @@ -37,7 +37,6 @@ use std::collections::VecDeque; -use indexmap::IndexSet; use la_arena::RawIdx; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -46,7 +45,8 @@ use text_size::TextRange; use crate::msg::ENCODE_CLOSE_SPAN_VERSION; -pub type SpanDataIndexMap = IndexSet; +pub type SpanDataIndexMap = + indexmap::IndexSet>; pub fn serialize_span_data_index_map(map: &SpanDataIndexMap) -> Vec { map.iter() @@ -328,7 +328,7 @@ impl InternableSpan for TokenId { } } impl InternableSpan for Span { - type Table = IndexSet; + type Table = SpanDataIndexMap; fn token_id_of(table: &mut Self::Table, span: Self) -> TokenId { TokenId(table.insert_full(span).0 as u32) } diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 1c37082bb29c..3a1a4cfa131b 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -7,7 +7,6 @@ use std::{ }; use paths::AbsPath; -use rustc_hash::FxHashMap; use stdx::JodChild; use crate::{ @@ -36,10 +35,11 @@ struct ProcessSrvState { impl ProcMacroProcessSrv { pub(crate) fn run( process_path: &AbsPath, - env: &FxHashMap, + env: impl IntoIterator, impl AsRef)> + + Clone, ) -> io::Result { let create_srv = |null_stderr| { - let mut process = Process::run(process_path, env, null_stderr)?; + let mut process = Process::run(process_path, env.clone(), null_stderr)?; let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { @@ -158,7 +158,7 @@ struct Process { impl Process { fn run( path: &AbsPath, - env: &FxHashMap, + env: impl IntoIterator, impl AsRef)>, null_stderr: bool, ) -> io::Result { let child = JodChild(mk_child(path, env, null_stderr)?); @@ -176,7 +176,7 @@ impl Process { fn mk_child( path: &AbsPath, - env: &FxHashMap, + env: impl IntoIterator, impl AsRef)>, null_stderr: bool, ) -> io::Result { let mut cmd = Command::new(path); diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index f6f6fdc864b7..407c1969cbd7 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -8,8 +8,6 @@ extern crate rustc_driver as _; use std::io; -use proc_macro_api::msg::ServerConfig; - fn main() -> std::io::Result<()> { let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); match v.as_deref() { @@ -48,7 +46,9 @@ fn run() -> io::Result<()> { msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION) } msg::Request::SetConfig(_) => { - msg::Response::SetConfig(ServerConfig { span_mode: msg::SpanMode::Id }) + msg::Response::SetConfig(proc_macro_api::msg::ServerConfig { + span_mode: msg::SpanMode::Id, + }) } }; write_response(res)? diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index bd0f733ef390..7b9a10fdb8c0 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -529,7 +529,7 @@ impl GlobalState { None => ws.find_sysroot_proc_macro_srv()?, }; - let env = match &ws.kind { + let env: FxHashMap<_, _> = match &ws.kind { ProjectWorkspaceKind::Cargo { cargo_config_extra_env, .. } | ProjectWorkspaceKind::DetachedFile { cargo: Some(_), From c236190b60c4e9e35149ac99088b0107b30723ab Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 16:54:31 +0200 Subject: [PATCH 10/11] Abstract proc-macro-srv protocol format --- crates/proc-macro-api/src/json.rs | 34 ++++++++++++++++++++ crates/proc-macro-api/src/lib.rs | 1 + crates/proc-macro-api/src/msg.rs | 46 ++++++++------------------- crates/proc-macro-api/src/process.rs | 5 +-- crates/proc-macro-srv-cli/src/main.rs | 12 ++++--- crates/proc-macro-srv/src/dylib.rs | 1 + 6 files changed, 60 insertions(+), 39 deletions(-) create mode 100644 crates/proc-macro-api/src/json.rs diff --git a/crates/proc-macro-api/src/json.rs b/crates/proc-macro-api/src/json.rs new file mode 100644 index 000000000000..415845c0bdc7 --- /dev/null +++ b/crates/proc-macro-api/src/json.rs @@ -0,0 +1,34 @@ +use std::io::{self, BufRead, Write}; + +pub fn read_json<'a>( + inp: &mut impl BufRead, + buf: &'a mut String, +) -> io::Result> { + loop { + buf.clear(); + + inp.read_line(buf)?; + buf.pop(); // Remove trailing '\n' + + if buf.is_empty() { + return Ok(None); + } + + // Some ill behaved macro try to use stdout for debugging + // We ignore it here + if !buf.starts_with('{') { + tracing::error!("proc-macro tried to print : {}", buf); + continue; + } + + return Ok(Some(buf)); + } +} + +pub fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { + tracing::debug!("> {}", msg); + out.write_all(msg.as_bytes())?; + out.write_all(b"\n")?; + out.flush()?; + Ok(()) +} diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index f21411bc8143..d7f49013aee1 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -5,6 +5,7 @@ //! is used to provide basic infrastructure for communication between two //! processes: Client (RA itself), Server (the external program) +pub mod json; pub mod msg; mod process; diff --git a/crates/proc-macro-api/src/msg.rs b/crates/proc-macro-api/src/msg.rs index 49ebedba7ddf..fa3ba9bbfcd7 100644 --- a/crates/proc-macro-api/src/msg.rs +++ b/crates/proc-macro-api/src/msg.rs @@ -122,8 +122,12 @@ impl ExpnGlobals { } pub trait Message: Serialize + DeserializeOwned { - fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result> { - Ok(match read_json(inp, buf)? { + fn read( + from_proto: ProtocolRead, + inp: &mut R, + buf: &mut String, + ) -> io::Result> { + Ok(match from_proto(inp, buf)? { None => None, Some(text) => { let mut deserializer = serde_json::Deserializer::from_str(text); @@ -134,44 +138,20 @@ pub trait Message: Serialize + DeserializeOwned { } }) } - fn write(self, out: &mut impl Write) -> io::Result<()> { + fn write(self, to_proto: ProtocolWrite, out: &mut W) -> io::Result<()> { let text = serde_json::to_string(&self)?; - write_json(out, &text) + to_proto(out, &text) } } impl Message for Request {} impl Message for Response {} -fn read_json<'a>(inp: &mut impl BufRead, buf: &'a mut String) -> io::Result> { - loop { - buf.clear(); - - inp.read_line(buf)?; - buf.pop(); // Remove trailing '\n' - - if buf.is_empty() { - return Ok(None); - } - - // Some ill behaved macro try to use stdout for debugging - // We ignore it here - if !buf.starts_with('{') { - tracing::error!("proc-macro tried to print : {}", buf); - continue; - } - - return Ok(Some(buf)); - } -} - -fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { - tracing::debug!("> {}", msg); - out.write_all(msg.as_bytes())?; - out.write_all(b"\n")?; - out.flush()?; - Ok(()) -} +#[allow(type_alias_bounds)] +type ProtocolRead = + for<'i, 'buf> fn(inp: &'i mut R, buf: &'buf mut String) -> io::Result>; +#[allow(type_alias_bounds)] +type ProtocolWrite = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) -> io::Result<()>; #[cfg(test)] mod tests { diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 3a1a4cfa131b..2b1a791827a7 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -10,6 +10,7 @@ use paths::AbsPath; use stdx::JodChild; use crate::{ + json::{read_json, write_json}, msg::{Message, Request, Response, SpanMode, CURRENT_API_VERSION, RUST_ANALYZER_SPAN_SUPPORT}, ProcMacroKind, ServerError, }; @@ -201,11 +202,11 @@ fn send_request( req: Request, buf: &mut String, ) -> Result { - req.write(&mut writer).map_err(|err| ServerError { + req.write(write_json, &mut writer).map_err(|err| ServerError { message: "failed to write request".into(), io: Some(Arc::new(err)), })?; - let res = Response::read(&mut reader, buf).map_err(|err| ServerError { + let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError { message: "failed to read response".into(), io: Some(Arc::new(err)), })?; diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 407c1969cbd7..174f9c524621 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -6,6 +6,8 @@ #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; +use proc_macro_api::json::{read_json, write_json}; + use std::io; fn main() -> std::io::Result<()> { @@ -30,9 +32,10 @@ fn run() -> io::Result<()> { eprintln!("{err}"); use proc_macro_api::msg::{self, Message}; - let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); + let read_request = + |buf: &mut String| msg::Request::read(read_json, &mut io::stdin().lock(), buf); - let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); + let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); let mut buf = String::new(); @@ -61,9 +64,10 @@ fn run() -> io::Result<()> { use proc_macro_api::msg::{self, Message}; use proc_macro_srv::EnvSnapshot; - let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); + let read_request = + |buf: &mut String| msg::Request::read(read_json, &mut io::stdin().lock(), buf); - let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); + let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); let env = EnvSnapshot::new(); let mut srv = proc_macro_srv::ProcMacroSrv::new(&env); diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index c2309cb3d116..78ae4574c409 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -142,6 +142,7 @@ impl Drop for Expander { fn drop(&mut self) { #[cfg(windows)] std::fs::remove_file(&self.path).ok(); + _ = self.path; } } From 956c8521a9fb0b4fe8e01ae0203223c024da552c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 30 Jun 2024 17:03:03 +0200 Subject: [PATCH 11/11] Arc proc-macro expander paths --- crates/proc-macro-api/src/json.rs | 1 + crates/proc-macro-api/src/lib.rs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-api/src/json.rs b/crates/proc-macro-api/src/json.rs index 415845c0bdc7..ec89f6a9e65d 100644 --- a/crates/proc-macro-api/src/json.rs +++ b/crates/proc-macro-api/src/json.rs @@ -1,3 +1,4 @@ +//! Protocol functions for json. use std::io::{self, BufRead, Write}; pub fn read_json<'a>( diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index d7f49013aee1..4c65dd5969cf 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -65,7 +65,7 @@ impl MacroDylib { #[derive(Debug, Clone)] pub struct ProcMacro { process: Arc, - dylib_path: AbsPathBuf, + dylib_path: Arc, name: SmolStr, kind: ProcMacroKind, } @@ -75,7 +75,7 @@ impl PartialEq for ProcMacro { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.kind == other.kind - && self.dylib_path == other.dylib_path + && Arc::ptr_eq(&self.dylib_path, &other.dylib_path) && Arc::ptr_eq(&self.process, &other.process) } } @@ -116,6 +116,7 @@ impl ProcMacroServer { let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered(); let macros = self.process.find_proc_macros(&dylib.path)?; + let dylib_path = Arc::new(dylib.path); match macros { Ok(macros) => Ok(macros .into_iter() @@ -123,7 +124,7 @@ impl ProcMacroServer { process: self.process.clone(), name: name.into(), kind, - dylib_path: dylib.path.clone(), + dylib_path: dylib_path.clone(), }) .collect()), Err(message) => Err(ServerError { message, io: None }),