about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/proc-macro-srv-cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/proc-macro-srv-cli')
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs48
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs56
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs74
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs58
5 files changed, 217 insertions, 23 deletions
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
index ab421021b8b..91e9e62b084 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
@@ -14,10 +14,14 @@ publish = false
 proc-macro-srv.workspace = true
 proc-macro-api.workspace = true
 tt.workspace = true
+clap = {version = "4.5.42", default-features = false, features = ["std"]}
+postcard = { version = "1.1.3", optional = true }
 
 [features]
+default = ["postcard"]
 sysroot-abi = ["proc-macro-srv/sysroot-abi"]
 in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"]
+postcard = ["dep:postcard"]
 
 
 [[bin]]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs
index 07f914fece0..12e7c8b05ba 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs
@@ -1,5 +1,49 @@
-//! This teaches cargo about our cfg(rust_analyzer)
+//! Construct version in the `commit-hash date channel` format
+
+use std::{env, path::PathBuf, process::Command};
 
 fn main() {
-    println!("cargo:rustc-check-cfg=cfg(rust_analyzer)");
+    set_rerun();
+    set_commit_info();
+    println!("cargo::rustc-check-cfg=cfg(rust_analyzer)");
+}
+
+fn set_rerun() {
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
+
+    let mut manifest_dir = PathBuf::from(
+        env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
+    );
+
+    while manifest_dir.parent().is_some() {
+        let head_ref = manifest_dir.join(".git/HEAD");
+        if head_ref.exists() {
+            println!("cargo:rerun-if-changed={}", head_ref.display());
+            return;
+        }
+
+        manifest_dir.pop();
+    }
+
+    println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
+}
+
+fn set_commit_info() {
+    #[allow(clippy::disallowed_methods)]
+    let output = match Command::new("git")
+        .arg("log")
+        .arg("-1")
+        .arg("--date=short")
+        .arg("--format=%H %h %cd")
+        .output()
+    {
+        Ok(output) if output.status.success() => output,
+        _ => return,
+    };
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let mut parts = stdout.split_whitespace();
+    let mut next = || parts.next().unwrap();
+    println!("cargo:rustc-env=RA_COMMIT_HASH={}", next());
+    println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next());
+    println!("cargo:rustc-env=RA_COMMIT_DATE={}", next())
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
index c47ed053254..662d34865ef 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
@@ -2,13 +2,16 @@
 //! Driver for proc macro server
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 #![cfg_attr(not(feature = "sysroot-abi"), allow(unused_crate_dependencies))]
-#![allow(clippy::print_stderr)]
+#![allow(clippy::print_stdout, clippy::print_stderr)]
 
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_driver as _;
 
+mod version;
+
 #[cfg(any(feature = "sysroot-abi", rust_analyzer))]
 mod main_loop;
+use clap::{Command, ValueEnum};
 #[cfg(any(feature = "sysroot-abi", rust_analyzer))]
 use main_loop::run;
 
@@ -23,12 +26,59 @@ fn main() -> std::io::Result<()> {
         );
         std::process::exit(122);
     }
+    let matches = Command::new("proc-macro-srv")
+        .args(&[
+            clap::Arg::new("format")
+                .long("format")
+                .action(clap::ArgAction::Set)
+                .default_value("json")
+                .value_parser(clap::builder::EnumValueParser::<ProtocolFormat>::new()),
+            clap::Arg::new("version")
+                .long("version")
+                .action(clap::ArgAction::SetTrue)
+                .help("Prints the version of the proc-macro-srv"),
+        ])
+        .get_matches();
+    if matches.get_flag("version") {
+        println!("rust-analyzer-proc-macro-srv {}", version::version());
+        return Ok(());
+    }
+    let &format =
+        matches.get_one::<ProtocolFormat>("format").expect("format value should always be present");
+    run(format)
+}
+
+#[derive(Copy, Clone)]
+enum ProtocolFormat {
+    Json,
+    #[cfg(feature = "postcard")]
+    Postcard,
+}
 
-    run()
+impl ValueEnum for ProtocolFormat {
+    fn value_variants<'a>() -> &'a [Self] {
+        &[ProtocolFormat::Json]
+    }
+
+    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
+        match self {
+            ProtocolFormat::Json => Some(clap::builder::PossibleValue::new("json")),
+            #[cfg(feature = "postcard")]
+            ProtocolFormat::Postcard => Some(clap::builder::PossibleValue::new("postcard")),
+        }
+    }
+    fn from_str(input: &str, _ignore_case: bool) -> Result<Self, String> {
+        match input {
+            "json" => Ok(ProtocolFormat::Json),
+            #[cfg(feature = "postcard")]
+            "postcard" => Ok(ProtocolFormat::Postcard),
+            _ => Err(format!("unknown protocol format: {input}")),
+        }
+    }
 }
 
 #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
-fn run() -> std::io::Result<()> {
+fn run(_: ProtocolFormat) -> std::io::Result<()> {
     Err(std::io::Error::new(
         std::io::ErrorKind::Unsupported,
         "proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function"
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
index f54dff1f2d8..703bc965db2 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
@@ -1,16 +1,48 @@
 //! The main loop of the proc-macro server.
 use std::io;
 
-use proc_macro_api::legacy_protocol::{
-    json::{read_json, write_json},
-    msg::{
-        self, CURRENT_API_VERSION, ExpandMacroData, ExpnGlobals, Message, SpanMode, TokenId,
-        deserialize_span_data_index_map, serialize_span_data_index_map,
+use proc_macro_api::{
+    legacy_protocol::{
+        json::{read_json, write_json},
+        msg::{
+            self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer,
+            deserialize_span_data_index_map, serialize_span_data_index_map,
+        },
     },
+    version::CURRENT_API_VERSION,
 };
-use proc_macro_srv::EnvSnapshot;
+use proc_macro_srv::{EnvSnapshot, SpanId};
 
-pub(crate) fn run() -> io::Result<()> {
+use crate::ProtocolFormat;
+
+struct SpanTrans;
+
+impl SpanTransformer for SpanTrans {
+    type Table = ();
+    type Span = SpanId;
+    fn token_id_of(
+        _: &mut Self::Table,
+        span: Self::Span,
+    ) -> proc_macro_api::legacy_protocol::SpanId {
+        proc_macro_api::legacy_protocol::SpanId(span.0)
+    }
+    fn span_for_token_id(
+        _: &Self::Table,
+        id: proc_macro_api::legacy_protocol::SpanId,
+    ) -> Self::Span {
+        SpanId(id.0)
+    }
+}
+
+pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> {
+    match format {
+        ProtocolFormat::Json => run_json(),
+        #[cfg(feature = "postcard")]
+        ProtocolFormat::Postcard => unimplemented!(),
+    }
+}
+
+fn run_json() -> io::Result<()> {
     fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind {
         match kind {
             proc_macro_srv::ProcMacroKind::CustomDerive => {
@@ -54,19 +86,20 @@ pub(crate) fn run() -> io::Result<()> {
                 } = *task;
                 match span_mode {
                     SpanMode::Id => msg::Response::ExpandMacro({
-                        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 def_site = SpanId(def_site as u32);
+                        let call_site = SpanId(call_site as u32);
+                        let mixed_site = SpanId(mixed_site as u32);
 
-                        let macro_body = macro_body.to_subtree_unresolved(CURRENT_API_VERSION);
-                        let attributes =
-                            attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION));
+                        let macro_body =
+                            macro_body.to_subtree_unresolved::<SpanTrans>(CURRENT_API_VERSION);
+                        let attributes = attributes
+                            .map(|it| it.to_subtree_unresolved::<SpanTrans>(CURRENT_API_VERSION));
 
                         srv.expand(
                             lib,
-                            env,
+                            &env,
                             current_dir,
-                            macro_name,
+                            &macro_name,
                             macro_body,
                             attributes,
                             def_site,
@@ -74,8 +107,12 @@ pub(crate) fn run() -> io::Result<()> {
                             mixed_site,
                         )
                         .map(|it| {
-                            msg::FlatTree::new_raw(tt::SubtreeView::new(&it), CURRENT_API_VERSION)
+                            msg::FlatTree::new_raw::<SpanTrans>(
+                                tt::SubtreeView::new(&it),
+                                CURRENT_API_VERSION,
+                            )
                         })
+                        .map_err(|e| e.into_string().unwrap_or_default())
                         .map_err(msg::PanicMessage)
                     }),
                     SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({
@@ -92,9 +129,9 @@ pub(crate) fn run() -> io::Result<()> {
                         });
                         srv.expand(
                             lib,
-                            env,
+                            &env,
                             current_dir,
-                            macro_name,
+                            &macro_name,
                             macro_body,
                             attributes,
                             def_site,
@@ -115,6 +152,7 @@ pub(crate) fn run() -> io::Result<()> {
                             tree,
                             span_data_table,
                         })
+                        .map_err(|e| e.into_string().unwrap_or_default())
                         .map_err(msg::PanicMessage)
                     }),
                 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs
new file mode 100644
index 00000000000..32499d055d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs
@@ -0,0 +1,58 @@
+//! Code for representing rust-analyzer's release version number.
+#![expect(dead_code)]
+
+use std::fmt;
+
+/// Information about the git repository where rust-analyzer was built from.
+pub(crate) struct CommitInfo {
+    pub(crate) short_commit_hash: &'static str,
+    pub(crate) commit_hash: &'static str,
+    pub(crate) commit_date: &'static str,
+}
+
+/// Cargo's version.
+pub(crate) struct VersionInfo {
+    /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc.
+    pub(crate) version: &'static str,
+    /// The release channel we were built for (stable/beta/nightly/dev).
+    ///
+    /// `None` if not built via bootstrap.
+    pub(crate) release_channel: Option<&'static str>,
+    /// Information about the Git repository we may have been built from.
+    ///
+    /// `None` if not built from a git repo.
+    pub(crate) commit_info: Option<CommitInfo>,
+}
+
+impl fmt::Display for VersionInfo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.version)?;
+
+        if let Some(ci) = &self.commit_info {
+            write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
+        };
+        Ok(())
+    }
+}
+
+/// Returns information about cargo's version.
+pub(crate) const fn version() -> VersionInfo {
+    let version = match option_env!("CFG_RELEASE") {
+        Some(x) => x,
+        None => "0.0.0",
+    };
+
+    let release_channel = option_env!("CFG_RELEASE_CHANNEL");
+    let commit_info = match (
+        option_env!("RA_COMMIT_SHORT_HASH"),
+        option_env!("RA_COMMIT_HASH"),
+        option_env!("RA_COMMIT_DATE"),
+    ) {
+        (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => {
+            Some(CommitInfo { short_commit_hash, commit_hash, commit_date })
+        }
+        _ => None,
+    };
+
+    VersionInfo { version, release_channel, commit_info }
+}