Skip to content

Commit e35cee4

Browse files
committed
Add 'floatcompare' linter
1 parent f5b92e1 commit e35cee4

File tree

7 files changed

+119
-0
lines changed

7 files changed

+119
-0
lines changed

.golangci.example.yml

+5
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:

go.mod

+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.1
6465
github.com/nakabonne/nestif v0.3.1
6566
github.com/nishanths/exhaustive v0.7.11
6667
github.com/nishanths/predeclared v0.2.1

go.sum

+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

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
const floatcompareName = "floatcompare"
12+
13+
func NewFloatCompare(settings *config.FloatCompareSettings) *goanalysis.Linter {
14+
a := floatcompare.NewAnalyzer()
15+
16+
var cfg map[string]map[string]interface{}
17+
if settings != nil {
18+
d := map[string]interface{}{
19+
"equalOnly": settings.EqualOnly,
20+
}
21+
22+
cfg = map[string]map[string]interface{}{a.Name: d}
23+
}
24+
25+
return goanalysis.NewLinter(
26+
floatcompareName,
27+
"search for float comparison, since these are potential errors",
28+
[]*analysis.Analyzer{a},
29+
cfg,
30+
).WithLoadMode(goanalysis.LoadModeTypesInfo)
31+
}

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

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

0 commit comments

Comments
 (0)