Repository: kythe/kythe
Pull request #5847 (2023-09-15 19:09:37)

feat(proto_indexer): link proto field names in signatures


Patch:
diff --git a/kythe/cxx/indexer/proto/BUILD b/kythe/cxx/indexer/proto/BUILD
index e5640652b..13912bd70 100644
--- a/kythe/cxx/indexer/proto/BUILD
+++ b/kythe/cxx/indexer/proto/BUILD
@@ -62,6 +62,7 @@ cc_library(
         "//kythe/proto:xref_cc_proto",
         "@com_google_absl//absl/container:flat_hash_map",
         "@com_google_absl//absl/container:node_hash_set",
+        "@com_google_absl//absl/functional:bind_front",
         "@com_google_absl//absl/log",
         "@com_google_absl//absl/log:check",
         "@com_google_absl//absl/status:statusor",
diff --git a/kythe/cxx/indexer/proto/file_descriptor_walker.cc b/kythe/cxx/indexer/proto/file_descriptor_walker.cc
index 054714909..bf58f09d1 100644
--- a/kythe/cxx/indexer/proto/file_descriptor_walker.cc
+++ b/kythe/cxx/indexer/proto/file_descriptor_walker.cc
@@ -18,6 +18,7 @@
 
 #include <optional>
 
+#include "absl/functional/bind_front.h"
 #include "absl/log/check.h"
 #include "absl/log/log.h"
 #include "absl/status/statusor.h"
@@ -438,7 +439,12 @@ void FileDescriptorWalker::VisitField(const std::string* parent_name,
                                 v_name, location);
   }
 
-  AttachMarkedSource(v_name, GenerateMarkedSourceForDescriptor(field));
+  AttachMarkedSource(
+      v_name,
+      GenerateMarkedSourceForDescriptor(
+          field, absl::bind_front(&ProtoGraphBuilder::VNameForDescriptor<
+                                      google::protobuf::FieldDescriptor>,
+                                  builder_)));
 
   // Check for [deprecated=true] annotations and emit deprecation tags.
   if (field->options().deprecated()) {
diff --git a/kythe/cxx/indexer/proto/marked_source.cc b/kythe/cxx/indexer/proto/marked_source.cc
index a21f7f024..c76b3e7d3 100644
--- a/kythe/cxx/indexer/proto/marked_source.cc
+++ b/kythe/cxx/indexer/proto/marked_source.cc
@@ -20,10 +20,12 @@
 
 #include "absl/strings/str_split.h"
 #include "google/protobuf/descriptor.h"
+#include "kythe/cxx/common/kythe_uri.h"
 
 namespace kythe {
 bool GenerateMarkedSourceForDottedName(absl::string_view name,
-                                       MarkedSource* root) {
+                                       MarkedSource* root,
+                                       std::optional<proto::VName> vname) {
   std::vector<absl::string_view> tokens = absl::StrSplit(name, '.');
   if (tokens.empty()) {
     return false;
@@ -31,11 +33,17 @@ bool GenerateMarkedSourceForDottedName(absl::string_view name,
   if (tokens.size() == 1) {
     root->set_kind(MarkedSource::IDENTIFIER);
     root->set_pre_text(std::string(tokens[0]));
+    if (vname) {
+      root->add_link()->add_definition(URI(*vname).ToString());
+    }
   } else {
     auto* context = root->add_child();
     auto* ident = root->add_child();
     ident->set_kind(MarkedSource::IDENTIFIER);
     ident->set_pre_text(std::string(tokens.back()));
+    if (vname) {
+      ident->add_link()->add_definition(URI(*vname).ToString());
+    }
     tokens.pop_back();
     context->set_kind(MarkedSource::CONTEXT);
     context->set_post_child_text(".");
@@ -127,7 +135,9 @@ std::optional<MarkedSource> GenerateMarkedSourceForType(
 }
 
 std::optional<MarkedSource> GenerateMarkedSourceForDescriptor(
-    const google::protobuf::FieldDescriptor* descriptor) {
+    const google::protobuf::FieldDescriptor* descriptor,
+    const std::function<proto::VName(const google::protobuf::FieldDescriptor*)>&
+        vname_for_desc) {
   std::string full_name;
   if (const google::protobuf::OneofDescriptor* oneof =
           descriptor->containing_oneof()) {
@@ -157,7 +167,8 @@ std::optional<MarkedSource> GenerateMarkedSourceForDescriptor(
           GenerateMarkedSourceForType(descriptor)) {
     *ms.add_child() = *t;
   }
-  if (GenerateMarkedSourceForDottedName(full_name, ms.add_child())) {
+  if (GenerateMarkedSourceForDottedName(full_name, ms.add_child(),
+                                        vname_for_desc(descriptor))) {
     return ms;
   }
   return std::nullopt;
diff --git a/kythe/cxx/indexer/proto/marked_source.h b/kythe/cxx/indexer/proto/marked_source.h
index 4cac4a4a2..1e0fc83b0 100644
--- a/kythe/cxx/indexer/proto/marked_source.h
+++ b/kythe/cxx/indexer/proto/marked_source.h
@@ -27,9 +27,11 @@ namespace kythe {
 // `name` is a proto-style dotted qualified name
 // `root` is the node to turn into a (box (context) (identifier)) or an
 // identifier, depending on the structure of `name`.
+// If given a vname, it will be added as a definition for the identifier.
 // Returns true if at least one token was found.
-bool GenerateMarkedSourceForDottedName(absl::string_view name,
-                                       MarkedSource* root);
+bool GenerateMarkedSourceForDottedName(
+    absl::string_view name, MarkedSource* root,
+    std::optional<proto::VName> vname = std::nullopt);
 
 // Given a proto descriptor, generates an appropriate code fact. Returns
 // `None` if a code fact couldn't be generated.
@@ -53,7 +55,9 @@ std::optional<MarkedSource> GenerateMarkedSourceForDescriptor(
     const google::protobuf::EnumValueDescriptor* descriptor);
 
 std::optional<MarkedSource> GenerateMarkedSourceForDescriptor(
-    const google::protobuf::FieldDescriptor* descriptor);
+    const google::protobuf::FieldDescriptor* descriptor,
+    const std::function<proto::VName(const google::protobuf::FieldDescriptor*)>&
+        vname_for_desc);
 
 std::optional<MarkedSource> GenerateMarkedSourceForDescriptor(
     const google::protobuf::ServiceDescriptor* descriptor);


Test patch:
diff --git a/kythe/cxx/indexer/proto/testdata/basic/message-fields.proto b/kythe/cxx/indexer/proto/testdata/basic/message-fields.proto
index 11fe0fb0e..7a5816ade 100644
--- a/kythe/cxx/indexer/proto/testdata/basic/message-fields.proto
+++ b/kythe/cxx/indexer/proto/testdata/basic/message-fields.proto
@@ -24,6 +24,7 @@ message MessageFields {
   //- FNName child.1 FNIdent
   //- FNIdent.pre_text field_name
   //- FNIdent.kind "IDENTIFIER"
+  //- FNIdent link FieldNameNode
   //- FNQualName.kind "CONTEXT"
   //- FNQualName.post_child_text "."
   //- FNQualName.add_final_list_token true