Additional reference / lifetime related unit tests.

PiperOrigin-RevId: 539716074
diff --git a/cc_bindings_from_rs/bindings.rs b/cc_bindings_from_rs/bindings.rs
index a60d903..3936e8c 100644
--- a/cc_bindings_from_rs/bindings.rs
+++ b/cc_bindings_from_rs/bindings.rs
@@ -3136,7 +3136,7 @@
     }
 
     #[test]
-    fn test_format_item_unsupported_fn_with_late_bound_lifetimes() {
+    fn test_format_item_unsupported_lifetime_generic_fn() {
         // TODO(b/258235219): Expect success after adding support for references.
         let test_src = r#"
                 pub fn foo(arg: &i32) -> &i32 { arg }
@@ -3154,7 +3154,7 @@
     }
 
     #[test]
-    fn test_format_item_unsupported_generic_fn() {
+    fn test_format_item_unsupported_type_generic_fn() {
         let test_src = r#"
                 use std::default::Default;
                 use std::fmt::Display;
@@ -3169,7 +3169,7 @@
     }
 
     #[test]
-    fn test_format_item_unsupported_generic_struct() {
+    fn test_format_item_unsupported_type_generic_struct() {
         let test_src = r#"
                 pub struct Point<T> {
                     pub x: T,
@@ -3183,6 +3183,26 @@
     }
 
     #[test]
+    fn test_format_item_unsupported_lifetime_generic_struct() {
+        let test_src = r#"
+                pub struct Point<'a> {
+                    pub x: &'a i32,
+                    pub y: &'a i32,
+                }
+
+                impl<'a> Point<'a> {
+                    // Some lifetimes are bound at the `impl` / `struct` level (the lifetime is
+                    // hidden underneath the `Self` type), and some at the `fn` level.
+                    pub fn new<'b, 'c>(_x: &'b i32, _y: &'c i32) -> Self { unimplemented!() }
+                }
+            "#;
+        test_format_item(test_src, "Point", |result| {
+            let err = result.unwrap_err();
+            assert_eq!(err, "Generic types are not supported yet (b/259749095)");
+        });
+    }
+
+    #[test]
     fn test_format_item_unsupported_generic_enum() {
         let test_src = r#"
                 pub enum Point<T> {
@@ -4007,7 +4027,7 @@
     }
 
     #[test]
-    fn test_format_item_static_method_with_generic_lifetime_parameters() {
+    fn test_format_item_static_method_with_generic_lifetime_parameters_at_fn_level() {
         let test_src = r#"
                 /// No-op `f32` placeholder is used, because ZSTs are not supported
                 /// (b/258259459).
@@ -4044,6 +4064,43 @@
     }
 
     #[test]
+    fn test_format_item_static_method_with_generic_lifetime_parameters_at_impl_level() {
+        let test_src = r#"
+                /// No-op `f32` placeholder is used, because ZSTs are not supported
+                /// (b/258259459).
+                pub struct SomeStruct(f32);
+
+                impl<'a> SomeStruct {
+                    pub fn fn_taking_reference(x: &'a i32) -> i32 { *x }
+                }
+            "#;
+        test_format_item(test_src, "SomeStruct", |result| {
+            let result = result.unwrap().unwrap();
+            let main_api = &result.main_api;
+            let unsupported_msg = "Error generating bindings for `SomeStruct::fn_taking_reference` \
+                                   defined at <crubit_unittests.rs>;l=7: \
+                                   Generic functions are not supported yet (b/259749023)";
+            assert_cc_matches!(
+                main_api.tokens,
+                quote! {
+                    ...
+                    struct ... SomeStruct final {
+                        ...
+                        __COMMENT__ #unsupported_msg
+                        ...
+                    };
+                    ...
+                }
+            );
+            assert_cc_not_matches!(
+                result.cc_details.tokens,
+                quote! { SomeStruct::fn_taking_reference },
+            );
+            assert_rs_not_matches!(result.rs_details, quote! { fn_taking_reference },);
+        });
+    }
+
+    #[test]
     fn test_format_item_method_taking_self_by_value() {
         let test_src = r#"
                 pub struct SomeStruct(f32);
@@ -4353,6 +4410,43 @@
         });
     }
 
+    /// This test verifies how reference type fields are represented in the
+    /// generated bindings.  See b/286256327.
+    ///
+    /// In some of the past discussions we tentatively decided that the
+    /// generated bindings shouldn't use C++ references in fields - instead
+    /// a C++ pointer should be used.  One reason is that C++ references
+    /// cannot be assigned to (i.e. rebound), and therefore C++ pointers
+    /// more accurately represent the semantics of Rust fields.  The pointer
+    /// type should probably use some form of C++ annotations to mark it as
+    /// non-nullable.
+    #[test]
+    fn test_format_item_struct_with_unsupported_field_of_reference_type() {
+        let test_src = r#"
+                // `'static` lifetime can be used in a non-generic struct - this let's us
+                // test reference fieles without requiring support for generic structs.
+                pub struct NonGenericSomeStruct {
+                    pub reference_field: &'static i32,
+                }
+            "#;
+        test_format_item(test_src, "NonGenericSomeStruct", |result| {
+            let result = result.unwrap().unwrap();
+            let main_api = &result.main_api;
+            let broken_field_msg = "Field type has been replaced with a blob of bytes: \
+                                    The following Rust type is not supported yet: &'static i32";
+            assert_cc_matches!(
+                main_api.tokens,
+                quote! {
+                    ...
+                    private:
+                        __COMMENT__ #broken_field_msg
+                        unsigned char reference_field[8];
+                    ...
+                }
+            );
+        });
+    }
+
     #[test]
     fn test_format_item_unsupported_struct_with_custom_drop_impl() {
         let test_src = r#"
@@ -5184,10 +5278,22 @@
                 "Tuples are not supported yet: (i32, i32) (b/254099023)",
             ),
             (
-                "&'static i32", // TyKind::Ref
+                "&'static i32", // TyKind::Ref (const/shared reference)
                 "The following Rust type is not supported yet: &'static i32",
             ),
             (
+                "&'static mut i32", // TyKind::Ref (mutable/exclusive reference)
+                "The following Rust type is not supported yet: &'static mut i32",
+            ),
+            (
+                "&'static &'static i32", // TyKind::Ref (nested reference - referent of reference)
+                "The following Rust type is not supported yet: &'static &'static i32",
+            ),
+            (
+                "extern \"C\" fn (&i32)", // TyKind::Ref (nested reference - underneath fn ptr)
+                "Generic functions are not supported yet (b/259749023)",
+            ),
+            (
                 "[i32; 42]", // TyKind::Array
                 "The following Rust type is not supported yet: [i32; 42]",
             ),