github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/godoc/analysis/analysis.go (about) 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 analysis performs type and pointer analysis 6 // and generates mark-up for the Go source view. 7 // 8 // The Run method populates a Result object by running type and 9 // (optionally) pointer analysis. The Result object is thread-safe 10 // and at all times may be accessed by a serving thread, even as it is 11 // progressively populated as analysis facts are derived. 12 // 13 // The Result is a mapping from each godoc file URL 14 // (e.g. /src/fmt/print.go) to information about that file. The 15 // information is a list of HTML markup links and a JSON array of 16 // structured data values. Some of the links call client-side 17 // JavaScript functions that index this array. 18 // 19 // The analysis computes mark-up for the following relations: 20 // 21 // IMPORTS: for each ast.ImportSpec, the package that it denotes. 22 // 23 // RESOLUTION: for each ast.Ident, its kind and type, and the location 24 // of its definition. 25 // 26 // METHOD SETS, IMPLEMENTS: for each ast.Ident defining a named type, 27 // its method-set, the set of interfaces it implements or is 28 // implemented by, and its size/align values. 29 // 30 // CALLERS, CALLEES: for each function declaration ('func' token), its 31 // callers, and for each call-site ('(' token), its callees. 32 // 33 // CALLGRAPH: the package docs include an interactive viewer for the 34 // intra-package call graph of "fmt". 35 // 36 // CHANNEL PEERS: for each channel operation make/<-/close, the set of 37 // other channel ops that alias the same channel(s). 38 // 39 // ERRORS: for each locus of a frontend (scanner/parser/type) error, the 40 // location is highlighted in red and hover text provides the compiler 41 // error message. 42 // 43 package analysis // import "github.com/powerman/golang-tools/godoc/analysis" 44 45 import ( 46 "io" 47 "sort" 48 "sync" 49 ) 50 51 // -- links ------------------------------------------------------------ 52 53 // A Link is an HTML decoration of the bytes [Start, End) of a file. 54 // Write is called before/after those bytes to emit the mark-up. 55 type Link interface { 56 Start() int 57 End() int 58 Write(w io.Writer, _ int, start bool) // the godoc.LinkWriter signature 59 } 60 61 // -- fileInfo --------------------------------------------------------- 62 63 // FileInfo holds analysis information for the source file view. 64 // Clients must not mutate it. 65 type FileInfo struct { 66 Data []interface{} // JSON serializable values 67 Links []Link // HTML link markup 68 } 69 70 // A fileInfo is the server's store of hyperlinks and JSON data for a 71 // particular file. 72 type fileInfo struct { 73 mu sync.Mutex 74 data []interface{} // JSON objects 75 links []Link 76 sorted bool 77 hasErrors bool // TODO(adonovan): surface this in the UI 78 } 79 80 // get returns the file info in external form. 81 // Callers must not mutate its fields. 82 func (fi *fileInfo) get() FileInfo { 83 var r FileInfo 84 // Copy slices, to avoid races. 85 fi.mu.Lock() 86 r.Data = append(r.Data, fi.data...) 87 if !fi.sorted { 88 sort.Sort(linksByStart(fi.links)) 89 fi.sorted = true 90 } 91 r.Links = append(r.Links, fi.links...) 92 fi.mu.Unlock() 93 return r 94 } 95 96 // PackageInfo holds analysis information for the package view. 97 // Clients must not mutate it. 98 type PackageInfo struct { 99 CallGraph []*PCGNodeJSON 100 CallGraphIndex map[string]int 101 Types []*TypeInfoJSON 102 } 103 104 type pkgInfo struct { 105 mu sync.Mutex 106 callGraph []*PCGNodeJSON 107 callGraphIndex map[string]int // keys are (*ssa.Function).RelString() 108 types []*TypeInfoJSON // type info for exported types 109 } 110 111 // get returns the package info in external form. 112 // Callers must not mutate its fields. 113 func (pi *pkgInfo) get() PackageInfo { 114 var r PackageInfo 115 // Copy slices, to avoid races. 116 pi.mu.Lock() 117 r.CallGraph = append(r.CallGraph, pi.callGraph...) 118 r.CallGraphIndex = pi.callGraphIndex 119 r.Types = append(r.Types, pi.types...) 120 pi.mu.Unlock() 121 return r 122 } 123 124 // -- Result ----------------------------------------------------------- 125 126 // Result contains the results of analysis. 127 // The result contains a mapping from filenames to a set of HTML links 128 // and JavaScript data referenced by the links. 129 type Result struct { 130 mu sync.Mutex // guards maps (but not their contents) 131 status string // global analysis status 132 fileInfos map[string]*fileInfo // keys are godoc file URLs 133 pkgInfos map[string]*pkgInfo // keys are import paths 134 } 135 136 // fileInfo returns the fileInfo for the specified godoc file URL, 137 // constructing it as needed. Thread-safe. 138 func (res *Result) fileInfo(url string) *fileInfo { 139 res.mu.Lock() 140 fi, ok := res.fileInfos[url] 141 if !ok { 142 if res.fileInfos == nil { 143 res.fileInfos = make(map[string]*fileInfo) 144 } 145 fi = new(fileInfo) 146 res.fileInfos[url] = fi 147 } 148 res.mu.Unlock() 149 return fi 150 } 151 152 // Status returns a human-readable description of the current analysis status. 153 func (res *Result) Status() string { 154 res.mu.Lock() 155 defer res.mu.Unlock() 156 return res.status 157 } 158 159 // FileInfo returns new slices containing opaque JSON values and the 160 // HTML link markup for the specified godoc file URL. Thread-safe. 161 // Callers must not mutate the elements. 162 // It returns "zero" if no data is available. 163 // 164 func (res *Result) FileInfo(url string) (fi FileInfo) { 165 return res.fileInfo(url).get() 166 } 167 168 // pkgInfo returns the pkgInfo for the specified import path, 169 // constructing it as needed. Thread-safe. 170 func (res *Result) pkgInfo(importPath string) *pkgInfo { 171 res.mu.Lock() 172 pi, ok := res.pkgInfos[importPath] 173 if !ok { 174 if res.pkgInfos == nil { 175 res.pkgInfos = make(map[string]*pkgInfo) 176 } 177 pi = new(pkgInfo) 178 res.pkgInfos[importPath] = pi 179 } 180 res.mu.Unlock() 181 return pi 182 } 183 184 // PackageInfo returns new slices of JSON values for the callgraph and 185 // type info for the specified package. Thread-safe. 186 // Callers must not mutate its fields. 187 // PackageInfo returns "zero" if no data is available. 188 // 189 func (res *Result) PackageInfo(importPath string) PackageInfo { 190 return res.pkgInfo(importPath).get() 191 } 192 193 type linksByStart []Link 194 195 func (a linksByStart) Less(i, j int) bool { return a[i].Start() < a[j].Start() } 196 func (a linksByStart) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 197 func (a linksByStart) Len() int { return len(a) }