Skip to content

Commit

Permalink
fix: added processing of more cases
Browse files Browse the repository at this point in the history
  • Loading branch information
lasiar committed Apr 26, 2024
1 parent 8a73b10 commit 89e9983
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 42 deletions.
76 changes: 42 additions & 34 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (

"github.com/go-toolsmith/astcast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
)

const (
Expand All @@ -20,64 +22,84 @@ const (
)

var Analyzer = &analysis.Analyzer{
Name: "canonicalheader",
Doc: "canonicalheader checks whether net/http.Header uses canonical header",
Run: run,
Name: "canonicalheader",
Doc: "canonicalheader checks whether net/http.Header uses canonical header",
Run: run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
}

func run(pass *analysis.Pass) (any, error) {
spctor, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
if !ok {
return nil, fmt.Errorf("want %T, got %T", spctor, pass.ResultOf[inspect.Analyzer])
}

nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
var outerErr error
inspect := func(node ast.Node) bool {

spctor.Preorder(nodeFilter, func(n ast.Node) {
if outerErr != nil {
return false
return
}

callExp, ok := n.(*ast.CallExpr)
if !ok {
return
}

callExp, ok := node.(*ast.CallExpr)
fn, ok := typeutil.Callee(pass.TypesInfo, callExp).(*types.Func)
if !ok {
return true
return
}

selExp, ok := callExp.Fun.(*ast.SelectorExpr)
signature, ok := fn.Type().(*types.Signature)
if !ok {
return false
return
}

object, ok := pass.TypesInfo.TypeOf(selExp.X).(*types.Named)
recv := signature.Recv()
if recv == nil {
return
}

object, ok := recv.Type().(*types.Named)
if !ok {
return false
return
}

if !isHTTPHeader(object) {
return false
return
}

if !isValidMethod(astcast.ToSelectorExpr(callExp.Fun).Sel.Name) {
return false
return
}

arg, ok := callExp.Args[0].(*ast.BasicLit)
if !ok {
return false
return
}

if arg.Kind != token.STRING {
return true
return
}

if len(arg.Value) < 2 {
return true
return
}

quote := arg.Value[0]
headerKeyOriginal, err := strconv.Unquote(arg.Value)
if err != nil {
outerErr = err
return true
return
}

headerKeyCanonical := http.CanonicalHeaderKey(headerKeyOriginal)
if headerKeyOriginal == headerKeyCanonical {
return true
return
}

newText := make([]byte, 0, len(headerKeyCanonical)+2)
Expand All @@ -104,21 +126,7 @@ func run(pass *analysis.Pass) (any, error) {
},
},
)

return true
}

for _, f := range pass.Files {
if outerErr != nil {
return nil, outerErr
}

if !astutil.UsesImport(f, pkgPath) {
continue
}

ast.Inspect(f, inspect)
}
})

return nil, outerErr
}
Expand Down
59 changes: 53 additions & 6 deletions analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package canonicalheader_test

import (
"net/http"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
"golang.org/x/tools/go/analysis/analysistest"

"github.com/lasiar/canonicalheader"
Expand All @@ -13,12 +16,56 @@ const testValue = "hello_world"

func TestAnalyzer(t *testing.T) {
t.Parallel()
analysistest.RunWithSuggestedFixes(
t,
analysistest.TestData(),
canonicalheader.Analyzer,
"p",
)

testCases := []struct {
dir string
}{
{
dir: "alias",
},

{
dir: "common",
},

{
dir: "embedded",
},

{
dir: "global",
},

{
dir: "struct",
},
}

for _, tt := range testCases {
tt := tt
t.Run(tt.dir, func(t *testing.T) {
t.Parallel()

analysistest.RunWithSuggestedFixes(
t,
analysistest.TestData(),
canonicalheader.Analyzer,
tt.dir,
)
})
}

t.Run("are_test_cases_complete", func(t *testing.T) {
t.Parallel()

dirs, err := os.ReadDir(filepath.Join(analysistest.TestData(), "src"))
require.NoError(t, err)
require.Len(t, testCases, len(dirs))

for i, dir := range dirs {
require.Equal(t, dir.Name(), testCases[i].dir)
}
})
}

func BenchmarkCanonical(b *testing.B) {
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ go 1.21

require (
github.com/go-toolsmith/astcast v1.1.0
github.com/stretchr/testify v1.9.0
golang.org/x/tools v0.20.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
9 changes: 9 additions & 0 deletions testdata/src/alias/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package alias

import "net/http"

type myHeader = http.Header

func _() {
myHeader{}.Get("TT") // want `non-canonical header "TT", instead use: "Tt"`
}
9 changes: 9 additions & 0 deletions testdata/src/alias/alias.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package alias

import "net/http"

type myHeader = http.Header

func _() {
myHeader{}.Get("Tt") // want `non-canonical header "TT", instead use: "Tt"`
}
6 changes: 5 additions & 1 deletion testdata/src/p/p.go → testdata/src/common/common.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package p
package common

import (
"net/http"
Expand All @@ -21,4 +21,8 @@ func p() {
v.Add("Test-Header", "value")
v.Del("Test-Header")
v.Values("Test-Header")

v.Write(nil)
v.Clone()
v.WriteSubset(nil, nil)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package p
package common

import (
"net/http"
Expand All @@ -21,4 +21,8 @@ func p() {
v.Add("Test-Header", "value")
v.Del("Test-Header")
v.Values("Test-Header")

v.Write(nil)
v.Clone()
v.WriteSubset(nil, nil)
}
11 changes: 11 additions & 0 deletions testdata/src/embedded/embedded.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package embedded

import "net/http"

type embeded struct {
http.Header
}

func _() {
embeded{}.Get("TT") // want `non-canonical header "TT", instead use: "Tt"`
}
11 changes: 11 additions & 0 deletions testdata/src/embedded/embedded.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package embedded

import "net/http"

type embeded struct {
http.Header
}

func _() {
embeded{}.Get("Tt") // want `non-canonical header "TT", instead use: "Tt"`
}
5 changes: 5 additions & 0 deletions testdata/src/global/global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package global

import "net/http"

var header http.Header
5 changes: 5 additions & 0 deletions testdata/src/global/global_usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package global

func dontImportPackage() {
header.Get("Test-HEader") // want `non-canonical header "Test-HEader", instead use: "Test-Header"`
}
5 changes: 5 additions & 0 deletions testdata/src/global/global_usage.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package global

func dontImportPackage() {
header.Get("Test-Header") // want `non-canonical header "Test-HEader", instead use: "Test-Header"`
}
15 changes: 15 additions & 0 deletions testdata/src/struct/struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package _struct

import "net/http"

type HeaderStruct struct {
header http.Header
}

func (h HeaderStruct) _() {
h.header.Get("TT") // want `non-canonical header "TT", instead use: "Tt"`
}

func _() {
HeaderStruct{}.header.Get("TT") // want `non-canonical header "TT", instead use: "Tt"`
}
15 changes: 15 additions & 0 deletions testdata/src/struct/struct.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package _struct

import "net/http"

type HeaderStruct struct {
header http.Header
}

func (h HeaderStruct) _() {
h.header.Get("Tt") // want `non-canonical header "TT", instead use: "Tt"`
}

func _() {
HeaderStruct{}.header.Get("Tt") // want `non-canonical header "TT", instead use: "Tt"`
}

0 comments on commit 89e9983

Please sign in to comment.