mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +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
	 Suzy Mueller
					Suzy Mueller