From e79d8ee955b63bd1f0a1b12b894b61fdd0773108 Mon Sep 17 00:00:00 2001 From: Cody Schroeder Date: Fri, 28 Apr 2023 10:36:47 -0600 Subject: [PATCH] feat(go_indexer): support metadata semantic types (#5598) --- kythe/go/indexer/emit.go | 19 +++++---- kythe/go/indexer/testdata/meta.go | 11 +++++ kythe/go/indexer/testdata/meta.go.linkage | 14 +++++++ kythe/go/util/metadata/BUILD | 2 +- kythe/go/util/metadata/metadata.go | 51 +++++++++++++++-------- kythe/go/util/metadata/metadata_test.go | 31 ++++++++------ kythe/go/util/schema/facts/facts.go | 35 ++++++++-------- 7 files changed, 108 insertions(+), 55 deletions(-) diff --git a/kythe/go/indexer/emit.go b/kythe/go/indexer/emit.go index 1cfdd1e4fe..ce221a49ff 100644 --- a/kythe/go/indexer/emit.go +++ b/kythe/go/indexer/emit.go @@ -1114,19 +1114,18 @@ func (e *emitter) writeRef(origin ast.Node, target *spb.VName, kind string) *spb } else { e.writeEdge(target, rule.VName, rule.EdgeOut) } + if rule.Semantic != nil { + e.writeFact(target, facts.SemanticGenerated, strings.ToLower(rule.Semantic.String())) + } if rule.EdgeOut == edges.Generates && !e.fmeta[file] { e.fmeta[file] = true if rule.VName.Path != "" && target.Path != "" { - ruleVName := *rule.VName - ruleVName.Signature = "" - ruleVName.Language = "" - fileTarget := *anchor - fileTarget.Signature = "" - fileTarget.Language = "" + ruleVName := narrowToFileVName(rule.VName) + fileTarget := narrowToFileVName(anchor) if rule.Reverse { - e.writeEdge(&ruleVName, &fileTarget, rule.EdgeOut) + e.writeEdge(ruleVName, fileTarget, rule.EdgeOut) } else { - e.writeEdge(&fileTarget, &ruleVName, rule.EdgeOut) + e.writeEdge(fileTarget, ruleVName, rule.EdgeOut) } } } @@ -1135,6 +1134,10 @@ func (e *emitter) writeRef(origin ast.Node, target *spb.VName, kind string) *spb return anchor } +func narrowToFileVName(v *spb.VName) *spb.VName { + return &spb.VName{Corpus: v.GetCorpus(), Root: v.GetRoot(), Path: v.GetPath()} +} + // mustWriteBinding is as writeBinding, but panics if id does not resolve. Use // this in cases where the object is known already to exist. func (e *emitter) mustWriteBinding(id *ast.Ident, kind string, parent *spb.VName) *spb.VName { diff --git a/kythe/go/indexer/testdata/meta.go b/kythe/go/indexer/testdata/meta.go index a571fe0e0d..e2977c749e 100644 --- a/kythe/go/indexer/testdata/meta.go +++ b/kythe/go/indexer/testdata/meta.go @@ -10,6 +10,11 @@ func Barfoo() {} // ^ ^ offset 84 // \ offset 78 +func SetFoo() {} + +// ^ ^ offset 143 +// \ offset 137 + // Note: The locations in this file are connected to the offsets defined in the // associated meta file. If you move anything above this comment without // updating the metadata, the test may break. @@ -27,3 +32,9 @@ func Barfoo() {} //- Barfoo.node/kind function //- _AltB=vname(gsig2, gcorp, groot, gpath, glang) generates Barfoo //- vname("", gcorp, groot, gpath, "") generates vname("", kythe, _, "go/indexer/metadata_test/meta.go", "") + +//- SA.node/kind anchor +//- SA.loc/start 137 +//- SA.loc/end 143 +//- SA defines/binding SetFoo +//- SetFoo.semantic/generated set diff --git a/kythe/go/indexer/testdata/meta.go.linkage b/kythe/go/indexer/testdata/meta.go.linkage index f08be12eeb..34955e0f8c 100644 --- a/kythe/go/indexer/testdata/meta.go.linkage +++ b/kythe/go/indexer/testdata/meta.go.linkage @@ -26,6 +26,20 @@ "language": "glang", "path": "gpath" } + }, + { + "type": "anchor_defines", + "begin": 137, + "end": 143, + "edge": "%/kythe/edge/generates", + "semantic": "SET", + "vname": { + "signature": "foo", + "corpus": "gcorp", + "root": "groot", + "language": "glang", + "path": "gpath" + } } ] } diff --git a/kythe/go/util/metadata/BUILD b/kythe/go/util/metadata/BUILD index 028542d728..f54bc94ab6 100644 --- a/kythe/go/util/metadata/BUILD +++ b/kythe/go/util/metadata/BUILD @@ -8,8 +8,8 @@ go_library( deps = [ "//kythe/go/util/schema/edges", "//kythe/proto:storage_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", "@org_golang_google_protobuf//encoding/protojson:go_default_library", + "@org_golang_google_protobuf//types/descriptorpb:go_default_library", ], ) diff --git a/kythe/go/util/metadata/metadata.go b/kythe/go/util/metadata/metadata.go index a607c1f9f4..88dae8204b 100644 --- a/kythe/go/util/metadata/metadata.go +++ b/kythe/go/util/metadata/metadata.go @@ -31,7 +31,7 @@ import ( "google.golang.org/protobuf/encoding/protojson" - protopb "github.com/golang/protobuf/protoc-gen-go/descriptor" + protopb "google.golang.org/protobuf/types/descriptorpb" spb "kythe.io/kythe/proto/storage_go_proto" ) @@ -64,16 +64,27 @@ func (rs Rules) MarshalJSON() ([]byte, error) { } } f.Meta[i] = rule{ - Type: rtype, - Begin: r.Begin, - End: r.End, - VName: v, - Edge: kind, + Type: rtype, + Begin: r.Begin, + End: r.End, + VName: v, + Edge: kind, + Semantic: r.Semantic, } } return json.Marshal(f) } +// Semantic is a reexport of protopb.GeneratedCodeInfo_Annotation_Semantic +type Semantic = protopb.GeneratedCodeInfo_Annotation_Semantic + +// Reexport of the Semantic enum values +var ( + SemanticNone Semantic = protopb.GeneratedCodeInfo_Annotation_NONE + SemanticSet Semantic = protopb.GeneratedCodeInfo_Annotation_SET + SemanticAlias Semantic = protopb.GeneratedCodeInfo_Annotation_ALIAS +) + // A Rule denotes a single metadata rule, associating type linkage information // for an anchor spanning a given range of text. type Rule struct { @@ -85,6 +96,8 @@ type Rule struct { EdgeOut string // outbound edge kind to emit VName *spb.VName // the vname to create an edge to or from Reverse bool // whether to draw to vname (false) or from it (true) + + Semantic *Semantic // whether to apply special semantics. } // The types below are intermediate structures used for JSON marshaling. @@ -104,6 +117,8 @@ type rule struct { End int `json:"end"` Edge string `json:"edge,omitempty"` VName json.RawMessage `json:"vname,omitempty"` + + Semantic *Semantic `json:"semantic,omitempty"` } // Parse parses a single JSON metadata object from r and returns the @@ -132,11 +147,12 @@ func Parse(r io.Reader) (Rules, error) { v = &msg } rs[i] = Rule{ - Begin: meta.Begin, - End: meta.End, - EdgeOut: edges.Canonical(meta.Edge), - Reverse: edges.IsReverse(meta.Edge), - VName: v, + Begin: meta.Begin, + End: meta.End, + EdgeOut: edges.Canonical(meta.Edge), + Reverse: edges.IsReverse(meta.Edge), + VName: v, + Semantic: meta.Semantic, } switch t := meta.Type; t { case "nop": @@ -182,12 +198,13 @@ func FromGeneratedCodeInfo(msg *protopb.GeneratedCodeInfo, vname *spb.VName) Rul Signature: strings.Join(sig, "."), } rs[i] = Rule{ - EdgeIn: edges.DefinesBinding, - EdgeOut: edges.Generates, - Reverse: true, - Begin: int(anno.GetBegin()), - End: int(anno.GetEnd()), - VName: vname, + EdgeIn: edges.DefinesBinding, + EdgeOut: edges.Generates, + Reverse: true, + Begin: int(anno.GetBegin()), + End: int(anno.GetEnd()), + VName: vname, + Semantic: anno.Semantic, } } return rs diff --git a/kythe/go/util/metadata/metadata_test.go b/kythe/go/util/metadata/metadata_test.go index 572352cf61..b1cbad6633 100644 --- a/kythe/go/util/metadata/metadata_test.go +++ b/kythe/go/util/metadata/metadata_test.go @@ -27,7 +27,7 @@ import ( "google.golang.org/protobuf/proto" - protopb "github.com/golang/protobuf/protoc-gen-go/descriptor" + protopb "google.golang.org/protobuf/types/descriptorpb" spb "kythe.io/kythe/proto/storage_go_proto" ) @@ -42,13 +42,17 @@ func TestParse(t *testing.T) { // NOP values, multiple rules. {`{"type":"kythe0","meta":[ {"type":"nop"}, - {"type":"nop","begin":42,"end":99} + {"type":"nop","begin":42,"end":99}, + {"type":"nop","semantic":"SET"} ]}`, Rules{ {}, { Begin: 42, End: 99, }, + { + Semantic: SemanticSet.Enum(), + }, }}, // Test vector from the C++ implementation. @@ -104,11 +108,12 @@ func TestRoundTrip(t *testing.T) { Language: "glang", Root: "groot", }, - Reverse: true, - EdgeIn: edges.DefinesBinding, - EdgeOut: edges.Generates, - Begin: 179, - End: 182, + Reverse: true, + EdgeIn: edges.DefinesBinding, + EdgeOut: edges.Generates, + Begin: 179, + End: 182, + Semantic: SemanticSet.Enum(), }}, } for _, test := range tests { @@ -137,6 +142,7 @@ func TestGeneratedCodeInfo(t *testing.T) { SourceFile: proto.String("a"), Begin: proto.Int32(1), End: proto.Int32(100), + Semantic: SemanticSet.Enum(), }}, } want := Rules{{ @@ -145,11 +151,12 @@ func TestGeneratedCodeInfo(t *testing.T) { Language: "protobuf", Path: "a", }, - Reverse: true, - EdgeIn: edges.DefinesBinding, - EdgeOut: edges.Generates, - Begin: 1, - End: 100, + Reverse: true, + EdgeIn: edges.DefinesBinding, + EdgeOut: edges.Generates, + Begin: 1, + End: 100, + Semantic: SemanticSet.Enum(), }} { got := FromGeneratedCodeInfo(in, nil) diff --git a/kythe/go/util/schema/facts/facts.go b/kythe/go/util/schema/facts/facts.go index 69ccc203d3..4b4bff2671 100644 --- a/kythe/go/util/schema/facts/facts.go +++ b/kythe/go/util/schema/facts/facts.go @@ -21,23 +21,24 @@ const prefix = "/kythe/" // duplicated to avoid a circular import // Node fact labels const ( - AnchorEnd = prefix + "loc/end" - AnchorStart = prefix + "loc/start" - BuildConfig = prefix + "build/config" - Code = prefix + "code" - Complete = prefix + "complete" - ContextURL = prefix + "context/url" - Deprecated = prefix + "tag/deprecated" - Details = prefix + "details" - DocURI = prefix + "doc/uri" - Message = prefix + "message" - NodeKind = prefix + "node/kind" - ParamDefault = prefix + "param/default" - SnippetEnd = prefix + "snippet/end" - SnippetStart = prefix + "snippet/start" - Subkind = prefix + "subkind" - Text = prefix + "text" - TextEncoding = prefix + "text/encoding" + AnchorEnd = prefix + "loc/end" + AnchorStart = prefix + "loc/start" + BuildConfig = prefix + "build/config" + Code = prefix + "code" + Complete = prefix + "complete" + ContextURL = prefix + "context/url" + Deprecated = prefix + "tag/deprecated" + Details = prefix + "details" + DocURI = prefix + "doc/uri" + Message = prefix + "message" + NodeKind = prefix + "node/kind" + ParamDefault = prefix + "param/default" + SemanticGenerated = prefix + "semantic/generated" + SnippetEnd = prefix + "snippet/end" + SnippetStart = prefix + "snippet/start" + Subkind = prefix + "subkind" + Text = prefix + "text" + TextEncoding = prefix + "text/encoding" ) // DefaultTextEncoding is the implicit value for TextEncoding if it is empty or