Skip to content

Commit d425974

Browse files
authored
feat(injector/typed): Enhance type checking with additional generic type test cases (#634)
Comprehensive tests have been added to validate these changes, ensuring that the type checker functions correctly across a wide range of generic type scenarios. Signed-off-by: Kemal Akkoyun <[email protected]> Signed-off-by: Kemal Akkoyun <[email protected]>
1 parent 8157bfb commit d425974

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

internal/injector/typed/typecheck.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,31 @@ func ResolveInterfaceTypeByName(name string) (*types.Interface, error) {
8383
// into its package path and local name.
8484
// Returns ("", "error") for built-in "error".
8585
// Returns ("", "MyType") for unqualified "MyType".
86+
// For generic types like "iter.Seq[T]" or "iter.Seq[io.Reader]", the type parameters
87+
// are included in the local name, so it returns ("iter", "Seq[T]") and ("iter", "Seq[io.Reader]").
8688
func SplitPackageAndName(fullName string) (pkgPath string, localName string) {
8789
if !strings.Contains(fullName, ".") {
8890
// Assume built-in type (like "error") or unqualified local type.
8991
return "", fullName
9092
}
91-
lastDot := strings.LastIndex(fullName, ".")
93+
94+
// Find the position of the first '[' which indicates generic type parameters
95+
bracketPos := strings.IndexByte(fullName, '[')
96+
97+
// Determine the substring to search for the last dot
98+
searchStr := fullName
99+
if bracketPos != -1 {
100+
// Only search for dots before the generic type parameters
101+
searchStr = fullName[:bracketPos]
102+
}
103+
104+
// Find the last dot in the search string
105+
lastDot := strings.LastIndex(searchStr, ".")
106+
if lastDot == -1 {
107+
// No dot found (shouldn't happen given the initial check, but be safe)
108+
return "", fullName
109+
}
110+
92111
pkgPath = fullName[:lastDot]
93112
localName = fullName[lastDot+1:]
94113
return pkgPath, localName

internal/injector/typed/typecheck_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,79 @@ func TestSplitPackageAndName(t *testing.T) {
129129
expectedPkg: "k8s.io/client-go/kubernetes",
130130
expectedLocal: "Clientset",
131131
},
132+
// Generic type test cases
133+
{
134+
name: "simple generic type",
135+
fullName: "iter.Seq[T]",
136+
expectedPkg: "iter",
137+
expectedLocal: "Seq[T]",
138+
},
139+
{
140+
name: "generic with qualified type parameter",
141+
fullName: "iter.Seq[io.Reader]",
142+
expectedPkg: "iter",
143+
expectedLocal: "Seq[io.Reader]",
144+
},
145+
{
146+
name: "generic with multiple type parameters",
147+
fullName: "maps.Map[string, int]",
148+
expectedPkg: "maps",
149+
expectedLocal: "Map[string, int]",
150+
},
151+
{
152+
name: "nested generic types",
153+
fullName: "container.List[maps.Map[string, io.Reader]]",
154+
expectedPkg: "container",
155+
expectedLocal: "List[maps.Map[string, io.Reader]]",
156+
},
157+
{
158+
name: "generic with slice type parameter",
159+
fullName: "sync.Pool[[]byte]",
160+
expectedPkg: "sync",
161+
expectedLocal: "Pool[[]byte]",
162+
},
163+
{
164+
name: "generic with pointer type parameter",
165+
fullName: "atomic.Pointer[*sync.Mutex]",
166+
expectedPkg: "atomic",
167+
expectedLocal: "Pointer[*sync.Mutex]",
168+
},
169+
{
170+
name: "generic from versioned package",
171+
fullName: "github.com/user/pkg/v2.Container[T]",
172+
expectedPkg: "github.com/user/pkg/v2",
173+
expectedLocal: "Container[T]",
174+
},
175+
{
176+
name: "complex generic with multiple qualified parameters",
177+
fullName: "github.com/example/collections.Map[database/sql.DB, net/http.Client]",
178+
expectedPkg: "github.com/example/collections",
179+
expectedLocal: "Map[database/sql.DB, net/http.Client]",
180+
},
181+
{
182+
name: "generic with map type parameter",
183+
fullName: "container.Set[map[string]interface{}]",
184+
expectedPkg: "container",
185+
expectedLocal: "Set[map[string]interface{}]",
186+
},
187+
{
188+
name: "generic with channel type parameter",
189+
fullName: "async.Queue[chan error]",
190+
expectedPkg: "async",
191+
expectedLocal: "Queue[chan error]",
192+
},
193+
{
194+
name: "unqualified generic type",
195+
fullName: "MyGeneric[T]",
196+
expectedPkg: "",
197+
expectedLocal: "MyGeneric[T]",
198+
},
199+
{
200+
name: "generic with function type parameter",
201+
fullName: "functional.Option[func(io.Writer) error]",
202+
expectedPkg: "functional",
203+
expectedLocal: "Option[func(io.Writer) error]",
204+
},
132205
}
133206

134207
for _, tc := range testCases {

0 commit comments

Comments
 (0)