Deduplicate handling of TagType and TypedefType in Importer::ConvertType

PiperOrigin-RevId: 433261074
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 655507a..dbd0d0b 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -939,6 +939,24 @@
                    .column = sm.getSpellingColumnNumber(loc)};
 }
 
+absl::StatusOr<MappedType> Importer::ConvertTypeDecl(
+    const clang::TypeDecl* decl) const {
+  if (!known_type_decls_.contains(decl)) {
+    return absl::NotFoundError(absl::Substitute(
+        "No generated bindings found for '$0'", decl->getNameAsString()));
+  }
+
+  std::optional<Identifier> id = GetTranslatedIdentifier(decl);
+  if (!id.has_value()) {
+    return absl::UnimplementedError(absl::Substitute(
+        "Cannot translate name of '$0'", decl->getNameAsString()));
+  }
+
+  std::string ident(id->Ident());
+  DeclId decl_id = GenerateDeclId(decl);
+  return MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
+}
+
 absl::StatusOr<MappedType> Importer::ConvertType(
     const clang::Type* type,
     std::optional<devtools_rust::TypeLifetimes>& lifetimes,
@@ -1032,38 +1050,10 @@
         }
     }
   } else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) {
-    clang::TagDecl* tag_decl = tag_type->getDecl();
-
-    // TODO(lukasza): Rather than falling back to `absl::UnimplementedError` at
-    // the bottom of this method, we should explicitly emit an error when
-    // `tag_decl` is missing from `known_type_decls` or can't be handled by
-    // GetTranslatedIdentifier. See also a corresponding TODO in
-    // `test_record_with_unsupported_field`.
-    if (known_type_decls_.contains(tag_decl)) {
-      if (std::optional<Identifier> id = GetTranslatedIdentifier(tag_decl)) {
-        std::string ident(id->Ident());
-        DeclId decl_id = GenerateDeclId(tag_decl);
-        return MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
-      }
-    }
+    return ConvertTypeDecl(tag_type->getDecl());
   } else if (const auto* typedef_type =
                  type->getAsAdjusted<clang::TypedefType>()) {
-    clang::TypedefNameDecl* typedef_name_decl = typedef_type->getDecl();
-
-    // TODO(lukasza): Rather than falling back to `absl::UnimplementedError` at
-    // the bottom of this method, we should explicitly emit an error when
-    // `typedef_name_decl` is missing from `known_type_decls` or can't be
-    // handled by GetTranslatedIdentifier. See also a corresponding TODO in
-    // `test_record_with_unsupported_field`.
-    // TODO(lukasza): Consider merging with `TagType` handling above.
-    if (known_type_decls_.contains(typedef_name_decl)) {
-      if (std::optional<Identifier> id =
-              GetTranslatedIdentifier(typedef_name_decl)) {
-        std::string ident(id->Ident());
-        DeclId decl_id = GenerateDeclId(typedef_name_decl);
-        return MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
-      }
-    }
+    return ConvertTypeDecl(typedef_type->getDecl());
   }
 
   return absl::UnimplementedError(absl::StrCat(
diff --git a/rs_bindings_from_cc/importer.h b/rs_bindings_from_cc/importer.h
index 686d000..788ccf6 100644
--- a/rs_bindings_from_cc/importer.h
+++ b/rs_bindings_from_cc/importer.h
@@ -179,6 +179,7 @@
       const clang::Type* type,
       std::optional<devtools_rust::TypeLifetimes>& lifetimes,
       bool nullable) const;
+  absl::StatusOr<MappedType> ConvertTypeDecl(const clang::TypeDecl* decl) const;
 
   SourceLoc ConvertSourceLocation(clang::SourceLocation loc) const;
 
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 80f0312..fa91dab 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -743,15 +743,12 @@
         };
     "#,
     )?;
-    // TODO(lukasza): Fix the error message below - saying that clang::Type
-    // class 'Record' is unsupported is incorrect (see also a corresponding
-    // TODO in Importer::ConvertType).
     assert_ir_matches!(
         ir,
         quote! {
               UnsupportedItem(UnsupportedItem {
                 name: "StructWithUnsupportedField",
-                message: "UNIMPLEMENTED: Type of field 'my_field' is not supported: Unsupported type 'union MyUnion': Unsupported clang::Type class 'Record'",
+                message: "UNIMPLEMENTED: Type of field 'my_field' is not supported: Unsupported type 'union MyUnion': No generated bindings found for 'MyUnion'",
                 ...
             })
         }
diff --git a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
index 55d7f5d..a09f066 100644
--- a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
@@ -17,7 +17,7 @@
 
 // rs_bindings_from_cc/test/golden/user_of_unsupported.h;l=10
 // Error while generating bindings for item 'UseUnsupportedType':
-// Parameter #0 is not supported: Unsupported type 'ns::StructInNamespace *': Unsupported type 'ns::StructInNamespace': Unsupported clang::Type class 'Elaborated'
+// Parameter #0 is not supported: Unsupported type 'ns::StructInNamespace *': Unsupported type 'ns::StructInNamespace': No generated bindings found for 'StructInNamespace'
 
 // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_USER_OF_UNSUPPORTED_H_