Emit IR items and comments in a stable order. The order primarily follows `Decl` source ordering, and is somewhat arbitrary for implicit declarations.

This is in preparation of changing the AST visitation order.

PiperOrigin-RevId: 423827220
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index 10344bc..219c243 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <tuple>
 #include <utility>
 #include <variant>
 #include <vector>
@@ -99,7 +100,7 @@
 
   // Skip declarations that we've already seen, except for namespaces, which
   // can and typically will contain new declarations when they are "reopened".
-  if (!seen_decls_.insert(decl->getCanonicalDecl()).second &&
+  if (seen_decls_.contains(decl->getCanonicalDecl()) &&
       !clang::isa<clang::NamespaceDecl>(decl)) {
     return true;
   }
@@ -135,9 +136,64 @@
   // Emit comments after the last decl
   comment_manager_.FlushComments();
 
+  EmitIRItems();
+
   return result;
 }
 
+void AstVisitor::EmitIRItems() {
+  std::vector<std::tuple<clang::SourceLocation, int, IR::Item>> items;
+
+  // We emit IR items in the order of the decls they were generated for.
+  // For decls that emit multiple items we use a stable, but arbitrary order.
+
+  for (const auto& [decl, decl_items] : seen_decls_) {
+    for (const auto& decl_item : decl_items) {
+      int local_order;
+
+      if (clang::isa<clang::RecordDecl>(decl)) {
+        local_order = decl->getDeclContext()->isRecord() ? 1 : 0;
+      } else if (auto ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
+        local_order = ctor->isDefaultConstructor() ? 2
+                      : ctor->isCopyConstructor()  ? 3
+                      : ctor->isMoveConstructor()  ? 4
+                                                   : 5;
+      } else if (clang::isa<clang::CXXDestructorDecl>(decl)) {
+        local_order = 6;
+      } else {
+        local_order = 7;
+      }
+
+      items.push_back(
+          std::make_tuple(decl->getBeginLoc(), local_order, decl_item));
+    }
+  }
+
+  clang::SourceManager& sm = ctx_->getSourceManager();
+  for (auto comment : comment_manager_.comments()) {
+    items.push_back(std::make_tuple(
+        comment->getBeginLoc(), 0,
+        Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())}));
+  }
+
+  std::stable_sort(items.begin(), items.end(),
+                   [&](const auto& a, const auto& b) {
+                     auto aloc = std::get<0>(a);
+                     auto bloc = std::get<0>(b);
+
+                     if (!aloc.isValid() || !bloc.isValid()) {
+                       return !aloc.isValid() && bloc.isValid();
+                     }
+
+                     return sm.isBeforeInTranslationUnit(aloc, bloc) ||
+                            (aloc == bloc && std::get<1>(a) < std::get<1>(b));
+                   });
+
+  for (const auto& item : items) {
+    ir_.items.push_back(std::get<2>(item));
+  }
+}
+
 bool AstVisitor::VisitFunctionDecl(clang::FunctionDecl* function_decl) {
   if (!IsFromCurrentTarget(function_decl)) return true;
   if (function_decl->isDeleted()) return true;
@@ -304,7 +360,7 @@
   std::optional<UnqualifiedIdentifier> translated_name =
       GetTranslatedName(function_decl);
   if (success && translated_name.has_value()) {
-    ir_.items.push_back(Func{
+    seen_decls_[function_decl->getCanonicalDecl()].push_back(Func{
         .name = *translated_name,
         .owning_target = GetOwningTarget(function_decl),
         .doc_comment = GetComment(function_decl),
@@ -414,7 +470,7 @@
     return true;
   }
   const clang::ASTRecordLayout& layout = ctx_->getASTRecordLayout(record_decl);
-  ir_.items.push_back(
+  seen_decls_[record_decl->getCanonicalDecl()].push_back(
       Record{.identifier = *record_name,
              .id = GenerateDeclId(record_decl),
              .owning_target = GetOwningTarget(record_decl),
@@ -462,7 +518,7 @@
       ConvertType(typedef_name_decl->getUnderlyingType());
   if (underlying_type.ok()) {
     known_type_decls_.insert(typedef_name_decl);
-    ir_.items.push_back(
+    seen_decls_[typedef_name_decl->getCanonicalDecl()].push_back(
         TypeAlias{.identifier = *identifier,
                   .id = GenerateDeclId(typedef_name_decl),
                   .owning_target = GetOwningTarget(typedef_name_decl),
@@ -499,7 +555,7 @@
   if (const auto* named_decl = llvm::dyn_cast<clang::NamedDecl>(decl)) {
     name = named_decl->getQualifiedNameAsString();
   }
-  ir_.items.push_back(UnsupportedItem{
+  seen_decls_[decl->getCanonicalDecl()].push_back(UnsupportedItem{
       .name = std::move(name),
       .message = std::move(message),
       .source_loc = ConvertSourceLocation(std::move(source_location))});
@@ -589,7 +645,7 @@
           }
         }
     }
-  } else if (const auto *tag_type =
+  } else if (const auto* tag_type =
                  qual_type->getAsAdjusted<clang::TagType>()) {
     clang::TagDecl* tag_decl = tag_type->getDecl();
 
@@ -600,7 +656,7 @@
         type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
       }
     }
-  } else if (const auto *typedef_type =
+  } else if (const auto* typedef_type =
                  qual_type->getAsAdjusted<clang::TypedefType>()) {
     clang::TypedefNameDecl* typedef_name_decl = typedef_type->getDecl();
 
@@ -791,10 +847,8 @@
 }
 
 void AstVisitor::CommentManager::VisitTopLevelComment(
-    clang::RawComment* comment) {
-  clang::SourceManager& sm = ctx_->getSourceManager();
-  ir_.items.push_back(
-      Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())});
+    const clang::RawComment* comment) {
+  comments_.push_back(comment);
 }
 
 }  // namespace rs_bindings_from_cc