github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 package analysis // import "golang.org/x/tools/godoc/analysis" 43 44 import ( 45 "io" 46 "sort" 47 "sync" 48 ) 49 50 // -- links ------------------------------------------------------------ 51 52 // A Link is an HTML decoration of the bytes [Start, End) of a file. 53 // Write is called before/after those bytes to emit the mark-up. 54 type Link interface { 55 Start() int 56 End() int 57 Write(w io.Writer, _ int, start bool) // the godoc.LinkWriter signature 58 } 59 60 // -- fileInfo --------------------------------------------------------- 61 62 // FileInfo holds analysis information for the source file view. 63 // Clients must not mutate it. 64 type FileInfo struct { 65 Data []interface{} // JSON serializable values 66 Links []Link // HTML link markup 67 } 68 69 // A fileInfo is the server's store of hyperlinks and JSON data for a 70 // particular file. 71 type fileInfo struct { 72 mu sync.Mutex 73 data []interface{} // JSON objects 74 links []Link 75 sorted bool 76 hasErrors bool // TODO(adonovan): surface this in the UI 77 } 78 79 // get returns the file info in external form. 80 // Callers must not mutate its fields. 81 func (fi *fileInfo) get() FileInfo { 82 var r FileInfo 83 // Copy slices, to avoid races. 84 fi.mu.Lock() 85 r.Data = append(r.Data, fi.data...) 86 if !fi.sorted { 87 sort.Sort(linksByStart(fi.links)) 88 fi.sorted = true 89 } 90 r.Links = append(r.Links, fi.links...) 91 fi.mu.Unlock() 92 return r 93 } 94 95 // PackageInfo holds analysis information for the package view. 96 // Clients must not mutate it. 97 type PackageInfo struct { 98 CallGraph []*PCGNodeJSON 99 CallGraphIndex map[string]int 100 Types []*TypeInfoJSON 101 } 102 103 type pkgInfo struct { 104 mu sync.Mutex 105 callGraph []*PCGNodeJSON 106 callGraphIndex map[string]int // keys are (*ssa.Function).RelString() 107 types []*TypeInfoJSON // type info for exported types 108 } 109 110 // get returns the package info in external form. 111 // Callers must not mutate its fields. 112 func (pi *pkgInfo) get() PackageInfo { 113 var r PackageInfo 114 // Copy slices, to avoid races. 115 pi.mu.Lock() 116 r.CallGraph = append(r.CallGraph, pi.callGraph...) 117 r.CallGraphIndex = pi.callGraphIndex 118 r.Types = append(r.Types, pi.types...) 119 pi.mu.Unlock() 120 return r 121 } 122 123 // -- Result ----------------------------------------------------------- 124 125 // Result contains the results of analysis. 126 // The result contains a mapping from filenames to a set of HTML links 127 // and JavaScript data referenced by the links. 128 type Result struct { 129 mu sync.Mutex // guards maps (but not their contents) 130 status string // global analysis status 131 fileInfos map[string]*fileInfo // keys are godoc file URLs 132 pkgInfos map[string]*pkgInfo // keys are import paths 133 } 134 135 // fileInfo returns the fileInfo for the specified godoc file URL, 136 // constructing it as needed. Thread-safe. 137 func (res *Result) fileInfo(url string) *fileInfo { 138 res.mu.Lock() 139 fi, ok := res.fileInfos[url] 140 if !ok { 141 if res.fileInfos == nil { 142 res.fileInfos = make(map[string]*fileInfo) 143 } 144 fi = new(fileInfo) 145 res.fileInfos[url] = fi 146 } 147 res.mu.Unlock() 148 return fi 149 } 150 151 // Status returns a human-readable description of the current analysis status. 152 func (res *Result) Status() string { 153 res.mu.Lock() 154 defer res.mu.Unlock() 155 return res.status 156 } 157 158 // FileInfo returns new slices containing opaque JSON values and the 159 // HTML link markup for the specified godoc file URL. Thread-safe. 160 // Callers must not mutate the elements. 161 // It returns "zero" if no data is available. 162 func (res *Result) FileInfo(url string) (fi FileInfo) { 163 return res.fileInfo(url).get() 164 } 165 166 // pkgInfo returns the pkgInfo for the specified import path, 167 // constructing it as needed. Thread-safe. 168 func (res *Result) pkgInfo(importPath string) *pkgInfo { 169 res.mu.Lock() 170 pi, ok := res.pkgInfos[importPath] 171 if !ok { 172 if res.pkgInfos == nil { 173 res.pkgInfos = make(map[string]*pkgInfo) 174 } 175 pi = new(pkgInfo) 176 res.pkgInfos[importPath] = pi 177 } 178 res.mu.Unlock() 179 return pi 180 } 181 182 // PackageInfo returns new slices of JSON values for the callgraph and 183 // type info for the specified package. Thread-safe. 184 // Callers must not mutate its fields. 185 // PackageInfo returns "zero" if no data is available. 186 func (res *Result) PackageInfo(importPath string) PackageInfo { 187 return res.pkgInfo(importPath).get() 188 } 189 190 type linksByStart []Link 191 192 func (a linksByStart) Less(i, j int) bool { return a[i].Start() < a[j].Start() } 193 func (a linksByStart) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 194 func (a linksByStart) Len() int { return len(a) }