fmt.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xerrors
  5. import (
  6. "fmt"
  7. "strings"
  8. "golang.org/x/xerrors/internal"
  9. )
  10. // Errorf formats according to a format specifier and returns the string as a
  11. // value that satisfies error.
  12. //
  13. // The returned error includes the file and line number of the caller when
  14. // formatted with additional detail enabled. If the last argument is an error
  15. // the returned error's Format method will return it if the format string ends
  16. // with ": %s", ": %v", or ": %w". If the last argument is an error and the
  17. // format string ends with ": %w", the returned error implements Wrapper
  18. // with an Unwrap method returning it.
  19. func Errorf(format string, a ...interface{}) error {
  20. err, wrap := lastError(format, a)
  21. format = formatPlusW(format)
  22. if err == nil {
  23. return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
  24. }
  25. // TODO: this is not entirely correct. The error value could be
  26. // printed elsewhere in format if it mixes numbered with unnumbered
  27. // substitutions. With relatively small changes to doPrintf we can
  28. // have it optionally ignore extra arguments and pass the argument
  29. // list in its entirety.
  30. msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
  31. frame := Frame{}
  32. if internal.EnableTrace {
  33. frame = Caller(1)
  34. }
  35. if wrap {
  36. return &wrapError{msg, err, frame}
  37. }
  38. return &noWrapError{msg, err, frame}
  39. }
  40. // formatPlusW is used to avoid the vet check that will barf at %w.
  41. func formatPlusW(s string) string {
  42. return s
  43. }
  44. func lastError(format string, a []interface{}) (err error, wrap bool) {
  45. wrap = strings.HasSuffix(format, ": %w")
  46. if !wrap &&
  47. !strings.HasSuffix(format, ": %s") &&
  48. !strings.HasSuffix(format, ": %v") {
  49. return nil, false
  50. }
  51. if len(a) == 0 {
  52. return nil, false
  53. }
  54. err, ok := a[len(a)-1].(error)
  55. if !ok {
  56. return nil, false
  57. }
  58. return err, wrap
  59. }
  60. type noWrapError struct {
  61. msg string
  62. err error
  63. frame Frame
  64. }
  65. func (e *noWrapError) Error() string {
  66. return fmt.Sprint(e)
  67. }
  68. func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
  69. func (e *noWrapError) FormatError(p Printer) (next error) {
  70. p.Print(e.msg)
  71. e.frame.Format(p)
  72. return e.err
  73. }
  74. type wrapError struct {
  75. msg string
  76. err error
  77. frame Frame
  78. }
  79. func (e *wrapError) Error() string {
  80. return fmt.Sprint(e)
  81. }
  82. func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
  83. func (e *wrapError) FormatError(p Printer) (next error) {
  84. p.Print(e.msg)
  85. e.frame.Format(p)
  86. return e.err
  87. }
  88. func (e *wrapError) Unwrap() error {
  89. return e.err
  90. }