printf

Imports

Imports #

"fmt"
"go/ast"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/internal/typeparams"
"bytes"
_ "embed"
"fmt"
"go/ast"
"go/constant"
"go/token"
"go/types"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"unicode/utf8"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/versions"

Constants & Variables

Analyzer var #

var Analyzer = *ast.UnaryExpr

KindErrorf const #

const KindErrorf

KindNone const #

const KindNone Kind = iota

KindPrint const #

const KindPrint

KindPrintf const #

const KindPrintf

allFlags const #

Common flag sets for printf verbs.

const allFlags = " -+.0#"

anyType const #

const anyType printfArgType = *ast.UnaryExpr

argBool const #

const argBool printfArgType = *ast.BinaryExpr

argComplex const #

const argComplex

argError const #

const argError

argFloat const #

const argFloat

argInt const #

const argInt

argPointer const #

const argPointer

argRune const #

const argRune

argString const #

const argString

doc var #

go:embed doc.go

var doc string

errorType var #

var errorType = *ast.TypeAssertExpr

flagsRE const #

const flagsRE = `[+\-#]*`

indexOptRE const #

const indexOptRE = `(\[[0-9]+\])?`

isPrint var #

isPrint records the print functions. If a key ends in 'f' then it is assumed to be a formatted print. Keys are either values returned by (*types.Func).FullName, or case-insensitive identifiers such as "errorf". The -funcs flag adds to this set. The set below includes facts for many important standard library functions, even though the analysis is capable of deducing that, for example, fmt.Printf forwards to fmt.Fprintf. We avoid relying on the driver applying analyzers to standard packages because "go vet" does not do so with gccgo, and nor do some other build systems.

var isPrint = stringSet{...}

noFlag const #

Common flag sets for printf verbs.

const noFlag = ""

numFlag const #

Common flag sets for printf verbs.

const numFlag = " -+.0"

numOptRE const #

const numOptRE = *ast.BinaryExpr

printFormatRE var #

printFormatRE is the regexp we match and report as a possible format string in the first argument to unformatted prints like fmt.Print. We exclude the space flag, so that printing a string like "x % y" is not reported as a format.

var printFormatRE = *ast.CallExpr

printVerbs var #

printVerbs identifies which flags are known to printf for each verb.

var printVerbs = []printVerb{...}

sharpNumFlag const #

Common flag sets for printf verbs.

const sharpNumFlag = " -+.0#"

suppressNonconstants var #

suppressNonconstants suppresses reporting printf calls with non-constant formatting strings (proposal #60529) when true. This variable is to allow for staging the transition to newer versions of x/tools by vendoring. Remove this after the 1.24 release.

var suppressNonconstants bool

verbRE const #

const verbRE = `[bcdefgopqstvxEFGTUX]`

Type Aliases

Kind type #

Kind is a kind of fmt function behavior.

type Kind int

printfArgType type #

printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.

type printfArgType int

stringSet type #

stringSet is a set-of-nonempty-strings-valued flag. Note: elements without a '.' get lower-cased.

type stringSet map[string]bool

Structs

Result struct #

Result is the printf analyzer's result type. Clients may query the result to learn whether a function behaves like fmt.Print or fmt.Printf.

type Result struct {
funcs map[*types.Func]Kind
}

argMatcher struct #

argMatcher recursively matches types against the printfArgType t. To short-circuit recursion, it keeps track of types that have already been matched (or are in the process of being matched) via the seen map. Recursion arises from the compound types {map,chan,slice} which may be printed with %d etc. if that is appropriate for their element types, as well as from type parameters, which are expanded to the constituents of their type set. The reason field may be set to report the cause of the mismatch.

type argMatcher struct {
t printfArgType
seen map[types.Type]bool
reason string
}

formatState struct #

formatState holds the parsed representation of a printf directive such as "%3.*[4]d". It is constructed by parsePrintfVerb.

type formatState struct {
verb rune
format string
name string
flags []byte
argNums []int
firstArg int
pass *analysis.Pass
call *ast.CallExpr
argNum int
hasIndex bool
indexPending bool
nbytes int
}

isWrapper struct #

isWrapper is a fact indicating that a function is a print or printf wrapper.

type isWrapper struct {
Kind Kind
}

printVerb struct #

type printVerb struct {
verb rune
flags string
typ printfArgType
}

printfCaller struct #

type printfCaller struct {
w *printfWrapper
call *ast.CallExpr
}

printfWrapper struct #

type printfWrapper struct {
obj *types.Func
fdecl *ast.FuncDecl
format *types.Var
args *types.Var
callers []printfCaller
failed bool
}

Functions

AFact method #

func (f *isWrapper) AFact()

Kind method #

Kind reports whether fn behaves like fmt.Print or fmt.Printf.

func (r *Result) Kind(fn *types.Func) Kind

Set method #

func (ss stringSet) Set(flag string) error

String method #

func (ss stringSet) String() string

String method #

func (kind Kind) String() string

String method #

func (f *isWrapper) String() string

argCanBeChecked function #

argCanBeChecked reports whether the specified argument is statically present; it may be beyond the list of arguments or in a terminal slice... argument, which means we can't see it.

func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool

checkCalls function #

checkCalls triggers the print-specific checks for calls that invoke a print function.

func checkCalls(pass *analysis.Pass)

checkPrint function #

checkPrint checks a call to an unformatted print routine such as Println.

func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func)

checkPrintf function #

checkPrintf checks a call to a formatted print routine such as Printf.

func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, fn *types.Func)

checkPrintfFwd function #

checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly. It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).

func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind Kind, res *Result)

count function #

count(n, what) returns "1 what" or "N whats" (assuming the plural of what is whats).

func count(n int, what string) string

findPrintfLike function #

findPrintfLike scans the entire package to find printf-like functions.

func findPrintfLike(pass *analysis.Pass, res *Result) (any, error)

formatStringIndex function #

formatStringIndex returns the index of the format string (the last non-variadic parameter) within the given printf-like call expression, or -1 if unknown.

func formatStringIndex(pass *analysis.Pass, call *ast.CallExpr) int

init function #

func init()

isConvertibleToString function #

func isConvertibleToString(typ types.Type) bool

isFormatter function #

isFormatter reports whether t could satisfy fmt.Formatter. The only interface method to look for is "Format(State, rune)".

func isFormatter(typ types.Type) bool

isFunctionValue function #

isFunctionValue reports whether the expression is a function as opposed to a function call. It is almost always a mistake to print a function value.

func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool

isStringer function #

isStringer reports whether the method signature matches the String() definition in fmt.Stringer.

func isStringer(sig *types.Signature) bool

match function #

func match(info *types.Info, arg ast.Expr, param *types.Var) bool

match method #

match checks if typ matches m's printf arg type. If topLevel is true, typ is the actual type of the printf arg, for which special rules apply. As a special case, top level type parameters pass topLevel=true when checking for matches among the constituents of their type set, as type arguments will replace the type parameter at compile time.

func (m *argMatcher) match(typ types.Type, topLevel bool) bool

matchArgType function #

matchArgType reports an error if printf verb t is not appropriate for operand arg. If arg is a type parameter, the verb t must be appropriate for every type in the type parameter type set.

func matchArgType(pass *analysis.Pass, t printfArgType, arg ast.Expr) (reason string, ok bool)

maybePrintfWrapper function #

maybePrintfWrapper decides whether decl (a declared function) may be a wrapper around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper function describing the declaration. Later processing will analyze the graph of potential printf wrappers to pick out the ones that are true wrappers. A function may be a Printf or Print wrapper if its last argument is ...interface{}. If the next-to-last argument is a string, then this may be a Printf wrapper. Otherwise it may be a Print wrapper.

func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper

okPrintfArg function #

okPrintfArg compares the formatState to the arguments actually present, reporting any discrepancies it can discern. If the final argument is ellipsissed, there's little it can do for that.

func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool)

parseFlags method #

parseFlags accepts any printf flags.

func (s *formatState) parseFlags()

parseIndex method #

parseIndex scans an index expression. It returns false if there is a syntax error.

func (s *formatState) parseIndex() bool

parseNum method #

parseNum scans a width or precision (or *). It returns false if there's a bad index expression.

func (s *formatState) parseNum() bool

parsePrecision method #

parsePrecision scans for a precision. It returns false if there's a bad index expression.

func (s *formatState) parsePrecision() bool

parsePrintfVerb function #

parsePrintfVerb looks the formatting directive that begins the format string and returns a formatState that encodes what the directive wants, without looking at the actual arguments present in the call. The result is nil if there is an error.

func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name string, format string, firstArg int, argNum int) *formatState

printfNameAndKind function #

func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind)

recursiveStringer function #

recursiveStringer reports whether the argument e is a potential recursive call to stringer or is an error, such as t and &t in these examples: func (t *T) String() string { printf("%s", t) } func (t T) Error() string { printf("%s", t) } func (t T) String() string { printf("%s", &t) }

func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool)

run function #

func run(pass *analysis.Pass) (any, error)

scanNum method #

scanNum advances through a decimal number if present.

func (s *formatState) scanNum()

stringConstantExpr function #

stringConstantExpr returns expression's string constant value. ("", false) is returned if expression isn't a string constant.

func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool)

Generated with Arrow