github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/oracle/implements14.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !go1.5 6 7 package oracle 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "reflect" 14 "sort" 15 "strings" 16 17 "golang.org/x/tools/go/loader" 18 "golang.org/x/tools/go/types" 19 "golang.org/x/tools/go/types/typeutil" 20 "golang.org/x/tools/oracle/serial" 21 "golang.org/x/tools/refactor/importgraph" 22 ) 23 24 // Implements displays the "implements" relation as it pertains to the 25 // selected type. 26 // If the selection is a method, 'implements' displays 27 // the corresponding methods of the types that would have been reported 28 // by an implements query on the receiver type. 29 // 30 func implements(q *Query) error { 31 lconf := loader.Config{Build: q.Build} 32 allowErrors(&lconf) 33 34 qpkg, err := importQueryPackage(q.Pos, &lconf) 35 if err != nil { 36 return err 37 } 38 39 // Set the packages to search. 40 if len(q.Scope) > 0 { 41 // Inspect all packages in the analysis scope, if specified. 42 if err := setPTAScope(&lconf, q.Scope); err != nil { 43 return err 44 } 45 } else { 46 // Otherwise inspect the forward and reverse 47 // transitive closure of the selected package. 48 // (In theory even this is incomplete.) 49 _, rev, _ := importgraph.Build(q.Build) 50 for path := range rev.Search(qpkg) { 51 lconf.ImportWithTests(path) 52 } 53 54 // TODO(adonovan): for completeness, we should also 55 // type-check and inspect function bodies in all 56 // imported packages. This would be expensive, but we 57 // could optimize by skipping functions that do not 58 // contain type declarations. This would require 59 // changing the loader's TypeCheckFuncBodies hook to 60 // provide the []*ast.File. 61 } 62 63 // Load/parse/type-check the program. 64 lprog, err := lconf.Load() 65 if err != nil { 66 return err 67 } 68 q.Fset = lprog.Fset 69 70 qpos, err := parseQueryPos(lprog, q.Pos, false) 71 if err != nil { 72 return err 73 } 74 75 // Find the selected type. 76 path, action := findInterestingNode(qpos.info, qpos.path) 77 78 var method *types.Func 79 var T types.Type // selected type (receiver if method != nil) 80 81 switch action { 82 case actionExpr: 83 // method? 84 if id, ok := path[0].(*ast.Ident); ok { 85 if obj, ok := qpos.info.ObjectOf(id).(*types.Func); ok { 86 recv := obj.Type().(*types.Signature).Recv() 87 if recv == nil { 88 return fmt.Errorf("this function is not a method") 89 } 90 method = obj 91 T = recv.Type() 92 } 93 } 94 case actionType: 95 T = qpos.info.TypeOf(path[0].(ast.Expr)) 96 } 97 if T == nil { 98 return fmt.Errorf("no type or method here") 99 } 100 101 // Find all named types, even local types (which can have 102 // methods via promotion) and the built-in "error". 103 var allNamed []types.Type 104 for _, info := range lprog.AllPackages { 105 for _, obj := range info.Defs { 106 if obj, ok := obj.(*types.TypeName); ok { 107 allNamed = append(allNamed, obj.Type()) 108 } 109 } 110 } 111 allNamed = append(allNamed, types.Universe.Lookup("error").Type()) 112 113 var msets typeutil.MethodSetCache 114 115 // Test each named type. 116 var to, from, fromPtr []types.Type 117 for _, U := range allNamed { 118 if isInterface(T) { 119 if msets.MethodSet(T).Len() == 0 { 120 continue // empty interface 121 } 122 if isInterface(U) { 123 if msets.MethodSet(U).Len() == 0 { 124 continue // empty interface 125 } 126 127 // T interface, U interface 128 if !types.Identical(T, U) { 129 if types.AssignableTo(U, T) { 130 to = append(to, U) 131 } 132 if types.AssignableTo(T, U) { 133 from = append(from, U) 134 } 135 } 136 } else { 137 // T interface, U concrete 138 if types.AssignableTo(U, T) { 139 to = append(to, U) 140 } else if pU := types.NewPointer(U); types.AssignableTo(pU, T) { 141 to = append(to, pU) 142 } 143 } 144 } else if isInterface(U) { 145 if msets.MethodSet(U).Len() == 0 { 146 continue // empty interface 147 } 148 149 // T concrete, U interface 150 if types.AssignableTo(T, U) { 151 from = append(from, U) 152 } else if pT := types.NewPointer(T); types.AssignableTo(pT, U) { 153 fromPtr = append(fromPtr, U) 154 } 155 } 156 } 157 158 var pos interface{} = qpos 159 if nt, ok := deref(T).(*types.Named); ok { 160 pos = nt.Obj() 161 } 162 163 // Sort types (arbitrarily) to ensure test determinism. 164 sort.Sort(typesByString(to)) 165 sort.Sort(typesByString(from)) 166 sort.Sort(typesByString(fromPtr)) 167 168 var toMethod, fromMethod, fromPtrMethod []*types.Selection // contain nils 169 if method != nil { 170 for _, t := range to { 171 toMethod = append(toMethod, 172 types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) 173 } 174 for _, t := range from { 175 fromMethod = append(fromMethod, 176 types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) 177 } 178 for _, t := range fromPtr { 179 fromPtrMethod = append(fromPtrMethod, 180 types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) 181 } 182 } 183 184 q.result = &implementsResult{ 185 qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod, 186 } 187 return nil 188 } 189 190 type implementsResult struct { 191 qpos *queryPos 192 193 t types.Type // queried type (not necessarily named) 194 pos interface{} // pos of t (*types.Name or *QueryPos) 195 to []types.Type // named or ptr-to-named types assignable to interface T 196 from []types.Type // named interfaces assignable from T 197 fromPtr []types.Type // named interfaces assignable only from *T 198 199 // if a method was queried: 200 method *types.Func // queried method 201 toMethod []*types.Selection // method of type to[i], if any 202 fromMethod []*types.Selection // method of type from[i], if any 203 fromPtrMethod []*types.Selection // method of type fromPtrMethod[i], if any 204 } 205 206 func (r *implementsResult) display(printf printfFunc) { 207 relation := "is implemented by" 208 209 meth := func(sel *types.Selection) { 210 if sel != nil { 211 printf(sel.Obj(), "\t%s method (%s).%s", 212 relation, r.qpos.typeString(sel.Recv()), sel.Obj().Name()) 213 } 214 } 215 216 if isInterface(r.t) { 217 if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset 218 printf(r.pos, "empty interface type %s", r.qpos.typeString(r.t)) 219 return 220 } 221 222 if r.method == nil { 223 printf(r.pos, "interface type %s", r.qpos.typeString(r.t)) 224 } else { 225 printf(r.method, "abstract method %s", r.qpos.objectString(r.method)) 226 } 227 228 // Show concrete types (or methods) first; use two passes. 229 for i, sub := range r.to { 230 if !isInterface(sub) { 231 if r.method == nil { 232 printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s", 233 relation, typeKind(sub), r.qpos.typeString(sub)) 234 } else { 235 meth(r.toMethod[i]) 236 } 237 } 238 } 239 for i, sub := range r.to { 240 if isInterface(sub) { 241 if r.method == nil { 242 printf(sub.(*types.Named).Obj(), "\t%s %s type %s", 243 relation, typeKind(sub), r.qpos.typeString(sub)) 244 } else { 245 meth(r.toMethod[i]) 246 } 247 } 248 } 249 250 relation = "implements" 251 for i, super := range r.from { 252 if r.method == nil { 253 printf(super.(*types.Named).Obj(), "\t%s %s", 254 relation, r.qpos.typeString(super)) 255 } else { 256 meth(r.fromMethod[i]) 257 } 258 } 259 } else { 260 relation = "implements" 261 262 if r.from != nil { 263 if r.method == nil { 264 printf(r.pos, "%s type %s", 265 typeKind(r.t), r.qpos.typeString(r.t)) 266 } else { 267 printf(r.method, "concrete method %s", 268 r.qpos.objectString(r.method)) 269 } 270 for i, super := range r.from { 271 if r.method == nil { 272 printf(super.(*types.Named).Obj(), "\t%s %s", 273 relation, r.qpos.typeString(super)) 274 } else { 275 meth(r.fromMethod[i]) 276 } 277 } 278 } 279 if r.fromPtr != nil { 280 if r.method == nil { 281 printf(r.pos, "pointer type *%s", r.qpos.typeString(r.t)) 282 } else { 283 // TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f. 284 printf(r.method, "concrete method %s", 285 r.qpos.objectString(r.method)) 286 } 287 288 for i, psuper := range r.fromPtr { 289 if r.method == nil { 290 printf(psuper.(*types.Named).Obj(), "\t%s %s", 291 relation, r.qpos.typeString(psuper)) 292 } else { 293 meth(r.fromPtrMethod[i]) 294 } 295 } 296 } else if r.from == nil { 297 printf(r.pos, "%s type %s implements only interface{}", 298 typeKind(r.t), r.qpos.typeString(r.t)) 299 } 300 } 301 } 302 303 func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) { 304 res.Implements = &serial.Implements{ 305 T: makeImplementsType(r.t, fset), 306 AssignableTo: makeImplementsTypes(r.to, fset), 307 AssignableFrom: makeImplementsTypes(r.from, fset), 308 AssignableFromPtr: makeImplementsTypes(r.fromPtr, fset), 309 AssignableToMethod: methodsToSerial(r.qpos.info.Pkg, r.toMethod, fset), 310 AssignableFromMethod: methodsToSerial(r.qpos.info.Pkg, r.fromMethod, fset), 311 AssignableFromPtrMethod: methodsToSerial(r.qpos.info.Pkg, r.fromPtrMethod, fset), 312 } 313 if r.method != nil { 314 res.Implements.Method = &serial.DescribeMethod{ 315 Name: r.qpos.objectString(r.method), 316 Pos: fset.Position(r.method.Pos()).String(), 317 } 318 } 319 } 320 321 func makeImplementsTypes(tt []types.Type, fset *token.FileSet) []serial.ImplementsType { 322 var r []serial.ImplementsType 323 for _, t := range tt { 324 r = append(r, makeImplementsType(t, fset)) 325 } 326 return r 327 } 328 329 func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType { 330 var pos token.Pos 331 if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named 332 pos = nt.Obj().Pos() 333 } 334 return serial.ImplementsType{ 335 Name: T.String(), 336 Pos: fset.Position(pos).String(), 337 Kind: typeKind(T), 338 } 339 } 340 341 // typeKind returns a string describing the underlying kind of type, 342 // e.g. "slice", "array", "struct". 343 func typeKind(T types.Type) string { 344 s := reflect.TypeOf(T.Underlying()).String() 345 return strings.ToLower(strings.TrimPrefix(s, "*types.")) 346 } 347 348 func isInterface(T types.Type) bool { return types.IsInterface(T) } 349 350 type typesByString []types.Type 351 352 func (p typesByString) Len() int { return len(p) } 353 func (p typesByString) Less(i, j int) bool { return p[i].String() < p[j].String() } 354 func (p typesByString) Swap(i, j int) { p[i], p[j] = p[j], p[i] }