GoPLS Viewer

Home|gopls/refactor/satisfy/find.go
1// Copyright 2014 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// Package satisfy inspects the type-checked ASTs of Go packages and
6// reports the set of discovered type constraints of the form (lhs, rhs
7// Type) where lhs is a non-trivial interface, rhs satisfies this
8// interface, and this fact is necessary for the package to be
9// well-typed.
10//
11// THIS PACKAGE IS EXPERIMENTAL AND MAY CHANGE AT ANY TIME.
12//
13// It is provided only for the gopls tool. It requires well-typed inputs.
14package satisfy // import "golang.org/x/tools/refactor/satisfy"
15
16// NOTES:
17//
18// We don't care about numeric conversions, so we don't descend into
19// types or constant expressions.  This is unsound because
20// constant expressions can contain arbitrary statements, e.g.
21//   const x = len([1]func(){func() {
22//     ...
23//   }})
24//
25// Assignability conversions are possible in the following places:
26// - in assignments y = x, y := x, var y = x.
27// - from call argument types to formal parameter types
28// - in append and delete calls
29// - from return operands to result parameter types
30// - in composite literal T{k:v}, from k and v to T's field/element/key type
31// - in map[key] from key to the map's key type
32// - in comparisons x==y and switch x { case y: }.
33// - in explicit conversions T(x)
34// - in sends ch <- x, from x to the channel element type
35// - in type assertions x.(T) and switch x.(type) { case T: }
36//
37// The results of this pass provide information equivalent to the
38// ssa.MakeInterface and ssa.ChangeInterface instructions.
39
40import (
41    "fmt"
42    "go/ast"
43    "go/token"
44    "go/types"
45
46    "golang.org/x/tools/go/ast/astutil"
47    "golang.org/x/tools/go/types/typeutil"
48    "golang.org/x/tools/internal/typeparams"
49)
50
51// A Constraint records the fact that the RHS type does and must
52// satisfy the LHS type, which is an interface.
53// The names are suggestive of an assignment statement LHS = RHS.
54//
55// The constraint is implicitly universally quantified over any type
56// parameters appearing within the two types.
57type Constraint struct {
58    LHSRHS types.Type
59}
60
61// A Finder inspects the type-checked ASTs of Go packages and
62// accumulates the set of type constraints (x, y) such that x is
63// assignable to y, y is an interface, and both x and y have methods.
64//
65// In other words, it returns the subset of the "implements" relation
66// that is checked during compilation of a package.  Refactoring tools
67// will need to preserve at least this part of the relation to ensure
68// continued compilation.
69type Finder struct {
70    Result    map[Constraint]bool
71    msetcache typeutil.MethodSetCache
72
73    // per-Find state
74    info *types.Info
75    sig  *types.Signature
76}
77
78// Find inspects a single package, populating Result with its pairs of
79// constrained types.
80//
81// The result is non-canonical and thus may contain duplicates (but this
82// tends to preserves names of interface types better).
83//
84// The package must be free of type errors, and
85// info.{Defs,Uses,Selections,Types} must have been populated by the
86// type-checker.
87func (f *FinderFind(info *types.Infofiles []*ast.File) {
88    if f.Result == nil {
89        f.Result = make(map[Constraint]bool)
90    }
91
92    f.info = info
93    for _file := range files {
94        for _d := range file.Decls {
95            switch d := d.(type) {
96            case *ast.GenDecl:
97                if d.Tok == token.VAR { // ignore consts
98                    for _spec := range d.Specs {
99                        f.valueSpec(spec.(*ast.ValueSpec))
100                    }
101                }
102
103            case *ast.FuncDecl:
104                if d.Body != nil {
105                    f.sig = f.info.Defs[d.Name].Type().(*types.Signature)
106                    f.stmt(d.Body)
107                    f.sig = nil
108                }
109            }
110        }
111    }
112    f.info = nil
113}
114
115var (
116    tInvalid     = types.Typ[types.Invalid]
117    tUntypedBool = types.Typ[types.UntypedBool]
118    tUntypedNil  = types.Typ[types.UntypedNil]
119)
120
121// exprN visits an expression in a multi-value context.
122func (f *FinderexprN(e ast.Exprtypes.Type {
123    typ := f.info.Types[e].Type.(*types.Tuple)
124    switch e := e.(type) {
125    case *ast.ParenExpr:
126        return f.exprN(e.X)
127
128    case *ast.CallExpr:
129        // x, err := f(args)
130        sig := coreType(f.expr(e.Fun)).(*types.Signature)
131        f.call(sige.Args)
132
133    case *ast.IndexExpr:
134        // y, ok := x[i]
135        x := f.expr(e.X)
136        f.assign(f.expr(e.Index), coreType(x).(*types.Map).Key())
137
138    case *ast.TypeAssertExpr:
139        // y, ok := x.(T)
140        f.typeAssert(f.expr(e.X), typ.At(0).Type())
141
142    case *ast.UnaryExpr// must be receive <-
143        // y, ok := <-x
144        f.expr(e.X)
145
146    default:
147        panic(e)
148    }
149    return typ
150}
151
152func (f *Findercall(sig *types.Signatureargs []ast.Expr) {
153    if len(args) == 0 {
154        return
155    }
156
157    // Ellipsis call?  e.g. f(x, y, z...)
158    if _ok := args[len(args)-1].(*ast.Ellipsis); ok {
159        for iarg := range args {
160            // The final arg is a slice, and so is the final param.
161            f.assign(sig.Params().At(i).Type(), f.expr(arg))
162        }
163        return
164    }
165
166    var argtypes []types.Type
167
168    // Gather the effective actual parameter types.
169    if tupleok := f.info.Types[args[0]].Type.(*types.Tuple); ok {
170        // f(g()) call where g has multiple results?
171        f.expr(args[0])
172        // unpack the tuple
173        for i := 0i < tuple.Len(); i++ {
174            argtypes = append(argtypestuple.At(i).Type())
175        }
176    } else {
177        for _arg := range args {
178            argtypes = append(argtypesf.expr(arg))
179        }
180    }
181
182    // Assign the actuals to the formals.
183    if !sig.Variadic() {
184        for iargtype := range argtypes {
185            f.assign(sig.Params().At(i).Type(), argtype)
186        }
187    } else {
188        // The first n-1 parameters are assigned normally.
189        nnormals := sig.Params().Len() - 1
190        for iargtype := range argtypes[:nnormals] {
191            f.assign(sig.Params().At(i).Type(), argtype)
192        }
193        // Remaining args are assigned to elements of varargs slice.
194        tElem := sig.Params().At(nnormals).Type().(*types.Slice).Elem()
195        for i := nnormalsi < len(argtypes); i++ {
196            f.assign(tElemargtypes[i])
197        }
198    }
199}
200
201// builtin visits the arguments of a builtin type with signature sig.
202func (f *Finderbuiltin(obj *types.Builtinsig *types.Signatureargs []ast.Expr) {
203    switch obj.Name() {
204    case "make""new":
205        // skip the type operand
206        for _arg := range args[1:] {
207            f.expr(arg)
208        }
209
210    case "append":
211        s := f.expr(args[0])
212        if _ok := args[len(args)-1].(*ast.Ellipsis); ok && len(args) == 2 {
213            // append(x, y...)   including append([]byte, "foo"...)
214            f.expr(args[1])
215        } else {
216            // append(x, y, z)
217            tElem := coreType(s).(*types.Slice).Elem()
218            for _arg := range args[1:] {
219                f.assign(tElemf.expr(arg))
220            }
221        }
222
223    case "delete":
224        m := f.expr(args[0])
225        k := f.expr(args[1])
226        f.assign(coreType(m).(*types.Map).Key(), k)
227
228    default:
229        // ordinary call
230        f.call(sigargs)
231    }
232}
233
234func (f *Finderextract(tuple types.Typei inttypes.Type {
235    if tupleok := tuple.(*types.Tuple); ok && i < tuple.Len() {
236        return tuple.At(i).Type()
237    }
238    return tInvalid
239}
240
241func (f *FindervalueSpec(spec *ast.ValueSpec) {
242    var T types.Type
243    if spec.Type != nil {
244        T = f.info.Types[spec.Type].Type
245    }
246    switch len(spec.Values) {
247    case len(spec.Names): // e.g. var x, y = f(), g()
248        for _value := range spec.Values {
249            v := f.expr(value)
250            if T != nil {
251                f.assign(Tv)
252            }
253        }
254
255    case 1// e.g. var x, y = f()
256        tuple := f.exprN(spec.Values[0])
257        for i := range spec.Names {
258            if T != nil {
259                f.assign(Tf.extract(tuplei))
260            }
261        }
262    }
263}
264
265// assign records pairs of distinct types that are related by
266// assignability, where the left-hand side is an interface and both
267// sides have methods.
268//
269// It should be called for all assignability checks, type assertions,
270// explicit conversions and comparisons between two types, unless the
271// types are uninteresting (e.g. lhs is a concrete type, or the empty
272// interface; rhs has no methods).
273func (f *Finderassign(lhsrhs types.Type) {
274    if types.Identical(lhsrhs) {
275        return
276    }
277    if !isInterface(lhs) {
278        return
279    }
280
281    if f.msetcache.MethodSet(lhs).Len() == 0 {
282        return
283    }
284    if f.msetcache.MethodSet(rhs).Len() == 0 {
285        return
286    }
287    // record the pair
288    f.Result[Constraint{lhsrhs}] = true
289}
290
291// typeAssert must be called for each type assertion x.(T) where x has
292// interface type I.
293func (f *FindertypeAssert(IT types.Type) {
294    // Type assertions are slightly subtle, because they are allowed
295    // to be "impossible", e.g.
296    //
297    //     var x interface{f()}
298    //    _ = x.(interface{f()int}) // legal
299    //
300    // (In hindsight, the language spec should probably not have
301    // allowed this, but it's too late to fix now.)
302    //
303    // This means that a type assert from I to T isn't exactly a
304    // constraint that T is assignable to I, but for a refactoring
305    // tool it is a conditional constraint that, if T is assignable
306    // to I before a refactoring, it should remain so after.
307
308    if types.AssignableTo(TI) {
309        f.assign(IT)
310    }
311}
312
313// compare must be called for each comparison x==y.
314func (f *Findercompare(xy types.Type) {
315    if types.AssignableTo(xy) {
316        f.assign(yx)
317    } else if types.AssignableTo(yx) {
318        f.assign(xy)
319    }
320}
321
322// expr visits a true expression (not a type or defining ident)
323// and returns its type.
324func (f *Finderexpr(e ast.Exprtypes.Type {
325    tv := f.info.Types[e]
326    if tv.Value != nil {
327        return tv.Type // prune the descent for constants
328    }
329
330    // tv.Type may be nil for an ast.Ident.
331
332    switch e := e.(type) {
333    case *ast.BadExpr, *ast.BasicLit:
334        // no-op
335
336    case *ast.Ident:
337        // (referring idents only)
338        if objok := f.info.Uses[e]; ok {
339            return obj.Type()
340        }
341        if e.Name == "_" { // e.g. "for _ = range x"
342            return tInvalid
343        }
344        panic("undefined ident: " + e.Name)
345
346    case *ast.Ellipsis:
347        if e.Elt != nil {
348            f.expr(e.Elt)
349        }
350
351    case *ast.FuncLit:
352        saved := f.sig
353        f.sig = tv.Type.(*types.Signature)
354        f.stmt(e.Body)
355        f.sig = saved
356
357    case *ast.CompositeLit:
358        // No need for coreType here: go1.18 disallows P{...} for type param P.
359        switch T := deref(tv.Type).Underlying().(type) {
360        case *types.Struct:
361            for ielem := range e.Elts {
362                if kvok := elem.(*ast.KeyValueExpr); ok {
363                    f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value))
364                } else {
365                    f.assign(T.Field(i).Type(), f.expr(elem))
366                }
367            }
368
369        case *types.Map:
370            for _elem := range e.Elts {
371                elem := elem.(*ast.KeyValueExpr)
372                f.assign(T.Key(), f.expr(elem.Key))
373                f.assign(T.Elem(), f.expr(elem.Value))
374            }
375
376        case *types.Array, *types.Slice:
377            tElem := T.(interface {
378                Elem() types.Type
379            }).Elem()
380            for _elem := range e.Elts {
381                if kvok := elem.(*ast.KeyValueExpr); ok {
382                    // ignore the key
383                    f.assign(tElemf.expr(kv.Value))
384                } else {
385                    f.assign(tElemf.expr(elem))
386                }
387            }
388
389        default:
390            panic("unexpected composite literal type: " + tv.Type.String())
391        }
392
393    case *ast.ParenExpr:
394        f.expr(e.X)
395
396    case *ast.SelectorExpr:
397        if _ok := f.info.Selections[e]; ok {
398            f.expr(e.X// selection
399        } else {
400            return f.info.Uses[e.Sel].Type() // qualified identifier
401        }
402
403    case *ast.IndexExpr:
404        if instance(f.infoe.X) {
405            // f[T] or C[T] -- generic instantiation
406        } else {
407            // x[i] or m[k] -- index or lookup operation
408            x := f.expr(e.X)
409            i := f.expr(e.Index)
410            if uxok := coreType(x).(*types.Map); ok {
411                f.assign(ux.Key(), i)
412            }
413        }
414
415    case *typeparams.IndexListExpr:
416        // f[X, Y] -- generic instantiation
417
418    case *ast.SliceExpr:
419        f.expr(e.X)
420        if e.Low != nil {
421            f.expr(e.Low)
422        }
423        if e.High != nil {
424            f.expr(e.High)
425        }
426        if e.Max != nil {
427            f.expr(e.Max)
428        }
429
430    case *ast.TypeAssertExpr:
431        x := f.expr(e.X)
432        f.typeAssert(xf.info.Types[e.Type].Type)
433
434    case *ast.CallExpr:
435        if tvFun := f.info.Types[e.Fun]; tvFun.IsType() {
436            // conversion
437            arg0 := f.expr(e.Args[0])
438            f.assign(tvFun.Typearg0)
439        } else {
440            // function call
441
442            // unsafe call. Treat calls to functions in unsafe like ordinary calls,
443            // except that their signature cannot be determined by their func obj.
444            // Without this special handling, f.expr(e.Fun) would fail below.
445            if sok := unparen(e.Fun).(*ast.SelectorExpr); ok {
446                if objok := f.info.Uses[s.Sel].(*types.Builtin); ok && obj.Pkg().Path() == "unsafe" {
447                    sig := f.info.Types[e.Fun].Type.(*types.Signature)
448                    f.call(sige.Args)
449                    return tv.Type
450                }
451            }
452
453            // builtin call
454            if idok := unparen(e.Fun).(*ast.Ident); ok {
455                if objok := f.info.Uses[id].(*types.Builtin); ok {
456                    sig := f.info.Types[id].Type.(*types.Signature)
457                    f.builtin(objsige.Args)
458                    return tv.Type
459                }
460            }
461
462            // ordinary call
463            f.call(coreType(f.expr(e.Fun)).(*types.Signature), e.Args)
464        }
465
466    case *ast.StarExpr:
467        f.expr(e.X)
468
469    case *ast.UnaryExpr:
470        f.expr(e.X)
471
472    case *ast.BinaryExpr:
473        x := f.expr(e.X)
474        y := f.expr(e.Y)
475        if e.Op == token.EQL || e.Op == token.NEQ {
476            f.compare(xy)
477        }
478
479    case *ast.KeyValueExpr:
480        f.expr(e.Key)
481        f.expr(e.Value)
482
483    case *ast.ArrayType,
484        *ast.StructType,
485        *ast.FuncType,
486        *ast.InterfaceType,
487        *ast.MapType,
488        *ast.ChanType:
489        panic(e)
490    }
491
492    if tv.Type == nil {
493        panic(fmt.Sprintf("no type for %T"e))
494    }
495
496    return tv.Type
497}
498
499func (f *Finderstmt(s ast.Stmt) {
500    switch s := s.(type) {
501    case *ast.BadStmt,
502        *ast.EmptyStmt,
503        *ast.BranchStmt:
504        // no-op
505
506    case *ast.DeclStmt:
507        d := s.Decl.(*ast.GenDecl)
508        if d.Tok == token.VAR { // ignore consts
509            for _spec := range d.Specs {
510                f.valueSpec(spec.(*ast.ValueSpec))
511            }
512        }
513
514    case *ast.LabeledStmt:
515        f.stmt(s.Stmt)
516
517    case *ast.ExprStmt:
518        f.expr(s.X)
519
520    case *ast.SendStmt:
521        ch := f.expr(s.Chan)
522        val := f.expr(s.Value)
523        f.assign(coreType(ch).(*types.Chan).Elem(), val)
524
525    case *ast.IncDecStmt:
526        f.expr(s.X)
527
528    case *ast.AssignStmt:
529        switch s.Tok {
530        case token.ASSIGNtoken.DEFINE:
531            // y := x   or   y = x
532            var rhsTuple types.Type
533            if len(s.Lhs) != len(s.Rhs) {
534                rhsTuple = f.exprN(s.Rhs[0])
535            }
536            for i := range s.Lhs {
537                var lhsrhs types.Type
538                if rhsTuple == nil {
539                    rhs = f.expr(s.Rhs[i]) // 1:1 assignment
540                } else {
541                    rhs = f.extract(rhsTuplei// n:1 assignment
542                }
543
544                if idok := s.Lhs[i].(*ast.Ident); ok {
545                    if id.Name != "_" {
546                        if objok := f.info.Defs[id]; ok {
547                            lhs = obj.Type() // definition
548                        }
549                    }
550                }
551                if lhs == nil {
552                    lhs = f.expr(s.Lhs[i]) // assignment
553                }
554                f.assign(lhsrhs)
555            }
556
557        default:
558            // y op= x
559            f.expr(s.Lhs[0])
560            f.expr(s.Rhs[0])
561        }
562
563    case *ast.GoStmt:
564        f.expr(s.Call)
565
566    case *ast.DeferStmt:
567        f.expr(s.Call)
568
569    case *ast.ReturnStmt:
570        formals := f.sig.Results()
571        switch len(s.Results) {
572        case formals.Len(): // 1:1
573            for iresult := range s.Results {
574                f.assign(formals.At(i).Type(), f.expr(result))
575            }
576
577        case 1// n:1
578            tuple := f.exprN(s.Results[0])
579            for i := 0i < formals.Len(); i++ {
580                f.assign(formals.At(i).Type(), f.extract(tuplei))
581            }
582        }
583
584    case *ast.SelectStmt:
585        f.stmt(s.Body)
586
587    case *ast.BlockStmt:
588        for _s := range s.List {
589            f.stmt(s)
590        }
591
592    case *ast.IfStmt:
593        if s.Init != nil {
594            f.stmt(s.Init)
595        }
596        f.expr(s.Cond)
597        f.stmt(s.Body)
598        if s.Else != nil {
599            f.stmt(s.Else)
600        }
601
602    case *ast.SwitchStmt:
603        if s.Init != nil {
604            f.stmt(s.Init)
605        }
606        var tag types.Type = tUntypedBool
607        if s.Tag != nil {
608            tag = f.expr(s.Tag)
609        }
610        for _cc := range s.Body.List {
611            cc := cc.(*ast.CaseClause)
612            for _cond := range cc.List {
613                f.compare(tagf.info.Types[cond].Type)
614            }
615            for _s := range cc.Body {
616                f.stmt(s)
617            }
618        }
619
620    case *ast.TypeSwitchStmt:
621        if s.Init != nil {
622            f.stmt(s.Init)
623        }
624        var I types.Type
625        switch ass := s.Assign.(type) {
626        case *ast.ExprStmt// x.(type)
627            I = f.expr(unparen(ass.X).(*ast.TypeAssertExpr).X)
628        case *ast.AssignStmt// y := x.(type)
629            I = f.expr(unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
630        }
631        for _cc := range s.Body.List {
632            cc := cc.(*ast.CaseClause)
633            for _cond := range cc.List {
634                tCase := f.info.Types[cond].Type
635                if tCase != tUntypedNil {
636                    f.typeAssert(ItCase)
637                }
638            }
639            for _s := range cc.Body {
640                f.stmt(s)
641            }
642        }
643
644    case *ast.CommClause:
645        if s.Comm != nil {
646            f.stmt(s.Comm)
647        }
648        for _s := range s.Body {
649            f.stmt(s)
650        }
651
652    case *ast.ForStmt:
653        if s.Init != nil {
654            f.stmt(s.Init)
655        }
656        if s.Cond != nil {
657            f.expr(s.Cond)
658        }
659        if s.Post != nil {
660            f.stmt(s.Post)
661        }
662        f.stmt(s.Body)
663
664    case *ast.RangeStmt:
665        x := f.expr(s.X)
666        // No conversions are involved when Tok==DEFINE.
667        if s.Tok == token.ASSIGN {
668            if s.Key != nil {
669                k := f.expr(s.Key)
670                var xelem types.Type
671                // Keys of array, *array, slice, string aren't interesting
672                // since the RHS key type is just an int.
673                switch ux := coreType(x).(type) {
674                case *types.Chan:
675                    xelem = ux.Elem()
676                case *types.Map:
677                    xelem = ux.Key()
678                }
679                if xelem != nil {
680                    f.assign(kxelem)
681                }
682            }
683            if s.Value != nil {
684                val := f.expr(s.Value)
685                var xelem types.Type
686                // Values of type strings aren't interesting because
687                // the RHS value type is just a rune.
688                switch ux := coreType(x).(type) {
689                case *types.Array:
690                    xelem = ux.Elem()
691                case *types.Map:
692                    xelem = ux.Elem()
693                case *types.Pointer// *array
694                    xelem = coreType(deref(ux)).(*types.Array).Elem()
695                case *types.Slice:
696                    xelem = ux.Elem()
697                }
698                if xelem != nil {
699                    f.assign(valxelem)
700                }
701            }
702        }
703        f.stmt(s.Body)
704
705    default:
706        panic(s)
707    }
708}
709
710// -- Plundered from golang.org/x/tools/go/ssa -----------------
711
712// deref returns a pointer's element type; otherwise it returns typ.
713func deref(typ types.Typetypes.Type {
714    if pok := coreType(typ).(*types.Pointer); ok {
715        return p.Elem()
716    }
717    return typ
718}
719
720func unparen(e ast.Exprast.Expr { return astutil.Unparen(e) }
721
722func isInterface(T types.Typebool { return types.IsInterface(T) }
723
724func coreType(T types.Typetypes.Type { return typeparams.CoreType(T) }
725
726func instance(info *types.Infoexpr ast.Exprbool {
727    var id *ast.Ident
728    switch x := expr.(type) {
729    case *ast.Ident:
730        id = x
731    case *ast.SelectorExpr:
732        id = x.Sel
733    default:
734        return false
735    }
736    _ok := typeparams.GetInstances(info)[id]
737    return ok
738}
739
MembersX
Finder.expr.BlockStmt.y
Finder.stmt.BlockStmt.BlockStmt.rhsTuple
coreType
Finder.extract
Finder.typeAssert.f
Finder.compare
Finder.extract.i
Finder.sig
Finder.call.BlockStmt.RangeStmt_5478.i
Finder.builtin.obj
Finder.assign.rhs
Constraint.RHS
Finder
Finder.call.BlockStmt.RangeStmt_5289.i
Finder.stmt.BlockStmt.RangeStmt_15482.BlockStmt.RangeStmt_15548.BlockStmt.tCase
Finder.stmt.BlockStmt.x
deref
Finder.builtin.BlockStmt.m
Finder.expr.f
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_13595.BlockStmt.rhs
Finder.stmt.BlockStmt.tag
Finder.exprN.f
Finder.call.args
Finder.compare.x
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_13595.i
isInterface.T
instance.info
typeutil
Finder.Find.RangeStmt_3239.file
Finder.builtin.sig
Finder.assign
Finder.expr.BlockStmt.BlockStmt.arg0
Finder.stmt.BlockStmt.BlockStmt.BlockStmt.k
deref.typ
isInterface
Constraint.LHS
Finder.Result
Finder.Find.RangeStmt_3239.BlockStmt.RangeStmt_3270.BlockStmt.BlockStmt.BlockStmt.RangeStmt_3399.spec
instance.expr
unparen
Finder.Find.f
Finder.valueSpec.BlockStmt.RangeStmt_7139.i
Finder.stmt.BlockStmt.RangeStmt_14964.BlockStmt.RangeStmt_15113.s
Finder.stmt.BlockStmt.BlockStmt.BlockStmt.xelem
Finder.info
Finder.extract.tuple
Finder.expr
Finder.compare.y
token
Finder.call.BlockStmt.i
Finder.extract.f
Finder.expr.BlockStmt.BlockStmt.RangeStmt_10285.elem
Finder.stmt.BlockStmt.RangeStmt_14964.BlockStmt.RangeStmt_15030.cond
Finder.stmt.BlockStmt.RangeStmt_15482.cc
Finder.expr.BlockStmt.BlockStmt.RangeStmt_10029.elem
Finder.stmt.BlockStmt.RangeStmt_14628.s
Finder.msetcache
Finder.call.BlockStmt.RangeStmt_4659.arg
Finder.expr.BlockStmt.BlockStmt.RangeStmt_9784.elem
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_14314.result
Finder.call
Finder.call.sig
Finder.valueSpec.BlockStmt.RangeStmt_6966.BlockStmt.v
Finder.stmt.BlockStmt.BlockStmt.BlockStmt.val
ast
Finder.valueSpec.f
Finder.valueSpec.spec
Finder.expr.BlockStmt.BlockStmt.i
Finder.stmt.BlockStmt.RangeStmt_15808.s
Constraint
Finder.Find.files
Finder.valueSpec.T
Finder.stmt.BlockStmt.formals
Finder.call.BlockStmt.RangeStmt_5478.argtype
Finder.builtin.BlockStmt.BlockStmt.RangeStmt_6342.arg
Finder.valueSpec.BlockStmt.RangeStmt_6966.value
Finder.assign.f
Finder.typeAssert
Finder.stmt.BlockStmt.BlockStmt.i
typeparams
Finder.call.f
Finder.builtin.BlockStmt.BlockStmt.tElem
Finder.expr.BlockStmt.BlockStmt.tElem
Finder.Find.info
Finder.exprN.BlockStmt.x
Finder.call.BlockStmt.tElem
unparen.e
Finder.call.BlockStmt.RangeStmt_5289.argtype
Finder.builtin.BlockStmt.s
Finder.stmt.BlockStmt.RangeStmt_15482.BlockStmt.RangeStmt_15548.cond
Finder.stmt.BlockStmt.RangeStmt_14964.cc
Finder.stmt.BlockStmt.I
instance
instance.id
astutil
Finder.exprN.e
Finder.stmt.s
Finder.Find
Finder.builtin.BlockStmt.k
Finder.stmt.BlockStmt.ch
Finder.valueSpec.BlockStmt.tuple
Finder.compare.f
Finder.stmt.f
Finder.call.BlockStmt.RangeStmt_5147.arg
Finder.builtin.args
Finder.typeAssert.T
Finder.stmt.BlockStmt.val
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_13595.BlockStmt.lhs
coreType.T
Finder.builtin.f
Finder.builtin
Finder.typeAssert.I
Finder.call.BlockStmt.RangeStmt_4659.i
fmt
types
Finder.exprN
Finder.expr.BlockStmt.BlockStmt.x
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_13076.spec
Finder.stmt.BlockStmt.BlockStmt.tuple
Finder.call.argtypes
Finder.builtin.BlockStmt.RangeStmt_6020.arg
Finder.expr.e
Finder.stmt.BlockStmt.BlockStmt.RangeStmt_14314.i
Finder.Find.RangeStmt_3239.BlockStmt.RangeStmt_3270.d
Finder.assign.lhs
Finder.expr.BlockStmt.saved
Finder.stmt
Finder.stmt.BlockStmt.RangeStmt_15482.BlockStmt.RangeStmt_15688.s
Finder.valueSpec
Finder.expr.BlockStmt.BlockStmt.RangeStmt_9784.i
Finder.expr.BlockStmt.x
Members
X