Skip to content

Commit c5ad941

Browse files
authored
Support for generic structs added #6
2 parents 05660f3 + 617279a commit c5ad941

File tree

7 files changed

+69
-15
lines changed

7 files changed

+69
-15
lines changed

goextractors/definition_test.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,43 @@ func TestDefinitionExtractor(t *testing.T) {
3030
assert.Empty(t, issues)
3131

3232
defs := extractCtx.Definitions
33+
3334
key := "github.com/vorlif/testdata.M"
3435
if assert.Contains(t, defs, key) {
3536
assert.Contains(t, defs[key], "Test")
3637
}
3738

38-
key = "github.com/vorlif/testdata.func github.com/vorlif/testdata.noop(sing string, plural string, context string, domain string)"
39+
key = "github.com/vorlif/testdata.methodStruct.Method"
40+
if assert.Contains(t, defs, key) {
41+
assert.Contains(t, defs[key], "0")
42+
}
43+
44+
key = "github.com/vorlif/testdata.genericMethodStruct.Method"
45+
if assert.Contains(t, defs, key) {
46+
assert.Contains(t, defs[key], "0")
47+
}
48+
49+
key = "github.com/vorlif/testdata.noop"
3950
if assert.Contains(t, defs, key) {
4051
assert.Contains(t, defs[key], "sing")
4152
assert.Contains(t, defs[key], "plural")
4253
assert.Contains(t, defs[key], "context")
4354
assert.Contains(t, defs[key], "domain")
4455
}
4556

46-
key = "github.com/vorlif/testdata.func github.com/vorlif/testdata.multiNamesFunc(a string, b string)"
57+
key = "github.com/vorlif/testdata.multiNamesFunc"
4758
if assert.Contains(t, defs, key) {
4859
assert.Contains(t, defs[key], "a")
4960
assert.Contains(t, defs[key], "b")
5061
}
5162

52-
key = "github.com/vorlif/testdata.func github.com/vorlif/testdata.noParamNames(string, string)"
63+
key = "github.com/vorlif/testdata.noParamNames"
5364
if assert.Contains(t, defs, key) {
5465
assert.Contains(t, defs[key], "0")
5566
assert.Contains(t, defs[key], "1")
5667
}
5768

58-
key = "github.com/vorlif/testdata.func github.com/vorlif/testdata.variadicFunc(a string, vars ...string)"
69+
key = "github.com/vorlif/testdata.variadicFunc"
5970
if assert.Contains(t, defs, key) {
6071
if assert.Contains(t, defs[key], "a") {
6172
assert.Equal(t, 0, defs[key]["a"].FieldPos)

goextractors/funccall_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ func TestFuncCallExtractor(t *testing.T) {
3131
"inline function",
3232

3333
"constCtxMsg", "constCtxVal",
34+
35+
"struct-method-call", "generic-struct-method-call",
3436
}
3537
got := collectIssueStrings(issues)
3638
assert.ElementsMatch(t, want, got)

goextractors/structdef.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,26 @@ func (v structDefExtractor) Run(_ context.Context, extractCtx *extractors.Contex
3535
return
3636
}
3737

38-
var obj types.Object
39-
var pkg *packages.Package
38+
var ident *ast.Ident
4039
switch val := node.Type.(type) {
4140
case *ast.SelectorExpr:
42-
pkg, obj = extractCtx.GetType(val.Sel)
43-
if pkg == nil {
44-
return
45-
}
41+
ident = val.Sel
4642
case *ast.Ident:
47-
pkg, obj = extractCtx.GetType(val)
48-
if pkg == nil {
49-
return
43+
ident = val
44+
case *ast.IndexExpr:
45+
switch x := val.X.(type) {
46+
case *ast.Ident:
47+
ident = x
5048
}
5149
default:
5250
return
5351
}
5452

53+
pkg, obj := extractCtx.GetType(ident)
54+
if pkg == nil {
55+
return
56+
}
57+
5558
if structAttr := extractCtx.Definitions.GetFields(util.ObjToKey(obj)); structAttr == nil {
5659
return
5760
}

goextractors/structdef_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func TestStructDefExtractor(t *testing.T) {
1818
"struct msgid arr2", "struct plural arr2",
1919
"A3", "B3", "C3",
2020
"A4", "B4", "C4",
21+
"GA3", "GB3", "GC3",
22+
"GA4", "GB4", "GC4",
2123
}
2224
assert.ElementsMatch(t, want, got)
2325
}

testdata/project/funccall.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ func GenericFunc[V int64 | float64](log alias.Singular, i V) V {
2020
return i
2121
}
2222

23+
type methodStruct struct{}
24+
25+
func (methodStruct) Method(alias.Singular) {}
26+
27+
type genericMethodStruct[T any] struct{}
28+
29+
func (genericMethodStruct[T]) Method(alias.Singular) {}
30+
2331
func outerFuncDef() {
2432
f := func(msgid alias.Singular, plural alias.Plural, context alias.Context, domain alias.Domain) {}
2533

@@ -77,3 +85,8 @@ func builtInFunctions() {
7785
t.DPGetf("domain-dp", "context-dp", "singular-dp")
7886
t.DNPGetf("domain-dnp", "context-dnp", "msgid-dnp", "pluralid-dnp", 10)
7987
}
88+
89+
func methodCall() {
90+
(methodStruct{}).Method("struct-method-call")
91+
(genericMethodStruct[string]{}).Method("generic-struct-method-call")
92+
}

testdata/project/struct.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ type OneLineStruct struct {
1515
A, B, C localize.Singular
1616
}
1717

18+
type OneLineGenericStruct[T any] struct {
19+
A, B, C localize.Singular
20+
}
21+
1822
func structLocalTest() []*sub.Sub {
1923

2024
// TRANSLATORS: Struct init
@@ -26,6 +30,15 @@ func structLocalTest() []*sub.Sub {
2630

2731
_ = OneLineStruct{"A4", "B4", "C4"}
2832

33+
// TRANSLATORS: Generic struct init
34+
_ = OneLineGenericStruct[string]{
35+
A: "GA3",
36+
B: "GB3",
37+
C: "GC3",
38+
}
39+
40+
_ = OneLineGenericStruct[string]{"GA4", "GB4", "GC4"}
41+
2942
item := &sub.Sub{
3043
Text: "local struct msgid",
3144
Plural: "local struct plural",

util/ast.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,23 @@ package util
33
import (
44
"fmt"
55
"go/types"
6+
"strings"
67
)
78

89
func ObjToKey(obj types.Object) string {
910
switch v := obj.Type().(type) {
1011
case *types.Signature:
11-
return fmt.Sprintf("%s.%s", obj.Pkg().Path(), obj.String())
12-
case *types.Named:
12+
if recv := v.Recv(); recv != nil {
13+
// Strip out the generic type declaration from the type name.
14+
// The ast.CallExpr reports its receiver as the actual type
15+
// (e.g.`Generic[string]`), whereas the ast.FuncDecl on the
16+
// same type as `Generic[T]`. The returned key values need
17+
// to be consistent between different invocation patterns.
18+
recv, _, _ := strings.Cut(recv.Type().String(), "[")
19+
20+
return fmt.Sprintf("%s.%s", recv, obj.Name())
21+
}
22+
1323
return fmt.Sprintf("%s.%s", obj.Pkg().Path(), obj.Name())
1424
case *types.Pointer:
1525
return v.Elem().String()

0 commit comments

Comments
 (0)