func (g *Grapher) assignPaths(s *types.Scope, prefix []string, pkgscope bool) { g.scopePaths[s] = prefix for _, name := range s.Names() { e := s.Lookup(name) if _, seen := g.paths[e]; seen { continue } path := append(append([]string{}, prefix...), name) g.paths[e] = path g.exported[e] = ast.IsExported(name) && pkgscope g.pkgscope[e] = pkgscope if tn, ok := e.(*types.TypeName); ok { // methods named := tn.Type().(*types.Named) g.assignMethodPaths(named, path, pkgscope) // struct fields typ := derefType(tn.Type().Underlying()) if styp, ok := typ.(*types.Struct); ok { g.assignStructFieldPaths(styp, path, pkgscope) } } else if v, ok := e.(*types.Var); ok { // struct fields if type is anonymous struct if styp, ok := derefType(v.Type()).(*types.Struct); ok { g.assignStructFieldPaths(styp, path, pkgscope) } } } seenChildPrefixes := map[string]struct{}{} for i := 0; i < s.NumChildren(); i++ { c := s.Child(i) childPrefix := prefix pkgscope := pkgscope if path := g.scopePath(prefix, c); path != nil { childPrefix = append([]string{}, path...) pkgscope = false } if len(childPrefix) >= 1 { // Ensure all child prefixes are unique. This is an issue when you // have, for example: // func init() { x:=0;_=x};func init() { x:=0;_=x} // This is valid Go code but if we don't uniquify the two `x`s, they // will have the same paths. cp := strings.Join(childPrefix, "/") if _, seen := seenChildPrefixes[cp]; seen { childPrefix[len(childPrefix)-1] += fmt.Sprintf("$%d", i) } seenChildPrefixes[cp] = struct{}{} } g.assignPaths(c, childPrefix, pkgscope) } }