func (a *analysis) posURL(pos token.Pos, len int) string {
	if pos == token.NoPos {
		return ""
	}
	posn := a.prog.Fset.Position(pos)
	url := a.path2url[posn.Filename]
	return fmt.Sprintf("%s?s=%d:%d#L%d",
		url, posn.Offset, posn.Offset+len, posn.Line)
}
posURL returns the URL of the source extent [pos, pos+len).
package analysis  
import (
	"fmt"
	"go/build"
	"go/scanner"
	"go/token"
	"go/types"
	"html"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/pointer"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"
)
type Link interface {
	Start() int
	End() int
	Write(w io.Writer, _ int, start bool)  
}
type aLink struct {
	start, end int     
	title      string  
	onclick    string  
	href       string  
}
func (a aLink) Start() int { return a.start }
func (a aLink) End() int   { return a.end }
func (a aLink) Write(w io.Writer, _ int, start bool) {
	if start {
		fmt.Fprintf(w, `<a title='%s'`, html.EscapeString(a.title))
		if a.onclick != "" {
			fmt.Fprintf(w, ` onclick='%s'`, html.EscapeString(a.onclick))
		}
		if a.href != "" {
			fmt.Fprintf(w, ` href='%s'`, html.EscapeString(a.href))
		}
		fmt.Fprintf(w, ">")
	} else {
		fmt.Fprintf(w, "</a>")
	}
}
type errorLink struct {
	start int
	msg   string
}
func (e errorLink) Start() int { return e.start }
func (e errorLink) End() int   { return e.start + 1 }
func (e errorLink) Write(w io.Writer, _ int, start bool) {
	if start {
		fmt.Fprintf(w, `<a class='error' title='%s'>`, html.EscapeString(e.msg))
	} else {
		fmt.Fprintf(w, "</a>")
	}
}
type FileInfo struct {
	Data  []interface{}  
	Links []Link         
}
type fileInfo struct {
	mu        sync.Mutex
	data      []interface{}  
	links     []Link
	sorted    bool
	hasErrors bool  
}
func (fi *fileInfo) addLink(link Link) {
	fi.mu.Lock()
	fi.links = append(fi.links, link)
	fi.sorted = false
	if _, ok := link.(errorLink); ok {
		fi.hasErrors = true
	}
	fi.mu.Unlock()
}
func (fi *fileInfo) addData(x interface{}) int {
	fi.mu.Lock()
	index := len(fi.data)
	fi.data = append(fi.data, x)
	fi.mu.Unlock()
	return index
}
func (fi *fileInfo) get() FileInfo {
	var r FileInfo
	fi.mu.Lock()
	r.Data = append(r.Data, fi.data...)
	if !fi.sorted {
		sort.Sort(linksByStart(fi.links))
		fi.sorted = true
	}
	r.Links = append(r.Links, fi.links...)
	fi.mu.Unlock()
	return r
}
type PackageInfo struct {
	CallGraph      []*PCGNodeJSON
	CallGraphIndex map[string]int
	Types          []*TypeInfoJSON
}
type pkgInfo struct {
	mu             sync.Mutex
	callGraph      []*PCGNodeJSON
	callGraphIndex map[string]int   
	types          []*TypeInfoJSON  
}
func (pi *pkgInfo) setCallGraph(callGraph []*PCGNodeJSON, callGraphIndex map[string]int) {
	pi.mu.Lock()
	pi.callGraph = callGraph
	pi.callGraphIndex = callGraphIndex
	pi.mu.Unlock()
}
func (pi *pkgInfo) addType(t *TypeInfoJSON) {
	pi.mu.Lock()
	pi.types = append(pi.types, t)
	pi.mu.Unlock()
}
func (pi *pkgInfo) get() PackageInfo {
	var r PackageInfo
	pi.mu.Lock()
	r.CallGraph = append(r.CallGraph, pi.callGraph...)
	r.CallGraphIndex = pi.callGraphIndex
	r.Types = append(r.Types, pi.types...)
	pi.mu.Unlock()
	return r
}
type Result struct {
	mu        sync.Mutex            
	status    string                
	fileInfos map[string]*fileInfo  
	pkgInfos  map[string]*pkgInfo   
}
func (res *Result) fileInfo(url string) *fileInfo {
	res.mu.Lock()
	fi, ok := res.fileInfos[url]
	if !ok {
		if res.fileInfos == nil {
			res.fileInfos = make(map[string]*fileInfo)
		}
		fi = new(fileInfo)
		res.fileInfos[url] = fi
	}
	res.mu.Unlock()
	return fi
}
func (res *Result) Status() string {
	res.mu.Lock()
	defer res.mu.Unlock()
	return res.status
}
func (res *Result) setStatusf(format string, args ...interface{}) {
	res.mu.Lock()
	res.status = fmt.Sprintf(format, args...)
	log.Printf(format, args...)
	res.mu.Unlock()
}
func (res *Result) FileInfo(url string) (fi FileInfo) {
	return res.fileInfo(url).get()
}
func (res *Result) pkgInfo(importPath string) *pkgInfo {
	res.mu.Lock()
	pi, ok := res.pkgInfos[importPath]
	if !ok {
		if res.pkgInfos == nil {
			res.pkgInfos = make(map[string]*pkgInfo)
		}
		pi = new(pkgInfo)
		res.pkgInfos[importPath] = pi
	}
	res.mu.Unlock()
	return pi
}
func (res *Result) PackageInfo(importPath string) PackageInfo {
	return res.pkgInfo(importPath).get()
}
type analysis struct {
	result    *Result
	prog      *ssa.Program
	ops       []chanOp        
	allNamed  []*types.Named  
	ptaConfig pointer.Config
	path2url  map[string]string  
	pcgs      map[*ssa.Package]*packageCallGraph
}
func (a *analysis) fileAndOffset(pos token.Pos) (fi *fileInfo, offset int) {
	return a.fileAndOffsetPosn(a.prog.Fset.Position(pos))
}
func (a *analysis) fileAndOffsetPosn(posn token.Position) (fi *fileInfo, offset int) {
	url := a.path2url[posn.Filename]
	return a.result.fileInfo(url), posn.Offset
}