Source file src/cmd/vendor/golang.org/x/xerrors/fmt.go

     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  
     5  package xerrors
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  	"unicode"
    11  	"unicode/utf8"
    12  
    13  	"golang.org/x/xerrors/internal"
    14  )
    15  
    16  const percentBangString = "%!"
    17  
    18  // Errorf formats according to a format specifier and returns the string as a
    19  // value that satisfies error.
    20  //
    21  // The returned error includes the file and line number of the caller when
    22  // formatted with additional detail enabled. If the last argument is an error
    23  // the returned error's Format method will return it if the format string ends
    24  // with ": %s", ": %v", or ": %w". If the last argument is an error and the
    25  // format string ends with ": %w", the returned error implements an Unwrap
    26  // method returning it.
    27  //
    28  // If the format specifier includes a %w verb with an error operand in a
    29  // position other than at the end, the returned error will still implement an
    30  // Unwrap method returning the operand, but the error's Format method will not
    31  // return the wrapped error.
    32  //
    33  // It is invalid to include more than one %w verb or to supply it with an
    34  // operand that does not implement the error interface. The %w verb is otherwise
    35  // a synonym for %v.
    36  func Errorf(format string, a ...interface{}) error {
    37  	format = formatPlusW(format)
    38  	// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
    39  	wrap := strings.HasSuffix(format, ": %w")
    40  	idx, format2, ok := parsePercentW(format)
    41  	percentWElsewhere := !wrap && idx >= 0
    42  	if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
    43  		err := errorAt(a, len(a)-1)
    44  		if err == nil {
    45  			return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
    46  		}
    47  		// TODO: this is not entirely correct. The error value could be
    48  		// printed elsewhere in format if it mixes numbered with unnumbered
    49  		// substitutions. With relatively small changes to doPrintf we can
    50  		// have it optionally ignore extra arguments and pass the argument
    51  		// list in its entirety.
    52  		msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
    53  		frame := Frame{}
    54  		if internal.EnableTrace {
    55  			frame = Caller(1)
    56  		}
    57  		if wrap {
    58  			return &wrapError{msg, err, frame}
    59  		}
    60  		return &noWrapError{msg, err, frame}
    61  	}
    62  	// Support %w anywhere.
    63  	// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
    64  	msg := fmt.Sprintf(format2, a...)
    65  	if idx < 0 {
    66  		return &noWrapError{msg, nil, Caller(1)}
    67  	}
    68  	err := errorAt(a, idx)
    69  	if !ok || err == nil {
    70  		// Too many %ws or argument of %w is not an error. Approximate the Go
    71  		// 1.13 fmt.Errorf message.
    72  		return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
    73  	}
    74  	frame := Frame{}
    75  	if internal.EnableTrace {
    76  		frame = Caller(1)
    77  	}
    78  	return &wrapError{msg, err, frame}
    79  }
    80  
    81  func errorAt(args []interface{}, i int) error {
    82  	if i < 0 || i >= len(args) {
    83  		return nil
    84  	}
    85  	err, ok := args[i].(error)
    86  	if !ok {
    87  		return nil
    88  	}
    89  	return err
    90  }
    91  
    92  // formatPlusW is used to avoid the vet check that will barf at %w.
    93  func formatPlusW(s string) string {
    94  	return s
    95  }
    96  
    97  // Return the index of the only %w in format, or -1 if none.
    98  // Also return a rewritten format string with %w replaced by %v, and
    99  // false if there is more than one %w.
   100  // TODO: handle "%[N]w".
   101  func parsePercentW(format string) (idx int, newFormat string, ok bool) {
   102  	// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
   103  	idx = -1
   104  	ok = true
   105  	n := 0
   106  	sz := 0
   107  	var isW bool
   108  	for i := 0; i < len(format); i += sz {
   109  		if format[i] != '%' {
   110  			sz = 1
   111  			continue
   112  		}
   113  		// "%%" is not a format directive.
   114  		if i+1 < len(format) && format[i+1] == '%' {
   115  			sz = 2
   116  			continue
   117  		}
   118  		sz, isW = parsePrintfVerb(format[i:])
   119  		if isW {
   120  			if idx >= 0 {
   121  				ok = false
   122  			} else {
   123  				idx = n
   124  			}
   125  			// "Replace" the last character, the 'w', with a 'v'.
   126  			p := i + sz - 1
   127  			format = format[:p] + "v" + format[p+1:]
   128  		}
   129  		n++
   130  	}
   131  	return idx, format, ok
   132  }
   133  
   134  // Parse the printf verb starting with a % at s[0].
   135  // Return how many bytes it occupies and whether the verb is 'w'.
   136  func parsePrintfVerb(s string) (int, bool) {
   137  	// Assume only that the directive is a sequence of non-letters followed by a single letter.
   138  	sz := 0
   139  	var r rune
   140  	for i := 1; i < len(s); i += sz {
   141  		r, sz = utf8.DecodeRuneInString(s[i:])
   142  		if unicode.IsLetter(r) {
   143  			return i + sz, r == 'w'
   144  		}
   145  	}
   146  	return len(s), false
   147  }
   148  
   149  type noWrapError struct {
   150  	msg   string
   151  	err   error
   152  	frame Frame
   153  }
   154  
   155  func (e *noWrapError) Error() string {
   156  	return fmt.Sprint(e)
   157  }
   158  
   159  func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
   160  
   161  func (e *noWrapError) FormatError(p Printer) (next error) {
   162  	p.Print(e.msg)
   163  	e.frame.Format(p)
   164  	return e.err
   165  }
   166  
   167  type wrapError struct {
   168  	msg   string
   169  	err   error
   170  	frame Frame
   171  }
   172  
   173  func (e *wrapError) Error() string {
   174  	return fmt.Sprint(e)
   175  }
   176  
   177  func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
   178  
   179  func (e *wrapError) FormatError(p Printer) (next error) {
   180  	p.Print(e.msg)
   181  	e.frame.Format(p)
   182  	return e.err
   183  }
   184  
   185  func (e *wrapError) Unwrap() error {
   186  	return e.err
   187  }
   188  

View as plain text