Repository: kythe/kythe
Pull request #5888 (2023-10-11 21:14:36)

feat(go_indexer): add subkinds to variable nodes


Patch:
diff --git a/kythe/go/indexer/emit.go b/kythe/go/indexer/emit.go
index 2039910dd..f1d9e632e 100644
--- a/kythe/go/indexer/emit.go
+++ b/kythe/go/indexer/emit.go
@@ -387,7 +387,7 @@ func (e *emitter) visitFuncDecl(decl *ast.FuncDecl, stack stackFunc) {
 	if sig.Recv() != nil {
 		// The receiver is treated as parameter 0.
 		if names := decl.Recv.List[0].Names; names != nil {
-			if recv := e.writeBinding(names[0], nodes.Variable, info.vname); recv != nil {
+			if recv := e.writeVarBinding(names[0], nodes.LocalParameter, info.vname); recv != nil {
 				e.writeEdge(info.vname, recv, edges.ParamIndex(0))
 			}
 		}
@@ -622,7 +622,11 @@ func (e *emitter) visitValueSpec(spec *ast.ValueSpec, stack stackFunc) {
 	}
 	doc := specComment(spec, stack)
 	for _, id := range spec.Names {
-		target := e.writeBinding(id, kind, e.nameContext(stack))
+		ctx := e.nameContext(stack)
+		target := e.writeBinding(id, kind, ctx)
+		if kind == nodes.Variable && e.isNonFileOrPackage(ctx) {
+			e.writeFact(target, facts.Subkind, nodes.Local)
+		}
 		if target == nil {
 			continue // type error (reported elsewhere)
 		}
@@ -640,6 +644,10 @@ func (e *emitter) visitValueSpec(spec *ast.ValueSpec, stack stackFunc) {
 	}
 }
 
+func (e *emitter) isNonFileOrPackage(v *spb.VName) bool {
+	return v.GetSignature() != "" && e.pi.VName != v
+}
+
 // visitTypeSpec handles type declarations, including the bindings for fields
 // of struct types and methods of interfaces.
 func (e *emitter) visitTypeSpec(spec *ast.TypeSpec, stack stackFunc) {
@@ -773,7 +781,11 @@ func (e *emitter) visitAssignStmt(stmt *ast.AssignStmt, stack stackFunc) {
 		if id, _ := expr.(*ast.Ident); id != nil {
 			// Add a binding only if this is the definition site for the name.
 			if obj := e.pi.Info.Defs[id]; obj != nil && obj.Pos() == id.Pos() {
-				e.mustWriteBinding(id, nodes.Variable, up)
+				var subkind string
+				if e.isNonFileOrPackage(up) {
+					subkind = nodes.Local
+				}
+				e.writeVarBinding(id, subkind, up)
 			}
 		}
 	}
@@ -790,10 +802,10 @@ func (e *emitter) visitRangeStmt(stmt *ast.RangeStmt, stack stackFunc) {
 	// In a well-typed program, the key and value will always be identifiers.
 	up := e.nameContext(stack)
 	if key, _ := stmt.Key.(*ast.Ident); key != nil {
-		e.writeBinding(key, nodes.Variable, up)
+		e.writeVarBinding(key, "", up)
 	}
 	if val, _ := stmt.Value.(*ast.Ident); val != nil {
-		e.writeBinding(val, nodes.Variable, up)
+		e.writeVarBinding(val, "", up)
 	}
 }
 
@@ -887,7 +899,7 @@ func (e *emitter) emitParameters(ftype *ast.FuncType, sig *types.Signature, info
 	// Emit bindings and parameter edges for the parameters.
 	mapFields(ftype.Params, func(i int, id *ast.Ident) {
 		if sig.Params().At(i) != nil {
-			if param := e.writeBinding(id, nodes.Variable, info.vname); param != nil {
+			if param := e.writeVarBinding(id, nodes.LocalParameter, info.vname); param != nil {
 				e.writeEdge(info.vname, param, edges.ParamIndex(paramIndex))
 
 				field := ftype.Params.List[i]
@@ -902,7 +914,7 @@ func (e *emitter) emitParameters(ftype *ast.FuncType, sig *types.Signature, info
 	// Emit bindings for any named result variables.
 	// Results are not considered parameters.
 	mapFields(ftype.Results, func(i int, id *ast.Ident) {
-		e.writeBinding(id, nodes.Variable, info.vname)
+		e.writeVarBinding(id, "", info.vname)
 	})
 	// Emit bindings for type parameters
 	mapFields(ftype.TypeParams, func(i int, id *ast.Ident) {


Test patch:
diff --git a/kythe/go/indexer/testdata/basic/functions.go b/kythe/go/indexer/testdata/basic/functions.go
index 26d5a4a0a..57417abca 100644
--- a/kythe/go/indexer/testdata/basic/functions.go
+++ b/kythe/go/indexer/testdata/basic/functions.go
@@ -23,6 +23,8 @@ var _ = func(z int) {}
 // - @F defines/binding Fun
 // -
 // - @input defines/binding FunInput
+// - FunInput.node/kind variable
+// - FunInput.subkind local/parameter
 // - Fun param.0 FunInput
 // - FunInput childof Fun
 // -
diff --git a/kythe/go/indexer/testdata/basic/locals.go b/kythe/go/indexer/testdata/basic/locals.go
index edd8b7bc2..4be1e898d 100644
--- a/kythe/go/indexer/testdata/basic/locals.go
+++ b/kythe/go/indexer/testdata/basic/locals.go
@@ -13,6 +13,7 @@ func foo() {
 	//
 	//- @bravo defines/binding Bravo
 	//- Bravo.node/kind variable
+	//- Bravo.subkind local
 	//- @alpha ref/writes Alpha1
 	//- !{@alpha defines/binding Alpha1}
 	alpha, bravo := 1, 2
diff --git a/kythe/go/indexer/testdata/basic/scopes.go b/kythe/go/indexer/testdata/basic/scopes.go
index 084d21435..57c682435 100644
--- a/kythe/go/indexer/testdata/basic/scopes.go
+++ b/kythe/go/indexer/testdata/basic/scopes.go
@@ -1,6 +1,8 @@
 package scopes
 
 // - @Ident defines/binding Ident
+// - Ident.node/kind variable
+// - !{ Ident.subkind _? }
 var Ident bool
 
 // - @F defines/binding F