[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        go: [ stable, oldstable ]\n    name: Go ${{ matrix.go }} test\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: ${{ matrix.go }}\n      - name: Install GolangCI-Lint\n        run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.1.5\n      - run: make lint\n      - run: make test_coverage\n      - name: Upload code coverage to codecov\n        if: matrix.go == 'stable'\n        uses: codecov/codecov-action@v3\n        with:\n          file: ./coverage.out\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: release\n\non:\n  push:\n    tags:\n      - \"v[0-9]+.[0-9]+.[0-9]+\"\n\njobs:\n  goreleaser:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Unshallow\n        run: git fetch --prune --unshallow\n      - name: Set up Go\n        uses: actions/setup-go@v5\n        with:\n          go-version: stable\n      - name: Run GoReleaser\n        uses: goreleaser/goreleaser-action@v6\n        with:\n          version: latest\n          args: release --clean\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "coverage.out\n/noctx\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\n\nformatters:\n  enable:\n    - gofumpt\n    - goimports\n\n\nlinters:\n  default: all\n  disable:\n    - exhaustruct\n    - gochecknoglobals\n    - gocognit\n    - lll\n    - mnd\n    - nestif\n    - nilnil\n    - paralleltest\n    - varnamelen\n\n  settings:\n    depguard:\n      rules:\n        main:\n          deny:\n            - pkg: github.com/instana/testify\n              desc: not allowed\n            - pkg: github.com/pkg/errors\n              desc: Should be replaced by standard lib errors package\n    govet:\n      enable-all: true\n    perfsprint:\n      err-error: true\n      errorf: true\n      sprintf1: true\n      strconcat: false\n\n  exclusions:\n    presets:\n      - comments\n      - common-false-positives\n      - std-error-handling\n"
  },
  {
    "path": ".goreleaser.yml",
    "content": "version: 2\nproject_name: noctx\n\nbuilds:\n  - binary: noctx\n\n    main: ./cmd/noctx/main.go\n    env:\n      - CGO_ENABLED=0\n    flags:\n      - -trimpath\n    goos:\n      - windows\n      - darwin\n      - linux\n    goarch:\n      - amd64\n      - 386\n      - arm\n      - arm64\n    goarm:\n      - 7\n      - 6\n      - 5\n    ignore:\n      - goos: darwin\n        goarch: 386\n      - goos: windows\n        goarch: arm\n\narchives:\n  - id: noctx\n    name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}'\n    formats: [ 'tar.gz' ]\n    format_overrides:\n      - goos: windows\n        formats: [ 'zip' ]\n    files:\n      - LICENSE\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 sonatard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": ".PHONY: all fmt test lint build\n\nbuild:\n\tgo build -ldflags \"-s -w\" -trimpath ./cmd/noctx/\n\nfmt:\n\tgolangci-lint fmt ./...\n\nlint:\n\tgolangci-lint run ./...\n\ntest:\n\tgo test -race ./...\n\ntest_coverage:\n\tgo test -race -coverprofile=coverage.out -covermode=atomic ./...\n"
  },
  {
    "path": "README.md",
    "content": "# noctx\n\n![](https://github.com/sonatard/noctx/workflows/CI/badge.svg)\n\n`noctx` finds function calls without context.Context.\n\nPassing `context.Context` enables library user to cancel request, getting trace information and so on.\n\n`noctx` helps you to identify code that could be rewritten to use the context.Context.\n\n## Usage\n\n### noctx with go vet\n\ngo vet is a Go standard tool for analyzing source code.\n\n1. Install noctx.\n```sh\n$ go install github.com/sonatard/noctx/cmd/noctx@latest\n```\n\n2. Execute noctx\n```sh\n$ go vet -vettool=`which noctx` main.go\n./main.go:6:11: net/http.Get must not be called\n```\n\n### noctx with golangci-lint\n\ngolangci-lint is a fast Go linters runner.\n\n1. Install golangci-lint.\n[golangci-lint - Install](https://golangci-lint.run/usage/install/)\n\n2. Setup .golangci.yml\n```yaml:\n# Add noctx to enable linters.\nlinters:\n  enable:\n    - noctx\n\n# Or enable-all is true.\nlinters:\n  default: all\n  disable:\n   - xxx # Add unused linter to disable linters.\n```\n\n3. Execute noctx\n```sh\n# Use .golangci.yml\n$ golangci-lint run\n\n# Only execute noctx\ngolangci-lint run --enable-only noctx\n```\n\n## net/http package\n### Rules\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/noctx.go#L41-L50\n\n### Sample\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/http_client/http_client.go#L11\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/http_request/http_request.go#L17\n\n### Reference\n- [net/http - NewRequest](https://pkg.go.dev/net/http#NewRequest)\n- [net/http - NewRequestWithContext](https://pkg.go.dev/net/http#NewRequestWithContext)\n- [net/http - Request.WithContext](https://pkg.go.dev/net/http#Request.WithContext)\n- [net/http/httptest - NewRequest](https://pkg.go.dev/net/http/httptest#NewRequest)\n\n## net package\n\n### Rules\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/noctx.go#L26-L39\n\n### Sample\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/network/net.go#L17\n\n### References\n- [net - ListenConfig](https://pkg.go.dev/net#ListenConfig)\n- [net - Dialer.DialContext](https://pkg.go.dev/net#Dialer.DialContext)\n- [net - Resolver](https://pkg.go.dev/net#Resolver)\n- [net - DefaultResolver](https://pkg.go.dev/net#DefaultResolver)\n\n## database/sql package\n### Rules\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/noctx.go#L52-L66\n\n### Sample\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/sql/sql.go#L18\n\n### Reference\n- [database/sql](https://pkg.go.dev/database/sql)\n\n## crypt/tls package\n### Rules\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/noctx.go#L71-L74\n\n### Sample\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/crypto_tls/tls.go#L17\n\n### Reference\n- [crypto/tls - Dialer.DialContext](https://pkg.go.dev/crypto/tls#Dialer.DialContext)\n- [crypto/tls - Conn.HandshakeContext](https://pkg.go.dev/crypto/tls#Conn.HandshakeContext)\n\n## exec package\n### Rules\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/noctx.go#L68-L69\n\n### Sample\nhttps://github.com/sonatard/noctx/blob/b768dab1764733f7f69c5075b7497eff4c58f260/testdata/src/exec_cmd/exec.go#L11\n\n### Reference\n- [exec - exec.CommandContext](https://pkg.go.dev/exec#CommandContext)\n\n"
  },
  {
    "path": "cmd/noctx/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/sonatard/noctx\"\n\t\"golang.org/x/tools/go/analysis/unitchecker\"\n)\n\nfunc main() { unitchecker.Main(noctx.Analyzer) }\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/sonatard/noctx\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gostaticanalysis/analysisutil v0.7.1\n\tgolang.org/x/tools v0.32.0\n)\n\nrequire (\n\tgithub.com/gostaticanalysis/comment v1.5.0 // indirect\n\tgolang.org/x/mod v0.24.0 // indirect\n\tgolang.org/x/sync v0.13.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=\ngithub.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=\ngithub.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=\ngithub.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8=\ngithub.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc=\ngithub.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4 h1:d2/eIbH9XjD1fFwD5SHv8x168fjbQ9PB8hvs8DSEC08=\ngithub.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=\ngithub.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=\ngithub.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=\ngithub.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=\ngithub.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=\ngithub.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=\ngithub.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=\ngithub.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=\ngithub.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=\ngithub.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=\ngithub.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=\ngithub.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=\ngolang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=\ngolang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=\ngolang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=\ngolang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=\ngolang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\n"
  },
  {
    "path": "noctx.go",
    "content": "package noctx\n\nimport (\n\t\"fmt\"\n\t\"maps\"\n\t\"slices\"\n\n\t\"github.com/gostaticanalysis/analysisutil\"\n\t\"golang.org/x/tools/go/analysis\"\n\t\"golang.org/x/tools/go/analysis/passes/buildssa\"\n)\n\nvar Analyzer = &analysis.Analyzer{\n\tName:             \"noctx\",\n\tDoc:              \"noctx finds function calls without context.Context\",\n\tRun:              Run,\n\tRunDespiteErrors: false,\n\tRequires: []*analysis.Analyzer{\n\t\tbuildssa.Analyzer,\n\t},\n\tResultType: nil,\n\tFactTypes:  nil,\n}\n\nvar ngFuncMessages = map[string]string{\n\t// net\n\t\"net.Listen\":       \"must not be called. use (*net.ListenConfig).Listen\",\n\t\"net.ListenPacket\": \"must not be called. use (*net.ListenConfig).ListenPacket\",\n\t\"net.Dial\":         \"must not be called. use (*net.Dialer).DialContext\",\n\t\"net.DialTimeout\":  \"must not be called. use (*net.Dialer).DialContext with (*net.Dialer).Timeout\",\n\t\"net.LookupCNAME\":  \"must not be called. use (*net.Resolver).LookupCNAME with a context\",\n\t\"net.LookupHost\":   \"must not be called. use (*net.Resolver).LookupHost with a context\",\n\t\"net.LookupIP\":     \"must not be called. use (*net.Resolver).LookupIPAddr with a context\",\n\t\"net.LookupPort\":   \"must not be called. use (*net.Resolver).LookupPort with a context\",\n\t\"net.LookupSRV\":    \"must not be called. use (*net.Resolver).LookupSRV with a context\",\n\t\"net.LookupMX\":     \"must not be called. use (*net.Resolver).LookupMX with a context\",\n\t\"net.LookupNS\":     \"must not be called. use (*net.Resolver).LookupNS with a context\",\n\t\"net.LookupTXT\":    \"must not be called. use (*net.Resolver).LookupTXT with a context\",\n\t\"net.LookupAddr\":   \"must not be called. use (*net.Resolver).LookupAddr with a context\",\n\n\t// net/http\n\t\"net/http.Get\":                 \"must not be called. use net/http.NewRequestWithContext and (*net/http.Client).Do(*http.Request)\",\n\t\"net/http.Head\":                \"must not be called. use net/http.NewRequestWithContext and (*net/http.Client).Do(*http.Request)\",\n\t\"net/http.Post\":                \"must not be called. use net/http.NewRequestWithContext and (*net/http.Client).Do(*http.Request)\",\n\t\"net/http.PostForm\":            \"must not be called. use net/http.NewRequestWithContext and (*net/http.Client).Do(*http.Request)\",\n\t\"(*net/http.Client).Get\":       \"must not be called. use (*net/http.Client).Do(*http.Request)\",\n\t\"(*net/http.Client).Head\":      \"must not be called. use (*net/http.Client).Do(*http.Request)\",\n\t\"(*net/http.Client).Post\":      \"must not be called. use (*net/http.Client).Do(*http.Request)\",\n\t\"(*net/http.Client).PostForm\":  \"must not be called. use (*net/http.Client).Do(*http.Request)\",\n\t\"net/http.NewRequest\":          \"must not be called. use net/http.NewRequestWithContext\",\n\t\"net/http/httptest.NewRequest\": \"must not be called. use net/http/httptest.NewRequestWithContext\",\n\n\t// database/sql\n\t\"(*database/sql.DB).Begin\":      \"must not be called. use (*database/sql.DB).BeginTx\",\n\t\"(*database/sql.DB).Exec\":       \"must not be called. use (*database/sql.DB).ExecContext\",\n\t\"(*database/sql.DB).Ping\":       \"must not be called. use (*database/sql.DB).PingContext\",\n\t\"(*database/sql.DB).Prepare\":    \"must not be called. use (*database/sql.DB).PrepareContext\",\n\t\"(*database/sql.DB).Query\":      \"must not be called. use (*database/sql.DB).QueryContext\",\n\t\"(*database/sql.DB).QueryRow\":   \"must not be called. use (*database/sql.DB).QueryRowContext\",\n\t\"(*database/sql.Tx).Exec\":       \"must not be called. use (*database/sql.Tx).ExecContext\",\n\t\"(*database/sql.Tx).Prepare\":    \"must not be called. use (*database/sql.Tx).PrepareContext\",\n\t\"(*database/sql.Tx).Query\":      \"must not be called. use (*database/sql.Tx).QueryContext\",\n\t\"(*database/sql.Tx).QueryRow\":   \"must not be called. use (*database/sql.Tx).QueryRowContext\",\n\t\"(*database/sql.Tx).Stmt\":       \"must not be called. use (*database/sql.Tx).StmtContext\",\n\t\"(*database/sql.Stmt).Exec\":     \"must not be called. use (*database/sql.Conn).ExecContext\",\n\t\"(*database/sql.Stmt).Query\":    \"must not be called. use (*database/sql.Conn).QueryContext\",\n\t\"(*database/sql.Stmt).QueryRow\": \"must not be called. use (*database/sql.Conn).QueryRowContext\",\n\n\t// exec\n\t\"os/exec.Command\": \"must not be called. use os/exec.CommandContext\",\n\n\t// crypto/tls dialer\n\t\"crypto/tls.Dial\":              \"must not be called. use (*crypto/tls.Dialer).DialContext\",\n\t\"crypto/tls.DialWithDialer\":    \"must not be called. use (*crypto/tls.Dialer).DialContext with NetDialer\",\n\t\"(*crypto/tls.Conn).Handshake\": \"must not be called. use (*crypto/tls.Conn).HandshakeContext\",\n\n\t// log/slog is out of scope of this analyzer, as slog doesn't use the [context.Context]\n\t// for context cancellation, but for key-value logging via the data stored in it.\n\t//\n\t// Related discussion: https://github.com/sonatard/noctx/issues/47\n}\n\nfunc Run(pass *analysis.Pass) (interface{}, error) {\n\tngFuncs := typeFuncs(pass, slices.Collect(maps.Keys(ngFuncMessages)))\n\tif len(ngFuncs) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tssa, ok := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"%T is not *buildssa.SSA\", pass.ResultOf[buildssa.Analyzer]))\n\t}\n\n\tfor _, sf := range ssa.SrcFuncs {\n\t\tfor _, b := range sf.Blocks {\n\t\t\tfor _, instr := range b.Instrs {\n\t\t\t\tfor _, ngFunc := range ngFuncs {\n\t\t\t\t\tif analysisutil.Called(instr, nil, ngFunc) {\n\t\t\t\t\t\tpass.Reportf(instr.Pos(), \"%s %s\", ngFunc.FullName(), ngFuncMessages[ngFunc.FullName()])\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "noctx_test.go",
    "content": "package noctx_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/sonatard/noctx\"\n\t\"golang.org/x/tools/go/analysis/analysistest\"\n)\n\nfunc TestAnalyzer(t *testing.T) {\n\ttestCases := []struct {\n\t\tdesc string\n\t}{\n\t\t{desc: \"crypto_tls\"},\n\t\t{desc: \"exec_cmd\"},\n\t\t{desc: \"http_client\"},\n\t\t{desc: \"http_request\"},\n\t\t{desc: \"httptest_request\"},\n\t\t{desc: \"network\"},\n\t\t{desc: \"sql\"},\n\t}\n\n\tfor _, test := range testCases {\n\t\tt.Run(test.desc, func(t *testing.T) {\n\t\t\tanalysistest.Run(t, analysistest.TestData(), noctx.Analyzer, test.desc)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "testdata/src/crypto_tls/tls.go",
    "content": "package crypto\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net\"\n)\n\nfunc _() {\n\tctx := context.Background()\n\n\tnetDialer := &net.Dialer{}\n\n\ttlsConfig := &tls.Config{}\n\n\t// dialers\n\ttls.Dial(\"tcp\", \"localhost:8080\", tlsConfig)                      // want `crypto/tls\\.Dial must not be called. use \\(\\*crypto/tls\\.Dialer\\)\\.DialContext`\n\ttls.DialWithDialer(netDialer, \"tcp\", \"localhost:8080\", tlsConfig) // want `crypto/tls\\.DialWithDialer must not be called. use \\(\\*crypto/tls\\.Dialer\\)\\.DialContext with NetDialer`\n\n\ttlsDialer := &tls.Dialer{\n\t\tConfig:    tlsConfig,\n\t\tNetDialer: netDialer,\n\t}\n\ttlsDialer.DialContext(ctx, \"tcp\", \"localhost:8080\")\n\n\t// connection\n\ttlsConn := &tls.Conn{}\n\ttlsConn.Handshake() // want `\\(\\*crypto/tls\\.Conn\\)\\.Handshake must not be called. use \\(\\*crypto/tls\\.Conn\\).HandshakeContext`\n\n\ttlsConn.HandshakeContext(ctx)\n}\n"
  },
  {
    "path": "testdata/src/exec_cmd/exec.go",
    "content": "package exec\n\nimport (\n\t\"context\"\n\t\"os/exec\"\n)\n\nfunc _() {\n\tctx := context.Background()\n\n\texec.Command(\"ls\", \"-l\") // want `os/exec.Command must not be called. use os/exec.CommandContext`\n\n\texec.CommandContext(ctx, \"ls\", \"-l\")\n}\n"
  },
  {
    "path": "testdata/src/http_client/http_client.go",
    "content": "package http_client\n\nimport (\n\t\"net/http\"\n)\n\nfunc _() {\n\tconst url = \"http://example.com\"\n\tcli := &http.Client{}\n\n\thttp.Get(url) // want `net/http\\.Get must not be called. use net/http\\.NewRequestWithContext and \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\t_ = http.Get  // OK\n\tf := http.Get // OK\n\tf(url)        // want `net/http\\.Get must not be called. use net/http\\.NewRequestWithContext and \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\n\thttp.Head(url)          // want `net/http\\.Head must not be called. use net/http\\.NewRequestWithContext and \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\thttp.Post(url, \"\", nil) // want `net/http\\.Post must not be called. use net/http\\.NewRequestWithContext and \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\thttp.PostForm(url, nil) // want `net/http\\.PostForm must not be called. use net/http\\.NewRequestWithContext and \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\n\tcli.Get(url) // want `\\(\\*net/http\\.Client\\)\\.Get must not be called. use \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\t_ = cli.Get  // OK\n\tm := cli.Get // OK\n\tm(url)       // want `\\(\\*net/http\\.Client\\)\\.Get must not be called. use \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\n\tcli.Head(url)          // want `\\(\\*net/http\\.Client\\)\\.Head must not be called. use \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\tcli.Post(url, \"\", nil) // want `\\(\\*net/http\\.Client\\)\\.Post must not be called. use \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n\tcli.PostForm(url, nil) // want `\\(\\*net/http\\.Client\\)\\.PostForm must not be called. use \\(\\*net/http.Client\\)\\.Do\\(\\*http.Request\\)`\n}\n"
  },
  {
    "path": "testdata/src/http_request/http_request.go",
    "content": "package http_request\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nvar newRequestPkg = http.NewRequest\n\nfunc _() {\n\tconst url = \"https://example.com\"\n\n\tcli := &http.Client{}\n\n\tctx := context.Background()\n\n\treq, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\tcli.Do(req)\n\n\treq2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK\n\tcli.Do(req2)\n\n\treq3, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq3 = req3.WithContext(ctx)\n\tcli.Do(req3)\n\n\tf2 := func(req *http.Request, ctx context.Context) *http.Request {\n\t\treturn req\n\t}\n\treq4, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq4 = f2(req4, ctx)\n\n\treq41, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq41 = req41.WithContext(ctx)\n\treq41 = f2(req41, ctx)\n\n\tnewRequest := http.NewRequest\n\treq5, _ := newRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\tcli.Do(req5)\n\n\treq51, _ := newRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq51 = req51.WithContext(ctx)\n\tcli.Do(req51)\n\n\treq52, _ := newRequestPkg(http.MethodPost, url, nil) // TODO: false negative `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\tcli.Do(req52)\n\n\ttype MyRequest = http.Request\n\tf3 := func(req *MyRequest, ctx context.Context) *MyRequest {\n\t\treturn req\n\t}\n\treq6, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq6 = f3(req6, ctx)\n\n\treq61, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq61 = req61.WithContext(ctx)\n\treq61 = f3(req61, ctx)\n\n\ttype MyRequest2 http.Request\n\tf4 := func(req *MyRequest2, ctx context.Context) *MyRequest2 {\n\t\treturn req\n\t}\n\treq7, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq71 := MyRequest2(*req7)\n\tf4(&req71, ctx)\n\n\treq72, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq72 = req72.WithContext(ctx)\n\treq73 := MyRequest2(*req7)\n\tf4(&req73, ctx)\n\n\treq8, _ := func() (*http.Request, error) {\n\t\treturn http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t}()\n\tcli.Do(req8)\n\n\treq82, _ := func() (*http.Request, error) {\n\t\treq82, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t\treq82 = req82.WithContext(ctx)\n\t\treturn req82, nil\n\t}()\n\tcli.Do(req82)\n\n\tf5 := func(req, req2 *http.Request, ctx context.Context) (*http.Request, *http.Request) {\n\t\treturn req, req2\n\t}\n\treq9, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq9, _ = f5(req9, req9, ctx)\n\n\treq91, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq91 = req91.WithContext(ctx)\n\treq9, _ = f5(req91, req91, ctx)\n\n\treq10, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq11, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq10, req11 = f5(req10, req11, ctx)\n\n\treq101, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq111, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq111 = req111.WithContext(ctx)\n\treq101, req111 = f5(req101, req111, ctx)\n\n\tfunc() (*http.Request, *http.Request) {\n\t\treq12, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t\treq13, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t\treturn req12, req13\n\t}()\n\n\tfunc() (*http.Request, *http.Request) {\n\t\treq14, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t\treq15, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\t\treq15 = req15.WithContext(ctx)\n\n\t\treturn req14, req15\n\t}()\n\n\treq121, _ := http.NewRequest(http.MethodPost, url, nil) // want `net/http\\.NewRequest must not be called. use net/http\\.NewRequestWithContext`\n\treq121.AddCookie(&http.Cookie{Name: \"k\", Value: \"v\"})\n\treq121 = req121.WithContext(context.WithValue(req121.Context(), struct{}{}, 0))\n\tcli.Do(req121)\n}\n"
  },
  {
    "path": "testdata/src/httptest_request/httptest_request.go",
    "content": "package httptest_request\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n)\n\nfunc _() {\n\tconst url = \"https://example.com\"\n\n\tcli := &http.Client{}\n\n\tctx := context.Background()\n\n\treq := httptest.NewRequest(http.MethodPost, url, nil) // want `net/http/httptest\\.NewRequest must not be called. use net/http/httptest\\.NewRequestWithContext`\n\tcli.Do(req)\n\n\treq2 := httptest.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK\n\tcli.Do(req2)\n\n\tnewRequest := httptest.NewRequest\n\treq3 := newRequest(http.MethodPost, url, nil) // want `net/http/httptest\\.NewRequest must not be called. use net/http/httptest\\.NewRequestWithContext`\n\tcli.Do(req3)\n}\n"
  },
  {
    "path": "testdata/src/network/net.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"time\"\n)\n\nvar timeout = 10 * time.Second\n\nfunc _() {\n\tctx := context.Background()\n\n\t// listenConfig\n\tlistenConfig := &net.ListenConfig{}\n\n\tnet.Listen(\"tcp\", \"localhost:8080\") // want `net\\.Listen must not be called. use \\(\\*net\\.ListenConfig\\)\\.Listen`\n\tlistenConfig.Listen(ctx, \"tcp\", \"localhost:8080\")\n\n\tnet.ListenPacket(\"udp\", \"localhost:8080\") // want `net\\.ListenPacket must not be called. use \\(\\*net\\.ListenConfig\\)\\.ListenPacket`\n\tlistenConfig.ListenPacket(ctx, \"udp\", \"localhost:8080\")\n\n\t// dialer\n\tnet.Dial(\"tcp\", \"localhost:8080\")                 // want `net\\.Dial must not be called. use \\(\\*net\\.Dialer\\)\\.DialContext`\n\tnet.DialTimeout(\"tcp\", \"localhost:8080\", timeout) // want `net\\.DialTimeout must not be called. use \\(\\*net\\.Dialer\\)\\.DialContext with \\(\\*net\\.Dialer\\)\\.Timeout`\n\n\tdialer := &net.Dialer{}\n\tdialer.DialContext(ctx, \"tcp\", \"localhost:8080\")\n\n\tdialerTimeout := &net.Dialer{Timeout: timeout}\n\tdialerTimeout.DialContext(ctx, \"tcp\", \"localhost:8080\")\n\n\t// resolver\n\tnet.LookupCNAME(\"example.com\")              // want `net\\.LookupCNAME must not be called. use \\(\\*net\\.Resolver\\)\\.LookupCNAME with a context`\n\tnet.LookupHost(\"example.com\")               // want `net\\.LookupHost must not be called. use \\(\\*net\\.Resolver\\)\\.LookupHost with a context`\n\tnet.LookupIP(\"example.com\")                 // want `net\\.LookupIP must not be called. use \\(\\*net\\.Resolver\\)\\.LookupIPAddr with a context`\n\tnet.LookupPort(\"tcp\", \"http\")               // want `net\\.LookupPort must not be called. use \\(\\*net\\.Resolver\\)\\.LookupPort with a context`\n\tnet.LookupSRV(\"http\", \"tcp\", \"example.com\") // want `net\\.LookupSRV must not be called. use \\(\\*net\\.Resolver\\)\\.LookupSRV with a context`\n\tnet.LookupMX(\"example.com\")                 // want `net\\.LookupMX must not be called. use \\(\\*net\\.Resolver\\)\\.LookupMX with a context`\n\tnet.LookupNS(\"example.com\")                 // want `net\\.LookupNS must not be called. use \\(\\*net\\.Resolver\\)\\.LookupNS with a context`\n\tnet.LookupTXT(\"example.com\")                // want `net\\.LookupTXT must not be called. use \\(\\*net\\.Resolver\\)\\.LookupTXT with a context`\n\tnet.LookupAddr(\"example.com\")               // want `net\\.LookupAddr must not be called. use \\(\\*net\\.Resolver\\)\\.LookupAddr with a context`\n\n\tresolver := net.DefaultResolver\n\tresolver.LookupCNAME(ctx, \"example.com\")\n\tresolver.LookupHost(ctx, \"example.com\")\n\tresolver.LookupIPAddr(ctx, \"example.com\")\n\tresolver.LookupPort(ctx, \"tcp\", \"http\")\n\tresolver.LookupSRV(ctx, \"http\", \"tcp\", \"example.com\")\n\tresolver.LookupMX(ctx, \"example.com\")\n\tresolver.LookupNS(ctx, \"example.com\")\n\tresolver.LookupTXT(ctx, \"example.com\")\n\tresolver.LookupAddr(ctx, \"example.com\")\n}\n"
  },
  {
    "path": "testdata/src/sql/sql.go",
    "content": "package http_request\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\nfunc _() {\n\tctx := context.Background()\n\n\tdb, _ := sql.Open(\"noctx\", \"noctx://\")\n\n\t// database/sql.DB methods\n\n\tdb.Begin() // want `\\(\\*database/sql\\.DB\\)\\.Begin must not be called. use \\(\\*database/sql\\.DB\\)\\.BeginTx`\n\tdb.BeginTx(ctx, nil)\n\n\tdb.Exec(\"select * from testdata\") // want `\\(\\*database/sql\\.DB\\)\\.Exec must not be called. use \\(\\*database/sql\\.DB\\)\\.ExecContext`\n\tdb.ExecContext(ctx, \"select * from testdata\")\n\n\tdb.Ping() // want `\\(\\*database/sql\\.DB\\)\\.Ping must not be called. use \\(\\*database/sql\\.DB\\)\\.PingContext`\n\tdb.PingContext(ctx)\n\n\tdb.Prepare(\"select * from testdata\") // want `\\(\\*database/sql\\.DB\\)\\.Prepare must not be called. use \\(\\*database/sql\\.DB\\)\\.PrepareContext`\n\tdb.PrepareContext(ctx, \"select * from testdata\")\n\n\tdb.Query(\"select * from testdata\") // want `\\(\\*database/sql\\.DB\\)\\.Query must not be called. use \\(\\*database/sql\\.DB\\)\\.QueryContext`\n\tdb.QueryContext(ctx, \"select * from testdata\")\n\n\tdb.QueryRow(\"select * from testdata\") // want `\\(\\*database/sql\\.DB\\)\\.QueryRow must not be called. use \\(\\*database/sql\\.DB\\)\\.QueryRowContext`\n\tdb.QueryRowContext(ctx, \"select * from testdata\")\n\n\t// database/sql.Stmt methods\n\tstmt, _ := db.PrepareContext(context.Background(), \"select * from testdata where id = ?\")\n\n\tstmt.Query(\"1\") // want `\\(\\*database/sql\\.Stmt\\)\\.Query must not be called. use \\(\\*database/sql\\.Conn\\)\\.QueryContext`\n\tstmt.QueryContext(ctx, \"1\")\n\n\tstmt.QueryRow(\"1\") // want `\\(\\*database/sql\\.Stmt\\)\\.QueryRow must not be called. use \\(\\*database/sql\\.Conn\\)\\.QueryRowContext`\n\tstmt.QueryRowContext(ctx, \"1\")\n\n\tstmt.Exec(\"1\") // want `\\(\\*database/sql\\.Stmt\\)\\.Exec must not be called. use \\(\\*database/sql\\.Conn\\)\\.ExecContext`\n\tstmt.ExecContext(ctx, \"1\")\n\n\t// database/sql.Tx methods\n\ttx, _ := db.BeginTx(ctx, nil)\n\ttx.Exec(\"select * from testdata\") // want `\\(\\*database/sql\\.Tx\\)\\.Exec must not be called. use \\(\\*database/sql\\.Tx\\)\\.ExecContext`\n\ttx.ExecContext(ctx, \"select * from testdata\")\n\n\ttx.Prepare(\"select * from testdata\") // want `\\(\\*database/sql\\.Tx\\)\\.Prepare must not be called. use \\(\\*database/sql\\.Tx\\)\\.PrepareContext`\n\ttx.PrepareContext(ctx, \"select * from testdata\")\n\n\ttx.Query(\"select * from testdata\") // want `\\(\\*database/sql\\.Tx\\)\\.Query must not be called. use \\(\\*database/sql\\.Tx\\)\\.QueryContext`\n\ttx.QueryContext(ctx, \"select * from testdata\")\n\n\ttx.QueryRow(\"select * from testdata\") // want `\\(\\*database/sql\\.Tx\\)\\.QueryRow must not be called. use \\(\\*database/sql\\.Tx\\)\\.QueryRowContext`\n\ttx.QueryRowContext(ctx, \"select * from testdata\")\n\n\ttx.Stmt(stmt) // want `\\(\\*database/sql\\.Tx\\)\\.Stmt must not be called. use \\(\\*database/sql\\.Tx\\)\\.StmtContext`\n\ttx.StmtContext(ctx, stmt)\n\n\t_ = tx.Commit()\n\n\t// database/sql.Conn are safe, they only have context-aware methods\n\t// these lines are just to show that they are not flagged\n\tconn, _ := db.Conn(ctx)\n\tconn.ExecContext(ctx, \"select * from testdata\")\n\tconn.QueryContext(ctx, \"select * from testdata\")\n\tconn.QueryRowContext(ctx, \"select * from testdata\")\n}\n"
  },
  {
    "path": "types.go",
    "content": "package noctx\n\nimport (\n\t\"errors\"\n\t\"go/types\"\n\t\"strings\"\n\n\t\"github.com/gostaticanalysis/analysisutil\"\n\t\"golang.org/x/tools/go/analysis\"\n)\n\nvar errNotFound = errors.New(\"function not found\")\n\nfunc typeFuncs(pass *analysis.Pass, funcs []string) []*types.Func {\n\tfs := make([]*types.Func, 0, len(funcs))\n\n\tfor _, fn := range funcs {\n\t\tf, err := typeFunc(pass, fn)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfs = append(fs, f)\n\t}\n\n\treturn fs\n}\n\nfunc typeFunc(pass *analysis.Pass, funcName string) (*types.Func, error) {\n\tnameParts := strings.Split(strings.TrimSpace(funcName), \".\")\n\n\tswitch len(nameParts) {\n\tcase 2:\n\t\t// package function: pkgname.Func\n\t\tf, ok := analysisutil.ObjectOf(pass, nameParts[0], nameParts[1]).(*types.Func)\n\t\tif !ok || f == nil {\n\t\t\treturn nil, errNotFound\n\t\t}\n\n\t\treturn f, nil\n\tcase 3:\n\t\t// method: (*pkgname.Type).Method\n\t\tpkgName := strings.TrimLeft(nameParts[0], \"(\")\n\t\ttypeName := strings.TrimRight(nameParts[1], \")\")\n\n\t\tif pkgName != \"\" && pkgName[0] == '*' {\n\t\t\tpkgName = pkgName[1:]\n\t\t\ttypeName = \"*\" + typeName\n\t\t}\n\n\t\ttyp := analysisutil.TypeOf(pass, pkgName, typeName)\n\t\tif typ == nil {\n\t\t\treturn nil, errNotFound\n\t\t}\n\n\t\tm := analysisutil.MethodOf(typ, nameParts[2])\n\t\tif m == nil {\n\t\t\treturn nil, errNotFound\n\t\t}\n\n\t\treturn m, nil\n\t}\n\n\treturn nil, errNotFound\n}\n"
  }
]