...

Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go

Documentation: cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal

     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 unmarshal
     6  
     7  import (
     8  	_ "embed"
     9  	"go/ast"
    10  	"go/types"
    11  
    12  	"golang.org/x/tools/go/analysis"
    13  	"golang.org/x/tools/go/analysis/passes/inspect"
    14  	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
    15  	"golang.org/x/tools/go/ast/inspector"
    16  	"golang.org/x/tools/go/types/typeutil"
    17  )
    18  
    19  //go:embed doc.go
    20  var doc string
    21  
    22  var Analyzer = &analysis.Analyzer{
    23  	Name:     "unmarshal",
    24  	Doc:      analysisutil.MustExtractDoc(doc, "unmarshal"),
    25  	URL:      "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
    26  	Requires: []*analysis.Analyzer{inspect.Analyzer},
    27  	Run:      run,
    28  }
    29  
    30  func run(pass *analysis.Pass) (interface{}, error) {
    31  	switch pass.Pkg.Path() {
    32  	case "encoding/gob", "encoding/json", "encoding/xml", "encoding/asn1":
    33  		// These packages know how to use their own APIs.
    34  		// Sometimes they are testing what happens to incorrect programs.
    35  		return nil, nil
    36  	}
    37  
    38  	// Note: (*"encoding/json".Decoder).Decode, (* "encoding/gob".Decoder).Decode
    39  	// and (* "encoding/xml".Decoder).Decode are methods and can be a typeutil.Callee
    40  	// without directly importing their packages. So we cannot just skip this package
    41  	// when !analysisutil.Imports(pass.Pkg, "encoding/...").
    42  	// TODO(taking): Consider using a prepass to collect typeutil.Callees.
    43  
    44  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    45  
    46  	nodeFilter := []ast.Node{
    47  		(*ast.CallExpr)(nil),
    48  	}
    49  	inspect.Preorder(nodeFilter, func(n ast.Node) {
    50  		call := n.(*ast.CallExpr)
    51  		fn := typeutil.StaticCallee(pass.TypesInfo, call)
    52  		if fn == nil {
    53  			return // not a static call
    54  		}
    55  
    56  		// Classify the callee (without allocating memory).
    57  		argidx := -1
    58  
    59  		recv := fn.Type().(*types.Signature).Recv()
    60  		if fn.Name() == "Unmarshal" && recv == nil {
    61  			// "encoding/json".Unmarshal
    62  			// "encoding/xml".Unmarshal
    63  			// "encoding/asn1".Unmarshal
    64  			switch fn.Pkg().Path() {
    65  			case "encoding/json", "encoding/xml", "encoding/asn1":
    66  				argidx = 1 // func([]byte, interface{})
    67  			}
    68  		} else if fn.Name() == "Decode" && recv != nil {
    69  			// (*"encoding/json".Decoder).Decode
    70  			// (* "encoding/gob".Decoder).Decode
    71  			// (* "encoding/xml".Decoder).Decode
    72  			t := recv.Type()
    73  			if ptr, ok := t.(*types.Pointer); ok {
    74  				t = ptr.Elem()
    75  			}
    76  			tname := t.(*types.Named).Obj()
    77  			if tname.Name() == "Decoder" {
    78  				switch tname.Pkg().Path() {
    79  				case "encoding/json", "encoding/xml", "encoding/gob":
    80  					argidx = 0 // func(interface{})
    81  				}
    82  			}
    83  		}
    84  		if argidx < 0 {
    85  			return // not a function we are interested in
    86  		}
    87  
    88  		if len(call.Args) < argidx+1 {
    89  			return // not enough arguments, e.g. called with return values of another function
    90  		}
    91  
    92  		t := pass.TypesInfo.Types[call.Args[argidx]].Type
    93  		switch t.Underlying().(type) {
    94  		case *types.Pointer, *types.Interface, *types.TypeParam:
    95  			return
    96  		}
    97  
    98  		switch argidx {
    99  		case 0:
   100  			pass.Reportf(call.Lparen, "call of %s passes non-pointer", fn.Name())
   101  		case 1:
   102  			pass.Reportf(call.Lparen, "call of %s passes non-pointer as second argument", fn.Name())
   103  		}
   104  	})
   105  	return nil, nil
   106  }
   107  

View as plain text