Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Procedural macros are implemented by compiling the macro providing crate
//! to a dynamic library with a particular ABI which the compiler uses to expand
//! macros. Unfortunately this ABI is not specified and can change from version
//! to version of the compiler. To support this we copy the ABI from the rust
//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47).
//!
//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple
//! interface the rest of rust analyzer can use to talk to the macro
//! provider.
//!
//! # Adding a new ABI
//!
//! To add a new ABI you'll need to copy the source of the target proc_macro
//! crate from the source tree of the Rust compiler into this directory tree.
//! Then you'll need to modify it
//! - Remove any feature! or other things which won't compile on stable
//! - change any absolute imports to relative imports within the ABI tree
//!
//! Then you'll need to add a branch to the `Abi` enum and an implementation of
//! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See
//! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll
//! need to update the conditionals in `Abi::from_lib` to return your new ABI
//! for the relevant versions of the rust compiler
//!

// pub(crate) so tests can use the TokenStream, more notes in test/utils.rs
pub(crate) mod abi_1_48;
mod abi_1_54;
mod abi_1_56;
mod abi_1_57;
mod abi_1_58;
mod abi_1_63;

use super::dylib::LoadProcMacroDylibError;
pub(crate) use abi_1_48::Abi as Abi_1_48;
pub(crate) use abi_1_54::Abi as Abi_1_54;
pub(crate) use abi_1_56::Abi as Abi_1_56;
pub(crate) use abi_1_57::Abi as Abi_1_57;
pub(crate) use abi_1_58::Abi as Abi_1_58;
pub(crate) use abi_1_63::Abi as Abi_1_63;
use libloading::Library;
use proc_macro_api::{ProcMacroKind, RustCInfo};

pub struct PanicMessage {
    message: Option<String>,
}

impl PanicMessage {
    pub fn as_str(&self) -> Option<String> {
        self.message.clone()
    }
}

pub(crate) enum Abi {
    Abi1_48(Abi_1_48),
    Abi1_54(Abi_1_54),
    Abi1_56(Abi_1_56),
    Abi1_57(Abi_1_57),
    Abi1_58(Abi_1_58),
    Abi1_63(Abi_1_63),
}

impl Abi {
    /// Load a new ABI.
    ///
    /// # Arguments
    ///
    /// *`lib` - The dynamic library containing the macro implementations
    /// *`symbol_name` - The symbol name the macros can be found attributes
    /// *`info` - RustCInfo about the compiler that was used to compile the
    ///           macro crate. This is the information we use to figure out
    ///           which ABI to return
    pub fn from_lib(
        lib: &Library,
        symbol_name: String,
        info: RustCInfo,
    ) -> Result<Abi, LoadProcMacroDylibError> {
        // FIXME: this should use exclusive ranges when they're stable
        // https://github.com/rust-lang/rust/issues/37854
        match (info.version.0, info.version.1) {
            (1, 48..=53) => {
                let inner = unsafe { Abi_1_48::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_48(inner))
            }
            (1, 54..=55) => {
                let inner = unsafe { Abi_1_54::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_54(inner))
            }
            (1, 56) => {
                let inner = unsafe { Abi_1_56::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_56(inner))
            }
            (1, 57) => {
                let inner = unsafe { Abi_1_57::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_57(inner))
            }
            (1, 58..=62) => {
                let inner = unsafe { Abi_1_58::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_58(inner))
            }
            (1, 63..) => {
                let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?;
                Ok(Abi::Abi1_63(inner))
            }
            _ => Err(LoadProcMacroDylibError::UnsupportedABI),
        }
    }

    pub fn expand(
        &self,
        macro_name: &str,
        macro_body: &tt::Subtree,
        attributes: Option<&tt::Subtree>,
    ) -> Result<tt::Subtree, PanicMessage> {
        match self {
            Self::Abi1_48(abi) => abi.expand(macro_name, macro_body, attributes),
            Self::Abi1_54(abi) => abi.expand(macro_name, macro_body, attributes),
            Self::Abi1_56(abi) => abi.expand(macro_name, macro_body, attributes),
            Self::Abi1_57(abi) => abi.expand(macro_name, macro_body, attributes),
            Self::Abi1_58(abi) => abi.expand(macro_name, macro_body, attributes),
            Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes),
        }
    }

    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
        match self {
            Self::Abi1_48(abi) => abi.list_macros(),
            Self::Abi1_54(abi) => abi.list_macros(),
            Self::Abi1_56(abi) => abi.list_macros(),
            Self::Abi1_57(abi) => abi.list_macros(),
            Self::Abi1_58(abi) => abi.list_macros(),
            Self::Abi1_63(abi) => abi.list_macros(),
        }
    }
}