"Fossies" - the Fresh Open Source Software Archive

Member "buildah-1.27.2/tests/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go" (20 Sep 2022, 6372 Bytes) of package /linux/misc/buildah-1.27.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "allowed.go": 1.26.4_vs_1.27.0.

    1 package errorlint
    2 
    3 import (
    4     "fmt"
    5     "go/ast"
    6 )
    7 
    8 var allowedErrors = []struct {
    9     err string
   10     fun string
   11 }{
   12     // pkg/archive/tar
   13     {err: "io.EOF", fun: "(*tar.Reader).Next"},
   14     {err: "io.EOF", fun: "(*tar.Reader).Read"},
   15     // pkg/bufio
   16     {err: "io.EOF", fun: "(*bufio.Reader).Discard"},
   17     {err: "io.EOF", fun: "(*bufio.Reader).Peek"},
   18     {err: "io.EOF", fun: "(*bufio.Reader).Read"},
   19     {err: "io.EOF", fun: "(*bufio.Reader).ReadByte"},
   20     {err: "io.EOF", fun: "(*bufio.Reader).ReadBytes"},
   21     {err: "io.EOF", fun: "(*bufio.Reader).ReadLine"},
   22     {err: "io.EOF", fun: "(*bufio.Reader).ReadSlice"},
   23     {err: "io.EOF", fun: "(*bufio.Reader).ReadString"},
   24     {err: "io.EOF", fun: "(*bufio.Scanner).Scan"},
   25     // pkg/bytes
   26     {err: "io.EOF", fun: "(*bytes.Buffer).Read"},
   27     {err: "io.EOF", fun: "(*bytes.Buffer).ReadByte"},
   28     {err: "io.EOF", fun: "(*bytes.Buffer).ReadBytes"},
   29     {err: "io.EOF", fun: "(*bytes.Buffer).ReadRune"},
   30     {err: "io.EOF", fun: "(*bytes.Buffer).ReadString"},
   31     {err: "io.EOF", fun: "(*bytes.Reader).Read"},
   32     {err: "io.EOF", fun: "(*bytes.Reader).ReadAt"},
   33     {err: "io.EOF", fun: "(*bytes.Reader).ReadByte"},
   34     {err: "io.EOF", fun: "(*bytes.Reader).ReadRune"},
   35     {err: "io.EOF", fun: "(*bytes.Reader).ReadString"},
   36     // pkg/database/sql
   37     {err: "sql.ErrNoRows", fun: "(*database/sql.Row).Scan"},
   38     // pkg/io
   39     {err: "io.EOF", fun: "(io.Reader).Read"},
   40     {err: "io.ErrClosedPipe", fun: "(*io.PipeWriter).Write"},
   41     {err: "io.ErrShortBuffer", fun: "io.ReadAtLeast"},
   42     {err: "io.ErrUnexpectedEOF", fun: "io.ReadAtLeast"},
   43     {err: "io.ErrUnexpectedEOF", fun: "io.ReadFull"},
   44     // pkg/net/http
   45     {err: "http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServe"},
   46     {err: "http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServeTLS"},
   47     {err: "http.ErrServerClosed", fun: "(*net/http.Server).Serve"},
   48     {err: "http.ErrServerClosed", fun: "(*net/http.Server).ServeTLS"},
   49     {err: "http.ErrServerClosed", fun: "http.ListenAndServe"},
   50     {err: "http.ErrServerClosed", fun: "http.ListenAndServeTLS"},
   51     {err: "http.ErrServerClosed", fun: "http.Serve"},
   52     {err: "http.ErrServerClosed", fun: "http.ServeTLS"},
   53     // pkg/os
   54     {err: "io.EOF", fun: "(*os.File).Read"},
   55     {err: "io.EOF", fun: "(*os.File).ReadAt"},
   56     {err: "io.EOF", fun: "(*os.File).ReadDir"},
   57     {err: "io.EOF", fun: "(*os.File).Readdir"},
   58     {err: "io.EOF", fun: "(*os.File).Readdirnames"},
   59     // pkg/strings
   60     {err: "io.EOF", fun: "(*strings.Reader).Read"},
   61     {err: "io.EOF", fun: "(*strings.Reader).ReadAt"},
   62     {err: "io.EOF", fun: "(*strings.Reader).ReadByte"},
   63     {err: "io.EOF", fun: "(*strings.Reader).ReadRune"},
   64 }
   65 
   66 func isAllowedErrAndFunc(err, fun string) bool {
   67     for _, allow := range allowedErrors {
   68         if allow.fun == fun && allow.err == err {
   69             return true
   70         }
   71     }
   72     return false
   73 }
   74 
   75 func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool {
   76     var errName string // `<package>.<name>`, e.g. `io.EOF`
   77     var callExprs []*ast.CallExpr
   78 
   79     // Figure out which half of the expression is the returned error and which
   80     // half is the presumed error declaration.
   81     for _, expr := range []ast.Expr{binExpr.X, binExpr.Y} {
   82         switch t := expr.(type) {
   83         case *ast.SelectorExpr:
   84             // A selector which we assume refers to a staticaly declared error
   85             // in a package.
   86             errName = selectorToString(t)
   87         case *ast.Ident:
   88             // Identifier, most likely to be the `err` variable or whatever
   89             // produces it.
   90             callExprs = assigningCallExprs(info, t)
   91         case *ast.CallExpr:
   92             callExprs = append(callExprs, t)
   93         }
   94     }
   95 
   96     // Unimplemented or not sure, disallow the expression.
   97     if errName == "" || len(callExprs) == 0 {
   98         return false
   99     }
  100 
  101     // Map call expressions to the function name format of the allow list.
  102     functionNames := make([]string, len(callExprs))
  103     for i, callExpr := range callExprs {
  104         functionSelector, ok := callExpr.Fun.(*ast.SelectorExpr)
  105         if !ok {
  106             // If the function is not a selector it is not an Std function that is
  107             // allowed.
  108             return false
  109         }
  110         if sel, ok := info.Selections[functionSelector]; ok {
  111             functionNames[i] = fmt.Sprintf("(%s).%s", sel.Recv(), sel.Obj().Name())
  112         } else {
  113             // If there is no selection, assume it is a package.
  114             functionNames[i] = selectorToString(callExpr.Fun.(*ast.SelectorExpr))
  115         }
  116     }
  117 
  118     // All assignments done must be allowed.
  119     for _, funcName := range functionNames {
  120         if !isAllowedErrAndFunc(errName, funcName) {
  121             return false
  122         }
  123     }
  124     return true
  125 }
  126 
  127 // assigningCallExprs finds all *ast.CallExpr nodes that are part of an
  128 // *ast.AssignStmt that assign to the subject identifier.
  129 func assigningCallExprs(info *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr {
  130     if subject.Obj == nil {
  131         return nil
  132     }
  133 
  134     // Find other identifiers that reference this same object. Make sure to
  135     // exclude the subject identifier as it will cause an infinite recursion
  136     // and is being used in a read operation anyway.
  137     sobj := info.ObjectOf(subject)
  138     identifiers := []*ast.Ident{}
  139     for _, ident := range info.IdentifiersForObject[sobj] {
  140         if subject.Pos() != ident.Pos() {
  141             identifiers = append(identifiers, ident)
  142         }
  143     }
  144 
  145     // Find out whether the identifiers are part of an assignment statement.
  146     var callExprs []*ast.CallExpr
  147     for _, ident := range identifiers {
  148         parent := info.NodeParent[ident]
  149         switch declT := parent.(type) {
  150         case *ast.AssignStmt:
  151             // The identifier is LHS of an assignment.
  152             assignment := declT
  153 
  154             assigningExpr := assignment.Rhs[0]
  155             // If the assignment is comprised of multiple expressions, find out
  156             // which LHS expression we should use by finding its index in the LHS.
  157             if len(assignment.Rhs) > 1 {
  158                 for i, lhs := range assignment.Lhs {
  159                     if subject.Name == lhs.(*ast.Ident).Name {
  160                         assigningExpr = assignment.Rhs[i]
  161                         break
  162                     }
  163                 }
  164             }
  165 
  166             switch assignT := assigningExpr.(type) {
  167             case *ast.CallExpr:
  168                 // Found the function call.
  169                 callExprs = append(callExprs, assignT)
  170             case *ast.Ident:
  171                 // Skip assignments here the RHS points to the same object as the subject.
  172                 if assignT.Obj == subject.Obj {
  173                     continue
  174                 }
  175                 // The subject was the result of assigning from another identifier.
  176                 callExprs = append(callExprs, assigningCallExprs(info, assignT)...)
  177             default:
  178                 // TODO: inconclusive?
  179             }
  180         }
  181     }
  182     return callExprs
  183 }
  184 
  185 func selectorToString(selExpr *ast.SelectorExpr) string {
  186     if ident, ok := selExpr.X.(*ast.Ident); ok {
  187         return ident.Name + "." + selExpr.Sel.Name
  188     }
  189     return ""
  190 }