...

Source file src/golang.org/x/tools/godoc/analysis/analysis.go

Documentation: golang.org/x/tools/godoc/analysis

     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) }
   195  

View as plain text