Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions crates/proc-macro-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
use std::{fmt, io, sync::Arc, time::SystemTime};

pub use crate::codec::Codec;
use crate::{legacy_protocol::SpanMode, process::ProcMacroServerProcess};
use crate::process::ProcMacroServerProcess;

/// The versions of the server protocol
pub mod version {
Expand Down Expand Up @@ -126,11 +126,7 @@ impl ProcMacroClient {
Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
> + Clone,
) -> io::Result<ProcMacroClient> {
let process = ProcMacroServerProcess::run(
process_path,
env,
process::Protocol::Postcard { mode: SpanMode::Id },
)?;
let process = ProcMacroServerProcess::run(process_path, env)?;
Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() })
}

Expand Down
114 changes: 40 additions & 74 deletions crates/proc-macro-api/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ pub(crate) struct ProcMacroServerProcess {

#[derive(Debug, Clone)]
pub(crate) enum Protocol {
LegacyJson { mode: SpanMode },
Postcard { mode: SpanMode },
LegacyJson {
mode: SpanMode,
},
#[expect(dead_code)]
Postcard {
mode: SpanMode,
},
}

/// Maintains the state of the proc-macro server process.
Expand All @@ -49,82 +54,50 @@ impl ProcMacroServerProcess {
env: impl IntoIterator<
Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
> + Clone,
protocol: Protocol,
) -> io::Result<ProcMacroServerProcess> {
let mut srv = {
let mut process = match Process::run(process_path, env.clone(), &protocol) {
Ok(process) => process,
Err(e) => {
// fallback
if matches!(protocol, Protocol::Postcard { .. }) {
// retry with json
return Self::run(
process_path,
env,
Protocol::LegacyJson { mode: SpanMode::Id },
);
}
return Err(e);
}
};
let create_srv = || {
let mut process = Process::run(process_path, env.clone())?;
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");

ProcMacroServerProcess {
io::Result::Ok(ProcMacroServerProcess {
state: Mutex::new(ProcessSrvState { process, stdin, stdout }),
version: 0,
protocol: protocol.clone(),
protocol: Protocol::LegacyJson { mode: SpanMode::Id },
exited: OnceLock::new(),
}
})
};
let mut srv = create_srv()?;
tracing::info!("sending proc-macro server version check");
let version = match srv.version_check() {
Ok(v) => v,
Err(e) => {
if matches!(protocol, Protocol::Postcard { .. }) {
// retry with json
return Self::run(
process_path,
env,
Protocol::LegacyJson { mode: SpanMode::Id },
);
match srv.version_check() {
Ok(v) if v > version::CURRENT_API_VERSION => {
#[allow(clippy::disallowed_methods)]
let process_version = Command::new(process_path)
.arg("--version")
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_owned())
.unwrap_or_else(|_| "unknown version".to_owned());
Err(io::Error::other(format!(
"Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain.",
version::CURRENT_API_VERSION
)))
}
Ok(v) => {
tracing::info!("Proc-macro server version: {v}");
srv.version = v;
if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT
&& let Ok(mode) = srv.enable_rust_analyzer_spans()
{
srv.protocol = Protocol::LegacyJson { mode };
}

tracing::info!("Proc-macro server protocol: {:?}", srv.protocol);
Ok(srv)
}
Err(e) => {
tracing::info!(%e, "proc-macro version check failed");
return Err(io::Error::other(format!(
"proc-macro server version check failed: {e}"
)));
Err(io::Error::other(format!("proc-macro server version check failed: {e}")))
}
};

if version > version::CURRENT_API_VERSION {
#[allow(clippy::disallowed_methods)]
let process_version = Command::new(process_path)
.arg("--version")
.output()
.map(|out| String::from_utf8_lossy(&out.stdout).trim().to_owned())
.unwrap_or_else(|_| "unknown version".to_owned());

return Err(io::Error::other(format!(
"Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain.",
version::CURRENT_API_VERSION
)));
}

tracing::info!("proc-macro server version: {version}");

srv.version = version;

if version >= version::RUST_ANALYZER_SPAN_SUPPORT
&& let Ok(new_mode) = srv.enable_rust_analyzer_spans()
{
match &mut srv.protocol {
Protocol::Postcard { mode } | Protocol::LegacyJson { mode } => *mode = new_mode,
};
}

tracing::info!("proc-macro server protocol: {:?}", srv.protocol);
Ok(srv)
}

/// Returns the server error if the process has exited.
Expand Down Expand Up @@ -247,9 +220,8 @@ impl Process {
env: impl IntoIterator<
Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
>,
protocol: &Protocol,
) -> io::Result<Process> {
let child = JodChild(mk_child(path, env, protocol)?);
let child = JodChild(mk_child(path, env)?);
Ok(Process { child })
}

Expand All @@ -269,15 +241,9 @@ fn mk_child<'a>(
extra_env: impl IntoIterator<
Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
>,
protocol: &Protocol,
) -> io::Result<Child> {
#[allow(clippy::disallowed_methods)]
let mut cmd = Command::new(path);
if matches!(protocol, Protocol::LegacyJson { .. }) {
cmd.args(["--format", "json"]);
} else {
cmd.args(["--format", "postcard"]);
}
for env in extra_env {
match env {
(key, Some(val)) => cmd.env(key, val),
Expand Down
18 changes: 10 additions & 8 deletions crates/proc-macro-srv-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() -> std::io::Result<()> {
clap::Arg::new("format")
.long("format")
.action(clap::ArgAction::Set)
.default_value("json")
.default_value("json-legacy")
.value_parser(clap::builder::EnumValueParser::<ProtocolFormat>::new()),
clap::Arg::new("version")
.long("version")
Expand All @@ -50,25 +50,27 @@ fn main() -> std::io::Result<()> {

#[derive(Copy, Clone)]
enum ProtocolFormat {
Json,
Postcard,
JsonLegacy,
PostcardLegacy,
}

impl ValueEnum for ProtocolFormat {
fn value_variants<'a>() -> &'a [Self] {
&[ProtocolFormat::Json, ProtocolFormat::Postcard]
&[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy]
}

fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
match self {
ProtocolFormat::Json => Some(clap::builder::PossibleValue::new("json")),
ProtocolFormat::Postcard => Some(clap::builder::PossibleValue::new("postcard")),
ProtocolFormat::JsonLegacy => Some(clap::builder::PossibleValue::new("json-legacy")),
ProtocolFormat::PostcardLegacy => {
Some(clap::builder::PossibleValue::new("postcard-legacy"))
}
}
}
fn from_str(input: &str, _ignore_case: bool) -> Result<Self, String> {
match input {
"json" => Ok(ProtocolFormat::Json),
"postcard" => Ok(ProtocolFormat::Postcard),
"json-legacy" => Ok(ProtocolFormat::JsonLegacy),
"postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy),
_ => Err(format!("unknown protocol format: {input}")),
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/proc-macro-srv-cli/src/main_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ impl SpanTransformer for SpanTrans {

pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> {
match format {
ProtocolFormat::Json => run_::<JsonProtocol>(),
ProtocolFormat::Postcard => run_::<PostcardProtocol>(),
ProtocolFormat::JsonLegacy => run_::<JsonProtocol>(),
ProtocolFormat::PostcardLegacy => run_::<PostcardProtocol>(),
}
}

Expand Down