From 82fcd2cb268bd0ab2cb8d8a2f0050906f3d32b64 Mon Sep 17 00:00:00 2001 From: polinasok <51177946+polinasok@users.noreply.github.com> Date: Thu, 14 Jan 2021 10:53:12 -0800 Subject: [PATCH] service/dap: Add support for evaluateName for variables (#2292) * Add support for evaluateName for variables * More evaluateName logic tweaks and tests * Make DeepSource happy Co-authored-by: Polina Sokolova --- service/dap/handles.go | 18 +- service/dap/server.go | 88 +++++--- service/dap/server_test.go | 399 ++++++++++++++++++++++--------------- 3 files changed, 312 insertions(+), 193 deletions(-) diff --git a/service/dap/handles.go b/service/dap/handles.go index ec9bfe1e..d01baf91 100644 --- a/service/dap/handles.go +++ b/service/dap/handles.go @@ -14,6 +14,18 @@ type handlesMap struct { handleToVal map[int]interface{} } +type fullyQualifiedVariable struct { + *proc.Variable + // A way to load this variable by either using all names in the hierarchic + // sequence above this variable (most readable when referenced by the UI) + // if available or a special expression based on: + // https://github.com/go-delve/delve/blob/master/Documentation/api/ClientHowto.md#loading-more-of-a-variable + // Empty if the variable cannot or should not be reloaded. + fullyQualifiedNameOrExpr string + // True if this represents variable scope + isScope bool +} + func newHandlesMap() *handlesMap { return &handlesMap{startHandle, make(map[int]interface{})} } @@ -43,16 +55,16 @@ func newVariablesHandlesMap() *variablesHandlesMap { return &variablesHandlesMap{newHandlesMap()} } -func (hs *variablesHandlesMap) create(value *proc.Variable) int { +func (hs *variablesHandlesMap) create(value *fullyQualifiedVariable) int { return hs.m.create(value) } -func (hs *variablesHandlesMap) get(handle int) (*proc.Variable, bool) { +func (hs *variablesHandlesMap) get(handle int) (*fullyQualifiedVariable, bool) { v, ok := hs.m.get(handle) if !ok { return nil, false } - return v.(*proc.Variable), true + return v.(*fullyQualifiedVariable), true } func (hs *variablesHandlesMap) reset() { diff --git a/service/dap/server.go b/service/dap/server.go index ccf12dc6..7206d133 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -832,7 +832,7 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) { s.sendErrorResponse(request.Request, UnableToListArgs, "Unable to list args", err.Error()) return } - argScope := &proc.Variable{Name: "Arguments", Children: slicePtrVarToSliceVar(args)} + argScope := &fullyQualifiedVariable{&proc.Variable{Name: "Arguments", Children: slicePtrVarToSliceVar(args)}, "", true} // Retrieve local variables locals, err := s.debugger.LocalVariables(goid, frame, 0, cfg) @@ -840,7 +840,7 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) { s.sendErrorResponse(request.Request, UnableToListLocals, "Unable to list locals", err.Error()) return } - locScope := &proc.Variable{Name: "Locals", Children: slicePtrVarToSliceVar(locals)} + locScope := &fullyQualifiedVariable{&proc.Variable{Name: "Locals", Children: slicePtrVarToSliceVar(locals)}, "", true} // TODO(polina): Annotate shadowed variables @@ -875,10 +875,10 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) { globals[i].Name = strings.TrimPrefix(g.Name, currPkg+".") } - globScope := &proc.Variable{ + globScope := &fullyQualifiedVariable{&proc.Variable{ Name: fmt.Sprintf("Globals (package %s)", currPkg), Children: slicePtrVarToSliceVar(globals), - } + }, currPkg, true} scopeGlobals := dap.Scope{Name: globScope.Name, VariablesReference: s.variableHandles.create(globScope)} scopes = append(scopes, scopeGlobals) } @@ -915,28 +915,45 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) { // A map will have twice as many children as there are key-value elements. kvIndex := i / 2 // Process children in pairs: even indices are map keys, odd indices are values. - keyv := &v.Children[i] - key, keyref := s.convertVariable(keyv) - val, valref := s.convertVariable(&v.Children[i+1]) + keyv, valv := &v.Children[i], &v.Children[i+1] + keyexpr := fmt.Sprintf("(*(*%q)(%#x))", keyv.TypeString(), keyv.Addr) + valexpr := fmt.Sprintf("%s[%s]", v.fullyQualifiedNameOrExpr, keyexpr) + switch keyv.Kind { + // For value expression, use the key value, not the corresponding expression if the key is a scalar. + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + valexpr = fmt.Sprintf("%s[%s]", v.fullyQualifiedNameOrExpr, api.VariableValueAsString(keyv)) + case reflect.String: + if key := constant.StringVal(keyv.Value); keyv.Len == int64(len(key)) { // fully loaded + valexpr = fmt.Sprintf("%s[%q]", v.fullyQualifiedNameOrExpr, key) + } + // TODO(polina): use nil for nil keys of different types + } + key, keyref := s.convertVariable(keyv, keyexpr) + val, valref := s.convertVariable(valv, valexpr) // If key or value or both are scalars, we can use // a single variable to represet key:value format. // Otherwise, we must return separate variables for both. if keyref > 0 && valref > 0 { // Both are not scalars keyvar := dap.Variable{ Name: fmt.Sprintf("[key %d]", kvIndex), + EvaluateName: keyexpr, Value: key, VariablesReference: keyref, } valvar := dap.Variable{ Name: fmt.Sprintf("[val %d]", kvIndex), + EvaluateName: valexpr, Value: val, VariablesReference: valref, } children = append(children, keyvar, valvar) } else { // At least one is a scalar kvvar := dap.Variable{ - Name: key, - Value: val, + Name: key, + EvaluateName: valexpr, + Value: val, } if keyref != 0 { // key is a type to be expanded kvvar.Name = fmt.Sprintf("%s(%#x)", kvvar.Name, keyv.Addr) // Make the name unique @@ -950,35 +967,52 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) { case reflect.Slice, reflect.Array: children = make([]dap.Variable, len(v.Children)) for i := range v.Children { - c := &v.Children[i] - value, varref := s.convertVariable(c) + cfqname := fmt.Sprintf("%s[%d]", v.fullyQualifiedNameOrExpr, i) + cvalue, cvarref := s.convertVariable(&v.Children[i], cfqname) children[i] = dap.Variable{ Name: fmt.Sprintf("[%d]", i), - Value: value, - VariablesReference: varref, + EvaluateName: cfqname, + Value: cvalue, + VariablesReference: cvarref, } } default: children = make([]dap.Variable, len(v.Children)) for i := range v.Children { c := &v.Children[i] - value, variablesReference := s.convertVariable(c) + cfqname := fmt.Sprintf("%s.%s", v.fullyQualifiedNameOrExpr, c.Name) + + if strings.HasPrefix(c.Name, "~") || strings.HasPrefix(c.Name, ".") { + cfqname = "" + } else if v.isScope && v.fullyQualifiedNameOrExpr == "" { + cfqname = c.Name + } else if v.fullyQualifiedNameOrExpr == "" { + cfqname = "" + } else if v.Kind == reflect.Interface { + cfqname = fmt.Sprintf("%s.(%s)", v.fullyQualifiedNameOrExpr, c.Name) // c is data + } else if v.Kind == reflect.Ptr { + cfqname = fmt.Sprintf("(*%v)", v.fullyQualifiedNameOrExpr) // c is the nameless pointer value + } else if v.Kind == reflect.Complex64 || v.Kind == reflect.Complex128 { + cfqname = "" // complex children are not struct fields and can't be accessed directly + } + cvalue, cvarref := s.convertVariable(c, cfqname) children[i] = dap.Variable{ Name: c.Name, - Value: value, - VariablesReference: variablesReference, + EvaluateName: cfqname, + Value: cvalue, + VariablesReference: cvarref, } } } response := &dap.VariablesResponse{ Response: *newResponse(request.Request), Body: dap.VariablesResponseBody{Variables: children}, - // TODO(polina): support evaluateName field } s.send(response) } -// convertVariable converts proc.Variable to dap.Variable value and reference. +// convertVariable converts proc.Variable to dap.Variable value and reference +// while keeping track of the full qualified name or load expression. // Variable reference is used to keep track of the children associated with each // variable. It is shared with the host via scopes or evaluate response and is an index // into the s.variableHandles map, used to look up variables and their children on @@ -986,23 +1020,23 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) { // variables request can be issued to get the elements of the compound variable. As a // custom, a zero reference, reminiscent of a zero pointer, is used to indicate that // a scalar variable cannot be "dereferenced" to get its elements (as there are none). -func (s *Server) convertVariable(v *proc.Variable) (value string, variablesReference int) { - return s.convertVariableWithOpts(v, false) +func (s *Server) convertVariable(v *proc.Variable, qualifiedNameOrExpr string) (value string, variablesReference int) { + return s.convertVariableWithOpts(v, qualifiedNameOrExpr, false) } func (s *Server) convertVariableToString(v *proc.Variable) string { - val, _ := s.convertVariableWithOpts(v, true) + val, _ := s.convertVariableWithOpts(v, "", true) return val } -// convertVarialbeWithOpts allows to skip reference generation in case all we need is +// convertVariableWithOpts allows to skip reference generation in case all we need is // a string representation of the variable. -func (s *Server) convertVariableWithOpts(v *proc.Variable, skipRef bool) (value string, variablesReference int) { +func (s *Server) convertVariableWithOpts(v *proc.Variable, qualifiedNameOrExpr string, skipRef bool) (value string, variablesReference int) { maybeCreateVariableHandle := func(v *proc.Variable) int { if skipRef { return 0 } - return s.variableHandles.create(v) + return s.variableHandles.create(&fullyQualifiedVariable{v, qualifiedNameOrExpr, false /*not a scope*/}) } if v.Unreadable != nil { value = fmt.Sprintf("unreadable <%v>", v.Unreadable) @@ -1224,7 +1258,7 @@ func (s *Server) onEvaluateRequest(request *dap.EvaluateRequest) { } response.Body = dap.EvaluateResponseBody{ Result: strings.TrimRight(retVarsAsStr, ", "), - VariablesReference: s.variableHandles.create(retVarsAsVar), + VariablesReference: s.variableHandles.create(&fullyQualifiedVariable{retVarsAsVar, "", false /*not a scope*/}), } } } else { // {expression} @@ -1233,7 +1267,9 @@ func (s *Server) onEvaluateRequest(request *dap.EvaluateRequest) { s.sendErrorResponseWithOpts(request.Request, UnableToEvaluateExpression, "Unable to evaluate expression", err.Error(), showErrorToUser) return } - exprVal, exprRef := s.convertVariable(exprVar) + // TODO(polina): as far as I can tell, evaluateName is ignored by vscode for expression variables. + // Should it be skipped alltogether for all levels? + exprVal, exprRef := s.convertVariable(exprVar, fmt.Sprintf("(%s)", request.Arguments.Expression)) response.Body = dap.EvaluateResponseBody{Result: exprVal, VariablesReference: exprRef} } s.send(response) diff --git a/service/dap/server_test.go b/service/dap/server_test.go index e80a2ba1..77341292 100644 --- a/service/dap/server_test.go +++ b/service/dap/server_test.go @@ -492,8 +492,8 @@ func TestPreSetBreakpoint(t *testing.T) { client.VariablesRequest(1000) // Arguments args := client.ExpectVariablesResponse(t) expectChildren(t, args, "Arguments", 2) - expectVarExact(t, args, 0, "y", "0", noChildren) - expectVarExact(t, args, 1, "~r1", "0", noChildren) + expectVarExact(t, args, 0, "y", "y", "0", noChildren) + expectVarExact(t, args, 1, "~r1", "", "0", noChildren) client.VariablesRequest(1001) // Locals locals := client.ExpectVariablesResponse(t) @@ -580,11 +580,12 @@ func expectChildren(t *testing.T, got *dap.VariablesResponse, parentName string, // expectVar is a helper for verifying the values within a VariablesResponse. // i - index of the variable within VariablesRespose.Body.Variables array (-1 will search all vars for a match) // name - name of the variable +// evalName - fully qualified variable name or alternative expression to load this variable // value - the value of the variable -// useExactMatch - true if name and value are to be compared to exactly, false if to be used as regex +// useExactMatch - true if name, evalName and value are to be compared to exactly, false if to be used as regex // hasRef - true if the variable should have children and therefore a non-0 variable reference // ref - reference to retrieve children of this variable (0 if none) -func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value string, useExactMatch, hasRef bool) (ref int) { +func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, useExactMatch, hasRef bool) (ref int) { t.Helper() if len(got.Body.Variables) <= i { t.Errorf("\ngot len=%d (children=%#v)\nwant len>%d", len(got.Body.Variables), got.Body.Variables, i) @@ -613,6 +614,15 @@ func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value stri if !matchedName || (goti.VariablesReference > 0) != hasRef { t.Errorf("\ngot %#v\nwant Name=%q hasRef=%t", goti, name, hasRef) } + matchedEvalName := false + if useExactMatch { + matchedEvalName = (goti.EvaluateName == evalName) + } else { + matchedEvalName, _ = regexp.MatchString(evalName, goti.EvaluateName) + } + if !matchedEvalName { + t.Errorf("\ngot %q\nwant EvaluateName=%q", goti.EvaluateName, evalName) + } matchedValue := false if useExactMatch { matchedValue = (goti.Value == value) @@ -626,15 +636,31 @@ func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value stri } // expectVarExact is a helper like expectVar that matches value exactly. -func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, value string, hasRef bool) (ref int) { +func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) { t.Helper() - return expectVar(t, got, i, name, value, true, hasRef) + return expectVar(t, got, i, name, evalName, value, true, hasRef) } -// expectVarRegex is a helper like expectVar that treats name and value as a regex. -func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, value string, hasRef bool) (ref int) { +// expectVarRegex is a helper like expectVar that treats value, evalName or name as a regex. +func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) { t.Helper() - return expectVar(t, got, i, name, value, false, hasRef) + return expectVar(t, got, i, name, evalName, value, false, hasRef) +} + +// validateEvaluateName issues an evaluate request with evaluateName of a variable and +// confirms that it succeeds and returns the same variable record as the original. +func validateEvaluateName(t *testing.T, client *daptest.Client, got *dap.VariablesResponse, i int) { + t.Helper() + original := got.Body.Variables[i] + client.EvaluateRequest(original.EvaluateName, 1000, "this context will be ignored") + validated := client.ExpectEvaluateResponse(t) + if original.VariablesReference == 0 && validated.Body.VariablesReference != 0 || + original.VariablesReference != 0 && validated.Body.VariablesReference == 0 { + t.Errorf("\ngot varref=%d\nwant %d", validated.Body.VariablesReference, original.VariablesReference) + } + if original.Value != validated.Body.Result { + t.Errorf("\ngot value=%q\nwant %q", validated.Body.Result, original.Value) + } } // TestStackTraceRequest executes to a breakpoint and tests different @@ -745,21 +771,23 @@ func TestScopesAndVariablesRequests(t *testing.T) { client.VariablesRequest(1000) args := client.ExpectVariablesResponse(t) expectChildren(t, args, "Arguments", 2) - expectVarExact(t, args, 0, "baz", `"bazburzum"`, noChildren) - ref := expectVarExact(t, args, 1, "bar", ``, hasChildren) + expectVarExact(t, args, 0, "baz", "baz", `"bazburzum"`, noChildren) + ref := expectVarExact(t, args, 1, "bar", "bar", ``, hasChildren) if ref > 0 { client.VariablesRequest(ref) bar := client.ExpectVariablesResponse(t) expectChildren(t, bar, "bar", 2) - expectVarExact(t, bar, 0, "Baz", "10", noChildren) - expectVarExact(t, bar, 1, "Bur", `"lorem"`, noChildren) + expectVarExact(t, bar, 0, "Baz", "bar.Baz", "10", noChildren) + expectVarExact(t, bar, 1, "Bur", "bar.Bur", `"lorem"`, noChildren) + validateEvaluateName(t, client, bar, 0) + validateEvaluateName(t, client, bar, 1) } // Globals client.VariablesRequest(1002) globals := client.ExpectVariablesResponse(t) - expectVarExact(t, globals, 0, "p1", "10", noChildren) + expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren) // Locals @@ -768,74 +796,75 @@ func TestScopesAndVariablesRequests(t *testing.T) { expectChildren(t, locals, "Locals", 30) // reflect.Kind == Bool - expectVarExact(t, locals, -1, "b1", "true", noChildren) - expectVarExact(t, locals, -1, "b2", "false", noChildren) + expectVarExact(t, locals, -1, "b1", "b1", "true", noChildren) + expectVarExact(t, locals, -1, "b2", "b2", "false", noChildren) // reflect.Kind == Int - expectVarExact(t, locals, -1, "a2", "6", noChildren) - expectVarExact(t, locals, -1, "neg", "-1", noChildren) + expectVarExact(t, locals, -1, "a2", "a2", "6", noChildren) + expectVarExact(t, locals, -1, "neg", "neg", "-1", noChildren) // reflect.Kind == Int8 - expectVarExact(t, locals, -1, "i8", "1", noChildren) + expectVarExact(t, locals, -1, "i8", "i8", "1", noChildren) // reflect.Kind == Int16 - see testvariables2 // reflect.Kind == Int32 - see testvariables2 // reflect.Kind == Int64 - see testvariables2 // reflect.Kind == Uint // reflect.Kind == Uint8 - expectVarExact(t, locals, -1, "u8", "255", noChildren) + expectVarExact(t, locals, -1, "u8", "u8", "255", noChildren) // reflect.Kind == Uint16 - expectVarExact(t, locals, -1, "u16", "65535", noChildren) + expectVarExact(t, locals, -1, "u16", "u16", "65535", noChildren) // reflect.Kind == Uint32 - expectVarExact(t, locals, -1, "u32", "4294967295", noChildren) + expectVarExact(t, locals, -1, "u32", "u32", "4294967295", noChildren) // reflect.Kind == Uint64 - expectVarExact(t, locals, -1, "u64", "18446744073709551615", noChildren) + expectVarExact(t, locals, -1, "u64", "u64", "18446744073709551615", noChildren) // reflect.Kind == Uintptr - expectVarExact(t, locals, -1, "up", "5", noChildren) + expectVarExact(t, locals, -1, "up", "up", "5", noChildren) // reflect.Kind == Float32 - expectVarExact(t, locals, -1, "f32", "1.2", noChildren) + expectVarExact(t, locals, -1, "f32", "f32", "1.2", noChildren) // reflect.Kind == Float64 - expectVarExact(t, locals, -1, "a3", "7.23", noChildren) + expectVarExact(t, locals, -1, "a3", "a3", "7.23", noChildren) // reflect.Kind == Complex64 - ref = expectVarExact(t, locals, -1, "c64", "(1 + 2i)", hasChildren) + ref = expectVarExact(t, locals, -1, "c64", "c64", "(1 + 2i)", hasChildren) if ref > 0 { client.VariablesRequest(ref) c64 := client.ExpectVariablesResponse(t) expectChildren(t, c64, "c64", 2) - expectVarExact(t, c64, 0, "real", "1", noChildren) - expectVarExact(t, c64, 1, "imaginary", "2", noChildren) + expectVarExact(t, c64, 0, "real", "", "1", noChildren) + expectVarExact(t, c64, 1, "imaginary", "", "2", noChildren) } // reflect.Kind == Complex128 - ref = expectVarExact(t, locals, -1, "c128", "(2 + 3i)", hasChildren) + ref = expectVarExact(t, locals, -1, "c128", "c128", "(2 + 3i)", hasChildren) if ref > 0 { client.VariablesRequest(ref) c128 := client.ExpectVariablesResponse(t) expectChildren(t, c128, "c128", 2) - expectVarExact(t, c128, 0, "real", "2", noChildren) - expectVarExact(t, c128, 1, "imaginary", "3", noChildren) + expectVarExact(t, c128, 0, "real", "", "2", noChildren) + expectVarExact(t, c128, 1, "imaginary", "", "3", noChildren) } // reflect.Kind == Array - ref = expectVarExact(t, locals, -1, "a4", "<[2]int>", hasChildren) + ref = expectVarExact(t, locals, -1, "a4", "a4", "<[2]int>", hasChildren) if ref > 0 { client.VariablesRequest(ref) a4 := client.ExpectVariablesResponse(t) expectChildren(t, a4, "a4", 2) - expectVarExact(t, a4, 0, "[0]", "1", noChildren) - expectVarExact(t, a4, 1, "[1]", "2", noChildren) + expectVarExact(t, a4, 0, "[0]", "a4[0]", "1", noChildren) + expectVarExact(t, a4, 1, "[1]", "a4[1]", "2", noChildren) } - ref = expectVarExact(t, locals, -1, "a11", "<[3]main.FooBar>", hasChildren) + ref = expectVarExact(t, locals, -1, "a11", "a11", "<[3]main.FooBar>", hasChildren) if ref > 0 { client.VariablesRequest(ref) a11 := client.ExpectVariablesResponse(t) expectChildren(t, a11, "a11", 3) - expectVarExact(t, a11, 0, "[0]", "", hasChildren) - ref = expectVarExact(t, a11, 1, "[1]", "", hasChildren) + expectVarExact(t, a11, 0, "[0]", "a11[0]", "", hasChildren) + ref = expectVarExact(t, a11, 1, "[1]", "a11[1]", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) a11_1 := client.ExpectVariablesResponse(t) expectChildren(t, a11_1, "a11[1]", 2) - expectVarExact(t, a11_1, 0, "Baz", "2", noChildren) - expectVarExact(t, a11_1, 1, "Bur", `"b"`, noChildren) - + expectVarExact(t, a11_1, 0, "Baz", "a11[1].Baz", "2", noChildren) + expectVarExact(t, a11_1, 1, "Bur", "a11[1].Bur", `"b"`, noChildren) + validateEvaluateName(t, client, a11_1, 0) + validateEvaluateName(t, client, a11_1, 1) } - expectVarExact(t, a11, 2, "[2]", "", hasChildren) + expectVarExact(t, a11, 2, "[2]", "a11[2]", "", hasChildren) } // reflect.Kind == Chan - see testvariables2 @@ -843,87 +872,96 @@ func TestScopesAndVariablesRequests(t *testing.T) { // reflect.Kind == Interface - see testvariables2 // reflect.Kind == Map - see testvariables2 // reflect.Kind == Ptr - ref = expectVarRegex(t, locals, -1, "a7", `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) + ref = expectVarRegex(t, locals, -1, "a7", "a7", `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) if ref > 0 { client.VariablesRequest(ref) a7 := client.ExpectVariablesResponse(t) expectChildren(t, a7, "a7", 1) - ref = expectVarExact(t, a7, 0, "", "", hasChildren) + ref = expectVarExact(t, a7, 0, "", "(*a7)", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) a7val := client.ExpectVariablesResponse(t) expectChildren(t, a7val, "*a7", 2) - expectVarExact(t, a7val, 0, "Baz", "5", noChildren) - expectVarExact(t, a7val, 1, "Bur", `"strum"`, noChildren) + expectVarExact(t, a7val, 0, "Baz", "(*a7).Baz", "5", noChildren) + expectVarExact(t, a7val, 1, "Bur", "(*a7).Bur", `"strum"`, noChildren) + validateEvaluateName(t, client, a7val, 0) + validateEvaluateName(t, client, a7val, 1) } } // TODO(polina): how to test for "nil" (without type) and "void"? - expectVarExact(t, locals, -1, "a9", "nil <*main.FooBar>", noChildren) + expectVarExact(t, locals, -1, "a9", "a9", "nil <*main.FooBar>", noChildren) // reflect.Kind == Slice - ref = expectVarExact(t, locals, -1, "a5", "<[]int> (length: 5, cap: 5)", hasChildren) + ref = expectVarExact(t, locals, -1, "a5", "a5", "<[]int> (length: 5, cap: 5)", hasChildren) if ref > 0 { client.VariablesRequest(ref) a5 := client.ExpectVariablesResponse(t) expectChildren(t, a5, "a5", 5) - expectVarExact(t, a5, 0, "[0]", "1", noChildren) - expectVarExact(t, a5, 4, "[4]", "5", noChildren) + expectVarExact(t, a5, 0, "[0]", "a5[0]", "1", noChildren) + expectVarExact(t, a5, 4, "[4]", "a5[4]", "5", noChildren) + validateEvaluateName(t, client, a5, 0) + validateEvaluateName(t, client, a5, 1) } - ref = expectVarExact(t, locals, -1, "a12", "<[]main.FooBar> (length: 2, cap: 2)", hasChildren) + ref = expectVarExact(t, locals, -1, "a12", "a12", "<[]main.FooBar> (length: 2, cap: 2)", hasChildren) if ref > 0 { client.VariablesRequest(ref) a12 := client.ExpectVariablesResponse(t) expectChildren(t, a12, "a12", 2) - expectVarExact(t, a12, 0, "[0]", "", hasChildren) - ref = expectVarExact(t, a12, 1, "[1]", "", hasChildren) + expectVarExact(t, a12, 0, "[0]", "a12[0]", "", hasChildren) + ref = expectVarExact(t, a12, 1, "[1]", "a12[1]", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) a12_1 := client.ExpectVariablesResponse(t) expectChildren(t, a12_1, "a12[1]", 2) - expectVarExact(t, a12_1, 0, "Baz", "5", noChildren) - expectVarExact(t, a12_1, 1, "Bur", `"e"`, noChildren) + expectVarExact(t, a12_1, 0, "Baz", "a12[1].Baz", "5", noChildren) + expectVarExact(t, a12_1, 1, "Bur", "a12[1].Bur", `"e"`, noChildren) + validateEvaluateName(t, client, a12_1, 0) + validateEvaluateName(t, client, a12_1, 1) } } - ref = expectVarExact(t, locals, -1, "a13", "<[]*main.FooBar> (length: 3, cap: 3)", hasChildren) + ref = expectVarExact(t, locals, -1, "a13", "a13", "<[]*main.FooBar> (length: 3, cap: 3)", hasChildren) if ref > 0 { client.VariablesRequest(ref) a13 := client.ExpectVariablesResponse(t) expectChildren(t, a13, "a13", 3) - expectVarRegex(t, a13, 0, `\[0\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) - expectVarRegex(t, a13, 1, `\[1\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) - ref = expectVarRegex(t, a13, 2, `\[2\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) + expectVarRegex(t, a13, 0, `\[0\]`, `a13\[0\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) + expectVarRegex(t, a13, 1, `\[1\]`, `a13\[1\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) + ref = expectVarRegex(t, a13, 2, `\[2\]`, `a13\[2\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren) if ref > 0 { client.VariablesRequest(ref) a13_2 := client.ExpectVariablesResponse(t) expectChildren(t, a13_2, "a13[2]", 1) - ref = expectVarExact(t, a13_2, 0, "", "", hasChildren) + ref = expectVarExact(t, a13_2, 0, "", "(*a13[2])", "", hasChildren) + validateEvaluateName(t, client, a13_2, 0) if ref > 0 { client.VariablesRequest(ref) val := client.ExpectVariablesResponse(t) expectChildren(t, val, "*a13[2]", 2) - expectVarExact(t, val, 0, "Baz", "8", noChildren) - expectVarExact(t, val, 1, "Bur", `"h"`, noChildren) + expectVarExact(t, val, 0, "Baz", "(*a13[2]).Baz", "8", noChildren) + expectVarExact(t, val, 1, "Bur", "(*a13[2]).Bur", `"h"`, noChildren) + validateEvaluateName(t, client, val, 0) + validateEvaluateName(t, client, val, 1) } } } // reflect.Kind == String - expectVarExact(t, locals, -1, "a1", `"foofoofoofoofoofoo"`, noChildren) - expectVarExact(t, locals, -1, "a10", `"ofo"`, noChildren) + expectVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, noChildren) + expectVarExact(t, locals, -1, "a10", "a10", `"ofo"`, noChildren) // reflect.Kind == Struct - ref = expectVarExact(t, locals, -1, "a6", "", hasChildren) + ref = expectVarExact(t, locals, -1, "a6", "a6", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) a6 := client.ExpectVariablesResponse(t) expectChildren(t, a6, "a6", 2) - expectVarExact(t, a6, 0, "Baz", "8", noChildren) - expectVarExact(t, a6, 1, "Bur", `"word"`, noChildren) + expectVarExact(t, a6, 0, "Baz", "a6.Baz", "8", noChildren) + expectVarExact(t, a6, 1, "Bur", "a6.Bur", `"word"`, noChildren) } - ref = expectVarExact(t, locals, -1, "a8", "", hasChildren) + ref = expectVarExact(t, locals, -1, "a8", "a8", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) a8 := client.ExpectVariablesResponse(t) expectChildren(t, a8, "a8", 2) - expectVarExact(t, a8, 0, "Bur", "10", noChildren) - expectVarExact(t, a8, 1, "Baz", `"feh"`, noChildren) + expectVarExact(t, a8, 0, "Bur", "a8.Bur", "10", noChildren) + expectVarExact(t, a8, 1, "Baz", "a8.Baz", `"feh"`, noChildren) } // reflect.Kind == UnsafePointer - see testvariables2 }, @@ -955,11 +993,11 @@ func TestScopesAndVariablesRequests(t *testing.T) { client.VariablesRequest(1001) // Locals locals := client.ExpectVariablesResponse(t) expectChildren(t, locals, "Locals", 1) - expectVarExact(t, locals, -1, "a1", `"bur"`, noChildren) + expectVarExact(t, locals, -1, "a1", "a1", `"bur"`, noChildren) client.VariablesRequest(1002) // Globals globals := client.ExpectVariablesResponse(t) - expectVarExact(t, globals, 0, "p1", "10", noChildren) + expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren) client.VariablesRequest(7777) erres = client.ExpectErrorResponse(t) @@ -1025,13 +1063,13 @@ func TestScopesAndVariablesRequests2(t *testing.T) { // reflect.Kind == Bool - see testvariables // reflect.Kind == Int - see testvariables // reflect.Kind == Int8 - expectVarExact(t, locals, -1, "ni8", "-5", noChildren) + expectVarExact(t, locals, -1, "ni8", "ni8", "-5", noChildren) // reflect.Kind == Int16 - expectVarExact(t, locals, -1, "ni16", "-5", noChildren) + expectVarExact(t, locals, -1, "ni16", "ni16", "-5", noChildren) // reflect.Kind == Int32 - expectVarExact(t, locals, -1, "ni32", "-5", noChildren) + expectVarExact(t, locals, -1, "ni32", "ni32", "-5", noChildren) // reflect.Kind == Int64 - expectVarExact(t, locals, -1, "ni64", "-5", noChildren) + expectVarExact(t, locals, -1, "ni64", "ni64", "-5", noChildren) // reflect.Kind == Uint // reflect.Kind == Uint8 - see testvariables // reflect.Kind == Uint16 - see testvariables @@ -1040,150 +1078,178 @@ func TestScopesAndVariablesRequests2(t *testing.T) { // reflect.Kind == Uintptr - see testvariables // reflect.Kind == Float32 - see testvariables // reflect.Kind == Float64 - expectVarExact(t, locals, -1, "pinf", "+Inf", noChildren) - expectVarExact(t, locals, -1, "ninf", "-Inf", noChildren) - expectVarExact(t, locals, -1, "nan", "NaN", noChildren) + expectVarExact(t, locals, -1, "pinf", "pinf", "+Inf", noChildren) + expectVarExact(t, locals, -1, "ninf", "ninf", "-Inf", noChildren) + expectVarExact(t, locals, -1, "nan", "nan", "NaN", noChildren) // reflect.Kind == Complex64 - see testvariables // reflect.Kind == Complex128 - see testvariables // reflect.Kind == Array - expectVarExact(t, locals, -1, "a0", "<[0]int>", noChildren) + expectVarExact(t, locals, -1, "a0", "a0", "<[0]int>", noChildren) // reflect.Kind == Chan - ref := expectVarExact(t, locals, -1, "ch1", "", hasChildren) + ref := expectVarExact(t, locals, -1, "ch1", "ch1", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) ch1 := client.ExpectVariablesResponse(t) expectChildren(t, ch1, "ch1", 11) - expectVarExact(t, ch1, 0, "qcount", "4", noChildren) - expectVarExact(t, ch1, 10, "lock", "", hasChildren) + expectVarExact(t, ch1, 0, "qcount", "ch1.qcount", "4", noChildren) + expectVarExact(t, ch1, 10, "lock", "ch1.lock", "", hasChildren) + validateEvaluateName(t, client, ch1, 0) + validateEvaluateName(t, client, ch1, 10) } - expectVarExact(t, locals, -1, "chnil", "nil ", noChildren) + expectVarExact(t, locals, -1, "chnil", "chnil", "nil ", noChildren) // reflect.Kind == Func - expectVarExact(t, locals, -1, "fn1", "main.afunc", noChildren) - expectVarExact(t, locals, -1, "fn2", "", noChildren) + expectVarExact(t, locals, -1, "fn1", "fn1", "main.afunc", noChildren) + expectVarExact(t, locals, -1, "fn2", "fn2", "", noChildren) // reflect.Kind == Interface - expectVarExact(t, locals, -1, "ifacenil", "nil ", noChildren) - ref = expectVarExact(t, locals, -1, "iface2", "", hasChildren) + expectVarExact(t, locals, -1, "ifacenil", "ifacenil", "nil ", noChildren) + ref = expectVarExact(t, locals, -1, "iface2", "iface2", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) iface2 := client.ExpectVariablesResponse(t) expectChildren(t, iface2, "iface2", 1) - expectVarExact(t, iface2, 0, "data", `"test"`, noChildren) + expectVarExact(t, iface2, 0, "data", "iface2.(data)", `"test"`, noChildren) + validateEvaluateName(t, client, iface2, 0) } - ref = expectVarExact(t, locals, -1, "iface4", "", hasChildren) + ref = expectVarExact(t, locals, -1, "iface4", "iface4", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) iface4 := client.ExpectVariablesResponse(t) expectChildren(t, iface4, "iface4", 1) - ref = expectVarExact(t, iface4, 0, "data", "<[]go/constant.Value> (length: 1, cap: 1)", hasChildren) + ref = expectVarExact(t, iface4, 0, "data", "iface4.(data)", "<[]go/constant.Value> (length: 1, cap: 1)", hasChildren) if ref > 0 { client.VariablesRequest(ref) iface4data := client.ExpectVariablesResponse(t) expectChildren(t, iface4data, "iface4.data", 1) - expectVarExact(t, iface4data, 0, "[0]", "", hasChildren) - - } - } - expectVarExact(t, locals, -1, "errnil", "nil ", noChildren) - expectVarExact(t, locals, -1, "err1", "", hasChildren) - // reflect.Kind == Map - expectVarExact(t, locals, -1, "mnil", "nil ", noChildren) - ref = expectVarExact(t, locals, -1, "m2", " (length: 1)", hasChildren) - if ref > 0 { - client.VariablesRequest(ref) - m2 := client.ExpectVariablesResponse(t) - expectChildren(t, m2, "m2", 1) - ref = expectVarRegex(t, m2, 0, "1", `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren) - if ref > 0 { - client.VariablesRequest(ref) - m2_1 := client.ExpectVariablesResponse(t) - expectChildren(t, m2_1, "m2[1]", 1) - ref = expectVarExact(t, m2_1, 0, "", "", hasChildren) + ref = expectVarExact(t, iface4data, 0, "[0]", "iface4.(data)[0]", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) - m2_1val := client.ExpectVariablesResponse(t) - expectChildren(t, m2_1val, "*m2[1]", 2) - expectVarExact(t, m2_1val, 0, "A", "10", noChildren) - expectVarExact(t, m2_1val, 1, "B", "11", noChildren) + iface4data0 := client.ExpectVariablesResponse(t) + expectChildren(t, iface4data0, "iface4.data[0]", 1) + expectVarExact(t, iface4data0, 0, "data", "iface4.(data)[0].(data)", "4", noChildren) + validateEvaluateName(t, client, iface4data0, 0) } } } - ref = expectVarExact(t, locals, -1, "m3", " (length: 2)", hasChildren) + expectVarExact(t, locals, -1, "errnil", "errnil", "nil ", noChildren) + ref = expectVarExact(t, locals, -1, "err1", "err1", "", hasChildren) + if ref > 0 { + client.VariablesRequest(ref) + err1 := client.ExpectVariablesResponse(t) + expectChildren(t, err1, "err1", 1) + expectVarRegex(t, err1, 0, "data", `err1\.\(data\)`, `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren) + validateEvaluateName(t, client, err1, 0) + } + // reflect.Kind == Map + expectVarExact(t, locals, -1, "mnil", "mnil", "nil ", noChildren) + // key - scalar, value - compound + ref = expectVarExact(t, locals, -1, "m2", "m2", " (length: 1)", hasChildren) + if ref > 0 { + client.VariablesRequest(ref) + m2 := client.ExpectVariablesResponse(t) + expectChildren(t, m2, "m2", 1) // each key-value represented by a single child + ref = expectVarRegex(t, m2, 0, "1", `m2\[1\]`, `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren) + if ref > 0 { + client.VariablesRequest(ref) + m2kv1 := client.ExpectVariablesResponse(t) + expectChildren(t, m2kv1, "m2[1]", 1) + ref = expectVarExact(t, m2kv1, 0, "", "(*m2[1])", "", hasChildren) + if ref > 0 { + client.VariablesRequest(ref) + m2kv1deref := client.ExpectVariablesResponse(t) + expectChildren(t, m2kv1deref, "*m2[1]", 2) + expectVarExact(t, m2kv1deref, 0, "A", "(*m2[1]).A", "10", noChildren) + expectVarExact(t, m2kv1deref, 1, "B", "(*m2[1]).B", "11", noChildren) + validateEvaluateName(t, client, m2kv1deref, 0) + validateEvaluateName(t, client, m2kv1deref, 1) + } + } + } + // key - compound, value - scalar + ref = expectVarExact(t, locals, -1, "m3", "m3", " (length: 2)", hasChildren) if ref > 0 { client.VariablesRequest(ref) m3 := client.ExpectVariablesResponse(t) - expectChildren(t, m3, "m3", 2) - ref = expectVarRegex(t, m3, 0, `\(0x[0-9a-f]+\)`, "42", hasChildren) + expectChildren(t, m3, "m3", 2) // each key-value represented by a single child + ref = expectVarRegex(t, m3, 0, `\(0x[0-9a-f]+\)`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", hasChildren) if ref > 0 { client.VariablesRequest(ref) - m3_0 := client.ExpectVariablesResponse(t) - expectChildren(t, m3_0, "m3[0]", 2) - expectVarExact(t, m3_0, 0, "A", "1", noChildren) - expectVarExact(t, m3_0, 1, "B", "1", noChildren) + m3kv0 := client.ExpectVariablesResponse(t) + expectChildren(t, m3kv0, "m3[0]", 2) + expectVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", noChildren) + validateEvaluateName(t, client, m3kv0, 0) } - ref = expectVarRegex(t, m3, 1, `\(0x[0-9a-f]+\)`, "43", hasChildren) - if ref > 0 { + ref = expectVarRegex(t, m3, 1, `\(0x[0-9a-f]+\)`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", hasChildren) + if ref > 0 { // inspect another key from another key-value child client.VariablesRequest(ref) - m3_1 := client.ExpectVariablesResponse(t) - expectChildren(t, m3_1, "m3[1]", 2) - expectVarExact(t, m3_1, 0, "A", "2", noChildren) - expectVarExact(t, m3_1, 1, "B", "2", noChildren) + m3kv1 := client.ExpectVariablesResponse(t) + expectChildren(t, m3kv1, "m3[1]", 2) + expectVarRegex(t, m3kv1, 1, "B", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren) + validateEvaluateName(t, client, m3kv1, 1) } } - ref = expectVarExact(t, locals, -1, "m4", " (length: 2)", hasChildren) + // key - compound, value - compound + ref = expectVarExact(t, locals, -1, "m4", "m4", " (length: 2)", hasChildren) if ref > 0 { client.VariablesRequest(ref) m4 := client.ExpectVariablesResponse(t) - expectChildren(t, m4, "m4", 4) - expectVarExact(t, m4, 0, "[key 0]", "", hasChildren) - expectVarExact(t, m4, 1, "[val 0]", "", hasChildren) - ref = expectVarExact(t, m4, 2, "[key 1]", "", hasChildren) + expectChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count + expectVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, ``, hasChildren) + expectVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, ``, hasChildren) + ref = expectVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, ``, hasChildren) if ref > 0 { client.VariablesRequest(ref) m4Key1 := client.ExpectVariablesResponse(t) expectChildren(t, m4Key1, "m4Key1", 2) - expectVarExact(t, m4Key1, 0, "A", "2", noChildren) - expectVarExact(t, m4Key1, 1, "B", "2", noChildren) + expectVarRegex(t, m4Key1, 0, "A", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "2", noChildren) + expectVarRegex(t, m4Key1, 1, "B", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren) + validateEvaluateName(t, client, m4Key1, 0) + validateEvaluateName(t, client, m4Key1, 1) } - ref = expectVarExact(t, m4, 3, "[val 1]", "", hasChildren) + ref = expectVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, ``, hasChildren) if ref > 0 { client.VariablesRequest(ref) m4Val1 := client.ExpectVariablesResponse(t) expectChildren(t, m4Val1, "m4Val1", 2) - expectVarExact(t, m4Val1, 0, "A", "22", noChildren) - expectVarExact(t, m4Val1, 1, "B", "22", noChildren) + expectVarRegex(t, m4Val1, 0, "A", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.A`, "22", noChildren) + expectVarRegex(t, m4Val1, 1, "B", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.B`, "22", noChildren) + validateEvaluateName(t, client, m4Val1, 0) + validateEvaluateName(t, client, m4Val1, 1) } } - expectVarExact(t, locals, -1, "emptymap", " (length: 0)", noChildren) + expectVarExact(t, locals, -1, "emptymap", "emptymap", " (length: 0)", noChildren) // reflect.Kind == Ptr - see testvariables // reflect.Kind == Slice - ref = expectVarExact(t, locals, -1, "zsslice", "<[]struct {}> (length: 3, cap: 3)", hasChildren) + ref = expectVarExact(t, locals, -1, "zsslice", "zsslice", "<[]struct {}> (length: 3, cap: 3)", hasChildren) if ref > 0 { client.VariablesRequest(ref) zsslice := client.ExpectVariablesResponse(t) expectChildren(t, zsslice, "zsslice", 3) + expectVarExact(t, zsslice, 2, "[2]", "zsslice[2]", "", noChildren) + validateEvaluateName(t, client, zsslice, 2) } - expectVarExact(t, locals, -1, "emptyslice", "<[]string> (length: 0, cap: 0)", noChildren) - expectVarExact(t, locals, -1, "nilslice", "nil <[]int>", noChildren) + expectVarExact(t, locals, -1, "emptyslice", "emptyslice", "<[]string> (length: 0, cap: 0)", noChildren) + expectVarExact(t, locals, -1, "nilslice", "nilslice", "nil <[]int>", noChildren) // reflect.Kind == String - expectVarExact(t, locals, -1, "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren) + expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren) // reflect.Kind == Struct - expectVarExact(t, locals, -1, "zsvar", "", noChildren) + expectVarExact(t, locals, -1, "zsvar", "zsvar", "", noChildren) // reflect.Kind == UnsafePointer // TODO(polina): how do I test for unsafe.Pointer(nil)? - expectVarRegex(t, locals, -1, "upnil", `unsafe\.Pointer\(0x0\)`, noChildren) - expectVarRegex(t, locals, -1, "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, noChildren) + expectVarRegex(t, locals, -1, "upnil", "upnil", `unsafe\.Pointer\(0x0\)`, noChildren) + expectVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, noChildren) // Test unreadable variable - ref = expectVarExact(t, locals, -1, "unread", "<*int>(0x3039)", hasChildren) + ref = expectVarExact(t, locals, -1, "unread", "unread", "<*int>(0x3039)", hasChildren) if ref > 0 { client.VariablesRequest(ref) val := client.ExpectVariablesResponse(t) expectChildren(t, val, "*unread", 1) - expectVarRegex(t, val, 0, "", "unreadable <.+>", noChildren) + expectVarRegex(t, val, 0, "^$", `\(\*unread\)`, "unreadable <.+>", noChildren) + validateEvaluateName(t, client, val, 0) } // Test that variables are not yet loaded completely. - ref = expectVarExact(t, locals, -1, "m1", " (length: 66)", hasChildren) + ref = expectVarExact(t, locals, -1, "m1", "m1", " (length: 66)", hasChildren) if ref > 0 { client.VariablesRequest(ref) m1 := client.ExpectVariablesResponse(t) @@ -1248,13 +1314,14 @@ func TestGlobalScopeAndVariables(t *testing.T) { client.VariablesRequest(1002) globals := client.ExpectVariablesResponse(t) expectChildren(t, globals, "Globals", 1) - ref := expectVarExact(t, globals, 0, "SomeVar", "", hasChildren) + ref := expectVarExact(t, globals, 0, "SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) somevar := client.ExpectVariablesResponse(t) expectChildren(t, somevar, "SomeVar", 1) - expectVarExact(t, somevar, 0, "X", "0", noChildren) + // TODO(polina): unlike main.p, this prefix won't work + expectVarExact(t, somevar, 0, "X", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar.X", "0", noChildren) } }, disconnect: false, @@ -1347,7 +1414,7 @@ func TestSetBreakpoint(t *testing.T) { handleStop(t, client, 1, "main.loop", 8) client.VariablesRequest(1001) // Locals locals := client.ExpectVariablesResponse(t) - expectVarExact(t, locals, 0, "i", "0", noChildren) // i == 0 + expectVarExact(t, locals, 0, "i", "i", "0", noChildren) // i == 0 // Edit the breakpoint to add a condition client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: "i == 3"}) @@ -1360,7 +1427,7 @@ func TestSetBreakpoint(t *testing.T) { handleStop(t, client, 1, "main.loop", 8) client.VariablesRequest(1001) // Locals locals = client.ExpectVariablesResponse(t) - expectVarExact(t, locals, 0, "i", "3", noChildren) // i == 3 + expectVarExact(t, locals, 0, "i", "i", "3", noChildren) // i == 3 // Edit the breakpoint to remove a condition client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: ""}) @@ -1373,7 +1440,7 @@ func TestSetBreakpoint(t *testing.T) { handleStop(t, client, 1, "main.loop", 8) client.VariablesRequest(1001) // Locals locals = client.ExpectVariablesResponse(t) - expectVarExact(t, locals, 0, "i", "4", noChildren) // i == 4 + expectVarExact(t, locals, 0, "i", "i", "4", noChildren) // i == 4 // Set at a line without a statement client.SetBreakpointsRequest(fixture.Source, []int{1000}) @@ -1421,8 +1488,10 @@ func TestEvaluateRequest(t *testing.T) { client.VariablesRequest(ref) a5 := client.ExpectVariablesResponse(t) expectChildren(t, a5, "a5", 5) - expectVarExact(t, a5, 0, "[0]", "1", noChildren) - expectVarExact(t, a5, 4, "[4]", "5", noChildren) + expectVarExact(t, a5, 0, "[0]", "(a5)[0]", "1", noChildren) + expectVarExact(t, a5, 4, "[4]", "(a5)[4]", "5", noChildren) + validateEvaluateName(t, client, a5, 0) + validateEvaluateName(t, client, a5, 4) } // All (binary and unary) on basic types except <-, ++ and -- @@ -1449,7 +1518,7 @@ func TestEvaluateRequest(t *testing.T) { expr := client.ExpectVariablesResponse(t) expectChildren(t, expr, "(*int)(2)", 1) // TODO(polina): should this be printed as (unknown int) instead? - expectVarExact(t, expr, 0, "", "", noChildren) + expectVarExact(t, expr, 0, "", "(*((*int)(2)))", "", noChildren) } // Type casts between string, []byte and []rune client.EvaluateRequest("[]byte(\"ABC€\")", 1000, "this context will be ignored") @@ -1476,7 +1545,8 @@ func TestEvaluateRequest(t *testing.T) { client.VariablesRequest(ref) expr := client.ExpectVariablesResponse(t) expectChildren(t, expr, "mp[1]", 1) - expectVarExact(t, expr, 0, "data", "42", noChildren) + expectVarExact(t, expr, 0, "data", "(mp[1]).(data)", "42", noChildren) + validateEvaluateName(t, client, expr, 0) } // Pointer dereference @@ -1487,7 +1557,8 @@ func TestEvaluateRequest(t *testing.T) { client.VariablesRequest(ref) expr := client.ExpectVariablesResponse(t) expectChildren(t, expr, "*ms.Nest", 2) - expectVarExact(t, expr, 0, "Level", "1", noChildren) + expectVarExact(t, expr, 0, "Level", "(*ms.Nest).Level", "1", noChildren) + validateEvaluateName(t, client, expr, 0) } // Calls to builtin functions: cap, len, complex, imag and real @@ -1622,7 +1693,7 @@ func TestEvaluateCallRequest(t *testing.T) { client.VariablesRequest(ref) rv := client.ExpectVariablesResponse(t) expectChildren(t, rv, "rv", 1) - expectVarExact(t, rv, 0, "~r2", "3", noChildren) + expectVarExact(t, rv, 0, "~r2", "", "3", noChildren) } // One named return value // Panic doesn't panic, but instead returns the error as a named return variable @@ -1633,12 +1704,12 @@ func TestEvaluateCallRequest(t *testing.T) { client.VariablesRequest(ref) rv := client.ExpectVariablesResponse(t) expectChildren(t, rv, "rv", 1) - ref = expectVarExact(t, rv, 0, "~panic", "", hasChildren) + ref = expectVarExact(t, rv, 0, "~panic", "", "", hasChildren) if ref > 0 { client.VariablesRequest(ref) p := client.ExpectVariablesResponse(t) expectChildren(t, p, "~panic", 1) - expectVarExact(t, p, 0, "data", "\"callpanic panicked\"", noChildren) + expectVarExact(t, p, 0, "data", "", "\"callpanic panicked\"", noChildren) } } // Multiple return values @@ -1649,8 +1720,8 @@ func TestEvaluateCallRequest(t *testing.T) { client.VariablesRequest(ref) rvs := client.ExpectVariablesResponse(t) expectChildren(t, rvs, "rvs", 2) - expectVarExact(t, rvs, 0, "~r2", "1", noChildren) - expectVarExact(t, rvs, 1, "~r3", "2", noChildren) + expectVarExact(t, rvs, 0, "~r2", "", "1", noChildren) + expectVarExact(t, rvs, 1, "~r3", "", "2", noChildren) } // No frame defaults to top-most frame client.EvaluateRequest("call call1(one, two)", 0, "this context will be ignored") @@ -2051,7 +2122,7 @@ func TestAttachRequest(t *testing.T) { client.VariablesRequest(1001) // Locals locals := client.ExpectVariablesResponse(t) expectChildren(t, locals, "Locals", 1) - expectVarRegex(t, locals, 0, "i", "[0-9]+", noChildren) + expectVarRegex(t, locals, 0, "i", "i", "[0-9]+", noChildren) }, disconnect: true, }})