structsImplementingInterface is a helper function that returns all the struct names implementing the given interface in the given package recursively
(interfaceName string, packageName ...string)
| 148 | // structsImplementingInterface is a helper function that returns all the struct names implementing the given interface |
| 149 | // in the given package recursively |
| 150 | func structsImplementingInterface(interfaceName string, packageName ...string) map[string]bool { |
| 151 | structs := make(map[string]bool) |
| 152 | |
| 153 | // if no package name is provided, default to using the current directory |
| 154 | if len(packageName) == 0 { |
| 155 | packageName = []string{"."} |
| 156 | } |
| 157 | |
| 158 | cfg := &packages.Config{ |
| 159 | Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | |
| 160 | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo, |
| 161 | } |
| 162 | |
| 163 | for _, p := range packageName { |
| 164 | pkgs, err := packages.Load(cfg, p) |
| 165 | if err != nil { |
| 166 | panic(err) |
| 167 | } |
| 168 | if len(pkgs) == 0 { |
| 169 | panic("no packages found") |
| 170 | } |
| 171 | |
| 172 | for _, pkg := range pkgs { |
| 173 | // scan the packages to find the interface and get its *types.Interface object |
| 174 | obj := pkgs[0].Types.Scope().Lookup(interfaceName) |
| 175 | if obj == nil { |
| 176 | continue |
| 177 | } |
| 178 | interfaceObj, ok := obj.Type().Underlying().(*types.Interface) |
| 179 | if !ok { |
| 180 | continue |
| 181 | } |
| 182 | |
| 183 | // iterate over all Go files in the package to find the structs implementing the interface |
| 184 | for _, filepath := range pkg.GoFiles { |
| 185 | fset := token.NewFileSet() |
| 186 | node, err := parser.ParseFile(fset, filepath, nil, parser.AllErrors) |
| 187 | if err != nil { |
| 188 | panic(err) |
| 189 | } |
| 190 | |
| 191 | ast.Inspect(node, func(n ast.Node) bool { |
| 192 | if typeSpec, ok := n.(*ast.TypeSpec); ok { |
| 193 | if _, ok := typeSpec.Type.(*ast.StructType); ok { |
| 194 | sObj := pkg.Types.Scope().Lookup(typeSpec.Name.Name) |
| 195 | if sObj == nil { |
| 196 | return true |
| 197 | } |
| 198 | sType, ok := types.Unalias(sObj.Type()).(*types.Named) |
| 199 | if !ok { |
| 200 | return true |
| 201 | } |
| 202 | |
| 203 | structMethods := getImplementedMethods(sType) |
| 204 | if interfaceObj.NumMethods() > len(structMethods) { |
| 205 | return true |
| 206 | } |
| 207 |
no test coverage detected