src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sa4027.go (1789B)


      1 package sa4027
      2 
      3 import (
      4 	"go/ast"
      5 
      6 	"honnef.co/go/tools/analysis/code"
      7 	"honnef.co/go/tools/analysis/lint"
      8 	"honnef.co/go/tools/analysis/report"
      9 	"honnef.co/go/tools/pattern"
     10 
     11 	"golang.org/x/tools/go/analysis"
     12 )
     13 
     14 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     15 	Analyzer: &analysis.Analyzer{
     16 		Name:     "SA4027",
     17 		Run:      run,
     18 		Requires: code.RequiredAnalyzers,
     19 	},
     20 	Doc: &lint.RawDocumentation{
     21 		Title: `\'(*net/url.URL).Query\' returns a copy, modifying it doesn't change the URL`,
     22 		Text: `\'(*net/url.URL).Query\' parses the current value of \'net/url.URL.RawQuery\'
     23 and returns it as a map of type \'net/url.Values\'. Subsequent changes to
     24 this map will not affect the URL unless the map gets encoded and
     25 assigned to the URL's \'RawQuery\'.
     26 
     27 As a consequence, the following code pattern is an expensive no-op:
     28 \'u.Query().Add(key, value)\'.`,
     29 		Since:    "2021.1",
     30 		Severity: lint.SeverityWarning,
     31 		MergeIf:  lint.MergeIfAny,
     32 	},
     33 })
     34 
     35 var Analyzer = SCAnalyzer.Analyzer
     36 
     37 var ineffectiveURLQueryAddQ = pattern.MustParse(`(CallExpr (SelectorExpr (CallExpr (SelectorExpr recv (Ident "Query")) []) (Ident meth)) _)`)
     38 
     39 func run(pass *analysis.Pass) (any, error) {
     40 	// TODO(dh): We could make this check more complex and detect
     41 	// pointless modifications of net/url.Values in general, but that
     42 	// requires us to get the state machine correct, else we'll cause
     43 	// false positives.
     44 
     45 	for node, m := range code.Matches(pass, ineffectiveURLQueryAddQ) {
     46 		if !code.IsOfPointerToTypeWithName(pass, m.State["recv"].(ast.Expr), "net/url.URL") {
     47 			continue
     48 		}
     49 		switch m.State["meth"].(string) {
     50 		case "Add", "Del", "Set":
     51 		default:
     52 			continue
     53 		}
     54 		report.Report(pass, node, "(*net/url.URL).Query returns a copy, modifying it doesn't change the URL")
     55 	}
     56 	return nil, nil
     57 }