TrimPath string "help:\"remove `prefix` from recorded source file paths\""
WB bool "help:\"enable write barrier\"" // TODO: remove
PgoProfile string "help:\"read profile from `file`\""
- Url bool "help:\"print explanatory URL with error message if applicable\""
+ ErrorURL bool "help:\"print explanatory URL with error message if applicable\""
// Configuration derived from flags; not a flag itself.
Cfg struct {
sort.Stable(byPos(errorMsgs))
for i, err := range errorMsgs {
if i == 0 || err.msg != errorMsgs[i-1].msg {
- fmt.Printf("%s", err.msg)
- if Flag.Url && err.code != 0 {
- // TODO(gri) we should come up with a better URL eventually
- fmt.Printf("\thttps://pkg.go.dev/internal/types/errors#%s\n", err.code)
- }
+ fmt.Print(err.msg)
}
}
errorMsgs = errorMsgs[:0]
Importer: &importer,
Sizes: &gcSizes{},
}
+ if base.Flag.ErrorURL {
+ conf.ErrorURL = " [go.dev/e/%s]"
+ }
info := &types2.Info{
StoreTypesInSyntax: true,
Defs: make(map[*syntax.Name]types2.Object),
// If DisableUnusedImportCheck is set, packages are not checked
// for unused imports.
DisableUnusedImportCheck bool
+
+ // If a non-empty ErrorURL format string is provided, it is used
+ // to format an error URL link that is appended to the first line
+ // of an error message. ErrorURL must be a format string containing
+ // exactly one "%s" format, e.g. "[go.dev/e/%s]".
+ ErrorURL string
}
func srcimporter_setUsesCgo(conf *Config) {
// V4 has no method m but has M. Should not report wrongType.
checkMissingMethod("V4", false)
}
+
+func TestErrorURL(t *testing.T) {
+ conf := Config{ErrorURL: " [go.dev/e/%s]"}
+
+ // test case for a one-line error
+ const src1 = `
+package p
+var _ T
+`
+ _, err := typecheck(src1, &conf, nil)
+ if err == nil || !strings.HasSuffix(err.Error(), " [go.dev/e/UndeclaredName]") {
+ t.Errorf("src1: unexpected error: got %v", err)
+ }
+
+ // test case for a multi-line error
+ const src2 = `
+package p
+func f() int { return 0 }
+var _ = f(1, 2)
+`
+ _, err = typecheck(src2, &conf, nil)
+ if err == nil || !strings.Contains(err.Error(), " [go.dev/e/WrongArgCount]\n") {
+ t.Errorf("src1: unexpected error: got %v", err)
+ }
+}
pos = check.errpos
}
+ // If we have an URL for error codes, add a link to the first line.
+ if code != 0 && check.conf.ErrorURL != "" {
+ u := fmt.Sprintf(check.conf.ErrorURL, code)
+ if i := strings.Index(msg, "\n"); i >= 0 {
+ msg = msg[:i] + u + msg[i:]
+ } else {
+ msg += u
+ }
+ }
+
err := Error{pos, stripAnnotations(msg), msg, soft, code}
if check.firstErr == nil {
check.firstErr = err
// If DisableUnusedImportCheck is set, packages are not checked
// for unused imports.
DisableUnusedImportCheck bool
+
+ // If a non-empty _ErrorURL format string is provided, it is used
+ // to format an error URL link that is appended to the first line
+ // of an error message. ErrorURL must be a format string containing
+ // exactly one "%s" format, e.g. "[go.dev/e/%s]".
+ _ErrorURL string
}
func srcimporter_setUsesCgo(conf *Config) {
// V4 has no method m but has M. Should not report wrongType.
checkMissingMethod("V4", false)
}
+
+func TestErrorURL(t *testing.T) {
+ var conf Config
+ *stringFieldAddr(&conf, "_ErrorURL") = " [go.dev/e/%s]"
+
+ // test case for a one-line error
+ const src1 = `
+package p
+var _ T
+`
+ _, err := typecheck(src1, &conf, nil)
+ if err == nil || !strings.HasSuffix(err.Error(), " [go.dev/e/UndeclaredName]") {
+ t.Errorf("src1: unexpected error: got %v", err)
+ }
+
+ // test case for a multi-line error
+ const src2 = `
+package p
+func f() int { return 0 }
+var _ = f(1, 2)
+`
+ _, err = typecheck(src2, &conf, nil)
+ if err == nil || !strings.Contains(err.Error(), " [go.dev/e/WrongArgCount]\n") {
+ t.Errorf("src1: unexpected error: got %v", err)
+ }
+}
return (*bool)(v.FieldByName(name).Addr().UnsafePointer())
}
+// stringFieldAddr(conf, name) returns the address of the string field conf.<name>.
+// For accessing unexported fields.
+func stringFieldAddr(conf *Config, name string) *string {
+ v := reflect.Indirect(reflect.ValueOf(conf))
+ return (*string)(v.FieldByName(name).Addr().UnsafePointer())
+}
+
// TestManual is for manual testing of a package - either provided
// as a list of filenames belonging to the package, or a directory
// name containing the package files - after the test arguments
panic("no error code provided")
}
+ // If we have an URL for error codes, add a link to the first line.
+ if errp.code != 0 && check.conf._ErrorURL != "" {
+ u := fmt.Sprintf(check.conf._ErrorURL, errp.code)
+ if i := strings.Index(msg, "\n"); i >= 0 {
+ msg = msg[:i] + u + msg[i:]
+ } else {
+ msg += u
+ }
+ }
+
span := spanOf(errp.desc[0].posn)
e := Error{
Fset: check.fset,