Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: kkHAIKE/contextcheck
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.1.4
Choose a base ref
...
head repository: kkHAIKE/contextcheck
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.1.5
Choose a head ref
  • 18 commits
  • 11 files changed
  • 3 contributors

Commits on Mar 13, 2023

  1. fix generics case

    kkHAIKE committed Mar 13, 2023
    Copy the full SHA
    026c7c7 View commit details
  2. add Dependabot

    kkHAIKE committed Mar 13, 2023
    Copy the full SHA
    439156b View commit details

Commits on Mar 26, 2023

  1. fix eng

    kkHAIKE committed Mar 26, 2023
    Copy the full SHA
    d33facc View commit details

Commits on Apr 7, 2023

  1. Bump golang.org/x/tools from 0.7.0 to 0.8.0

    Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.7.0 to 0.8.0.
    - [Release notes](https://github.com/golang/tools/releases)
    - [Commits](golang/tools@v0.7.0...v0.8.0)
    
    ---
    updated-dependencies:
    - dependency-name: golang.org/x/tools
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Apr 7, 2023
    Copy the full SHA
    e19b6fe View commit details

Commits on Apr 8, 2023

  1. Merge pull request #12 from kkHAIKE/dependabot/go_modules/golang.org/…

    …x/tools-0.8.0
    
    Bump golang.org/x/tools from 0.7.0 to 0.8.0
    kkHAIKE authored Apr 8, 2023
    Copy the full SHA
    b4dc4b7 View commit details

Commits on Mar 20, 2024

  1. Copy the full SHA
    ddc9c99 View commit details
  2. chore: ignore binary

    ldez committed Mar 20, 2024
    Copy the full SHA
    9dd73ac View commit details
  3. Copy the full SHA
    d442b7c View commit details
  4. tests: add tests

    ldez committed Mar 20, 2024
    Copy the full SHA
    fbe3efa View commit details
  5. chore: remove CircleCI

    ldez committed Mar 20, 2024
    Copy the full SHA
    93d2bb5 View commit details
  6. chore: add GitHub Action

    ldez committed Mar 20, 2024
    Copy the full SHA
    87e3db6 View commit details

Commits on Mar 21, 2024

  1. Copy the full SHA
    7fdfd4d View commit details
  2. Copy the full SHA
    3cc6ce5 View commit details

Commits on Mar 22, 2024

  1. Copy the full SHA
    b08c735 View commit details
  2. chore: simplify

    ldez committed Mar 22, 2024
    Copy the full SHA
    925e56d View commit details
  3. chore: simplify again

    ldez committed Mar 22, 2024
    Copy the full SHA
    9f1f2d1 View commit details

Commits on Mar 23, 2024

  1. Merge pull request #22 from ldez/fix/report-without-filepath

    fix: don't report issue related to invalid position
    kkHAIKE authored Mar 23, 2024
    Copy the full SHA
    82fe695 View commit details
  2. Merge pull request #23 from ldez/fix/ci

    chore: use GitHub Action
    kkHAIKE authored Mar 23, 2024
    Copy the full SHA
    df8a0ab View commit details
Showing with 155 additions and 84 deletions.
  1. +0 −26 .circleci/config.yml
  2. +6 −0 .github/dependabot.yml
  3. +32 −0 .github/workflows/go-cross.yml
  4. +44 −0 .github/workflows/main.yml
  5. +2 −0 .gitignore
  6. +12 −2 Makefile
  7. +5 −5 README.md
  8. +29 −39 contextcheck.go
  9. +2 −3 go.mod
  10. +5 −7 go.sum
  11. +18 −2 testdata/src/a/a.go
26 changes: 0 additions & 26 deletions .circleci/config.yml

This file was deleted.

6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: "daily"
32 changes: 32 additions & 0 deletions .github/workflows/go-cross.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Go Matrix
on: [push, pull_request]

jobs:

cross:
name: Go
runs-on: ${{ matrix.os }}
env:
CGO_ENABLED: 0

strategy:
matrix:
go-version: [ oldstable, stable ]
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
# https://github.com/marketplace/actions/checkout
- name: Checkout code
uses: actions/checkout@v4

# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Test
run: go test -v -cover ./...

- name: Build
run: go build -v -ldflags "-s -w" -trimpath
44 changes: 44 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Main

on:
push:
branches:
- main
pull_request:

jobs:

main:
name: Main Process
runs-on: ubuntu-latest
env:
GO_VERSION: stable
GOLANGCI_LINT_VERSION: v1.57.0
CGO_ENABLED: 0

steps:
# https://github.com/marketplace/actions/checkout
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0

# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}

- name: Check and get dependencies
run: |
go mod download
go mod tidy
git diff --exit-code go.mod
git diff --exit-code go.sum
# https://golangci-lint.run/usage/install#other-ci
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}

- name: Make
run: make
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -16,3 +16,5 @@

.idea
.DS_Store

/contextcheck
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
.PHONY: clean test build

default: test build

clean:
rm -rf dist/ cover.out

test: clean
go test -v -cover ./...

build:
@GO111MODULE=on go build -ldflags '-s -w' -o contextcheck ./cmd/contextcheck/main.go
go build -ldflags '-s -w' -o contextcheck ./cmd/contextcheck/main.go

install:
@GO111MODULE=on go install -ldflags '-s -w' ./cmd/contextcheck
go install -ldflags '-s -w' ./cmd/contextcheck
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

# contextcheck

`contextcheck` is a static analysis tool, it is used to check whether the function uses a non-inherited context, which will result in a broken call link.
`contextcheck` is a static analysis tool used to check whether a function uses a non-inherited context that could result in a broken call link.

For example:

@@ -94,8 +94,8 @@ func NoInheritCancel(_ context.Context) (context.Context,context.CancelFunc) {
}
```

### skip check specify function
You can add `// nolint: contextcheck` in function decl doc comment, to skip this linter in some false-positive case.
### skip the check for the specified function
To skip this linter in some false-positive cases, you can add // nolint: contextcheck to the function declaration's comment.

```go
// nolint: contextcheck
@@ -112,8 +112,8 @@ func call3() {
}
```

### force mark specify function have server-side http.Request parameter
default behavior is mark http.HandlerFunc or a function use r.Context().
### force the marking of a specified function as having a server-side http.Request parameter
The default behavior is to mark `http.HandlerFunc` or any function that uses `r.Context()`.

```go
// @contextcheck(req_has_ctx)
68 changes: 29 additions & 39 deletions contextcheck.go
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@ package contextcheck

import (
"go/ast"
"go/token"
"go/types"
"regexp"
"strconv"
"strings"
"sync"

@@ -68,6 +68,11 @@ var (
pkgFactMu sync.RWMutex
)

type element interface {
Pos() token.Pos
Parent() *ssa.Function
}

type resInfo struct {
Valid bool
Funcs []string
@@ -216,37 +221,6 @@ func (r *runner) collectHttpTyps(pssa *buildssa.SSA) {
}
}

func (r *runner) noImportedContextAndHttp(f *ssa.Function) (ret bool) {
if !f.Pos().IsValid() {
return false
}

file := analysisutil.File(r.pass, f.Pos())
if file == nil {
return false
}

if skip, has := r.skipFile[file]; has {
return skip
}
defer func() {
r.skipFile[file] = ret
}()

for _, impt := range file.Imports {
path, err := strconv.Unquote(impt.Path.Value)
if err != nil {
continue
}
path = analysisutil.RemoveVendor(path)
if path == ctxPkg || path == httpPkg {
return false
}
}

return true
}

func (r *runner) checkIsEntry(f *ssa.Function) (ret entryType) {
// if r.noImportedContextAndHttp(f) {
// return EntryNormal
@@ -456,15 +430,15 @@ func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[

for instr := range storeInstrs {
if !checkedRefMap[instr.Val] {
r.pass.Reportf(instr.Pos(), "Non-inherited new context, use function like `context.WithXXX` instead")
r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead")
ok = false
}
}

for instr := range phiInstrs {
for _, v := range instr.Edges {
if !checkedRefMap[v] {
r.pass.Reportf(instr.Pos(), "Non-inherited new context, use function like `context.WithXXX` instead")
r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead")
ok = false
}
}
@@ -564,9 +538,9 @@ func (r *runner) checkFuncWithCtx(f *ssa.Function, tp entryType) {
if tp&CtxIn != 0 {
if !refMap[instr] {
if isHttpHandler {
r.pass.Reportf(instr.Pos(), "Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead")
r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead")
} else {
r.pass.Reportf(instr.Pos(), "Non-inherited new context, use function like `context.WithXXX` instead")
r.Reportf(instr, "Non-inherited new context, use function like `context.WithXXX` instead")
}
}
}
@@ -578,9 +552,11 @@ func (r *runner) checkFuncWithCtx(f *ssa.Function, tp entryType) {

key := ff.RelString(nil)
res, ok := r.getValue(key, ff)
if ok {
if !res.Valid {
r.pass.Reportf(instr.Pos(), "Function `%s` should pass the context parameter", strings.Join(reverse(res.Funcs), "->"))
if ok && !res.Valid {
if instr.Pos().IsValid() {
r.Reportf(instr, "Function `%s` should pass the context parameter", strings.Join(reverse(res.Funcs), "->"))
} else {
r.Reportf(ff, "Function `%s` should pass the context parameter", strings.Join(reverse(res.Funcs), "->"))
}
}
}
@@ -806,6 +782,20 @@ func (r *runner) setFact(key string, valid bool, funcs ...string) {
}
}

func (r *runner) Reportf(instr element, format string, args ...interface{}) {
pos := instr.Pos()

if !pos.IsValid() && instr.Parent() != nil {
pos = instr.Parent().Pos()
}

if !pos.IsValid() {
return
}

r.pass.Reportf(pos, format, args...)
}

// setPkgFact save fact to mem
func setPkgFact(pkg *types.Package, fact ctxFact) {
pkgFactMu.Lock()
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -4,11 +4,10 @@ go 1.20

require (
github.com/gostaticanalysis/analysisutil v0.7.1
golang.org/x/tools v0.7.0
golang.org/x/tools v0.19.0
)

require (
github.com/gostaticanalysis/comment v1.4.2 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/mod v0.16.0 // indirect
)
12 changes: 5 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
@@ -24,20 +24,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
@@ -46,8 +44,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
20 changes: 18 additions & 2 deletions testdata/src/a/a.go
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ func f11() {
type MySlice[T int | float32] []T

func (s MySlice[T]) f12(ctx context.Context) T {
f3() // generics, Block is nil, wont report
f3() // want "Function `f3` should pass the context parameter"

var sum T
for _, value := range s {
@@ -147,11 +147,27 @@ func (s MySlice[T]) f12(ctx context.Context) T {
}

func f13[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64](ctx context.Context, a, b T) T {
f3() // generics, Block is nil, wont report
f3() // want "Function `f3` should pass the context parameter"

if a > b {
return a
}

return b
}

/* ----------------- issue 21 ----------------- */

func f16(ctx context.Context, k string) func() {
return func() { // want "Function `f16\\$1` should pass the context parameter"
f16(context.Background(), k)
}
}

func f17(ctx context.Context, k string) func() func() {
return func() func() { // want "Function `f17\\$1->f17\\$1\\$1` should pass the context parameter"
return func() {
f16(context.Background(), k)
}
}
}