mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 17:56:45 +08:00
service/dap: add len as metadata for map (#2584)
This commit is contained in:
@ -1907,10 +1907,15 @@ func (s *Server) childrenToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variab
|
||||
|
||||
func getNamedVariableCount(v *proc.Variable) int {
|
||||
namedVars := 0
|
||||
if v.Kind == reflect.Map && v.Len > 0 {
|
||||
// len
|
||||
namedVars += 1
|
||||
}
|
||||
if isListOfBytesOrRunes(v) {
|
||||
// string value of array/slice of bytes and runes.
|
||||
namedVars += 1
|
||||
}
|
||||
|
||||
return namedVars
|
||||
}
|
||||
|
||||
@ -1919,6 +1924,15 @@ func getNamedVariableCount(v *proc.Variable) int {
|
||||
func (s *Server) metadataToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variable, error) {
|
||||
children := []dap.Variable{} // must return empty array, not null, if no children
|
||||
|
||||
if v.Kind == reflect.Map && v.Len > 0 {
|
||||
children = append(children, dap.Variable{
|
||||
Name: "len()",
|
||||
Value: fmt.Sprintf("%d", v.Len),
|
||||
Type: "int",
|
||||
EvaluateName: fmt.Sprintf("len(%s)", v.fullyQualifiedNameOrExpr),
|
||||
})
|
||||
}
|
||||
|
||||
if isListOfBytesOrRunes(v.Variable) {
|
||||
// Return the string value of []byte or []rune.
|
||||
typeName := api.PrettyTypeName(v.DwarfType)
|
||||
|
||||
@ -1288,8 +1288,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m2 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, m2, "m2", 1) // each key-value represented by a single child
|
||||
ref = checkVarExact(t, m2, 0, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
|
||||
checkChildren(t, m2, "m2", 2) // each key-value represented by a single child
|
||||
checkVarExact(t, m2, 0, "len()", "len(m2)", "1", "int", noChildren)
|
||||
ref = checkVarExact(t, m2, 1, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m2kv1 := client.ExpectVariablesResponse(t)
|
||||
@ -1311,8 +1312,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m3 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, m3, "m3", 2) // each key-value represented by a single child
|
||||
ref = checkVarRegex(t, m3, 0, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
|
||||
checkChildren(t, m3, "m3", 3) // each key-value represented by a single child
|
||||
checkVarExact(t, m3, 0, "len()", "len(m3)", "2", "int", noChildren)
|
||||
ref = checkVarRegex(t, m3, 1, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m3kv0 := client.ExpectVariablesResponse(t)
|
||||
@ -1320,7 +1322,7 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
||||
checkVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", "int", noChildren)
|
||||
validateEvaluateName(t, client, m3kv0, 0)
|
||||
}
|
||||
ref = checkVarRegex(t, m3, 1, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
|
||||
ref = checkVarRegex(t, m3, 2, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
|
||||
if ref > 0 { // inspect another key from another key-value child
|
||||
client.VariablesRequest(ref)
|
||||
m3kv1 := client.ExpectVariablesResponse(t)
|
||||
@ -1334,10 +1336,11 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m4 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count
|
||||
checkVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
|
||||
checkVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
|
||||
ref = checkVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
|
||||
checkChildren(t, m4, "m4", 5) // each key and value represented by a child, so double the key-value count
|
||||
checkVarExact(t, m4, 0, "len()", "len(m4)", "2", "int", noChildren)
|
||||
checkVarRegex(t, m4, 1, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
|
||||
checkVarRegex(t, m4, 2, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
|
||||
ref = checkVarRegex(t, m4, 3, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m4Key1 := client.ExpectVariablesResponse(t)
|
||||
@ -1347,7 +1350,7 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
||||
validateEvaluateName(t, client, m4Key1, 0)
|
||||
validateEvaluateName(t, client, m4Key1, 1)
|
||||
}
|
||||
ref = checkVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
|
||||
ref = checkVarRegex(t, m4, 4, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m4Val1 := client.ExpectVariablesResponse(t)
|
||||
@ -1555,11 +1558,11 @@ func TestVariablesLoading(t *testing.T) {
|
||||
|
||||
// Map not fully loaded based on LoadConfig.MaxArrayValues
|
||||
// Expect to be able to load map by paging.
|
||||
ref = checkVarRegexIndexed(t, locals, -1, "m1", "m1", `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren, 66, 0)
|
||||
ref = checkVarRegexIndexed(t, locals, -1, "m1", "m1", `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren, 66, 1)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m1 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, m1, "m1", 64)
|
||||
checkChildren(t, m1, "m1", 65)
|
||||
|
||||
client.IndexedVariablesRequest(ref, 0, 66)
|
||||
m1 = client.ExpectVariablesResponse(t)
|
||||
@ -1587,6 +1590,10 @@ func TestVariablesLoading(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
client.NamedVariablesRequest(ref)
|
||||
named := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, named, "m1", 1)
|
||||
checkVarExact(t, named, 0, "len()", "len(m1)", "66", "int", noChildren)
|
||||
}
|
||||
|
||||
// Struct partially missing based on LoadConfig.MaxStructFields
|
||||
@ -1665,7 +1672,7 @@ func TestVariablesLoading(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
tmV0 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, tmV0, "tm.v[0]", 64)
|
||||
checkChildren(t, tmV0, "tm.v[0]", 65)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1695,7 +1702,7 @@ func TestVariablesLoading(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
tmV0 := client.ExpectVariablesResponse(t)
|
||||
checkChildren(t, tmV0, "tm.v[0]", 64)
|
||||
checkChildren(t, tmV0, "tm.v[0]", 65)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3052,20 +3059,20 @@ func TestVariableValueTruncation(t *testing.T) {
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
// Key format: <truncated>... @<address>
|
||||
checkVarRegex(t, client.ExpectVariablesResponse(t), 0, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
|
||||
checkVarRegex(t, client.ExpectVariablesResponse(t), 1, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
|
||||
}
|
||||
// key - scalar, value - scalar (inlined key:value display) => key not truncated
|
||||
ref = checkVarExact(t, locals, -1, "m6", "m6", "map[string]int ["+longstr+": 123, ]", "map[string]int", hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
checkVarExact(t, client.ExpectVariablesResponse(t), 0, longstr, `m6[`+longstr+`]`, "123", "string: int", noChildren)
|
||||
checkVarExact(t, client.ExpectVariablesResponse(t), 1, longstr, `m6[`+longstr+`]`, "123", "string: int", noChildren)
|
||||
}
|
||||
// key - compound, value - compound (array-like display) => key not truncated
|
||||
ref = checkVarExact(t, locals, -1, "m7", "m7", "map[main.C]main.C [{s: "+longstr+"}: {s: \"hello\"}, ]", "map[main.C]main.C", hasChildren)
|
||||
if ref > 0 {
|
||||
client.VariablesRequest(ref)
|
||||
m7 := client.ExpectVariablesResponse(t)
|
||||
checkVarRegex(t, m7, 0, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstr+`}`, `main\.C`, hasChildren)
|
||||
checkVarRegex(t, m7, 1, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstr+`}`, `main\.C`, hasChildren)
|
||||
}
|
||||
},
|
||||
disconnect: true,
|
||||
@ -4400,7 +4407,7 @@ func TestSetVariable(t *testing.T) {
|
||||
tester.evaluate(`m1["Malone"]`, "main.astruct {A: 2, B: 3}", hasChildren)
|
||||
m1Ref := checkVarRegex(t, locals, -1, "m1", "m1", `.*map\[string\]main\.astruct.*`, `map\[string\]main\.astruct`, hasChildren)
|
||||
m1 := tester.variables(m1Ref)
|
||||
elem1 := m1.Body.Variables[0]
|
||||
elem1 := m1.Body.Variables[1]
|
||||
tester.expectSetVariable(elem1.VariablesReference, "A", "-9999")
|
||||
tester.expectSetVariable(elem1.VariablesReference, "B", "10000")
|
||||
tester.evaluate(elem1.EvaluateName, "main.astruct {A: -9999, B: 10000}", hasChildren)
|
||||
|
||||
Reference in New Issue
Block a user