From f25d20ad0a1be9c57740c328937e8cfc382e1cd8 Mon Sep 17 00:00:00 2001 From: Joel Speed Date: Wed, 12 Nov 2025 15:31:02 -0500 Subject: [PATCH] Update typechecker to use qualified name --- pkg/analysis/helpers/inspector/inspector.go | 45 +------------ pkg/analysis/integers/testdata/src/a/a.go | 58 ++++++++-------- pkg/analysis/nobools/testdata/src/a/a.go | 28 ++++---- pkg/analysis/nofloats/testdata/src/a/a.go | 52 +++++++-------- pkg/analysis/utils/testdata/src/a/a.go | 22 +++---- pkg/analysis/utils/type_check.go | 2 +- pkg/analysis/utils/utils.go | 73 +++++++++++++++++++++ pkg/analysis/utils/utils_test.go | 43 ++++++++++++ 8 files changed, 198 insertions(+), 125 deletions(-) diff --git a/pkg/analysis/helpers/inspector/inspector.go b/pkg/analysis/helpers/inspector/inspector.go index a23bac17..ac87404f 100644 --- a/pkg/analysis/helpers/inspector/inspector.go +++ b/pkg/analysis/helpers/inspector/inspector.go @@ -20,7 +20,6 @@ import ( "go/ast" "go/token" "go/types" - "slices" astinspector "golang.org/x/tools/go/ast/inspector" "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags" @@ -102,7 +101,7 @@ func (i *inspector) inspectFields(inspectField func(field *ast.Field, jsonTagInf // The 0th node in the stack is the *ast.File. file, ok := stack[0].(*ast.File) if ok { - structName = getStructName(file, field) + structName = utils.GetStructNameFromFile(file, field) } if structName != "" { @@ -202,45 +201,3 @@ func printDebugInfo(field *ast.Field) string { return debug } - -func getStructName(file *ast.File, field *ast.Field) string { - var ( - structName string - found bool - ) - - ast.Inspect(file, func(n ast.Node) bool { - if found { - return false - } - - typeSpec, ok := n.(*ast.TypeSpec) - if !ok { - return true - } - - structType, ok := typeSpec.Type.(*ast.StructType) - if !ok { - return true - } - - structName = typeSpec.Name.Name - - if structType.Fields == nil { - return true - } - - if slices.Contains(structType.Fields.List, field) { - found = true - return false - } - - return true - }) - - if found { - return structName - } - - return "" -} diff --git a/pkg/analysis/integers/testdata/src/a/a.go b/pkg/analysis/integers/testdata/src/a/a.go index 48ddcef0..574152fb 100644 --- a/pkg/analysis/integers/testdata/src/a/a.go +++ b/pkg/analysis/integers/testdata/src/a/a.go @@ -13,39 +13,39 @@ type Integers struct { ValidInt64Ptr *int64 - InvalidInt int // want "field InvalidInt should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidInt int // want "field Integers.InvalidInt should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidIntPtr *int // want "field InvalidIntPtr pointer should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidIntPtr *int // want "field Integers.InvalidIntPtr pointer should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidInt8 int8 // want "field InvalidInt8 should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidInt8 int8 // want "field Integers.InvalidInt8 should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidInt16 int16 // want "field InvalidInt16 should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidInt16 int16 // want "field Integers.InvalidInt16 should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidUInt uint // want "field InvalidUInt should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUInt uint // want "field Integers.InvalidUInt should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUIntPtr uint // want "field InvalidUIntPtr should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUIntPtr uint // want "field Integers.InvalidUIntPtr should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUInt8 uint8 // want "field InvalidUInt8 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUInt8 uint8 // want "field Integers.InvalidUInt8 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUInt16 uint16 // want "field InvalidUInt16 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUInt16 uint16 // want "field Integers.InvalidUInt16 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUInt32 uint32 // want "field InvalidUInt32 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUInt32 uint32 // want "field Integers.InvalidUInt32 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUInt64 uint64 // want "field InvalidUInt64 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUInt64 uint64 // want "field Integers.InvalidUInt64 should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" ValidInt32Alias ValidInt32Alias ValidInt32AliasPtr *ValidInt32Alias - InvalidIntAlias InvalidIntAlias // want "field InvalidIntAlias type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidIntAlias InvalidIntAlias // want "field Integers.InvalidIntAlias type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidIntAliasPtr *InvalidIntAlias // want "field InvalidIntAliasPtr pointer type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidIntAliasPtr *InvalidIntAlias // want "field Integers.InvalidIntAliasPtr pointer type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidUIntAlias InvalidUIntAlias // want "field InvalidUIntAlias type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUIntAlias InvalidUIntAlias // want "field Integers.InvalidUIntAlias type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidUIntAliasPtr *InvalidUIntAlias // want "field InvalidUIntAliasPtr pointer type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidUIntAliasPtr *InvalidUIntAlias // want "field Integers.InvalidUIntAliasPtr pointer type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidIntAliasAlias InvalidIntAliasAlias // want "field InvalidIntAliasAlias type InvalidIntAliasAlias type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidIntAliasAlias InvalidIntAliasAlias // want "field Integers.InvalidIntAliasAlias type InvalidIntAliasAlias type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" ValidSliceInt32 []int32 @@ -55,41 +55,41 @@ type Integers struct { ValidSliceInt64Ptr []*int64 - InvalidSliceInt []int // want "field InvalidSliceInt array element should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidSliceInt []int // want "field Integers.InvalidSliceInt array element should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidSliceIntPtr []*int // want "field InvalidSliceIntPtr array element pointer should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidSliceIntPtr []*int // want "field Integers.InvalidSliceIntPtr array element pointer should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidSliceUInt []uint // want "field InvalidSliceUInt array element should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidSliceUInt []uint // want "field Integers.InvalidSliceUInt array element should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidSliceUIntPtr []*uint // want "field InvalidSliceUIntPtr array element pointer should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidSliceUIntPtr []*uint // want "field Integers.InvalidSliceUIntPtr array element pointer should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidSliceIntAlias []InvalidIntAlias // want "field InvalidSliceIntAlias array element type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidSliceIntAlias []InvalidIntAlias // want "field Integers.InvalidSliceIntAlias array element type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidSliceIntAliasPtr []*InvalidIntAlias // want "field InvalidSliceIntAliasPtr array element pointer type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidSliceIntAliasPtr []*InvalidIntAlias // want "field Integers.InvalidSliceIntAliasPtr array element pointer type InvalidIntAlias should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidSliceUIntAlias []InvalidUIntAlias // want "field InvalidSliceUIntAlias array element type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidSliceUIntAlias []InvalidUIntAlias // want "field Integers.InvalidSliceUIntAlias array element type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidSliceUIntAliasPtr []*InvalidUIntAlias // want "field InvalidSliceUIntAliasPtr array element pointer type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidSliceUIntAliasPtr []*InvalidUIntAlias // want "field Integers.InvalidSliceUIntAliasPtr array element pointer type InvalidUIntAlias should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" ValidMapStringToInt32 map[string]int32 ValidMapStringToInt64 map[string]int64 - InvalidMapStringToInt map[string]int // want "field InvalidMapStringToInt map value should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidMapStringToInt map[string]int // want "field Integers.InvalidMapStringToInt map value should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidMapStringToUInt map[string]uint // want "field InvalidMapStringToUInt map value should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidMapStringToUInt map[string]uint // want "field Integers.InvalidMapStringToUInt map value should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" ValidMapInt32ToString map[int32]string ValidMapInt64ToString map[int64]string - InvalidMapIntToString map[int]string // want "field InvalidMapIntToString map key should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidMapIntToString map[int]string // want "field Integers.InvalidMapIntToString map key should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidMapUIntToString map[uint]string // want "field InvalidMapUIntToString map key should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" + InvalidMapUIntToString map[uint]string // want "field Integers.InvalidMapUIntToString map key should not use unsigned integers, use only int32 or int64 and apply validation to ensure the value is positive" - InvalidIntFromAnotherFile IntB // want "field InvalidIntFromAnotherFile type IntB should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidIntFromAnotherFile IntB // want "field Integers.InvalidIntFromAnotherFile type IntB should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" - InvalidSliceIntAliasFromAnotherFile InvalidSliceIntAliasB // want "field InvalidSliceIntAliasFromAnotherFile type InvalidSliceIntAliasB array element should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" + InvalidSliceIntAliasFromAnotherFile InvalidSliceIntAliasB // want "field Integers.InvalidSliceIntAliasFromAnotherFile type InvalidSliceIntAliasB array element should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements" } // DoNothing is used to check that the analyser doesn't report on methods. diff --git a/pkg/analysis/nobools/testdata/src/a/a.go b/pkg/analysis/nobools/testdata/src/a/a.go index c1c60672..e1fa6e35 100644 --- a/pkg/analysis/nobools/testdata/src/a/a.go +++ b/pkg/analysis/nobools/testdata/src/a/a.go @@ -9,33 +9,33 @@ type Bools struct { ValidInt64 int64 - InvalidBool bool // want "field InvalidBool should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBool bool // want "field Bools.InvalidBool should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolPtr *bool // want "field InvalidBoolPtr pointer should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolPtr *bool // want "field Bools.InvalidBoolPtr pointer should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolSlice []bool // want "field InvalidBoolSlice array element should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolSlice []bool // want "field Bools.InvalidBoolSlice array element should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolPtrSlice []*bool // want "field InvalidBoolPtrSlice array element pointer should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolPtrSlice []*bool // want "field Bools.InvalidBoolPtrSlice array element pointer should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolAlias BoolAlias // want "field InvalidBoolAlias type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolAlias BoolAlias // want "field Bools.InvalidBoolAlias type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolPtrAlias *BoolAlias // want "field InvalidBoolPtrAlias pointer type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolPtrAlias *BoolAlias // want "field Bools.InvalidBoolPtrAlias pointer type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolSliceAlias []BoolAlias // want "field InvalidBoolSliceAlias array element type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolSliceAlias []BoolAlias // want "field Bools.InvalidBoolSliceAlias array element type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolPtrSliceAlias []*BoolAlias // want "field InvalidBoolPtrSliceAlias array element pointer type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolPtrSliceAlias []*BoolAlias // want "field Bools.InvalidBoolPtrSliceAlias array element pointer type BoolAlias should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidMapStringToBool map[string]bool // want "field InvalidMapStringToBool map value should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidMapStringToBool map[string]bool // want "field Bools.InvalidMapStringToBool map value should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidMapStringToBoolPtr map[string]*bool // want "field InvalidMapStringToBoolPtr map value pointer should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidMapStringToBoolPtr map[string]*bool // want "field Bools.InvalidMapStringToBoolPtr map value pointer should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidMapBoolToString map[bool]string // want "field InvalidMapBoolToString map key should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidMapBoolToString map[bool]string // want "field Bools.InvalidMapBoolToString map key should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidMapBoolPtrToString map[*bool]string // want "field InvalidMapBoolPtrToString map key pointer should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidMapBoolPtrToString map[*bool]string // want "field Bools.InvalidMapBoolPtrToString map key pointer should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolAliasFromAnotherFile BoolAliasB // want "field InvalidBoolAliasFromAnotherFile type BoolAliasB should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolAliasFromAnotherFile BoolAliasB // want "field Bools.InvalidBoolAliasFromAnotherFile type BoolAliasB should not use a bool. Use a string type with meaningful constant values as an enum." - InvalidBoolPtrAliasFromAnotherFile *BoolAliasB // want "field InvalidBoolPtrAliasFromAnotherFile pointer type BoolAliasB should not use a bool. Use a string type with meaningful constant values as an enum." + InvalidBoolPtrAliasFromAnotherFile *BoolAliasB // want "field Bools.InvalidBoolPtrAliasFromAnotherFile pointer type BoolAliasB should not use a bool. Use a string type with meaningful constant values as an enum." } // DoNothing is used to check that the analyser doesn't report on methods. diff --git a/pkg/analysis/nofloats/testdata/src/a/a.go b/pkg/analysis/nofloats/testdata/src/a/a.go index 11a6942f..cf5554cd 100644 --- a/pkg/analysis/nofloats/testdata/src/a/a.go +++ b/pkg/analysis/nofloats/testdata/src/a/a.go @@ -9,57 +9,57 @@ type Floats struct { ValidInt64 int64 - InvalidFloat32 float32 // want "field InvalidFloat32 should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32 float32 // want "field Floats.InvalidFloat32 should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64 float64 // want "field InvalidFloat64 should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64 float64 // want "field Floats.InvalidFloat64 should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32Ptr *float32 // want "field InvalidFloat32Ptr pointer should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32Ptr *float32 // want "field Floats.InvalidFloat32Ptr pointer should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64Ptr *float64 // want "field InvalidFloat64Ptr pointer should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64Ptr *float64 // want "field Floats.InvalidFloat64Ptr pointer should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32Slice []float32 // want "field InvalidFloat32Slice array element should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32Slice []float32 // want "field Floats.InvalidFloat32Slice array element should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64Slice []float64 // want "field InvalidFloat64Slice array element should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64Slice []float64 // want "field Floats.InvalidFloat64Slice array element should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32PtrSlice []*float32 // want "field InvalidFloat32PtrSlice array element pointer should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32PtrSlice []*float32 // want "field Floats.InvalidFloat32PtrSlice array element pointer should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64PtrSlice []*float64 // want "field InvalidFloat64PtrSlice array element pointer should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64PtrSlice []*float64 // want "field Floats.InvalidFloat64PtrSlice array element pointer should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32Alias Float32Alias // want "field InvalidFloat32Alias type Float32Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32Alias Float32Alias // want "field Floats.InvalidFloat32Alias type Float32Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64Alias Float64Alias // want "field InvalidFloat64Alias type Float64Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64Alias Float64Alias // want "field Floats.InvalidFloat64Alias type Float64Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32PtrAlias *Float32Alias // want "field InvalidFloat32PtrAlias pointer type Float32Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32PtrAlias *Float32Alias // want "field Floats.InvalidFloat32PtrAlias pointer type Float32Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64PtrAlias *Float64Alias // want "field InvalidFloat64PtrAlias pointer type Float64Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64PtrAlias *Float64Alias // want "field Floats.InvalidFloat64PtrAlias pointer type Float64Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32SliceAlias []Float32Alias // want "field InvalidFloat32SliceAlias array element type Float32Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32SliceAlias []Float32Alias // want "field Floats.InvalidFloat32SliceAlias array element type Float32Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64SliceAlias []Float64Alias // want "field InvalidFloat64SliceAlias array element type Float64Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64SliceAlias []Float64Alias // want "field Floats.InvalidFloat64SliceAlias array element type Float64Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32PtrSliceAlias []*Float32Alias // want "field InvalidFloat32PtrSliceAlias array element pointer type Float32Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32PtrSliceAlias []*Float32Alias // want "field Floats.InvalidFloat32PtrSliceAlias array element pointer type Float32Alias should not use a float value because they cannot be reliably round-tripped." - InvalidFloat64PtrSliceAlias []*Float64Alias // want "field InvalidFloat64PtrSliceAlias array element pointer type Float64Alias should not use a float value because they cannot be reliably round-tripped." + InvalidFloat64PtrSliceAlias []*Float64Alias // want "field Floats.InvalidFloat64PtrSliceAlias array element pointer type Float64Alias should not use a float value because they cannot be reliably round-tripped." - InvalidMapStringToFloat32 map[string]float32 // want "field InvalidMapStringToFloat32 map value should not use a float value because they cannot be reliably round-tripped." + InvalidMapStringToFloat32 map[string]float32 // want "field Floats.InvalidMapStringToFloat32 map value should not use a float value because they cannot be reliably round-tripped." - InvalidMapStringToFloat64 map[string]float64 // want "field InvalidMapStringToFloat64 map value should not use a float value because they cannot be reliably round-tripped." + InvalidMapStringToFloat64 map[string]float64 // want "field Floats.InvalidMapStringToFloat64 map value should not use a float value because they cannot be reliably round-tripped." - InvalidMapStringToFloat32Ptr map[string]*float32 // want "field InvalidMapStringToFloat32Ptr map value pointer should not use a float value because they cannot be reliably round-tripped." + InvalidMapStringToFloat32Ptr map[string]*float32 // want "field Floats.InvalidMapStringToFloat32Ptr map value pointer should not use a float value because they cannot be reliably round-tripped." - InvalidMapStringToFloat64Ptr map[string]*float64 // want "field InvalidMapStringToFloat64Ptr map value pointer should not use a float value because they cannot be reliably round-tripped." + InvalidMapStringToFloat64Ptr map[string]*float64 // want "field Floats.InvalidMapStringToFloat64Ptr map value pointer should not use a float value because they cannot be reliably round-tripped." - InvalidMapFloat32ToString map[float32]string // want "field InvalidMapFloat32ToString map key should not use a float value because they cannot be reliably round-tripped." + InvalidMapFloat32ToString map[float32]string // want "field Floats.InvalidMapFloat32ToString map key should not use a float value because they cannot be reliably round-tripped." - InvalidMapFloat64ToString map[float64]string // want "field InvalidMapFloat64ToString map key should not use a float value because they cannot be reliably round-tripped." + InvalidMapFloat64ToString map[float64]string // want "field Floats.InvalidMapFloat64ToString map key should not use a float value because they cannot be reliably round-tripped." - InvalidMapFloat32PtrToString map[*float32]string // want "field InvalidMapFloat32PtrToString map key pointer should not use a float value because they cannot be reliably round-tripped." + InvalidMapFloat32PtrToString map[*float32]string // want "field Floats.InvalidMapFloat32PtrToString map key pointer should not use a float value because they cannot be reliably round-tripped." - InvalidMapFloat64PtrToString map[*float64]string // want "field InvalidMapFloat64PtrToString map key pointer should not use a float value because they cannot be reliably round-tripped." + InvalidMapFloat64PtrToString map[*float64]string // want "field Floats.InvalidMapFloat64PtrToString map key pointer should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32AliasFromAnotherFile Float32AliasB // want "field InvalidFloat32AliasFromAnotherFile type Float32AliasB should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32AliasFromAnotherFile Float32AliasB // want "field Floats.InvalidFloat32AliasFromAnotherFile type Float32AliasB should not use a float value because they cannot be reliably round-tripped." - InvalidFloat32PtrAliasFromAnotherFile Float32AliasPtrB // want "field InvalidFloat32PtrAliasFromAnotherFile type Float32AliasPtrB pointer should not use a float value because they cannot be reliably round-tripped." + InvalidFloat32PtrAliasFromAnotherFile Float32AliasPtrB // want "field Floats.InvalidFloat32PtrAliasFromAnotherFile type Float32AliasPtrB pointer should not use a float value because they cannot be reliably round-tripped." } // DoNothingFloat32 is used to check that the analyser doesn't report on methods. diff --git a/pkg/analysis/utils/testdata/src/a/a.go b/pkg/analysis/utils/testdata/src/a/a.go index b682f75c..4938ca46 100644 --- a/pkg/analysis/utils/testdata/src/a/a.go +++ b/pkg/analysis/utils/testdata/src/a/a.go @@ -1,11 +1,11 @@ package a type Integers struct { - String string // want "field String is a string" + String string // want "field Integers.String is a string" - Map map[string]string // want "field Map map key is a string" "field Map map value is a string" + Map map[string]string // want "field Integers.Map map key is a string" "field Integers.Map map value is a string" - MapStringToStringAlias map[string]StringAlias // want "field MapStringToStringAlias map key is a string" "field MapStringToStringAlias map value type StringAlias is a string" + MapStringToStringAlias map[string]StringAlias // want "field Integers.MapStringToStringAlias map key is a string" "field Integers.MapStringToStringAlias map value type StringAlias is a string" Int32 int32 @@ -13,21 +13,21 @@ type Integers struct { Bool bool - StringPtr *string // want "field StringPtr pointer is a string" + StringPtr *string // want "field Integers.StringPtr pointer is a string" - StringSlice []string // want "field StringSlice array element is a string" + StringSlice []string // want "field Integers.StringSlice array element is a string" - StringPtrSlice []*string // want "field StringPtrSlice array element pointer is a string" + StringPtrSlice []*string // want "field Integers.StringPtrSlice array element pointer is a string" - StringAlias StringAlias // want "field StringAlias type StringAlias is a string" + StringAlias StringAlias // want "field Integers.StringAlias type StringAlias is a string" - StringAliasPtr *StringAlias // want "field StringAliasPtr pointer type StringAlias is a string" + StringAliasPtr *StringAlias // want "field Integers.StringAliasPtr pointer type StringAlias is a string" - StringAliasSlice []StringAlias // want "field StringAliasSlice array element type StringAlias is a string" + StringAliasSlice []StringAlias // want "field Integers.StringAliasSlice array element type StringAlias is a string" - StringAliasPtrSlice []*StringAlias // want "field StringAliasPtrSlice array element pointer type StringAlias is a string" + StringAliasPtrSlice []*StringAlias // want "field Integers.StringAliasPtrSlice array element pointer type StringAlias is a string" - StringAliasFromAnotherFile StringAliasB // want "field StringAliasFromAnotherFile type StringAliasB is a string" + StringAliasFromAnotherFile StringAliasB // want "field Integers.StringAliasFromAnotherFile type StringAliasB is a string" } type StringAlias string // want "type StringAlias is a string" diff --git a/pkg/analysis/utils/type_check.go b/pkg/analysis/utils/type_check.go index d6b8e1b4..1491d358 100644 --- a/pkg/analysis/utils/type_check.go +++ b/pkg/analysis/utils/type_check.go @@ -62,7 +62,7 @@ func (t *typeChecker) CheckNode(pass *analysis.Pass, node ast.Node) { } func (t *typeChecker) checkField(pass *analysis.Pass, field *ast.Field) { - fieldName := FieldName(field) + fieldName := GetQualifiedFieldName(pass, field) if fieldName == "" { return } diff --git a/pkg/analysis/utils/utils.go b/pkg/analysis/utils/utils.go index 71a481f5..d35edacb 100644 --- a/pkg/analysis/utils/utils.go +++ b/pkg/analysis/utils/utils.go @@ -21,6 +21,7 @@ import ( "go/ast" "go/token" "go/types" + "slices" "strings" "golang.org/x/tools/go/analysis" @@ -159,6 +160,78 @@ func FieldName(field *ast.Field) string { return "" } +// GetStructName returns the name of the struct that the field is in. +func GetStructName(pass *analysis.Pass, field *ast.Field) string { + _, astFile := getFilesForField(pass, field) + if astFile == nil { + return "" + } + + return GetStructNameFromFile(astFile, field) +} + +// GetStructNameFromFile returns the name of the struct that the field is in. +func GetStructNameFromFile(file *ast.File, field *ast.Field) string { + var ( + structName string + found bool + ) + + ast.Inspect(file, func(n ast.Node) bool { + if found { + return false + } + + typeSpec, ok := n.(*ast.TypeSpec) + if !ok { + return true + } + + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + return true + } + + structName = typeSpec.Name.Name + + if structType.Fields == nil { + return true + } + + if slices.Contains(structType.Fields.List, field) { + found = true + return false + } + + return true + }) + + if found { + return structName + } + + return "" +} + +// GetQualifiedFieldName returns the qualified field name. +func GetQualifiedFieldName(pass *analysis.Pass, field *ast.Field) string { + fieldName := FieldName(field) + structName := GetStructName(pass, field) + + return fmt.Sprintf("%s.%s", structName, fieldName) +} + +func getFilesForField(pass *analysis.Pass, field *ast.Field) (*token.File, *ast.File) { + tokenFile := pass.Fset.File(field.Pos()) + for _, astFile := range pass.Files { + if astFile.FileStart == token.Pos(tokenFile.Base()) { + return tokenFile, astFile + } + } + + return tokenFile, nil +} + func getFilesForType(pass *analysis.Pass, ident *ast.Ident) (*token.File, *ast.File) { namedType, ok := pass.TypesInfo.TypeOf(ident).(*types.Named) if !ok { diff --git a/pkg/analysis/utils/utils_test.go b/pkg/analysis/utils/utils_test.go index 8eb7b6ed..113916ac 100644 --- a/pkg/analysis/utils/utils_test.go +++ b/pkg/analysis/utils/utils_test.go @@ -17,9 +17,14 @@ package utils_test import ( "go/ast" + "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/analysistest" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" "sigs.k8s.io/kube-api-linter/pkg/analysis/utils" ) @@ -73,3 +78,41 @@ var _ = Describe("FieldName", func() { }), ) }) + +func TestGetStrctName(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, structNameAnalyzer(), "getstructname") +} + +func structNameAnalyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "test", + Doc: "test", + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: func(pass *analysis.Pass) (any, error) { + inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, errCouldNotGetInspector + } + + // Filter to structs so that we can iterate over fields in a struct. + nodeFilter := []ast.Node{ + (*ast.Field)(nil), + } + + inspect.Preorder(nodeFilter, func(n ast.Node) { + field, ok := n.(*ast.Field) + if !ok { + return + } + + fieldName := utils.FieldName(field) + structName := utils.GetStructName(pass, field) + + pass.Reportf(field.Pos(), "field %s is in struct %s", fieldName, structName) + }) + + return nil, nil + }, + } +}