Skip to content

Commit 25c2815

Browse files
committed
Fine tune type-alias handling
Empirically, we visit the "real" type before any aliases, so if we find that a type already has comments, this MUST be an alias. Test errors look like: ``` W0902 12:41:47.282429 3445399 parse.go:451] Mismatched comments on type k8s.io/gengo/v2/parser/testdata/type-alias/v1.Blah. Using comments: ``` Blah is a test. A test, I tell you. ``` Ignoring comments from presumed type alias: ``` This is an alias within the same package. It comes before the type it aliases. ``` W0902 12:41:47.282468 3445399 parse.go:451] Mismatched comments on type k8s.io/gengo/v2/parser/testdata/type-alias/v1.Blah. Using comments: ``` Blah is a test. A test, I tell you. ``` Ignoring comments from presumed type alias: ``` This is an alias for v1.Blah. ``` ```
1 parent 604196b commit 25c2815

File tree

3 files changed

+76
-66
lines changed

3 files changed

+76
-66
lines changed

v2/parser/parse.go

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"go/ast"
2323
"go/constant"
24+
"go/parser"
2425
"go/token"
2526
gotypes "go/types"
2627
"maps"
@@ -37,6 +38,8 @@ import (
3738
"k8s.io/klog/v2"
3839
)
3940

41+
var typeAliasEnabled = goTypeAliasEnabled()
42+
4043
// Parser lets you add all the go files in all the packages that you care
4144
// about, then constructs the type source data.
4245
type Parser struct {
@@ -416,61 +419,81 @@ func minimize(lines []string) []string {
416419
func (p *Parser) addCommentsToType(obj gotypes.Object, t *types.Type) {
417420
if newLines, oldLines := p.docComment(obj.Pos()), t.CommentLines; len(newLines) > 0 {
418421
switch {
419-
case len(oldLines) == 0, reflect.DeepEqual(oldLines, newLines):
422+
case reflect.DeepEqual(oldLines, newLines):
423+
// nothing needed
424+
425+
case len(oldLines) == 0:
420426
// no comments associated, or comments match exactly
421427
t.CommentLines = newLines
422428

423-
case isTypeAlias(obj.Type()):
424-
// ignore mismatched comments from obj because it's an alias
425-
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
426-
klog.Warningf(
427-
"Mismatched comments seen for type %v. Using comments:\n%s\nIgnoring comments from type alias:\n%s\n",
429+
case typeAliasEnabled:
430+
if isTypeAlias(obj.Type()) {
431+
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
432+
// ignore mismatched comments from obj because it's an alias
433+
klog.Warningf(
434+
"Mismatched comments on type %v.\n Using comments:\n%s\n Ignoring comments from type alias:\n%s\n",
435+
t.GoType,
436+
formatCommentBlock(oldLines),
437+
formatCommentBlock(newLines),
438+
)
439+
}
440+
} else {
441+
panic(fmt.Sprintf("type %v already has comments; somehow we processed it again, but it's not an alias\n old:\n%s\n new:\n%s",
428442
t.GoType,
429443
formatCommentBlock(oldLines),
430444
formatCommentBlock(newLines),
431-
)
445+
))
432446
}
433447

434-
case !isTypeAlias(obj.Type()):
435-
// overwrite existing comments with ones from obj because obj is not an alias
436-
t.CommentLines = newLines
448+
case !typeAliasEnabled:
449+
// ignore mismatched comments from obj because it's an PROBABLY alias
437450
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
438451
klog.Warningf(
439-
"Mismatched comments seen for type %v. Using comments:\n%s\nIgnoring comments from type alias:\n%s\n",
452+
"Mismatched comments on type %v.\n Using comments:\n%s\n Ignoring comments from presumed type alias:\n%s\n",
440453
t.GoType,
441-
formatCommentBlock(newLines),
442454
formatCommentBlock(oldLines),
455+
formatCommentBlock(newLines),
443456
)
444457
}
445458
}
446459
}
447460

448461
if newLines, oldLines := p.priorDetachedComment(obj.Pos()), t.SecondClosestCommentLines; len(newLines) > 0 {
449462
switch {
450-
case len(oldLines) == 0, reflect.DeepEqual(oldLines, newLines):
463+
case reflect.DeepEqual(oldLines, newLines):
464+
// nothing needed
465+
466+
case len(oldLines) == 0:
451467
// no comments associated, or comments match exactly
452468
t.SecondClosestCommentLines = newLines
453469

454-
case isTypeAlias(obj.Type()):
455-
// ignore mismatched comments from obj because it's an alias
456-
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
457-
klog.Warningf(
458-
"Mismatched secondClosestCommentLines seen for type %v. Using comments:\n%s\nIgnoring comments from type alias:\n%s\n",
470+
case typeAliasEnabled:
471+
if isTypeAlias(obj.Type()) {
472+
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
473+
// ignore mismatched comments from obj because it's an alias
474+
klog.Warningf(
475+
"Mismatched secondClosestCommentLines on type %v.\n Using comments:\n%s\n Ignoring comments from type alias:\n%s\n",
476+
t.GoType,
477+
formatCommentBlock(oldLines),
478+
formatCommentBlock(newLines),
479+
)
480+
}
481+
} else {
482+
panic(fmt.Sprintf("type %v already has comments; somehow we processed it again, but it's not an alias\n old:\n%s\n new:\n%s",
459483
t.GoType,
460484
formatCommentBlock(oldLines),
461485
formatCommentBlock(newLines),
462-
)
486+
))
463487
}
464488

465-
case !isTypeAlias(obj.Type()):
466-
// overwrite existing comments with ones from obj because obj is not an alias
467-
t.SecondClosestCommentLines = newLines
489+
case !typeAliasEnabled:
490+
// ignore mismatched comments from obj because it's an PROBABLY alias
468491
if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) {
469492
klog.Warningf(
470-
"Mismatched secondClosestCommentLines seen for type %v. Using comments:\n%s\nIgnoring comments from type alias:\n%s\n",
493+
"Mismatched secondClosestCommentLines on type %v.\n Using comments:\n%s\n Ignoring comments from presumed type alias:\n%s\n",
471494
t.GoType,
472-
formatCommentBlock(newLines),
473495
formatCommentBlock(oldLines),
496+
formatCommentBlock(newLines),
474497
)
475498
}
476499
}
@@ -984,3 +1007,22 @@ func (p *Parser) addConstant(u types.Universe, useName *types.Name, in *gotypes.
9841007
out.ConstValue = &constval
9851008
return out
9861009
}
1010+
1011+
// Copied from https://github.com/golang/tools/blob/3e377036196f644e59e757af8a38ea6afa07677c/internal/aliases/aliases_go122.go#L64
1012+
func goTypeAliasEnabled() bool {
1013+
// The only reliable way to compute the answer is to invoke go/types.
1014+
// We don't parse the GODEBUG environment variable, because
1015+
// (a) it's tricky to do so in a manner that is consistent
1016+
// with the godebug package; in particular, a simple
1017+
// substring check is not good enough. The value is a
1018+
// rightmost-wins list of options. But more importantly:
1019+
// (b) it is impossible to detect changes to the effective
1020+
// setting caused by os.Setenv("GODEBUG"), as happens in
1021+
// many tests. Therefore any attempt to cache the result
1022+
// is just incorrect.
1023+
fset := token.NewFileSet()
1024+
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", parser.SkipObjectResolution)
1025+
pkg, _ := new(gotypes.Config).Check("p", fset, []*ast.File{f}, nil)
1026+
_, enabled := pkg.Scope().Lookup("A").Type().(*gotypes.Alias)
1027+
return enabled
1028+
}

v2/parser/parse_test.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ package parser
1919
import (
2020
"encoding/json"
2121
"fmt"
22-
"go/ast"
23-
"go/parser"
24-
"go/token"
25-
gotypes "go/types"
2622
"path/filepath"
2723
"reflect"
2824
"sort"
@@ -34,8 +30,6 @@ import (
3430
"k8s.io/gengo/v2/types"
3531
)
3632

37-
var typeAliasEnabled = goTypeAliasEnabled()
38-
3933
func TestNew(t *testing.T) {
4034
parser := New()
4135
if parser.goPkgs == nil {
@@ -1121,10 +1115,6 @@ func TestStructParse(t *testing.T) {
11211115
},
11221116
expected: func() *types.Type {
11231117
expectedTypeComments := []string{"Blah is a test.", "A test, I tell you."}
1124-
if !typeAliasEnabled {
1125-
// Comments from the last processed package wins.
1126-
expectedTypeComments = []string{"This is an alias for v1.Blah."}
1127-
}
11281118

11291119
return &types.Type{
11301120
Name: types.Name{
@@ -1231,10 +1221,6 @@ func TestCommentsWithAliasedType(t *testing.T) {
12311221
}
12321222

12331223
expectedTypeComments := []string{"Blah is a test.", "A test, I tell you."}
1234-
if !typeAliasEnabled {
1235-
// Comments from the last processed package wins.
1236-
expectedTypeComments = []string{"This is an alias for v1.Blah."}
1237-
}
12381224
for _, typ := range pkg.Types {
12391225
if typ.Name.Name != "Blah" {
12401226
continue
@@ -1246,22 +1232,3 @@ func TestCommentsWithAliasedType(t *testing.T) {
12461232
}
12471233
}
12481234
}
1249-
1250-
// Copied from https://github.com/golang/tools/blob/3e377036196f644e59e757af8a38ea6afa07677c/internal/aliases/aliases_go122.go#L64
1251-
func goTypeAliasEnabled() bool {
1252-
// The only reliable way to compute the answer is to invoke go/types.
1253-
// We don't parse the GODEBUG environment variable, because
1254-
// (a) it's tricky to do so in a manner that is consistent
1255-
// with the godebug package; in particular, a simple
1256-
// substring check is not good enough. The value is a
1257-
// rightmost-wins list of options. But more importantly:
1258-
// (b) it is impossible to detect changes to the effective
1259-
// setting caused by os.Setenv("GODEBUG"), as happens in
1260-
// many tests. Therefore any attempt to cache the result
1261-
// is just incorrect.
1262-
fset := token.NewFileSet()
1263-
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", parser.SkipObjectResolution)
1264-
pkg, _ := new(gotypes.Config).Check("p", fset, []*ast.File{f}, nil)
1265-
_, enabled := pkg.Scope().Lookup("A").Type().(*gotypes.Alias)
1266-
return enabled
1267-
}
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package v1
22

3+
// This is an alias within the same package.
4+
// It comes before the type it aliases.
5+
type LocalBlahAlias = Blah
6+
37
// Blah is a test.
48
// A test, I tell you.
59
type Blah struct {
@@ -11,18 +15,15 @@ type Blah struct {
1115
B string `json:"b"`
1216
}
1317

14-
// This is an alias within the same package.
15-
type LocalBlahAlias = Blah
16-
17-
// This is for back compat.
18-
// It has the same number of lines as Blah's comment.
18+
// Blah is a test.
19+
// A test, I tell you.
1920
//
20-
// Deprecated: use Blah instead.
21+
// Deprecated: use Blah instead. This is another alias within the same package.
2122
type LocalBlahAliasDeprecated = Blah
2223

23-
// This is for back compat.
24-
// It has the same number of lines as Blah's comment.
24+
// Blah is a test.
25+
// A test, I tell you.
2526
//
26-
// Deprecated: use Blah instead.
27+
// Deprecated: use Blah instead. This is a third alias within the same package.
2728
// It's a whole paragraph of deprecated notes
2829
type LocalBlahAliasDeprecatedLong = Blah

0 commit comments

Comments
 (0)