diff --git a/README.md b/README.md index 624a82b..08683d4 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,10 @@ options. See the ConfigState documentation for more details. Specifies whether ASCII comment annotations are attached to byte slice and array dumps. +* CommentPointers + CommentPointer specifies whether pointer information will be added + as comments. + * IgnoreUnexported Specifies that unexported fields should be ignored. diff --git a/common.go b/common.go index 559fe99..198afd6 100644 --- a/common.go +++ b/common.go @@ -157,6 +157,9 @@ var ( hexZeroBytes = []byte("0x") zeroBytes = []byte("0") pointZeroBytes = []byte(".0") + openCommentBytes = []byte(" /*") + closeCommentBytes = []byte("*/ ") + pointerChainBytes = []byte("->") circularBytes = []byte("()") invalidAngleBytes = []byte("") ) diff --git a/config.go b/config.go index 9fee717..fb5ad0c 100644 --- a/config.go +++ b/config.go @@ -49,6 +49,10 @@ type ConfigState struct { // comment annotations. CommentBytes bool + // CommentPointer specifies whether pointer information will be added + // as comments. + CommentPointers bool + // IgnoreUnexported specifies that unexported struct fields should be // ignored during a dump. IgnoreUnexported bool @@ -110,6 +114,7 @@ func (c *ConfigState) Sdump(a interface{}) string { // Indent: " " // BytesWidth: 16 // CommentBytes: true +// CommentPointers: false // IgnoreUnexported: false // ElideType: false // SortKeys: false diff --git a/doc.go b/doc.go index 3c024b3..32375e5 100644 --- a/doc.go +++ b/doc.go @@ -65,6 +65,10 @@ The following configuration options are available: Specifies whether ASCII comment annotations are attached to byte slice and array dumps. + * CommentPointers + CommentPointer specifies whether pointer information will be added + as comments. + * IgnoreUnexported Specifies that unexported fields should be ignored. diff --git a/dump.go b/dump.go index da8bdc9..08ac1e4 100644 --- a/dump.go +++ b/dump.go @@ -87,6 +87,9 @@ func (d *dumpState) dumpPtr(v reflect.Value) { } } + // Keep list of all dereferenced pointers to show later. + var pointerChain []uintptr + // Figure out how many levels of indirection there are by dereferencing // pointers and unpacking interfaces down the chain while detecting circular // references. @@ -101,6 +104,9 @@ func (d *dumpState) dumpPtr(v reflect.Value) { } indirects++ addr := ve.Pointer() + if d.cs.CommentPointers { + pointerChain = append(pointerChain, addr) + } if pd, ok := d.pointers[addr]; ok && pd < d.depth { cycleFound = true indirects-- @@ -129,6 +135,18 @@ func (d *dumpState) dumpPtr(v reflect.Value) { d.w.Write(closeParenBytes) } + // Display pointer information. + if len(pointerChain) > 0 { + d.w.Write(openCommentBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr, true) + } + d.w.Write(closeCommentBytes) + } + // Display dereferenced value. switch { case nilFound == true: diff --git a/spew_test.go b/spew_test.go index dbec85e..92363e9 100644 --- a/spew_test.go +++ b/spew_test.go @@ -95,6 +95,10 @@ func initSpewTests() { noComDefault := utter.NewDefaultConfig() noComDefault.CommentBytes = false + // Byte slice without comments. + comPtrDefault := utter.NewDefaultConfig() + comPtrDefault.CommentPointers = true + // Byte slice with 8 columns. bs8Default := utter.NewDefaultConfig() bs8Default.BytesWidth = 8 @@ -116,6 +120,12 @@ func initSpewTests() { m map[string]int } + v := new(int) + *v = 10 + s := struct{ *int }{v} + sp := &s + spp := &sp + utterTests = []utterTest{ {scsDefault, fCSFdump, int8(127), "int8(127)\n"}, {scsDefault, fCSSdump, uint8(64), "uint8(0x40)\n"}, @@ -123,6 +133,9 @@ func initSpewTests() { {noComDefault, fCSFdump, []byte{1, 2, 3, 4, 5, 0}, "[]uint8{\n 0x01, 0x02, 0x03, 0x04, 0x05, 0x00,\n}\n", }, + {comPtrDefault, fCSFdump, s, fmt.Sprintf("struct { *int }{\n int: &int /*%p*/ (10),\n}\n", v)}, + {comPtrDefault, fCSFdump, sp, fmt.Sprintf("&struct { *int } /*%p*/ {\n int: &int /*%p*/ (10),\n}\n", sp, v)}, + {comPtrDefault, fCSFdump, spp, fmt.Sprintf("&&struct { *int } /*%p->%p*/ {\n int: &int /*%p*/ (10),\n}\n", spp, sp, v)}, {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0}, "[]uint8{\n" + " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" + " 0x03, 0x04, 0x05, 0x00, // |....|\n}\n",