Fixed use of rust-analyzer with rust_static_library and rust_shared_library (#1482)

diff --git a/examples/WORKSPACE.bazel b/examples/WORKSPACE.bazel
index 005d052..ad29a83 100644
--- a/examples/WORKSPACE.bazel
+++ b/examples/WORKSPACE.bazel
@@ -16,6 +16,10 @@
     edition = "2018",
 )
 
+load("@rules_rust//tools/rust_analyzer:deps.bzl", "rust_analyzer_dependencies")
+
+rust_analyzer_dependencies()
+
 load("@rules_rust//bindgen:repositories.bzl", "rust_bindgen_dependencies", "rust_bindgen_register_toolchains")
 
 rust_bindgen_dependencies()
diff --git a/rust/private/rust_analyzer.bzl b/rust/private/rust_analyzer.bzl
index 8408197..48582b3 100644
--- a/rust/private/rust_analyzer.bzl
+++ b/rust/private/rust_analyzer.bzl
@@ -39,7 +39,7 @@
 )
 
 def _rust_analyzer_aspect_impl(target, ctx):
-    if rust_common.crate_info not in target:
+    if rust_common.crate_info not in target and rust_common.test_crate_info not in target:
         return []
 
     toolchain = find_toolchain(ctx)
@@ -70,7 +70,12 @@
 
     crate_spec = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_crate_spec")
 
-    crate_info = target[rust_common.crate_info]
+    if rust_common.crate_info in target:
+        crate_info = target[rust_common.crate_info]
+    elif rust_common.test_crate_info in target:
+        crate_info = target[rust_common.test_crate_info].crate
+    else:
+        fail("Unexpected target type: {}".format(target))
 
     rust_analyzer_info = RustAnalyzerInfo(
         crate = crate_info,
@@ -101,7 +106,14 @@
     Returns:
         (path): The path to the proc macro dylib, or None if this crate is not a proc-macro.
     """
-    if target[rust_common.crate_info].type != "proc-macro":
+    if rust_common.crate_info in target:
+        crate_info = target[rust_common.crate_info]
+    elif rust_common.test_crate_info in target:
+        crate_info = target[rust_common.test_crate_info].crate
+    else:
+        return None
+
+    if crate_info.type != "proc-macro":
         return None
 
     dylib_ext = system_to_dylib_ext(triple_to_system(toolchain.target_triple))
diff --git a/test/rust_analyzer/rust_analyzer_test_runner.sh b/test/rust_analyzer/rust_analyzer_test_runner.sh
index 781fd34..1696506 100755
--- a/test/rust_analyzer/rust_analyzer_test_runner.sh
+++ b/test/rust_analyzer/rust_analyzer_test_runner.sh
@@ -21,7 +21,7 @@
     local new_workspace="${temp_dir}/rules_rust_test_rust_analyzer"
 
     mkdir -p "${new_workspace}"
-    cat << EOF > "${new_workspace}/WORKSPACE.bazel"
+    cat <<EOF >"${new_workspace}/WORKSPACE.bazel"
 workspace(name = "rules_rust_test_rust_analyzer")
 local_repository(
     name = "rules_rust",
@@ -33,7 +33,7 @@
 rust_analyzer_dependencies()
 EOF
 
-cat << EOF > "${new_workspace}/.bazelrc"
+    cat <<EOF >"${new_workspace}/.bazelrc"
 build --keep_going
 test --test_output=errors
 # The 'strict' config is used to ensure extra checks are run on the test
@@ -45,17 +45,18 @@
 build:strict --output_groups=+clippy_checks
 EOF
 
-  echo "${new_workspace}"
+    echo "${new_workspace}"
 }
 
 function rust_analyzer_test() {
     local source_dir="$1"
     local workspace="$2"
-    
+    local generator_arg="$3"
+
     echo "Testing '$(basename "${source_dir}")'"
-    rm -f "${workspace}"/*.rs "${workspace}"/*.json "${workspace}/BUILD.bazel"
+    rm -f "${workspace}"/*.rs "${workspace}"/*.json "${workspace}"/*.bzl "${workspace}/BUILD.bazel" "${workspace}/BUILD.bazel-e"
     cp -r "${source_dir}"/* "${workspace}"
-    
+
     # Drop the 'manual' tags
     if [ "$(uname)" == "Darwin" ]; then
         SEDOPTS=(-i '' -e)
@@ -63,17 +64,29 @@
         SEDOPTS=(-i)
     fi
     sed ${SEDOPTS[@]} 's/"manual"//' "${workspace}/BUILD.bazel"
-    
-    pushd "${workspace}" &> /dev/null
+
+    pushd "${workspace}" &>/dev/null
     echo "Generating rust-project.json..."
-    bazel run "@rules_rust//tools/rust_analyzer:gen_rust_project" -- //:mylib_test
+    if [[ -n "${generator_arg}" ]]; then
+        bazel run "@rules_rust//tools/rust_analyzer:gen_rust_project" -- "${generator_arg}"
+    else
+        bazel run "@rules_rust//tools/rust_analyzer:gen_rust_project"
+    fi
     echo "Building..."
     bazel build //...
     echo "Testing..."
     bazel test //...
     echo "Building with Aspects..."
     bazel build //... --config=strict
-    popd &> /dev/null
+    popd &>/dev/null
+}
+
+function cleanup() {
+    local workspace="$1"
+    pushd "${workspace}" &>/dev/null
+    bazel clean --async
+    popd &>/dev/null
+    rm -rf "${workspace}"
 }
 
 function run_test_suite() {
@@ -86,10 +99,20 @@
             continue
         fi
 
-        rust_analyzer_test "${test_dir}" "${temp_workspace}"
+        # Some tests have arguments that need to be passed to the rust-project.json generator.
+        if [[ "${test_dir}" = "aspect_traversal_test" ]]; then
+            test_arg="//mylib_test"
+        elif [[ "${test_dir}" = "merging_crates_test" ]]; then
+            test_arg="//mylib_test"
+        else
+            test_arg=""
+        fi
+
+        rust_analyzer_test "${test_dir}" "${temp_workspace}" "${test_arg}"
     done
 
-    rm -rf "${temp_workspace}"
+    echo "Done"
+    cleanup "${temp_workspace}"
 }
 
 run_test_suite
diff --git a/test/rust_analyzer/static_and_shared_lib_test/BUILD.bazel b/test/rust_analyzer/static_and_shared_lib_test/BUILD.bazel
new file mode 100644
index 0000000..7efd036
--- /dev/null
+++ b/test/rust_analyzer/static_and_shared_lib_test/BUILD.bazel
@@ -0,0 +1,38 @@
+load(
+    "@rules_rust//rust:defs.bzl",
+    "rust_shared_library",
+    "rust_static_library",
+    "rust_test",
+)
+
+rust_shared_library(
+    name = "greeter_cdylib",
+    srcs = [
+        "greeter.rs",
+        "shared_lib.rs",
+    ],
+    crate_root = "shared_lib.rs",
+    edition = "2018",
+)
+
+rust_static_library(
+    name = "greeter_staticlib",
+    srcs = [
+        "greeter.rs",
+        "static_lib.rs",
+    ],
+    crate_root = "static_lib.rs",
+    edition = "2018",
+)
+
+rust_test(
+    name = "rust_project_json_test",
+    srcs = ["rust_project_json_test.rs"],
+    data = [":rust-project.json"],
+    edition = "2018",
+    env = {"RUST_PROJECT_JSON": "$(rootpath :rust-project.json)"},
+    # This target is tagged as manual since it's not expected to pass in
+    # contexts outside of `//test/rust_analyzer:rust_analyzer_test`. Run
+    # that target to execute this test.
+    tags = ["manual"],
+)
diff --git a/test/rust_analyzer/static_and_shared_lib_test/greeter.rs b/test/rust_analyzer/static_and_shared_lib_test/greeter.rs
new file mode 100644
index 0000000..ac87521
--- /dev/null
+++ b/test/rust_analyzer/static_and_shared_lib_test/greeter.rs
@@ -0,0 +1,61 @@
+/// Object that displays a greeting.
+pub struct Greeter {
+    greeting: String,
+}
+
+/// Implementation of Greeter.
+impl Greeter {
+    /// Constructs a new `Greeter`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hello_lib::greeter::Greeter;
+    ///
+    /// let greeter = Greeter::new("Hello");
+    /// ```
+    pub fn new(greeting: &str) -> Greeter {
+        Greeter {
+            greeting: greeting.to_string(),
+        }
+    }
+
+    /// Returns the greeting as a string.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hello_lib::greeter::Greeter;
+    ///
+    /// let greeter = Greeter::new("Hello");
+    /// let greeting = greeter.greeting("World");
+    /// ```
+    pub fn greeting(&self, thing: &str) -> String {
+        format!("{} {}", &self.greeting, thing)
+    }
+
+    /// Prints the greeting.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hello_lib::greeter::Greeter;
+    ///
+    /// let greeter = Greeter::new("Hello");
+    /// greeter.greet("World");
+    /// ```
+    pub fn greet(&self, thing: &str) {
+        println!("{} {}", &self.greeting, thing);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::Greeter;
+
+    #[test]
+    fn test_greeting() {
+        let hello = Greeter::new("Hi");
+        assert_eq!("Hi Rust", hello.greeting("Rust"));
+    }
+}
diff --git a/test/rust_analyzer/static_and_shared_lib_test/rust_project_json_test.rs b/test/rust_analyzer/static_and_shared_lib_test/rust_project_json_test.rs
new file mode 100644
index 0000000..fc573d6
--- /dev/null
+++ b/test/rust_analyzer/static_and_shared_lib_test/rust_project_json_test.rs
@@ -0,0 +1,22 @@
+#[cfg(test)]
+mod tests {
+    use std::env;
+    use std::path::PathBuf;
+
+    #[test]
+    fn test_deps_of_crate_and_its_test_are_merged() {
+        let rust_project_path = PathBuf::from(env::var("RUST_PROJECT_JSON").unwrap());
+
+        let content = std::fs::read_to_string(&rust_project_path)
+            .unwrap_or_else(|_| panic!("couldn't open {:?}", &rust_project_path));
+
+        assert!(
+            content.contains(r#"{"display_name":"greeter_cdylib","root_module":"shared_lib.rs"#),
+            "expected rust-project.json to contain a rust_shared_library target."
+        );
+        assert!(
+            content.contains(r#"{"display_name":"greeter_staticlib","root_module":"static_lib.rs"#),
+            "expected rust-project.json to contain a rust_static_library target."
+        );
+    }
+}
diff --git a/test/rust_analyzer/static_and_shared_lib_test/shared_lib.rs b/test/rust_analyzer/static_and_shared_lib_test/shared_lib.rs
new file mode 100644
index 0000000..44969c6
--- /dev/null
+++ b/test/rust_analyzer/static_and_shared_lib_test/shared_lib.rs
@@ -0,0 +1 @@
+pub mod greeter;
diff --git a/test/rust_analyzer/static_and_shared_lib_test/static_lib.rs b/test/rust_analyzer/static_and_shared_lib_test/static_lib.rs
new file mode 100644
index 0000000..44969c6
--- /dev/null
+++ b/test/rust_analyzer/static_and_shared_lib_test/static_lib.rs
@@ -0,0 +1 @@
+pub mod greeter;