go x/exp/apidiff:在检查一个结构体是否实现了接口时,缺少了一个情况,

zmeyuzjn  于 5个月前  发布在  Go
关注(0)|答案(1)|浏览(52)

你使用的Go版本是什么( go version )?

$ go version
go1.18

这个问题在最新版本的发布中是否重现?

yes

你正在使用什么操作系统和处理器架构( go env )?

$ go env
GOHOSTARCH="amd64"
GOOS="linux"

你做了什么?

首先,我在不同的文件夹中创建了两个名为old和new的包,并在每个包中创建了一个文件。
文件内容如下。

// the file in old package
package demo

type Iface interface{
	Func()
}

type S struct {}

func (s *S) Func() {}
// the file in new package
package demo

type Iface interface{
	Func()
}

type S struct {}

// func (s *S) Func() {}

然后我使用apidiff来比较这两个包。

func ImplementTest() {
	// get pkgs in old package
	oldDir := "/the/old/package/path"
	oldCfg := &packages.Config{
		Mode:  packages.NeedTypes | packages.NeedName | packages.NeedImports | packages.NeedDeps,
		Tests: false,
		Dir:   oldDir,
	}
	oldPkgs, err := packages.Load(oldCfg, "./...")
	if err != nil {
		fmt.Println("packages.Load() error: ", err.Error())
	}
	// then do same action in new package
	// ...
	
	// then use apidiff the diff them
	for _, op := range oldPkgs {
		for _, np := range newPkgs {
			if op.Name == np.Name {
				fmt.Println(apidiff.Changes(op.Types, np.Types))
			}
		}
	}
}

你期望看到什么?

Incompatible changes:
- (*S).Func: removed
- (*S): no longer implements Iface

你实际看到了什么?

Incompatible changes:
- (*S).Func: removed

我发现的问题

问题位置

// in file apidiff.go
// line 109 ~ 116
for otn2, nt2 := range d.correspondMap {
	if otn1 == otn2 {
		continue
	}
	if types.Implements(otn2.Type(), oIface) && !types.Implements(nt2, nIface) {
		d.incompatible(otn2, "", "no longer implements %s", objectString(otn1))
	}
}

这段代码只能检查S是否实现了Iface,但不能检查*S是否实现了Iface,这就是为什么我得到的结果不如预期的原因。
这段代码是否应该改为这样?

// in file apidiff.go
// line 109 ~ 116
for otn2, nt2 := range d.correspondMap {
	if otn1 == otn2 {
		continue
	}
	if types.Implements(otn2.Type(), oIface) && !types.Implements(nt2, nIface) {
		d.incompatible(otn2, "", "no longer implements %s", objectString(otn1))
	}
	// to check whether *S implements interface
	if types.Implements(types.NewPointer(otn2.Type()), oIface) && !types.Implements(types.NewPointer(nt2), nIface) {
		d.incompatible(otn2, "", "no longer implements %s", objectString(otn1))
	}
}

相关问题