mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 18:27:37 +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 {
|
func getNamedVariableCount(v *proc.Variable) int {
|
||||||
namedVars := 0
|
namedVars := 0
|
||||||
|
if v.Kind == reflect.Map && v.Len > 0 {
|
||||||
|
// len
|
||||||
|
namedVars += 1
|
||||||
|
}
|
||||||
if isListOfBytesOrRunes(v) {
|
if isListOfBytesOrRunes(v) {
|
||||||
// string value of array/slice of bytes and runes.
|
// string value of array/slice of bytes and runes.
|
||||||
namedVars += 1
|
namedVars += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return namedVars
|
return namedVars
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1919,6 +1924,15 @@ func getNamedVariableCount(v *proc.Variable) int {
|
|||||||
func (s *Server) metadataToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variable, error) {
|
func (s *Server) metadataToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variable, error) {
|
||||||
children := []dap.Variable{} // must return empty array, not null, if no children
|
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) {
|
if isListOfBytesOrRunes(v.Variable) {
|
||||||
// Return the string value of []byte or []rune.
|
// Return the string value of []byte or []rune.
|
||||||
typeName := api.PrettyTypeName(v.DwarfType)
|
typeName := api.PrettyTypeName(v.DwarfType)
|
||||||
|
|||||||
@ -1288,8 +1288,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
|||||||
if ref > 0 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m2 := client.ExpectVariablesResponse(t)
|
m2 := client.ExpectVariablesResponse(t)
|
||||||
checkChildren(t, m2, "m2", 1) // each key-value represented by a single child
|
checkChildren(t, m2, "m2", 2) // 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)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m2kv1 := client.ExpectVariablesResponse(t)
|
m2kv1 := client.ExpectVariablesResponse(t)
|
||||||
@ -1311,8 +1312,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
|||||||
if ref > 0 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m3 := client.ExpectVariablesResponse(t)
|
m3 := client.ExpectVariablesResponse(t)
|
||||||
checkChildren(t, m3, "m3", 2) // each key-value represented by a single child
|
checkChildren(t, m3, "m3", 3) // 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)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m3kv0 := client.ExpectVariablesResponse(t)
|
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)
|
checkVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", "int", noChildren)
|
||||||
validateEvaluateName(t, client, m3kv0, 0)
|
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
|
if ref > 0 { // inspect another key from another key-value child
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m3kv1 := client.ExpectVariablesResponse(t)
|
m3kv1 := client.ExpectVariablesResponse(t)
|
||||||
@ -1334,10 +1336,11 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
|||||||
if ref > 0 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m4 := client.ExpectVariablesResponse(t)
|
m4 := client.ExpectVariablesResponse(t)
|
||||||
checkChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count
|
checkChildren(t, m4, "m4", 5) // 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)
|
checkVarExact(t, m4, 0, "len()", "len(m4)", "2", "int", noChildren)
|
||||||
checkVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
|
checkVarRegex(t, m4, 1, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `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)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m4Key1 := client.ExpectVariablesResponse(t)
|
m4Key1 := client.ExpectVariablesResponse(t)
|
||||||
@ -1347,7 +1350,7 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
|
|||||||
validateEvaluateName(t, client, m4Key1, 0)
|
validateEvaluateName(t, client, m4Key1, 0)
|
||||||
validateEvaluateName(t, client, m4Key1, 1)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m4Val1 := client.ExpectVariablesResponse(t)
|
m4Val1 := client.ExpectVariablesResponse(t)
|
||||||
@ -1555,11 +1558,11 @@ func TestVariablesLoading(t *testing.T) {
|
|||||||
|
|
||||||
// Map not fully loaded based on LoadConfig.MaxArrayValues
|
// Map not fully loaded based on LoadConfig.MaxArrayValues
|
||||||
// Expect to be able to load map by paging.
|
// 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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m1 := client.ExpectVariablesResponse(t)
|
m1 := client.ExpectVariablesResponse(t)
|
||||||
checkChildren(t, m1, "m1", 64)
|
checkChildren(t, m1, "m1", 65)
|
||||||
|
|
||||||
client.IndexedVariablesRequest(ref, 0, 66)
|
client.IndexedVariablesRequest(ref, 0, 66)
|
||||||
m1 = client.ExpectVariablesResponse(t)
|
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
|
// Struct partially missing based on LoadConfig.MaxStructFields
|
||||||
@ -1665,7 +1672,7 @@ func TestVariablesLoading(t *testing.T) {
|
|||||||
if ref > 0 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
tmV0 := client.ExpectVariablesResponse(t)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
tmV0 := client.ExpectVariablesResponse(t)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
// Key format: <truncated>... @<address>
|
// 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
|
// 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)
|
ref = checkVarExact(t, locals, -1, "m6", "m6", "map[string]int ["+longstr+": 123, ]", "map[string]int", hasChildren)
|
||||||
if ref > 0 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
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
|
// 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)
|
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 {
|
if ref > 0 {
|
||||||
client.VariablesRequest(ref)
|
client.VariablesRequest(ref)
|
||||||
m7 := client.ExpectVariablesResponse(t)
|
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,
|
disconnect: true,
|
||||||
@ -4400,7 +4407,7 @@ func TestSetVariable(t *testing.T) {
|
|||||||
tester.evaluate(`m1["Malone"]`, "main.astruct {A: 2, B: 3}", hasChildren)
|
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)
|
m1Ref := checkVarRegex(t, locals, -1, "m1", "m1", `.*map\[string\]main\.astruct.*`, `map\[string\]main\.astruct`, hasChildren)
|
||||||
m1 := tester.variables(m1Ref)
|
m1 := tester.variables(m1Ref)
|
||||||
elem1 := m1.Body.Variables[0]
|
elem1 := m1.Body.Variables[1]
|
||||||
tester.expectSetVariable(elem1.VariablesReference, "A", "-9999")
|
tester.expectSetVariable(elem1.VariablesReference, "A", "-9999")
|
||||||
tester.expectSetVariable(elem1.VariablesReference, "B", "10000")
|
tester.expectSetVariable(elem1.VariablesReference, "B", "10000")
|
||||||
tester.evaluate(elem1.EvaluateName, "main.astruct {A: -9999, B: 10000}", hasChildren)
|
tester.evaluate(elem1.EvaluateName, "main.astruct {A: -9999, B: 10000}", hasChildren)
|
||||||
|
|||||||
Reference in New Issue
Block a user