From 08d54e9751c32b72a026de02e4a9a1cfe2ca5429 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 18 Sep 2022 17:17:00 +0900 Subject: [PATCH] .github/workflows/vettools: add a static analysis for image importing Updates #2336 Closes #2337 --- .github/workflows/test.yml | 2 +- .../workflows/vettools/imageimportcheck.go | 83 +++++++++++++++++++ .github/workflows/vettools/main.go | 4 +- 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/vettools/imageimportcheck.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 52e439340..60bcf6c19 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,7 +73,7 @@ jobs: run: | go vet -tags=example -v ./... - - name: go vet (atomic align, error check) + - name: go vet (vettool) run: | (cd .github/workflows/vettools; go install .) go vet -vettool=$(which vettools)${{ startsWith(matrix.os, 'windows-') && '.exe' || '' }} -tags=example -v ./... diff --git a/.github/workflows/vettools/imageimportcheck.go b/.github/workflows/vettools/imageimportcheck.go new file mode 100644 index 000000000..97d67888d --- /dev/null +++ b/.github/workflows/vettools/imageimportcheck.go @@ -0,0 +1,83 @@ +// Copyright 2022 The Ebitengine Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "go/token" + "reflect" + "strconv" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// imageImportCheckAnalyzer is an analyzer to check whether unexpected `image/*` packages are imported. +// Importing `image/gif`, `image/jpeg`, and `image/png` registers their recorders at `init` functions, so +// have affect the result of `image.Decode`. Ebitengine should not have such side-effects. +var imageImportCheckAnalyzer = &analysis.Analyzer{ + Name: "imageimportcheck", + Doc: "check importing image/gif, image/jpeg, and image/png packages", + Run: runImageImportCheck, + ResultType: reflect.TypeOf(imageImportCheckResult{}), +} + +type imageImportCheckResult struct { + Errors []imageImportCheckError +} + +type imageImportCheckError struct { + Pos token.Pos + Import string +} + +func runImageImportCheck(pass *analysis.Pass) (interface{}, error) { + pkgPath := pass.Pkg.Path() + if strings.HasPrefix(pkgPath, "github.com/hajimehoshi/ebiten/v2/example") { + return nil, nil + } + if strings.HasSuffix(pkgPath, "_test") { + return nil, nil + } + + // TODO: Remove this exception after v3 is released (#2336). + if strings.HasPrefix(pkgPath, "github.com/hajimehoshi/ebiten/v2/ebitenutil") { + return nil, nil + } + + var errs []imageImportCheckError + for _, f := range pass.Files { + for _, i := range f.Imports { + path, err := strconv.Unquote(i.Path.Value) + if err != nil { + return nil, err + } + if path == "image/gif" || path == "image/jpeg" || path == "image/png" { + err := imageImportCheckError{ + Pos: pass.Fset.File(f.Pos()).Pos(int(i.Pos())), + Import: path, + } + errs = append(errs, err) + pass.Report(analysis.Diagnostic{ + Pos: err.Pos, + Message: fmt.Sprintf("unexpected import %q", err.Import), + }) + } + } + } + return imageImportCheckResult{ + Errors: errs, + }, nil +} diff --git a/.github/workflows/vettools/main.go b/.github/workflows/vettools/main.go index e274d9f14..a24fea666 100644 --- a/.github/workflows/vettools/main.go +++ b/.github/workflows/vettools/main.go @@ -23,9 +23,9 @@ import ( ) func main() { - filename := ".errcheck_excludes" + const filename = ".errcheck_excludes" if _, err := os.Stat(filename); err == nil { errcheck.Analyzer.Flags.Set("exclude", filename) } - multichecker.Main(atomicalign.Analyzer, errcheck.Analyzer) + multichecker.Main(atomicalign.Analyzer, errcheck.Analyzer, imageImportCheckAnalyzer) }