GoPLS Viewer

Home|gopls/godoc/analysis/analysis.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 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.
42package analysis // import "golang.org/x/tools/godoc/analysis"
43
44import (
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.
54type Link interface {
55    Start() int
56    End() int
57    Write(w io.Writer_ intstart 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.
64type 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.
71type 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.
81func (fi *fileInfoget() FileInfo {
82    var r FileInfo
83    // Copy slices, to avoid races.
84    fi.mu.Lock()
85    r.Data = append(r.Datafi.data...)
86    if !fi.sorted {
87        sort.Sort(linksByStart(fi.links))
88        fi.sorted = true
89    }
90    r.Links = append(r.Linksfi.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.
97type PackageInfo struct {
98    CallGraph      []*PCGNodeJSON
99    CallGraphIndex map[string]int
100    Types          []*TypeInfoJSON
101}
102
103type 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.
112func (pi *pkgInfoget() PackageInfo {
113    var r PackageInfo
114    // Copy slices, to avoid races.
115    pi.mu.Lock()
116    r.CallGraph = append(r.CallGraphpi.callGraph...)
117    r.CallGraphIndex = pi.callGraphIndex
118    r.Types = append(r.Typespi.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.
128type 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.
137func (res *ResultfileInfo(url string) *fileInfo {
138    res.mu.Lock()
139    fiok := 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.
152func (res *ResultStatus() 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.
162func (res *ResultFileInfo(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.
168func (res *ResultpkgInfo(importPath string) *pkgInfo {
169    res.mu.Lock()
170    piok := 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.
186func (res *ResultPackageInfo(importPath stringPackageInfo {
187    return res.pkgInfo(importPath).get()
188}
189
190type linksByStart []Link
191
192func (a linksByStartLess(ij intbool { return a[i].Start() < a[j].Start() }
193func (a linksByStartSwap(ij int)      { a[i], a[j] = a[j], a[i] }
194func (a linksByStartLen() int           { return len(a) }
195
MembersX
linksByStart.Len
fileInfo.data
Result.pkgInfo.res
Result.pkgInfo.importPath
Result.PackageInfo.res
linksByStart.Less.j
linksByStart.Less.i
fileInfo.sorted
pkgInfo.callGraph
pkgInfo.callGraphIndex
Result.fileInfo.res
linksByStart
FileInfo
pkgInfo.get.r
fileInfo.get.fi
Result.FileInfo.res
Result.PackageInfo
linksByStart.Swap.a
fileInfo
Result.status
Result.pkgInfos
Result.FileInfo
Result.FileInfo.url
sort
PackageInfo.CallGraph
Result.mu
Result.pkgInfo
sync
FileInfo.Links
pkgInfo.types
Result.PackageInfo.importPath
fileInfo.get
Result.Status.res
linksByStart.Less.a
io
fileInfo.mu
fileInfo.hasErrors
pkgInfo.mu
linksByStart.Swap
Link
fileInfo.links
PackageInfo.CallGraphIndex
PackageInfo
Result.Status
linksByStart.Less
linksByStart.Swap.i
linksByStart.Len.a
pkgInfo
pkgInfo.get.pi
fileInfo.get.r
PackageInfo.Types
pkgInfo.get
Result.fileInfo.url
Result.FileInfo.fi
FileInfo.Data
Result
Result.fileInfos
Result.fileInfo
linksByStart.Swap.j
Members
X