-
Notifications
You must be signed in to change notification settings - Fork 208
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The reporter tries to aggresively elide data that is not interesting to the user. However, doing so many result in an output that does not visually indicate the difference between semantically different objects. This CL modifies the reporter to try increasingly verbose presets until two different objects are formatted differently. This CL includes a custom implementation of reflect.Type.String that can print the type with fully qualified names to disambiguate types that happen to have the same base package name. Fixes #194
- Loading branch information
Showing
10 changed files
with
597 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright 2020, The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE.md file. | ||
|
||
// Package foo is deliberately named differently than the parent directory. | ||
// It contain declarations that have ambiguity in their short names, | ||
// relative to a different package also called foo. | ||
package foo | ||
|
||
type Bar struct{ S string } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright 2020, The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE.md file. | ||
|
||
// Package foo is deliberately named differently than the parent directory. | ||
// It contain declarations that have ambiguity in their short names, | ||
// relative to a different package also called foo. | ||
package foo | ||
|
||
type Bar struct{ S string } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Copyright 2020, The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE.md file. | ||
|
||
package value | ||
|
||
import ( | ||
"reflect" | ||
"strconv" | ||
) | ||
|
||
// TypeString is nearly identical to reflect.Type.String, | ||
// but has an additional option to specify that full type names be used. | ||
func TypeString(t reflect.Type, qualified bool) string { | ||
return string(appendTypeName(nil, t, qualified, false)) | ||
} | ||
|
||
func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { | ||
// BUG: Go reflection provides no way to disambiguate two named types | ||
// of the same name and within the same package, | ||
// but declared within the namespace of different functions. | ||
|
||
// Named type. | ||
if t.Name() != "" { | ||
if qualified && t.PkgPath() != "" { | ||
b = append(b, '"') | ||
b = append(b, t.PkgPath()...) | ||
b = append(b, '"') | ||
b = append(b, '.') | ||
b = append(b, t.Name()...) | ||
} else { | ||
b = append(b, t.String()...) | ||
} | ||
return b | ||
} | ||
|
||
// Unnamed type. | ||
switch k := t.Kind(); k { | ||
case reflect.Bool, reflect.String, reflect.UnsafePointer, | ||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | ||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, | ||
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: | ||
b = append(b, k.String()...) | ||
case reflect.Chan: | ||
if t.ChanDir() == reflect.RecvDir { | ||
b = append(b, "<-"...) | ||
} | ||
b = append(b, "chan"...) | ||
if t.ChanDir() == reflect.SendDir { | ||
b = append(b, "<-"...) | ||
} | ||
b = append(b, ' ') | ||
b = appendTypeName(b, t.Elem(), qualified, false) | ||
case reflect.Func: | ||
if !elideFunc { | ||
b = append(b, "func"...) | ||
} | ||
b = append(b, '(') | ||
for i := 0; i < t.NumIn(); i++ { | ||
if i > 0 { | ||
b = append(b, ", "...) | ||
} | ||
if i == t.NumIn()-1 && t.IsVariadic() { | ||
b = append(b, "..."...) | ||
b = appendTypeName(b, t.In(i).Elem(), qualified, false) | ||
} else { | ||
b = appendTypeName(b, t.In(i), qualified, false) | ||
} | ||
} | ||
b = append(b, ')') | ||
switch t.NumOut() { | ||
case 0: | ||
// Do nothing | ||
case 1: | ||
b = append(b, ' ') | ||
b = appendTypeName(b, t.Out(0), qualified, false) | ||
default: | ||
b = append(b, " ("...) | ||
for i := 0; i < t.NumOut(); i++ { | ||
if i > 0 { | ||
b = append(b, ", "...) | ||
} | ||
b = appendTypeName(b, t.Out(i), qualified, false) | ||
} | ||
b = append(b, ')') | ||
} | ||
case reflect.Struct: | ||
b = append(b, "struct{ "...) | ||
for i := 0; i < t.NumField(); i++ { | ||
if i > 0 { | ||
b = append(b, "; "...) | ||
} | ||
sf := t.Field(i) | ||
if !sf.Anonymous { | ||
if qualified && sf.PkgPath != "" { | ||
b = append(b, '"') | ||
b = append(b, sf.PkgPath...) | ||
b = append(b, '"') | ||
b = append(b, '.') | ||
} | ||
b = append(b, sf.Name...) | ||
b = append(b, ' ') | ||
} | ||
b = appendTypeName(b, sf.Type, qualified, false) | ||
if sf.Tag != "" { | ||
b = append(b, ' ') | ||
b = strconv.AppendQuote(b, string(sf.Tag)) | ||
} | ||
} | ||
if b[len(b)-1] == ' ' { | ||
b = b[:len(b)-1] | ||
} else { | ||
b = append(b, ' ') | ||
} | ||
b = append(b, '}') | ||
case reflect.Slice, reflect.Array: | ||
b = append(b, '[') | ||
if k == reflect.Array { | ||
b = strconv.AppendUint(b, uint64(t.Len()), 10) | ||
} | ||
b = append(b, ']') | ||
b = appendTypeName(b, t.Elem(), qualified, false) | ||
case reflect.Map: | ||
b = append(b, "map["...) | ||
b = appendTypeName(b, t.Key(), qualified, false) | ||
b = append(b, ']') | ||
b = appendTypeName(b, t.Elem(), qualified, false) | ||
case reflect.Ptr: | ||
b = append(b, '*') | ||
b = appendTypeName(b, t.Elem(), qualified, false) | ||
case reflect.Interface: | ||
b = append(b, "interface{ "...) | ||
for i := 0; i < t.NumMethod(); i++ { | ||
if i > 0 { | ||
b = append(b, "; "...) | ||
} | ||
m := t.Method(i) | ||
if qualified && m.PkgPath != "" { | ||
b = append(b, '"') | ||
b = append(b, m.PkgPath...) | ||
b = append(b, '"') | ||
b = append(b, '.') | ||
} | ||
b = append(b, m.Name...) | ||
b = appendTypeName(b, m.Type, qualified, true) | ||
} | ||
if b[len(b)-1] == ' ' { | ||
b = b[:len(b)-1] | ||
} else { | ||
b = append(b, ' ') | ||
} | ||
b = append(b, '}') | ||
default: | ||
panic("invalid kind: " + k.String()) | ||
} | ||
return b | ||
} |
Oops, something went wrong.