Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'floatcompare' linter #2608

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .golangci.example.yml
Expand Up @@ -285,6 +285,11 @@ linters-settings:
- '*.Test'
- 'example.com/package.ExampleStruct'

floatcompare:
# Search only for == and != no other comparisons
# Default: false
equal-only: true

forbidigo:
# Forbid the following identifiers (list of regexp).
forbid:
Expand Down Expand Up @@ -1636,6 +1641,7 @@ linters:
- exhaustive
- exhaustivestruct
- exportloopref
- floatcompare
- forbidigo
- forcetypeassert
- funlen
Expand Down Expand Up @@ -1726,6 +1732,7 @@ linters:
- exhaustive
- exhaustivestruct
- exportloopref
- floatcompare
- forbidigo
- forcetypeassert
- funlen
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Expand Up @@ -61,6 +61,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-ps v1.0.0
github.com/moricho/tparallel v0.2.1
github.com/mweb/floatcompare v1.0.4
github.com/nakabonne/nestif v0.3.1
github.com/nishanths/exhaustive v0.7.11
github.com/nishanths/predeclared v0.2.1
Expand Down Expand Up @@ -162,7 +163,7 @@ require (
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/config/linters_settings.go
Expand Up @@ -123,6 +123,7 @@ type LintersSettings struct {
ErrorLint ErrorLintSettings
Exhaustive ExhaustiveSettings
ExhaustiveStruct ExhaustiveStructSettings
FloatCompare FloatCompareSettings
Forbidigo ForbidigoSettings
Funlen FunlenSettings
Gci GciSettings
Expand Down Expand Up @@ -255,6 +256,10 @@ type ExhaustiveStructSettings struct {
StructPatterns []string `mapstructure:"struct-patterns"`
}

type FloatCompareSettings struct {
EqualOnly bool `mapstructure:"equal-only"`
}

type ForbidigoSettings struct {
Forbid []string `mapstructure:"forbid"`
ExcludeGodocExamples bool `mapstructure:"exclude-godoc-examples"`
Expand Down
29 changes: 29 additions & 0 deletions pkg/golinters/floatcompare.go
@@ -0,0 +1,29 @@
package golinters

import (
"github.com/mweb/floatcompare"
"golang.org/x/tools/go/analysis"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)

func NewFloatCompare(settings *config.FloatCompareSettings) *goanalysis.Linter {
a := floatcompare.NewAnalyzer()

var cfg map[string]map[string]interface{}
if settings != nil {
d := map[string]interface{}{
"equalOnly": settings.EqualOnly,
}

cfg = map[string]map[string]interface{}{a.Name: d}
}

return goanalysis.NewLinter(
a.Name,
a.Doc,
[]*analysis.Analyzer{a},
cfg,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
}
8 changes: 8 additions & 0 deletions pkg/lint/lintersdb/manager.go
Expand Up @@ -107,6 +107,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var errorlintCfg *config.ErrorLintSettings
var exhaustiveCfg *config.ExhaustiveSettings
var exhaustiveStructCfg *config.ExhaustiveStructSettings
var floatCompareStructCfg *config.FloatCompareSettings
var gciCfg *config.GciSettings
var goModDirectivesCfg *config.GoModDirectivesSettings
var goMndCfg *config.GoMndSettings
Expand Down Expand Up @@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
exhaustiveStructCfg = &m.cfg.LintersSettings.ExhaustiveStruct
floatCompareStructCfg = &m.cfg.LintersSettings.FloatCompare
gciCfg = &m.cfg.LintersSettings.Gci
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
goMndCfg = &m.cfg.LintersSettings.Gomnd
Expand Down Expand Up @@ -289,6 +291,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/kyoh86/exportloopref"),

linter.NewConfig(golinters.NewFloatCompare(floatCompareStructCfg)).
WithSince("v1.46.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/mweb/floatcompare"),

linter.NewConfig(golinters.NewForbidigo()).
WithSince("v1.34.0").
WithPresets(linter.PresetStyle).
Expand Down
71 changes: 71 additions & 0 deletions test/testdata/floatcompare.go
@@ -0,0 +1,71 @@
// args: -Efloatcompare
package testdata

import "fmt"

func EqualCompareIfFloats() {
x, y := 400., 500.
if 300. == 100. { // ERROR `float comparison found "300. == 100."`
dummy()
}
if x == y { // ERROR `float comparison found "x == y"`
dummy()
}
if 300.+200. == 10. { // ERROR `float comparison found "300.+200. == 10."`
dummy()
}
if 300 == 200 {
dummy()
}
}

func NotEqualCompareIfFloats() {
x, y := 400., 500.
if 300. != 100. { // ERROR `float comparison found "300. != 100."`

dummy()
}
if x != y { // ERROR `float comparison found "x != y"`
dummy()
}
}

func EqualCompareIfCustomType() {
type number float64
var x, y number = 300., 400.
if x == y { // ERROR `float comparison found "x == y"`
dummy()
}
}

func GreaterLessCompareIfFloats() {
if 300. >= 100. { // ERROR `float comparison found "300. >= 100."`
dummy()
}
if 300. <= 100. { // ERROR `float comparison found "300. <= 100."`
dummy()
}
if 300. < 100. { // ERROR `float comparison found "300. < 100."`
dummy()
}
if 300. > 100. { // ERROR `float comparison found "300. > 100."`
dummy()
}
}

func SwitchStmtWithFloat() {
switch 300. { // ERROR "float comparison with switch statement"
case 100.:
case 200:
}
}

func EqualCompareSwitchFloats() {
switch {
case 100. == 200.: // ERROR `float comparison found "100. == 200."`
}
}

func dummy() {
fmt.Println("dummy()")
}