From ca7dc69a8e87883c6a0c9df88c936fa2a4658c7b Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 13 Apr 2020 00:05:45 +0800 Subject: [PATCH] Add tests for proc_macro --- .github/workflows/ci.yaml | 4 + .../rust-analyzer/tests/heavy_tests/main.rs | 89 ++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 00f299ff182..13a11c95b0f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -85,6 +85,10 @@ jobs: - name: Compile run: cargo test --no-run + # We have to build ra_proc_macro_srv first for running related heavy tests + - name: Build ra_proc_macro_srv + run: cargo build -p ra_proc_macro_srv + - name: Test run: cargo test diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 63881331123..26ab81a8f6e 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -9,7 +9,7 @@ }; use rust_analyzer::req::{ CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, - Formatting, GotoDefinition, OnEnter, Runnables, RunnablesParams, + Formatting, GotoDefinition, HoverRequest, OnEnter, Runnables, RunnablesParams, }; use serde_json::json; use tempfile::TempDir; @@ -625,3 +625,90 @@ fn main() { )); assert!(format!("{}", res).contains("hello.rs")); } + +#[test] +fn resolve_proc_macro() { + if skip_slow_tests() { + return; + } + let server = Project::with_fixture( + r###" +//- foo/Cargo.toml +[package] +name = "foo" +version = "0.0.0" +edition = "2018" +[dependencies] +bar = {path = "../bar"} + +//- foo/src/main.rs +use bar::Bar; +trait Bar { + fn bar(); +} +#[derive(Bar)] +struct Foo {} +fn main() { + Foo::bar(); +} + +//- bar/Cargo.toml +[package] +name = "bar" +version = "0.0.0" +edition = "2018" + +[lib] +proc-macro = true + +//- bar/src/lib.rs +extern crate proc_macro; +use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +macro_rules! t { + ($n:literal) => { + TokenTree::from(Ident::new($n, Span::call_site())) + }; + ({}) => { + TokenTree::from(Group::new(Delimiter::Brace, TokenStream::new())) + }; + (()) => { + TokenTree::from(Group::new(Delimiter::Parenthesis, TokenStream::new())) + }; +} +#[proc_macro_derive(Bar)] +pub fn foo(_input: TokenStream) -> TokenStream { + // We hard code the output here for preventing to use any deps + let mut res = TokenStream::new(); + + // impl Bar for Foo { fn bar() {} } + let mut tokens = vec![t!("impl"), t!("Bar"), t!("for"), t!("Foo")]; + let mut fn_stream = TokenStream::new(); + fn_stream.extend(vec![t!("fn"), t!("bar"), t!(()), t!({})]); + tokens.push(Group::new(Delimiter::Brace, fn_stream).into()); + res.extend(tokens); + res +} + +"###, + ) + .with_config(|config| { + let macro_srv_path = std::path::Path::new(std::env!("CARGO_MANIFEST_DIR")) + .join("../../target/debug/ra_proc_macro_srv") + .to_string_lossy() + .to_string(); + + config.cargo.load_out_dirs_from_check = true; + config.proc_macro_srv = Some(macro_srv_path) + }) + .root("foo") + .root("bar") + .server(); + server.wait_until_workspace_is_loaded(); + let res = server.send_request::(TextDocumentPositionParams::new( + server.doc_id("foo/src/main.rs"), + Position::new(7, 9), + )); + + let value = res.get("contents").unwrap().get("value").unwrap().to_string(); + assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) +}