golangci-lint icon indicating copy to clipboard operation
golangci-lint copied to clipboard

typecheck doesn't seem to recognise go:wasmimport directives

Open mattjohnsonpint opened this issue 1 year ago • 8 comments

Welcome

  • [X] Yes, I'm using a binary release within 2 latest releases. Only such installations are supported.
  • [X] Yes, I've searched similar issues on GitHub and didn't find any.
  • [X] Yes, I've read the typecheck section of the FAQ.
  • [X] Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.).
  • [X] I agree to follow this project's Code of Conduct

Description of the problem

Functions that are marked with //go:wasmimport cannot (by design) have a function body. They're simply the declaration for the function that will be imported. However, golangci-lint fails with missing function body (typecheck).

I understand this probably isn't an issue that can be fixed here, but I'm really uncertain where/how to report it elsewhere.

The example program below compiles properly with either Go or TinyGo.

Go:

GOOS=wasip1 GOARCH=wasm go build -o test.wasm

TinyGo:

tinygo build -target=wasip1 -o test.wasm 

But it fails linting with golangci-lint. I also tried staticheck, and it fails in a similar way there too.

Please let me know if I should report this elsewhere also. Thanks.

Version of golangci-lint

golangci-lint has version 1.60.3 built with go1.23.0 from c2e095c on 2024-08-22T21:45:24Z

Configuration

n/a

Go environment

go version go1.23.0 darwin/arm64
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/matt/Library/Caches/go-build'
GOENV='/Users/matt/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/matt/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/matt/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.23.0/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.23.0/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.0'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/matt/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
GOMOD='/Users/matt/Code/gotemp/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/sf/btdk_dj52jx9lpzxfq01q9d00000gn/T/go-build4013300433=/tmp/go-build -gno-record-gcc-switches -fno-common'

Verbose output of running

INFO golangci-lint has version 1.60.3 built with go1.23.0 from c2e095c on 2024-08-22T21:45:24Z 
INFO [config_reader] Config search paths: [./ /Users/matt/Code/gotemp /Users/matt/Code /Users/matt /Users /] 
INFO [lintersdb] Active 6 linters: [errcheck gosimple govet ineffassign staticcheck unused] 
INFO [loader] Go packages loading at mode 575 (types_sizes|exports_file|name|files|imports|compiled_files|deps) took 130.07175ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 404.458µs 
INFO [linters_context/goanalysis] analyzers took 3.235584ms with top 10 stages: buildir: 499.333µs, fact_deprecated: 467.917µs, ifaceassert: 118.667µs, S1012: 92.125µs, inspect: 81µs, directive: 66.125µs, S1017: 64.417µs, ineffassign: 62.834µs, cgocall: 52.708µs, S1002: 50.875µs 
INFO [runner] Issues before processing: 175, after processing: 1 
INFO [runner] Processors filtering stat (in/out): diff: 1/1, source_code: 1/1, nolint: 175/175, max_from_linter: 1/1, path_shortener: 1/1, filename_unadjuster: 175/175, skip_files: 175/175, exclude: 175/175, max_per_file_from_linter: 1/1, max_same_issues: 1/1, severity-rules: 1/1, path_prefixer: 1/1, sort_results: 1/1, cgo: 175/175, invalid_issue: 175/175, path_prettifier: 175/175, skip_dirs: 175/175, autogenerated_exclude: 175/175, identifier_marker: 175/175, exclude-rules: 175/175, uniq_by_line: 175/1, fixer: 1/1 
INFO [runner] processing took 2.059ms with stages: identifier_marker: 1.389708ms, skip_dirs: 372.667µs, path_prettifier: 207.167µs, source_code: 28.416µs, autogenerated_exclude: 20.167µs, nolint: 15.542µs, uniq_by_line: 5.083µs, invalid_issue: 4.833µs, filename_unadjuster: 4.666µs, cgo: 4.542µs, exclude-rules: 2.583µs, max_same_issues: 1.333µs, path_shortener: 792ns, max_from_linter: 292ns, skip_files: 292ns, exclude: 209ns, sort_results: 208ns, max_per_file_from_linter: 208ns, fixer: 167ns, severity-rules: 84ns, diff: 41ns, path_prefixer: 0s 
INFO [runner] linters took 14.731083ms with stages: goanalysis_metalinter: 12.599834ms 
main.go:1: : # main
./main.go:10:6: missing function body (typecheck)
package main
INFO File cache stats: 1 entries of total size 134B 
INFO Memory: 3 samples, avg is 28.1MB, max is 30.9MB 
INFO Execution took 151.832167ms 

A minimal reproducible example or link to a public repository

package main

func main() {
	result := add(1, 2)
	println(result)
}

//go:noescape
//go:wasmimport foo add
func add(a, b int32) int32

Validation

  • [X] Yes, I've included all information above (version, config, etc.).

Supporter

mattjohnsonpint avatar Aug 26 '24 04:08 mattjohnsonpint

Hey, thank you for opening your first Issue ! 🙂 If you would like to contribute we have a guide for contributors.

boring-cyborg[bot] avatar Aug 26 '24 04:08 boring-cyborg[bot]

You need to define the build tags inside the configuration:

run:
  build-tags:
    - wasip1

Also, it's not needed but you can additionally add build tags inside your code:

//go:build wasip1

package main

func main() {
	result := add(1, 2)
	println(result)
}

//go:noescape
//go:wasmimport foo add
func add(a, b int32) int32

ldez avatar Aug 26 '24 06:08 ldez

Perfect. Thank you!

mattjohnsonpint avatar Aug 26 '24 06:08 mattjohnsonpint

@ldez - there's still something slightly off. If I have everything in one main.go file and add the build tag to the run configuration it lints correctly. But if I move the imported function to a sub package, it fails again.

.golangci.yml

run:
  build-tags:
    - wasip1

go.mod

module main

go 1.23.0

main.go

package main

import "main/foo"

func main() {
	result := foo.Add(1, 2)
	println(result)
}

foo/add.go

package foo

//go:noescape
//go:wasmimport foo add
func Add(a, b int32) int32

output from golangci-lint run

foo/add.go:1: : # main/foo
foo/add.go:5:6: missing function body (typecheck)
package foo
main.go:5:8: could not import main/foo (-: # main/foo
foo/add.go:5:6: missing function body) (typecheck)
import "main/foo"

Adding the build tag directly in the file doesn't seem to help.

mattjohnsonpint avatar Aug 26 '24 14:08 mattjohnsonpint

as a workaround, you can play with build tags.

You can remove the build tags from the golancgi-lint configuration and use the following pattern:

main.go
package main

import "github.com/golangci/sandbox/foo"

func main() {
	result := foo.Add(1, 2)
	println(result)
}

foo/add.go
//go:build wasip1

package foo

//go:noescape
//go:wasmimport foo add
func Add(a, b int32) int32

foo/add_fake.go
//go:build !wasip1

package foo

func Add(a, b int32) int32 {
	return a + b
}

ldez avatar Aug 26 '24 17:08 ldez

Ok. I can do that for now. Did you want to re-open this then? Or is it an issue for Go itself?

mattjohnsonpint avatar Aug 26 '24 18:08 mattjohnsonpint

For now, I don't know where is the problem. I have several topics to handle at the same time (like these spam bots that come on every new issue) so I'll analyze the problem as quickly as possible, but "time is a limit". :wink:

ldez avatar Aug 26 '24 18:08 ldez

Understood. Thank you.

mattjohnsonpint avatar Aug 26 '24 19:08 mattjohnsonpint

FYI, the workaround with build tags in separate files is actually working quite nicely for me. I can use the "fake" one for mocking the imported functions in unit tests. I think this is the way. 😄

mattjohnsonpint avatar Aug 30 '24 21:08 mattjohnsonpint

Does golangci-lint have configurations to skip directories? I tested exclusions.paths, but unfortunately, it doesn't work.

vm-001 avatar Apr 08 '25 04:04 vm-001

Does golangci-lint have configurations to skip directories? I tested exclusions.paths, but unfortunately, it doesn't work.

You mean instead of using build tags?

Build tags is one way, but exclusions won't change what's analyzed, just what's reported. See #5438 and #5297

bombsimon avatar Apr 08 '25 06:04 bombsimon

Yes, without using build tags. I'm looking for a feature to skip the entire directories including analyzing. I suppose golangci-lint doesn't support this yet.

vm-001 avatar Apr 09 '25 06:04 vm-001