Skip to content

Commit dc69689

Browse files
committed
Add 'floatcompare' linter
1 parent a2e6c76 commit dc69689

File tree

7 files changed

+125
-3
lines changed

7 files changed

+125
-3
lines changed

.golangci.example.yml

+6
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ linters-settings:
285285
- '*.Test'
286286
- 'example.com/package.ExampleStruct'
287287

288+
floatcompare:
289+
# Search only for == and != no other comparisons
290+
# Default: false
291+
equal-only: true
292+
288293
forbidigo:
289294
# Forbid the following identifiers (list of regexp).
290295
forbid:
@@ -1726,6 +1731,7 @@ linters:
17261731
- exhaustive
17271732
- exhaustivestruct
17281733
- exportloopref
1734+
- floatcompare
17291735
- forbidigo
17301736
- forcetypeassert
17311737
- funlen

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ require (
6161
github.com/mitchellh/go-homedir v1.1.0
6262
github.com/mitchellh/go-ps v1.0.0
6363
github.com/moricho/tparallel v0.2.1
64+
github.com/mweb/floatcompare v1.0.3
6465
github.com/nakabonne/nestif v0.3.1
6566
github.com/nishanths/exhaustive v0.7.11
6667
github.com/nishanths/predeclared v0.2.1
@@ -162,7 +163,7 @@ require (
162163
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
163164
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
164165
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
165-
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
166+
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 // indirect
166167
golang.org/x/text v0.3.7 // indirect
167168
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
168169
google.golang.org/protobuf v1.27.1 // indirect

go.sum

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/linters_settings.go

+5
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ type LintersSettings struct {
123123
ErrorLint ErrorLintSettings
124124
Exhaustive ExhaustiveSettings
125125
ExhaustiveStruct ExhaustiveStructSettings
126+
FloatCompare FloatCompareSettings
126127
Forbidigo ForbidigoSettings
127128
Funlen FunlenSettings
128129
Gci GciSettings
@@ -255,6 +256,10 @@ type ExhaustiveStructSettings struct {
255256
StructPatterns []string `mapstructure:"struct-patterns"`
256257
}
257258

259+
type FloatCompareSettings struct {
260+
EqualOnly bool `mapstructure:"equal-only"`
261+
}
262+
258263
type ForbidigoSettings struct {
259264
Forbid []string `mapstructure:"forbid"`
260265
ExcludeGodocExamples bool `mapstructure:"exclude-godoc-examples"`

pkg/golinters/floatcompare.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package golinters
2+
3+
import (
4+
"github.com/mweb/floatcompare"
5+
"golang.org/x/tools/go/analysis"
6+
7+
"github.com/golangci/golangci-lint/pkg/config"
8+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9+
)
10+
11+
func NewFloatCompare(settings *config.FloatCompareSettings) *goanalysis.Linter {
12+
a := floatcompare.NewAnalyzer()
13+
14+
var cfg map[string]map[string]interface{}
15+
if settings != nil {
16+
d := map[string]interface{}{
17+
"equalOnly": settings.EqualOnly,
18+
}
19+
20+
cfg = map[string]map[string]interface{}{a.Name: d}
21+
}
22+
23+
return goanalysis.NewLinter(
24+
a.Name,
25+
a.Doc,
26+
[]*analysis.Analyzer{a},
27+
cfg,
28+
).WithLoadMode(goanalysis.LoadModeTypesInfo)
29+
}

pkg/lint/lintersdb/manager.go

+8
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
107107
var errorlintCfg *config.ErrorLintSettings
108108
var exhaustiveCfg *config.ExhaustiveSettings
109109
var exhaustiveStructCfg *config.ExhaustiveStructSettings
110+
var floatCompareStructCfg *config.FloatCompareSettings
110111
var gciCfg *config.GciSettings
111112
var goModDirectivesCfg *config.GoModDirectivesSettings
112113
var goMndCfg *config.GoMndSettings
@@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
140141
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
141142
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
142143
exhaustiveStructCfg = &m.cfg.LintersSettings.ExhaustiveStruct
144+
floatCompareStructCfg = &m.cfg.LintersSettings.FloatCompare
143145
gciCfg = &m.cfg.LintersSettings.Gci
144146
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
145147
goMndCfg = &m.cfg.LintersSettings.Gomnd
@@ -289,6 +291,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
289291
WithLoadForGoAnalysis().
290292
WithURL("https://github.com/kyoh86/exportloopref"),
291293

294+
linter.NewConfig(golinters.NewFloatCompare(floatCompareStructCfg)).
295+
WithSince("v1.46.0").
296+
WithPresets(linter.PresetBugs).
297+
WithLoadForGoAnalysis().
298+
WithURL("https://github.com/mweb/floatcompare"),
299+
292300
linter.NewConfig(golinters.NewForbidigo()).
293301
WithSince("v1.34.0").
294302
WithPresets(linter.PresetStyle).

test/testdata/floatcompare.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// args: -Efloatcompare
2+
package testdata
3+
4+
import "fmt"
5+
6+
func EqualCompareIfFloats() {
7+
x, y := 400., 500.
8+
if 300. == 100. { // ERROR `float comparison found "300. == 100."`
9+
dummy()
10+
}
11+
if x == y { // ERROR `float comparison found "x == y"`
12+
dummy()
13+
}
14+
if 300.+200. == 10. { // ERROR `float comparison found "300.+200. == 10."`
15+
dummy()
16+
}
17+
if 300 == 200 {
18+
dummy()
19+
}
20+
}
21+
22+
func NotEqualCompareIfFloats() {
23+
x, y := 400., 500.
24+
if 300. != 100. { // ERROR `float comparison found "300. != 100."`
25+
26+
dummy()
27+
}
28+
if x != y { // ERROR `float comparison found "x != y"`
29+
dummy()
30+
}
31+
}
32+
33+
func EqualCompareIfCustomType() {
34+
type number float64
35+
var x, y number = 300., 400.
36+
if x == y { // ERROR `float comparison found "x == y"`
37+
dummy()
38+
}
39+
}
40+
41+
func GreaterLessCompareIfFloats() {
42+
if 300. >= 100. { // ERROR `float comparison found "300. >= 100."`
43+
dummy()
44+
}
45+
if 300. <= 100. { // ERROR `float comparison found "300. <= 100."`
46+
dummy()
47+
}
48+
if 300. < 100. { // ERROR `float comparison found "300. < 100."`
49+
dummy()
50+
}
51+
if 300. > 100. { // ERROR `float comparison found "300. > 100."`
52+
dummy()
53+
}
54+
}
55+
56+
func SwitchStmtWithFloat() {
57+
switch 300. { // ERROR "float comparison with switch statement"
58+
case 100.:
59+
case 200:
60+
}
61+
}
62+
63+
func EqualCompareSwitchFloats() {
64+
switch {
65+
case 100. == 200.: // ERROR `float comparison found "100. == 200."`
66+
}
67+
}
68+
69+
func dummy() {
70+
fmt.Println("dummy()")
71+
}

0 commit comments

Comments
 (0)