mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/guru: support streaming plain and -json output
Visible changes: - "referrers" queries now emit a stream of results, so they start appearing quickly even in large queries. We no longer report the total number of matches. - packageReferrers now also uses AfterTypeCheck hook and streaming. - XML support has been dropped. - The -format flag has been replaced by -json. JSON protocol changes: - The enclosing Result struct has been removed. - Likewise the 'mode' field (since the caller knows it already) - "freevars" and "referrers" now emit a stream of objects In the case of referrers, the first object has a different from the rest. - The "referrers" results include the text of the matching line (parity with -json=false) Implementation details: - the concurrency-safe q.Output function can be called many times, each with a queryResult to print. - fset is no longer saved in Query (cleaner) - queryResult methods renamed PrintPlain, JSON Change-Id: I41a4e3f57f266fcf043ece4045bca82c6f6a356f Reviewed-on: https://go-review.googlesource.com/21397 Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
13c24a6d6a
commit
2da0720e4f
@ -32,7 +32,6 @@ func callees(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
|
||||
if err != nil {
|
||||
@ -69,10 +68,10 @@ func callees(q *Query) error {
|
||||
return fmt.Errorf("this is a call to the built-in '%s' operator", obj.Name())
|
||||
case *types.Func:
|
||||
// This is a static function call
|
||||
q.result = &calleesTypesResult{
|
||||
q.Output(lprog.Fset, &calleesTypesResult{
|
||||
site: e,
|
||||
callee: obj,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
@ -83,10 +82,10 @@ func callees(q *Query) error {
|
||||
// or to top level function.
|
||||
callee := qpos.info.Uses[funexpr.Sel]
|
||||
if obj, ok := callee.(*types.Func); ok {
|
||||
q.result = &calleesTypesResult{
|
||||
q.Output(lprog.Fset, &calleesTypesResult{
|
||||
site: e,
|
||||
callee: obj,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
} else if sel.Kind() == types.MethodVal {
|
||||
@ -98,10 +97,10 @@ func callees(q *Query) error {
|
||||
recvtype := method.Type().(*types.Signature).Recv().Type()
|
||||
if !types.IsInterface(recvtype) {
|
||||
// static method call
|
||||
q.result = &calleesTypesResult{
|
||||
q.Output(lprog.Fset, &calleesTypesResult{
|
||||
site: e,
|
||||
callee: method,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -139,10 +138,10 @@ func callees(q *Query) error {
|
||||
return err
|
||||
}
|
||||
|
||||
q.result = &calleesSSAResult{
|
||||
q.Output(lprog.Fset, &calleesSSAResult{
|
||||
site: site,
|
||||
funcs: funcs,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -204,7 +203,7 @@ type calleesTypesResult struct {
|
||||
callee *types.Func
|
||||
}
|
||||
|
||||
func (r *calleesSSAResult) display(printf printfFunc) {
|
||||
func (r *calleesSSAResult) PrintPlain(printf printfFunc) {
|
||||
if len(r.funcs) == 0 {
|
||||
// dynamic call on a provably nil func/interface
|
||||
printf(r.site, "%s on nil value", r.site.Common().Description())
|
||||
@ -216,37 +215,37 @@ func (r *calleesSSAResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *calleesSSAResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *calleesSSAResult) JSON(fset *token.FileSet) []byte {
|
||||
j := &serial.Callees{
|
||||
Pos: fset.Position(r.site.Pos()).String(),
|
||||
Desc: r.site.Common().Description(),
|
||||
}
|
||||
for _, callee := range r.funcs {
|
||||
j.Callees = append(j.Callees, &serial.CalleesItem{
|
||||
j.Callees = append(j.Callees, &serial.Callee{
|
||||
Name: callee.String(),
|
||||
Pos: fset.Position(callee.Pos()).String(),
|
||||
})
|
||||
}
|
||||
res.Callees = j
|
||||
return toJSON(j)
|
||||
}
|
||||
|
||||
func (r *calleesTypesResult) display(printf printfFunc) {
|
||||
func (r *calleesTypesResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.site, "this static function call dispatches to:")
|
||||
printf(r.callee, "\t%s", r.callee.FullName())
|
||||
}
|
||||
|
||||
func (r *calleesTypesResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *calleesTypesResult) JSON(fset *token.FileSet) []byte {
|
||||
j := &serial.Callees{
|
||||
Pos: fset.Position(r.site.Pos()).String(),
|
||||
Desc: "static function call",
|
||||
}
|
||||
j.Callees = []*serial.CalleesItem{
|
||||
&serial.CalleesItem{
|
||||
j.Callees = []*serial.Callee{
|
||||
&serial.Callee{
|
||||
Name: r.callee.FullName(),
|
||||
Pos: fset.Position(r.callee.Pos()).String(),
|
||||
},
|
||||
}
|
||||
res.Callees = j
|
||||
return toJSON(j)
|
||||
}
|
||||
|
||||
// NB: byFuncPos is not deterministic across packages since it depends on load order.
|
||||
|
@ -31,7 +31,6 @@ func callers(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, false)
|
||||
if err != nil {
|
||||
@ -77,11 +76,11 @@ func callers(q *Query) error {
|
||||
|
||||
// TODO(adonovan): sort + dedup calls to ensure test determinism.
|
||||
|
||||
q.result = &callersResult{
|
||||
q.Output(lprog.Fset, &callersResult{
|
||||
target: target,
|
||||
callgraph: cg,
|
||||
edges: edges,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -167,7 +166,7 @@ type callersResult struct {
|
||||
edges []*callgraph.Edge
|
||||
}
|
||||
|
||||
func (r *callersResult) display(printf printfFunc) {
|
||||
func (r *callersResult) PrintPlain(printf printfFunc) {
|
||||
root := r.callgraph.Root
|
||||
if r.edges == nil {
|
||||
printf(r.target, "%s is not reachable in this program.", r.target)
|
||||
@ -183,7 +182,7 @@ func (r *callersResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *callersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *callersResult) JSON(fset *token.FileSet) []byte {
|
||||
var callers []serial.Caller
|
||||
for _, edge := range r.edges {
|
||||
callers = append(callers, serial.Caller{
|
||||
@ -192,5 +191,5 @@ func (r *callersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
Desc: edge.Description(),
|
||||
})
|
||||
}
|
||||
res.Callers = callers
|
||||
return toJSON(callers)
|
||||
}
|
||||
|
@ -96,12 +96,11 @@ func callstack(q *Query) error {
|
||||
}
|
||||
}
|
||||
|
||||
q.Fset = fset
|
||||
q.result = &callstackResult{
|
||||
q.Output(fset, &callstackResult{
|
||||
qpos: qpos,
|
||||
target: target,
|
||||
callpath: callpath,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -111,7 +110,7 @@ type callstackResult struct {
|
||||
callpath []*callgraph.Edge
|
||||
}
|
||||
|
||||
func (r *callstackResult) display(printf printfFunc) {
|
||||
func (r *callstackResult) PrintPlain(printf printfFunc) {
|
||||
if r.callpath != nil {
|
||||
printf(r.qpos, "Found a call path from root to %s", r.target)
|
||||
printf(r.target, "%s", r.target)
|
||||
@ -124,7 +123,7 @@ func (r *callstackResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *callstackResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *callstackResult) JSON(fset *token.FileSet) []byte {
|
||||
var callers []serial.Caller
|
||||
for i := len(r.callpath) - 1; i >= 0; i-- { // (innermost first)
|
||||
edge := r.callpath[i]
|
||||
@ -134,9 +133,9 @@ func (r *callstackResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
Desc: edge.Description(),
|
||||
})
|
||||
}
|
||||
res.Callstack = &serial.CallStack{
|
||||
return toJSON(&serial.CallStack{
|
||||
Pos: fset.Position(r.target.Pos()).String(),
|
||||
Target: r.target.String(),
|
||||
Callers: callers,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -31,11 +31,10 @@ func definition(q *Query) error {
|
||||
}
|
||||
|
||||
if obj := id.Obj; obj != nil && obj.Pos().IsValid() {
|
||||
q.Fset = qpos.fset
|
||||
q.result = &definitionResult{
|
||||
q.Output(qpos.fset, &definitionResult{
|
||||
pos: obj.Pos(),
|
||||
descr: fmt.Sprintf("%s %s", obj.Kind, obj.Name),
|
||||
}
|
||||
})
|
||||
return nil // success
|
||||
}
|
||||
}
|
||||
@ -53,7 +52,6 @@ func definition(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, false)
|
||||
if err != nil {
|
||||
@ -77,10 +75,10 @@ func definition(q *Query) error {
|
||||
return fmt.Errorf("%s is built in", obj.Name())
|
||||
}
|
||||
|
||||
q.result = &definitionResult{
|
||||
q.Output(lprog.Fset, &definitionResult{
|
||||
pos: obj.Pos(),
|
||||
descr: qpos.objectString(obj),
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -89,14 +87,13 @@ type definitionResult struct {
|
||||
descr string // description of object it denotes
|
||||
}
|
||||
|
||||
func (r *definitionResult) display(printf printfFunc) {
|
||||
func (r *definitionResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.pos, "defined here as %s", r.descr)
|
||||
}
|
||||
|
||||
func (r *definitionResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
definition := &serial.Definition{
|
||||
func (r *definitionResult) JSON(fset *token.FileSet) []byte {
|
||||
return toJSON(&serial.Definition{
|
||||
Desc: r.descr,
|
||||
ObjPos: fset.Position(r.pos).String(),
|
||||
}
|
||||
res.Definition = definition
|
||||
})
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ func describe(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, true) // (need exact pos)
|
||||
if err != nil {
|
||||
@ -52,43 +51,48 @@ func describe(q *Query) error {
|
||||
astutil.NodeDescription(qpos.path[0]), pathToString(qpos.path))
|
||||
}
|
||||
|
||||
var qr QueryResult
|
||||
path, action := findInterestingNode(qpos.info, qpos.path)
|
||||
switch action {
|
||||
case actionExpr:
|
||||
q.result, err = describeValue(qpos, path)
|
||||
qr, err = describeValue(qpos, path)
|
||||
|
||||
case actionType:
|
||||
q.result, err = describeType(qpos, path)
|
||||
qr, err = describeType(qpos, path)
|
||||
|
||||
case actionPackage:
|
||||
q.result, err = describePackage(qpos, path)
|
||||
qr, err = describePackage(qpos, path)
|
||||
|
||||
case actionStmt:
|
||||
q.result, err = describeStmt(qpos, path)
|
||||
qr, err = describeStmt(qpos, path)
|
||||
|
||||
case actionUnknown:
|
||||
q.result = &describeUnknownResult{path[0]}
|
||||
qr = &describeUnknownResult{path[0]}
|
||||
|
||||
default:
|
||||
panic(action) // unreachable
|
||||
}
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Output(lprog.Fset, qr)
|
||||
return nil
|
||||
}
|
||||
|
||||
type describeUnknownResult struct {
|
||||
node ast.Node
|
||||
}
|
||||
|
||||
func (r *describeUnknownResult) display(printf printfFunc) {
|
||||
func (r *describeUnknownResult) PrintPlain(printf printfFunc) {
|
||||
// Nothing much to say about misc syntax.
|
||||
printf(r.node, "%s", astutil.NodeDescription(r.node))
|
||||
}
|
||||
|
||||
func (r *describeUnknownResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
res.Describe = &serial.Describe{
|
||||
func (r *describeUnknownResult) JSON(fset *token.FileSet) []byte {
|
||||
return toJSON(&serial.Describe{
|
||||
Desc: astutil.NodeDescription(r.node),
|
||||
Pos: fset.Position(r.node.Pos()).String(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type action int
|
||||
@ -350,7 +354,7 @@ type describeValueResult struct {
|
||||
fields []describeField
|
||||
}
|
||||
|
||||
func (r *describeValueResult) display(printf printfFunc) {
|
||||
func (r *describeValueResult) PrintPlain(printf printfFunc) {
|
||||
var prefix, suffix string
|
||||
if r.constVal != nil {
|
||||
suffix = fmt.Sprintf(" of constant value %s", constValString(r.constVal))
|
||||
@ -393,7 +397,7 @@ func (r *describeValueResult) display(printf printfFunc) {
|
||||
printFields(printf, r.expr, r.fields)
|
||||
}
|
||||
|
||||
func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *describeValueResult) JSON(fset *token.FileSet) []byte {
|
||||
var value, objpos string
|
||||
if r.constVal != nil {
|
||||
value = r.constVal.String()
|
||||
@ -402,7 +406,7 @@ func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet)
|
||||
objpos = fset.Position(r.obj.Pos()).String()
|
||||
}
|
||||
|
||||
res.Describe = &serial.Describe{
|
||||
return toJSON(&serial.Describe{
|
||||
Desc: astutil.NodeDescription(r.expr),
|
||||
Pos: fset.Position(r.expr.Pos()).String(),
|
||||
Detail: "value",
|
||||
@ -411,7 +415,7 @@ func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet)
|
||||
Value: value,
|
||||
ObjPos: objpos,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---- TYPE ------------------------------------------------------------
|
||||
@ -519,11 +523,12 @@ func printFields(printf printfFunc, node ast.Node, fields []describeField) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *describeTypeResult) display(printf printfFunc) {
|
||||
func (r *describeTypeResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.node, "%s", r.description)
|
||||
|
||||
// Show the underlying type for a reference to a named type.
|
||||
if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
|
||||
// TODO(adonovan): improve display of complex struct/interface types.
|
||||
printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
|
||||
}
|
||||
|
||||
@ -540,13 +545,13 @@ func (r *describeTypeResult) display(printf printfFunc) {
|
||||
printFields(printf, r.node, r.fields)
|
||||
}
|
||||
|
||||
func (r *describeTypeResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *describeTypeResult) JSON(fset *token.FileSet) []byte {
|
||||
var namePos, nameDef string
|
||||
if nt, ok := r.typ.(*types.Named); ok {
|
||||
namePos = fset.Position(nt.Obj().Pos()).String()
|
||||
nameDef = nt.Underlying().String()
|
||||
}
|
||||
res.Describe = &serial.Describe{
|
||||
return toJSON(&serial.Describe{
|
||||
Desc: r.description,
|
||||
Pos: fset.Position(r.node.Pos()).String(),
|
||||
Detail: "type",
|
||||
@ -556,7 +561,7 @@ func (r *describeTypeResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
NameDef: nameDef,
|
||||
Methods: methodsToSerial(r.qpos.info.Pkg, r.methods, fset),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---- PACKAGE ------------------------------------------------------------
|
||||
@ -633,7 +638,7 @@ type describeMember struct {
|
||||
methods []*types.Selection // in types.MethodSet order
|
||||
}
|
||||
|
||||
func (r *describePackageResult) display(printf printfFunc) {
|
||||
func (r *describePackageResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.node, "%s", r.description)
|
||||
|
||||
// Compute max width of name "column".
|
||||
@ -700,7 +705,7 @@ func formatMember(obj types.Object, maxname int) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (r *describePackageResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *describePackageResult) JSON(fset *token.FileSet) []byte {
|
||||
var members []*serial.DescribeMember
|
||||
for _, mem := range r.members {
|
||||
typ := mem.obj.Type()
|
||||
@ -720,7 +725,7 @@ func (r *describePackageResult) toSerial(res *serial.Result, fset *token.FileSet
|
||||
Methods: methodsToSerial(r.pkg, mem.methods, fset),
|
||||
})
|
||||
}
|
||||
res.Describe = &serial.Describe{
|
||||
return toJSON(&serial.Describe{
|
||||
Desc: r.description,
|
||||
Pos: fset.Position(r.node.Pos()).String(),
|
||||
Detail: "package",
|
||||
@ -728,7 +733,7 @@ func (r *describePackageResult) toSerial(res *serial.Result, fset *token.FileSet
|
||||
Path: r.pkg.Path(),
|
||||
Members: members,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func tokenOf(o types.Object) string {
|
||||
@ -778,16 +783,16 @@ type describeStmtResult struct {
|
||||
description string
|
||||
}
|
||||
|
||||
func (r *describeStmtResult) display(printf printfFunc) {
|
||||
func (r *describeStmtResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.node, "%s", r.description)
|
||||
}
|
||||
|
||||
func (r *describeStmtResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
res.Describe = &serial.Describe{
|
||||
func (r *describeStmtResult) JSON(fset *token.FileSet) []byte {
|
||||
return toJSON(&serial.Describe{
|
||||
Desc: r.description,
|
||||
Pos: fset.Position(r.node.Pos()).String(),
|
||||
Detail: "unknown",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ------------------- Utilities -------------------
|
||||
|
@ -42,7 +42,6 @@ func freevars(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, false)
|
||||
if err != nil {
|
||||
@ -156,10 +155,10 @@ func freevars(q *Query) error {
|
||||
}
|
||||
sort.Sort(byRef(refs))
|
||||
|
||||
q.result = &freevarsResult{
|
||||
q.Output(lprog.Fset, &freevarsResult{
|
||||
qpos: qpos,
|
||||
refs: refs,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -175,7 +174,7 @@ type freevarsRef struct {
|
||||
obj types.Object
|
||||
}
|
||||
|
||||
func (r *freevarsResult) display(printf printfFunc) {
|
||||
func (r *freevarsResult) PrintPlain(printf printfFunc) {
|
||||
if len(r.refs) == 0 {
|
||||
printf(r.qpos, "No free identifiers.")
|
||||
} else {
|
||||
@ -192,18 +191,20 @@ func (r *freevarsResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *freevarsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
var refs []*serial.FreeVar
|
||||
for _, ref := range r.refs {
|
||||
refs = append(refs,
|
||||
&serial.FreeVar{
|
||||
Pos: fset.Position(ref.obj.Pos()).String(),
|
||||
Kind: ref.kind,
|
||||
Ref: ref.ref,
|
||||
Type: ref.typ.String(),
|
||||
})
|
||||
func (r *freevarsResult) JSON(fset *token.FileSet) []byte {
|
||||
var buf bytes.Buffer
|
||||
for i, ref := range r.refs {
|
||||
if i > 0 {
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
buf.Write(toJSON(serial.FreeVar{
|
||||
Pos: fset.Position(ref.obj.Pos()).String(),
|
||||
Kind: ref.kind,
|
||||
Ref: ref.ref,
|
||||
Type: ref.typ.String(),
|
||||
}))
|
||||
}
|
||||
res.Freevars = refs
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// -------- utils --------
|
||||
|
@ -301,11 +301,9 @@ function containing the current point."
|
||||
(defun go-guru-definition ()
|
||||
"Jump to the definition of the selected identifier."
|
||||
(interactive)
|
||||
;; TODO(adonovan): use -format=sexpr when available to avoid a
|
||||
;; dependency and to simplify parsing.
|
||||
(let* ((res (with-current-buffer (go-guru--exec "definition" nil '("-format=json"))
|
||||
(let* ((res (with-current-buffer (go-guru--exec "definition" nil '("-json"))
|
||||
(goto-char (point-min))
|
||||
(cdr (car (json-read)))))
|
||||
(json-read)))
|
||||
(desc (cdr (assoc 'desc res))))
|
||||
(push-mark)
|
||||
(ring-insert find-tag-marker-ring (point-marker))
|
||||
@ -360,11 +358,10 @@ expression (of type 'error') may refer."
|
||||
|
||||
(defun go-guru-what ()
|
||||
"Run a 'what' query and return the parsed JSON response as an
|
||||
associative list."
|
||||
(let ((res (with-current-buffer (go-guru--exec "what" nil '("-format=json") t)
|
||||
(goto-char (point-min))
|
||||
(cdr (car (json-read))))))
|
||||
res))
|
||||
association list."
|
||||
(with-current-buffer (go-guru--exec "what" nil '("-json") t)
|
||||
(goto-char (point-min))
|
||||
(json-read)))
|
||||
|
||||
(defun go-guru--hl-symbols (posn face id)
|
||||
"Highlight the symbols at the positions POSN by creating
|
||||
|
@ -11,6 +11,7 @@ package main
|
||||
// (&T{}, var t T, new(T), new(struct{array [3]T}), etc.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
@ -18,9 +19,9 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/tools/cmd/guru/serial"
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
"golang.org/x/tools/go/loader"
|
||||
@ -30,10 +31,15 @@ import (
|
||||
|
||||
type printfFunc func(pos interface{}, format string, args ...interface{})
|
||||
|
||||
// queryResult is the interface of each query-specific result type.
|
||||
type queryResult interface {
|
||||
toSerial(res *serial.Result, fset *token.FileSet)
|
||||
display(printf printfFunc)
|
||||
// A QueryResult is an item of output. Each query produces a stream of
|
||||
// query results, calling Query.Output for each one.
|
||||
type QueryResult interface {
|
||||
// JSON returns the QueryResult in JSON form.
|
||||
JSON(fset *token.FileSet) []byte
|
||||
|
||||
// PrintPlain prints the QueryResult in plain text form.
|
||||
// The implementation calls printfFunc to print each line of output.
|
||||
PrintPlain(printf printfFunc)
|
||||
}
|
||||
|
||||
// A QueryPos represents the position provided as input to a query:
|
||||
@ -65,7 +71,6 @@ func (qpos *queryPos) selectionString(sel *types.Selection) string {
|
||||
|
||||
// A Query specifies a single guru query.
|
||||
type Query struct {
|
||||
Mode string // query mode ("callers", etc)
|
||||
Pos string // query position
|
||||
Build *build.Context // package loading configuration
|
||||
|
||||
@ -74,32 +79,13 @@ type Query struct {
|
||||
PTALog io.Writer // (optional) pointer-analysis log file
|
||||
Reflection bool // model reflection soundly (currently slow).
|
||||
|
||||
// Populated during Run()
|
||||
Fset *token.FileSet
|
||||
result queryResult
|
||||
}
|
||||
|
||||
// Serial returns an instance of serial.Result, which implements the
|
||||
// {xml,json}.Marshaler interfaces so that query results can be
|
||||
// serialized as JSON or XML.
|
||||
//
|
||||
func (q *Query) Serial() *serial.Result {
|
||||
resj := &serial.Result{Mode: q.Mode}
|
||||
q.result.toSerial(resj, q.Fset)
|
||||
return resj
|
||||
}
|
||||
|
||||
// WriteTo writes the guru query result res to out in a compiler diagnostic format.
|
||||
func (q *Query) WriteTo(out io.Writer) {
|
||||
printf := func(pos interface{}, format string, args ...interface{}) {
|
||||
fprintf(out, q.Fset, pos, format, args...)
|
||||
}
|
||||
q.result.display(printf)
|
||||
// result-printing function
|
||||
Output func(*token.FileSet, QueryResult)
|
||||
}
|
||||
|
||||
// Run runs an guru query and populates its Fset and Result.
|
||||
func Run(q *Query) error {
|
||||
switch q.Mode {
|
||||
func Run(mode string, q *Query) error {
|
||||
switch mode {
|
||||
case "callees":
|
||||
return callees(q)
|
||||
case "callers":
|
||||
@ -125,7 +111,7 @@ func Run(q *Query) error {
|
||||
case "what":
|
||||
return what(q)
|
||||
default:
|
||||
return fmt.Errorf("invalid mode: %q", q.Mode)
|
||||
return fmt.Errorf("invalid mode: %q", mode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,7 +305,6 @@ func deref(typ types.Type) types.Type {
|
||||
//
|
||||
// The output format is is compatible with the 'gnu'
|
||||
// compilation-error-regexp in Emacs' compilation mode.
|
||||
// TODO(adonovan): support other editors.
|
||||
//
|
||||
func fprintf(w io.Writer, fset *token.FileSet, pos interface{}, format string, args ...interface{}) {
|
||||
var start, end token.Pos
|
||||
@ -360,3 +345,11 @@ func fprintf(w io.Writer, fset *token.FileSet, pos interface{}, format string, a
|
||||
fmt.Fprintf(w, format, args...)
|
||||
io.WriteString(w, "\n")
|
||||
}
|
||||
|
||||
func toJSON(x interface{}) []byte {
|
||||
b, err := json.MarshalIndent(x, "", "\t")
|
||||
if err != nil {
|
||||
log.Fatalf("JSON error: %v", err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
@ -41,8 +40,10 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
guru "golang.org/x/tools/cmd/guru"
|
||||
@ -150,51 +151,53 @@ func parseQueries(t *testing.T, filename string) []*query {
|
||||
return queries
|
||||
}
|
||||
|
||||
// WriteResult writes res (-format=plain) to w, stripping file locations.
|
||||
func WriteResult(w io.Writer, q *guru.Query) {
|
||||
capture := new(bytes.Buffer) // capture standard output
|
||||
q.WriteTo(capture)
|
||||
for _, line := range strings.Split(capture.String(), "\n") {
|
||||
// Remove a "file:line: " prefix.
|
||||
if i := strings.Index(line, ": "); i >= 0 {
|
||||
line = line[i+2:]
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", line)
|
||||
}
|
||||
}
|
||||
|
||||
// doQuery poses query q to the guru and writes its response and
|
||||
// error (if any) to out.
|
||||
func doQuery(out io.Writer, q *query, useJson bool) {
|
||||
func doQuery(out io.Writer, q *query, json bool) {
|
||||
fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id)
|
||||
|
||||
var buildContext = build.Default
|
||||
buildContext.GOPATH = "testdata"
|
||||
pkg := filepath.Dir(strings.TrimPrefix(q.filename, "testdata/src/"))
|
||||
|
||||
var outputMu sync.Mutex // guards out, jsons
|
||||
var jsons []string
|
||||
output := func(fset *token.FileSet, qr guru.QueryResult) {
|
||||
outputMu.Lock()
|
||||
defer outputMu.Unlock()
|
||||
if json {
|
||||
jsons = append(jsons, string(qr.JSON(fset)))
|
||||
} else {
|
||||
// suppress position information
|
||||
qr.PrintPlain(func(_ interface{}, format string, args ...interface{}) {
|
||||
fmt.Fprintf(out, format, args...)
|
||||
io.WriteString(out, "\n")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
query := guru.Query{
|
||||
Mode: q.verb,
|
||||
Pos: q.queryPos,
|
||||
Build: &buildContext,
|
||||
Scope: []string{pkg},
|
||||
Reflection: true,
|
||||
Output: output,
|
||||
}
|
||||
if err := guru.Run(&query); err != nil {
|
||||
|
||||
if err := guru.Run(q.verb, &query); err != nil {
|
||||
fmt.Fprintf(out, "\nError: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if useJson {
|
||||
// JSON output
|
||||
b, err := json.MarshalIndent(query.Serial(), "", "\t")
|
||||
if err != nil {
|
||||
fmt.Fprintf(out, "JSON error: %s\n", err.Error())
|
||||
return
|
||||
if json {
|
||||
if q.verb == "referrers" {
|
||||
sort.Strings(jsons[1:]) // for determinism
|
||||
}
|
||||
for _, json := range jsons {
|
||||
fmt.Fprintf(out, "%s\n", json)
|
||||
}
|
||||
out.Write(b)
|
||||
fmt.Fprintln(out)
|
||||
} else {
|
||||
// "plain" (compiler diagnostic format) output
|
||||
WriteResult(out, &query)
|
||||
io.WriteString(out, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +233,7 @@ func TestGuru(t *testing.T) {
|
||||
"testdata/src/referrers-json/main.go",
|
||||
"testdata/src/what-json/main.go",
|
||||
} {
|
||||
useJson := strings.Contains(filename, "-json/")
|
||||
json := strings.Contains(filename, "-json/")
|
||||
queries := parseQueries(t, filename)
|
||||
golden := filename + "lden"
|
||||
got := filename + "t"
|
||||
@ -245,7 +248,7 @@ func TestGuru(t *testing.T) {
|
||||
// Run the guru on each query, redirecting its output
|
||||
// and error (if any) to the foo.got file.
|
||||
for _, q := range queries {
|
||||
doQuery(gotfh, q, useJson)
|
||||
doQuery(gotfh, q, json)
|
||||
}
|
||||
|
||||
// Compare foo.got with foo.golden.
|
||||
@ -277,11 +280,10 @@ func TestIssue14684(t *testing.T) {
|
||||
var buildContext = build.Default
|
||||
buildContext.GOPATH = "testdata"
|
||||
query := guru.Query{
|
||||
Mode: "freevars",
|
||||
Pos: "testdata/src/README.txt:#1",
|
||||
Build: &buildContext,
|
||||
}
|
||||
err := guru.Run(&query)
|
||||
err := guru.Run("freevars", &query)
|
||||
if err == nil {
|
||||
t.Fatal("guru query succeeded unexpectedly")
|
||||
}
|
||||
|
@ -63,7 +63,6 @@ func implements(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, false)
|
||||
if err != nil {
|
||||
@ -179,9 +178,9 @@ func implements(q *Query) error {
|
||||
}
|
||||
}
|
||||
|
||||
q.result = &implementsResult{
|
||||
q.Output(lprog.Fset, &implementsResult{
|
||||
qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -201,7 +200,7 @@ type implementsResult struct {
|
||||
fromPtrMethod []*types.Selection // method of type fromPtrMethod[i], if any
|
||||
}
|
||||
|
||||
func (r *implementsResult) display(printf printfFunc) {
|
||||
func (r *implementsResult) PrintPlain(printf printfFunc) {
|
||||
relation := "is implemented by"
|
||||
|
||||
meth := func(sel *types.Selection) {
|
||||
@ -298,8 +297,15 @@ func (r *implementsResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
res.Implements = &serial.Implements{
|
||||
func (r *implementsResult) JSON(fset *token.FileSet) []byte {
|
||||
var method *serial.DescribeMethod
|
||||
if r.method != nil {
|
||||
method = &serial.DescribeMethod{
|
||||
Name: r.qpos.objectString(r.method),
|
||||
Pos: fset.Position(r.method.Pos()).String(),
|
||||
}
|
||||
}
|
||||
return toJSON(&serial.Implements{
|
||||
T: makeImplementsType(r.t, fset),
|
||||
AssignableTo: makeImplementsTypes(r.to, fset),
|
||||
AssignableFrom: makeImplementsTypes(r.from, fset),
|
||||
@ -307,13 +313,9 @@ func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
AssignableToMethod: methodsToSerial(r.qpos.info.Pkg, r.toMethod, fset),
|
||||
AssignableFromMethod: methodsToSerial(r.qpos.info.Pkg, r.fromMethod, fset),
|
||||
AssignableFromPtrMethod: methodsToSerial(r.qpos.info.Pkg, r.fromPtrMethod, fset),
|
||||
}
|
||||
if r.method != nil {
|
||||
res.Implements.Method = &serial.DescribeMethod{
|
||||
Name: r.qpos.objectString(r.method),
|
||||
Pos: fset.Position(r.method.Pos()).String(),
|
||||
}
|
||||
}
|
||||
Method: method,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func makeImplementsTypes(tt []types.Type, fset *token.FileSet) []serial.ImplementsType {
|
||||
|
@ -14,11 +14,10 @@ package main // import "golang.org/x/tools/cmd/guru"
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -27,6 +26,7 @@ import (
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
)
|
||||
@ -36,7 +36,7 @@ var (
|
||||
modifiedFlag = flag.Bool("modified", false, "read archive of modified files from standard input")
|
||||
scopeFlag = flag.String("scope", "", "comma-separated list of `packages` the analysis should be limited to")
|
||||
ptalogFlag = flag.String("ptalog", "", "write points-to analysis log to `file`")
|
||||
formatFlag = flag.String("format", "plain", "output `format`; one of {plain,json,xml}")
|
||||
jsonFlag = flag.Bool("json", false, "emit output in JSON format")
|
||||
reflectFlag = flag.Bool("reflect", false, "analyze reflection soundly (slow)")
|
||||
cpuprofileFlag = flag.String("cpuprofile", "", "write CPU profile to `file`")
|
||||
)
|
||||
@ -71,11 +71,10 @@ of the syntax element to query. For example:
|
||||
foo.go:#123,#128
|
||||
bar.go:#123
|
||||
|
||||
The -format flag controls the output format:
|
||||
plain an editor-friendly format in which every line of output
|
||||
is of the form "pos: text", where pos is "-" if unknown.
|
||||
json structured data in JSON syntax.
|
||||
xml structured data in XML syntax.
|
||||
The -json flag causes guru to emit output in JSON format;
|
||||
golang.org/x/tools/cmd/guru/serial defines its schema.
|
||||
Otherwise, the output is in an editor-friendly format in which
|
||||
every line has the form "pos: text", where pos is "-" if unknown.
|
||||
|
||||
The -modified flag causes guru to read an archive from standard input.
|
||||
Files in this archive will be used in preference to those in
|
||||
@ -163,14 +162,6 @@ func main() {
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
// -format flag
|
||||
switch *formatFlag {
|
||||
case "json", "plain", "xml":
|
||||
// ok
|
||||
default:
|
||||
log.Fatalf("illegal -format value: %q.\n"+useHelp, *formatFlag)
|
||||
}
|
||||
|
||||
ctxt := &build.Default
|
||||
|
||||
// If there were modified files,
|
||||
@ -191,39 +182,35 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
var outputMu sync.Mutex
|
||||
output := func(fset *token.FileSet, qr QueryResult) {
|
||||
outputMu.Lock()
|
||||
defer outputMu.Unlock()
|
||||
if *jsonFlag {
|
||||
// JSON output
|
||||
fmt.Printf("%s\n", qr.JSON(fset))
|
||||
} else {
|
||||
// plain output
|
||||
printf := func(pos interface{}, format string, args ...interface{}) {
|
||||
fprintf(os.Stdout, fset, pos, format, args...)
|
||||
}
|
||||
qr.PrintPlain(printf)
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the guru.
|
||||
query := Query{
|
||||
Mode: mode,
|
||||
Pos: posn,
|
||||
Build: ctxt,
|
||||
Scope: strings.Split(*scopeFlag, ","),
|
||||
PTALog: ptalog,
|
||||
Reflection: *reflectFlag,
|
||||
Output: output,
|
||||
}
|
||||
|
||||
if err := Run(&query); err != nil {
|
||||
if err := Run(mode, &query); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Print the result.
|
||||
switch *formatFlag {
|
||||
case "json":
|
||||
b, err := json.MarshalIndent(query.Serial(), "", "\t")
|
||||
if err != nil {
|
||||
log.Fatalf("JSON error: %s", err)
|
||||
}
|
||||
os.Stdout.Write(b)
|
||||
|
||||
case "xml":
|
||||
b, err := xml.MarshalIndent(query.Serial(), "", "\t")
|
||||
if err != nil {
|
||||
log.Fatalf("XML error: %s", err)
|
||||
}
|
||||
os.Stdout.Write(b)
|
||||
|
||||
case "plain":
|
||||
query.WriteTo(os.Stdout)
|
||||
}
|
||||
}
|
||||
|
||||
func parseArchive(archive io.Reader) (map[string][]byte, error) {
|
||||
|
@ -35,7 +35,6 @@ func peers(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, false)
|
||||
if err != nil {
|
||||
@ -127,14 +126,14 @@ func peers(q *Query) error {
|
||||
sort.Sort(byPos(receives))
|
||||
sort.Sort(byPos(closes))
|
||||
|
||||
q.result = &peersResult{
|
||||
q.Output(lprog.Fset, &peersResult{
|
||||
queryPos: opPos,
|
||||
queryType: queryType,
|
||||
makes: makes,
|
||||
sends: sends,
|
||||
receives: receives,
|
||||
closes: closes,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -195,13 +194,14 @@ func chanOps(instr ssa.Instruction) []chanOp {
|
||||
return ops
|
||||
}
|
||||
|
||||
// TODO(adonovan): show the line of text for each pos, like "referrers" does.
|
||||
type peersResult struct {
|
||||
queryPos token.Pos // of queried channel op
|
||||
queryType types.Type // type of queried channel
|
||||
makes, sends, receives, closes []token.Pos // positions of aliased makechan/send/receive/close instrs
|
||||
}
|
||||
|
||||
func (r *peersResult) display(printf printfFunc) {
|
||||
func (r *peersResult) PrintPlain(printf printfFunc) {
|
||||
if len(r.makes) == 0 {
|
||||
printf(r.queryPos, "This channel can't point to anything.")
|
||||
return
|
||||
@ -221,7 +221,7 @@ func (r *peersResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *peersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *peersResult) JSON(fset *token.FileSet) []byte {
|
||||
peers := &serial.Peers{
|
||||
Pos: fset.Position(r.queryPos).String(),
|
||||
Type: r.queryType.String(),
|
||||
@ -238,7 +238,7 @@ func (r *peersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
for _, clos := range r.closes {
|
||||
peers.Closes = append(peers.Closes, fset.Position(clos).String())
|
||||
}
|
||||
res.Peers = peers
|
||||
return toJSON(peers)
|
||||
}
|
||||
|
||||
// -------- utils --------
|
||||
|
@ -38,7 +38,6 @@ func pointsto(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
|
||||
if err != nil {
|
||||
@ -103,11 +102,11 @@ func pointsto(q *Query) error {
|
||||
return err // e.g. analytically unreachable
|
||||
}
|
||||
|
||||
q.result = &pointstoResult{
|
||||
q.Output(lprog.Fset, &pointstoResult{
|
||||
qpos: qpos,
|
||||
typ: typ,
|
||||
ptrs: ptrs,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -209,7 +208,7 @@ type pointstoResult struct {
|
||||
ptrs []pointerResult // pointer info (typ is concrete => len==1)
|
||||
}
|
||||
|
||||
func (r *pointstoResult) display(printf printfFunc) {
|
||||
func (r *pointstoResult) PrintPlain(printf printfFunc) {
|
||||
if pointer.CanHaveDynamicTypes(r.typ) {
|
||||
// Show concrete types for interface, reflect.Type or
|
||||
// reflect.Value expression.
|
||||
@ -244,7 +243,7 @@ func (r *pointstoResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *pointstoResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *pointstoResult) JSON(fset *token.FileSet) []byte {
|
||||
var pts []serial.PointsTo
|
||||
for _, ptr := range r.ptrs {
|
||||
var namePos string
|
||||
@ -264,7 +263,7 @@ func (r *pointstoResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
res.PointsTo = pts
|
||||
return toJSON(pts)
|
||||
}
|
||||
|
||||
type byTypeString []pointerResult
|
||||
|
@ -82,17 +82,13 @@ func referrers(q *Query) error {
|
||||
return globalReferrers(q, qpos.info.Pkg.Path(), defpkg, objposn, pkglevel)
|
||||
}
|
||||
|
||||
// Find uses of obj within the query package.
|
||||
refs := usesOf(obj, qpos.info)
|
||||
sort.Sort(byNamePos{fset, refs})
|
||||
q.Fset = fset
|
||||
q.result = &referrersResult{
|
||||
build: q.Build,
|
||||
fset: fset,
|
||||
q.Output(fset, &referrersInitialResult{
|
||||
qinfo: qpos.info,
|
||||
obj: obj,
|
||||
refs: refs,
|
||||
}
|
||||
})
|
||||
|
||||
outputUses(q, fset, usesOf(obj, qpos.info), obj.Pkg())
|
||||
|
||||
return nil // success
|
||||
}
|
||||
|
||||
@ -113,8 +109,8 @@ func classify(obj types.Object) (global, pkglevel bool) {
|
||||
return false, false
|
||||
}
|
||||
|
||||
// packageReferrers finds all references to the specified package
|
||||
// throughout the workspace and populates q.result.
|
||||
// packageReferrers reports all references to the specified package
|
||||
// throughout the workspace.
|
||||
func packageReferrers(q *Query, path string) error {
|
||||
// Scan the workspace and build the import graph.
|
||||
// Ignore broken packages.
|
||||
@ -134,34 +130,86 @@ func packageReferrers(q *Query, path string) error {
|
||||
},
|
||||
}
|
||||
allowErrors(&lconf)
|
||||
|
||||
// The importgraph doesn't treat external test packages
|
||||
// as separate nodes, so we must use ImportWithTests.
|
||||
for path := range users {
|
||||
lconf.ImportWithTests(path)
|
||||
}
|
||||
lprog, err := lconf.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
// Subtle! AfterTypeCheck needs no mutex for qpkg because the
|
||||
// topological import order gives us the necessary happens-before edges.
|
||||
// TODO(adonovan): what about import cycles?
|
||||
var qpkg *types.Package
|
||||
|
||||
// For efficiency, we scan each package for references
|
||||
// just after it has been type-checked. The loader calls
|
||||
// AfterTypeCheck (concurrently), providing us with a stream of
|
||||
// packages.
|
||||
lconf.AfterTypeCheck = func(info *loader.PackageInfo, files []*ast.File) {
|
||||
// AfterTypeCheck may be called twice for the same package due to augmentation.
|
||||
|
||||
if info.Pkg.Path() == path && qpkg == nil {
|
||||
// Found the package of interest.
|
||||
qpkg = info.Pkg
|
||||
fakepkgname := types.NewPkgName(token.NoPos, qpkg, qpkg.Name(), qpkg)
|
||||
q.Output(fset, &referrersInitialResult{
|
||||
qinfo: info,
|
||||
obj: fakepkgname, // bogus
|
||||
})
|
||||
}
|
||||
|
||||
// Only inspect packages that directly import the
|
||||
// declaring package (and thus were type-checked).
|
||||
if lconf.TypeCheckFuncBodies(info.Pkg.Path()) {
|
||||
// Find PkgNames that refer to qpkg.
|
||||
// TODO(adonovan): perhaps more useful would be to show imports
|
||||
// of the package instead of qualified identifiers.
|
||||
var refs []*ast.Ident
|
||||
for id, obj := range info.Uses {
|
||||
if obj, ok := obj.(*types.PkgName); ok && obj.Imported() == qpkg {
|
||||
refs = append(refs, id)
|
||||
}
|
||||
}
|
||||
outputUses(q, fset, refs, info.Pkg)
|
||||
}
|
||||
|
||||
clearInfoFields(info) // save memory
|
||||
}
|
||||
|
||||
// Find uses of [a fake PkgName that imports] the package.
|
||||
//
|
||||
// TODO(adonovan): perhaps more useful would be to show imports
|
||||
// of the package instead of qualified identifiers.
|
||||
qinfo := lprog.Package(path)
|
||||
obj := types.NewPkgName(token.NoPos, qinfo.Pkg, qinfo.Pkg.Name(), qinfo.Pkg)
|
||||
refs := usesOf(obj, lprog.InitialPackages()...)
|
||||
sort.Sort(byNamePos{fset, refs})
|
||||
q.Fset = fset
|
||||
q.result = &referrersResult{
|
||||
build: q.Build,
|
||||
fset: fset,
|
||||
qinfo: qinfo,
|
||||
obj: obj,
|
||||
refs: refs,
|
||||
lconf.Load() // ignore error
|
||||
|
||||
if qpkg == nil {
|
||||
log.Fatalf("query package %q not found during reloading", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// globalReferrers finds references throughout the entire workspace to the
|
||||
func usesOf(queryObj types.Object, info *loader.PackageInfo) []*ast.Ident {
|
||||
var refs []*ast.Ident
|
||||
for id, obj := range info.Uses {
|
||||
if sameObj(queryObj, obj) {
|
||||
refs = append(refs, id)
|
||||
}
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
// outputUses outputs a result describing refs, which appear in the package denoted by info.
|
||||
func outputUses(q *Query, fset *token.FileSet, refs []*ast.Ident, pkg *types.Package) {
|
||||
if len(refs) > 0 {
|
||||
sort.Sort(byNamePos{fset, refs})
|
||||
q.Output(fset, &referrersPackageResult{
|
||||
pkg: pkg,
|
||||
build: q.Build,
|
||||
fset: fset,
|
||||
refs: refs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// globalReferrers reports references throughout the entire workspace to the
|
||||
// object at the specified source position. Its defining package is defpkg,
|
||||
// and the query package is qpkg. isPkgLevel indicates whether the object
|
||||
// is defined at package-level.
|
||||
@ -207,6 +255,11 @@ func globalReferrers(q *Query, qpkg, defpkg string, objposn token.Position, isPk
|
||||
// so we can't use them here.
|
||||
// TODO(adonovan): smooth things out once the other changes have landed.
|
||||
|
||||
// Results are reported concurrently from within the
|
||||
// AfterTypeCheck hook. The program may provide a useful stream
|
||||
// of information even if the user doesn't let the program run
|
||||
// to completion.
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
qobj types.Object
|
||||
@ -217,8 +270,9 @@ func globalReferrers(q *Query, qpkg, defpkg string, objposn token.Position, isPk
|
||||
// just after it has been type-checked. The loader calls
|
||||
// AfterTypeCheck (concurrently), providing us with a stream of
|
||||
// packages.
|
||||
ch := make(chan []*ast.Ident)
|
||||
lconf.AfterTypeCheck = func(info *loader.PackageInfo, files []*ast.File) {
|
||||
// AfterTypeCheck may be called twice for the same package due to augmentation.
|
||||
|
||||
// Only inspect packages that depend on the declaring package
|
||||
// (and thus were type-checked).
|
||||
if lconf.TypeCheckFuncBodies(info.Pkg.Path()) {
|
||||
@ -233,66 +287,32 @@ func globalReferrers(q *Query, qpkg, defpkg string, objposn token.Position, isPk
|
||||
log.Fatalf("object at %s not found in package %s",
|
||||
objposn, defpkg)
|
||||
}
|
||||
|
||||
// Object found.
|
||||
qinfo = info
|
||||
q.Output(fset, &referrersInitialResult{
|
||||
qinfo: qinfo,
|
||||
obj: qobj,
|
||||
})
|
||||
}
|
||||
obj := qobj
|
||||
mu.Unlock()
|
||||
|
||||
// Look for references to the query object.
|
||||
if obj != nil {
|
||||
ch <- usesOf(obj, info)
|
||||
outputUses(q, fset, usesOf(obj, info), info.Pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(adonovan): opt: save memory by eliminating unneeded scopes/objects.
|
||||
// (Requires go/types change for Go 1.7.)
|
||||
// info.Pkg.Scope().ClearChildren()
|
||||
|
||||
// Discard the file ASTs and their accumulated type
|
||||
// information to save memory.
|
||||
info.Files = nil
|
||||
info.Defs = make(map[*ast.Ident]types.Object)
|
||||
info.Uses = make(map[*ast.Ident]types.Object)
|
||||
info.Implicits = make(map[ast.Node]types.Object)
|
||||
|
||||
// Also, disable future collection of wholly unneeded
|
||||
// type information for the package in case there is
|
||||
// more type-checking to do (augmentation).
|
||||
info.Types = nil
|
||||
info.Scopes = nil
|
||||
info.Selections = nil
|
||||
clearInfoFields(info) // save memory
|
||||
}
|
||||
|
||||
go func() {
|
||||
lconf.Load() // ignore error
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
var refs []*ast.Ident
|
||||
for ids := range ch {
|
||||
refs = append(refs, ids...)
|
||||
}
|
||||
sort.Sort(byNamePos{fset, refs})
|
||||
lconf.Load() // ignore error
|
||||
|
||||
if qobj == nil {
|
||||
log.Fatal("query object not found during reloading")
|
||||
}
|
||||
|
||||
// TODO(adonovan): in a follow-up, do away with the
|
||||
// analyze/display split so we can print a stream of output
|
||||
// directly from the AfterTypeCheck hook.
|
||||
// (We should not assume that users let the program run long
|
||||
// enough for Load to return.)
|
||||
|
||||
q.Fset = fset
|
||||
q.result = &referrersResult{
|
||||
build: q.Build,
|
||||
fset: fset,
|
||||
qinfo: qinfo,
|
||||
obj: qobj,
|
||||
refs: refs,
|
||||
}
|
||||
|
||||
return nil // success
|
||||
}
|
||||
|
||||
@ -318,20 +338,6 @@ func findObject(fset *token.FileSet, info *types.Info, objposn token.Position) t
|
||||
return nil
|
||||
}
|
||||
|
||||
// usesOf returns all identifiers in the packages denoted by infos
|
||||
// that refer to queryObj.
|
||||
func usesOf(queryObj types.Object, infos ...*loader.PackageInfo) []*ast.Ident {
|
||||
var refs []*ast.Ident
|
||||
for _, info := range infos {
|
||||
for id, obj := range info.Uses {
|
||||
if sameObj(queryObj, obj) {
|
||||
refs = append(refs, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
// same reports whether x and y are identical, or both are PkgNames
|
||||
// that import the same Package.
|
||||
//
|
||||
@ -347,6 +353,26 @@ func sameObj(x, y types.Object) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func clearInfoFields(info *loader.PackageInfo) {
|
||||
// TODO(adonovan): opt: save memory by eliminating unneeded scopes/objects.
|
||||
// (Requires go/types change for Go 1.7.)
|
||||
// info.Pkg.Scope().ClearChildren()
|
||||
|
||||
// Discard the file ASTs and their accumulated type
|
||||
// information to save memory.
|
||||
info.Files = nil
|
||||
info.Defs = make(map[*ast.Ident]types.Object)
|
||||
info.Uses = make(map[*ast.Ident]types.Object)
|
||||
info.Implicits = make(map[ast.Node]types.Object)
|
||||
|
||||
// Also, disable future collection of wholly unneeded
|
||||
// type information for the package in case there is
|
||||
// more type-checking to do (augmentation).
|
||||
info.Types = nil
|
||||
info.Scopes = nil
|
||||
info.Selections = nil
|
||||
}
|
||||
|
||||
// -------- utils --------
|
||||
|
||||
// An deterministic ordering for token.Pos that doesn't
|
||||
@ -371,19 +397,39 @@ func (p byNamePos) Less(i, j int) bool {
|
||||
return lessPos(p.fset, p.ids[i].NamePos, p.ids[j].NamePos)
|
||||
}
|
||||
|
||||
type referrersResult struct {
|
||||
// referrersInitialResult is the initial result of a "referrers" query.
|
||||
type referrersInitialResult struct {
|
||||
qinfo *loader.PackageInfo
|
||||
obj types.Object // object it denotes
|
||||
}
|
||||
|
||||
func (r *referrersInitialResult) PrintPlain(printf printfFunc) {
|
||||
printf(r.obj, "references to %s",
|
||||
types.ObjectString(r.obj, types.RelativeTo(r.qinfo.Pkg)))
|
||||
}
|
||||
|
||||
func (r *referrersInitialResult) JSON(fset *token.FileSet) []byte {
|
||||
var objpos string
|
||||
if pos := r.obj.Pos(); pos.IsValid() {
|
||||
objpos = fset.Position(pos).String()
|
||||
}
|
||||
return toJSON(&serial.ReferrersInitial{
|
||||
Desc: r.obj.String(),
|
||||
ObjPos: objpos,
|
||||
})
|
||||
}
|
||||
|
||||
// referrersPackageResult is the streaming result for one package of a "referrers" query.
|
||||
type referrersPackageResult struct {
|
||||
pkg *types.Package
|
||||
build *build.Context
|
||||
fset *token.FileSet
|
||||
qinfo *loader.PackageInfo
|
||||
qpos *queryPos
|
||||
obj types.Object // object it denotes
|
||||
refs []*ast.Ident // set of all other references to it
|
||||
}
|
||||
|
||||
func (r *referrersResult) display(printf printfFunc) {
|
||||
printf(r.obj, "%d references to %s",
|
||||
len(r.refs), types.ObjectString(r.obj, types.RelativeTo(r.qinfo.Pkg)))
|
||||
|
||||
// forEachRef calls f(id, text) for id in r.refs, in order.
|
||||
// Text is the text of the line on which id appears.
|
||||
func (r *referrersPackageResult) foreachRef(f func(id *ast.Ident, text string)) {
|
||||
// Show referring lines, like grep.
|
||||
type fileinfo struct {
|
||||
refs []*ast.Ident
|
||||
@ -432,13 +478,13 @@ func (r *referrersResult) display(printf printfFunc) {
|
||||
if more := len(fi.refs) - 1; more > 0 {
|
||||
suffix = fmt.Sprintf(" (+ %d more refs in this file)", more)
|
||||
}
|
||||
printf(fi.refs[0], "%v%s", err, suffix)
|
||||
f(fi.refs[0], err.Error()+suffix)
|
||||
continue
|
||||
}
|
||||
|
||||
lines := bytes.Split(v.([]byte), []byte("\n"))
|
||||
for i, ref := range fi.refs {
|
||||
printf(ref, "%s", lines[fi.linenums[i]-1])
|
||||
f(ref, string(lines[fi.linenums[i]-1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -458,15 +504,19 @@ func readFile(ctxt *build.Context, filename string) ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (r *referrersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
referrers := &serial.Referrers{
|
||||
Desc: r.obj.String(),
|
||||
}
|
||||
if pos := r.obj.Pos(); pos != token.NoPos { // Package objects have no Pos()
|
||||
referrers.ObjPos = fset.Position(pos).String()
|
||||
}
|
||||
for _, ref := range r.refs {
|
||||
referrers.Refs = append(referrers.Refs, fset.Position(ref.NamePos).String())
|
||||
}
|
||||
res.Referrers = referrers
|
||||
func (r *referrersPackageResult) PrintPlain(printf printfFunc) {
|
||||
r.foreachRef(func(id *ast.Ident, text string) {
|
||||
printf(id, "%s", text)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *referrersPackageResult) JSON(fset *token.FileSet) []byte {
|
||||
refs := serial.ReferrersPackage{Package: r.pkg.Path()}
|
||||
r.foreachRef(func(id *ast.Ident, text string) {
|
||||
refs.Refs = append(refs.Refs, serial.Ref{
|
||||
Pos: fset.Position(id.NamePos).String(),
|
||||
Text: text,
|
||||
})
|
||||
})
|
||||
return toJSON(refs)
|
||||
}
|
||||
|
@ -2,17 +2,30 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package serial defines the guru's schema for structured data
|
||||
// serialization using JSON, XML, etc.
|
||||
package serial
|
||||
|
||||
// All 'pos' strings are of the form "file:line:col".
|
||||
// TODO(adonovan): improve performance by sharing filename strings.
|
||||
// TODO(adonovan): improve precision by providing the start/end
|
||||
// interval when available.
|
||||
// Package serial defines the guru's schema for -json output.
|
||||
//
|
||||
// TODO(adonovan): consider richer encodings of types, functions,
|
||||
// methods, etc.
|
||||
// The output of a guru query is a stream of one or more JSON objects.
|
||||
// This table shows the types of objects in the result stream for each
|
||||
// query type.
|
||||
//
|
||||
// Query Result stream
|
||||
// ----- -------------
|
||||
// callees Callees
|
||||
// callers Caller ...
|
||||
// callstack CallStack
|
||||
// definition Definition
|
||||
// describe Describe
|
||||
// freevars FreeVar ...
|
||||
// implements Implements
|
||||
// peers Peers
|
||||
// pointsto PointsTo ...
|
||||
// referrers ReferrersInitial ReferrersPackage ...
|
||||
// what What
|
||||
// whicherrs WhichErrs
|
||||
//
|
||||
// All 'pos' strings in the output are of the form "file:line:col",
|
||||
// where line is the 1-based line number and col is the 1-based byte index.
|
||||
package serial
|
||||
|
||||
// A Peers is the result of a 'peers' query.
|
||||
// If Allocs is empty, the selected channel can't point to anything.
|
||||
@ -25,12 +38,22 @@ type Peers struct {
|
||||
Closes []string `json:"closes,omitempty"` // locations of aliased close(ch) ops
|
||||
}
|
||||
|
||||
// A Referrers is the result of a 'referrers' query.
|
||||
type Referrers struct {
|
||||
ObjPos string `json:"objpos,omitempty"` // location of the definition
|
||||
Desc string `json:"desc"` // description of the denoted object
|
||||
Refs []string `json:"refs,omitempty"` // locations of all references
|
||||
}
|
||||
// A "referrers" query emits a ReferrersInitial object followed by zero or
|
||||
// more ReferrersPackage objects, one per package that contains a reference.
|
||||
type (
|
||||
ReferrersInitial struct {
|
||||
ObjPos string `json:"objpos,omitempty"` // location of the definition
|
||||
Desc string `json:"desc"` // description of the denoted object
|
||||
}
|
||||
ReferrersPackage struct {
|
||||
Package string `json:"package"`
|
||||
Refs []Ref `json:"refs"` // non-empty list of references within this package
|
||||
}
|
||||
Ref struct {
|
||||
Pos string `json:"pos"` // location of all references
|
||||
Text string `json:"text"` // text of the referring line
|
||||
}
|
||||
)
|
||||
|
||||
// A Definition is the result of a 'definition' query.
|
||||
type Definition struct {
|
||||
@ -38,20 +61,21 @@ type Definition struct {
|
||||
Desc string `json:"desc"` // description of the denoted object
|
||||
}
|
||||
|
||||
type CalleesItem struct {
|
||||
Name string `json:"name"` // full name of called function
|
||||
Pos string `json:"pos"` // location of called function
|
||||
}
|
||||
|
||||
// A Callees is the result of a 'callees' query.
|
||||
//
|
||||
// Callees is nonempty unless the call was a dynamic call on a
|
||||
// provably nil func or interface value.
|
||||
type Callees struct {
|
||||
Pos string `json:"pos"` // location of selected call site
|
||||
Desc string `json:"desc"` // description of call site
|
||||
Callees []*CalleesItem `json:"callees,omitempty"` // set of possible call targets
|
||||
}
|
||||
type (
|
||||
Callees struct {
|
||||
Pos string `json:"pos"` // location of selected call site
|
||||
Desc string `json:"desc"` // description of call site
|
||||
Callees []*Callee `json:"callees"`
|
||||
}
|
||||
Callee struct {
|
||||
Name string `json:"name"` // full name of called function
|
||||
Pos string `json:"pos"` // location of called function
|
||||
}
|
||||
)
|
||||
|
||||
// A Caller is one element of the slice returned by a 'callers' query.
|
||||
// (Callstack also contains a similar slice.)
|
||||
@ -233,27 +257,3 @@ type WhichErrsType struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Position string `json:"position,omitempty"`
|
||||
}
|
||||
|
||||
// A Result is the common result of any guru query.
|
||||
// It contains a query-specific result element.
|
||||
//
|
||||
// TODO(adonovan): perhaps include other info such as: analysis scope,
|
||||
// raw query position, stack of ast nodes, query package, etc.
|
||||
type Result struct {
|
||||
Mode string `json:"mode"` // mode of the query
|
||||
|
||||
// Exactly one of the following fields is populated:
|
||||
// the one specified by 'mode'.
|
||||
Callees *Callees `json:"callees,omitempty"`
|
||||
Callers []Caller `json:"callers,omitempty"`
|
||||
Callstack *CallStack `json:"callstack,omitempty"`
|
||||
Definition *Definition `json:"definition,omitempty"`
|
||||
Describe *Describe `json:"describe,omitempty"`
|
||||
Freevars []*FreeVar `json:"freevars,omitempty"`
|
||||
Implements *Implements `json:"implements,omitempty"`
|
||||
Peers *Peers `json:"peers,omitempty"`
|
||||
PointsTo []PointsTo `json:"pointsto,omitempty"`
|
||||
Referrers *Referrers `json:"referrers,omitempty"`
|
||||
What *What `json:"what,omitempty"`
|
||||
WhichErrs *WhichErrs `json:"whicherrs,omitempty"`
|
||||
}
|
||||
|
50
cmd/guru/testdata/src/calls-json/main.golden
vendored
50
cmd/guru/testdata/src/calls-json/main.golden
vendored
@ -1,34 +1,28 @@
|
||||
-------- @callees @callees-f --------
|
||||
{
|
||||
"mode": "callees",
|
||||
"callees": {
|
||||
"pos": "testdata/src/calls-json/main.go:8:3",
|
||||
"desc": "dynamic function call",
|
||||
"callees": [
|
||||
{
|
||||
"name": "calls-json.main$1",
|
||||
"pos": "testdata/src/calls-json/main.go:12:7"
|
||||
}
|
||||
]
|
||||
}
|
||||
"pos": "testdata/src/calls-json/main.go:8:3",
|
||||
"desc": "dynamic function call",
|
||||
"callees": [
|
||||
{
|
||||
"name": "calls-json.main$1",
|
||||
"pos": "testdata/src/calls-json/main.go:12:7"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @callstack callstack-main.anon --------
|
||||
{
|
||||
"mode": "callstack",
|
||||
"callstack": {
|
||||
"pos": "testdata/src/calls-json/main.go:12:7",
|
||||
"target": "calls-json.main$1",
|
||||
"callers": [
|
||||
{
|
||||
"pos": "testdata/src/calls-json/main.go:8:3",
|
||||
"desc": "dynamic function call",
|
||||
"caller": "calls-json.call"
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/calls-json/main.go:12:6",
|
||||
"desc": "static function call",
|
||||
"caller": "calls-json.main"
|
||||
}
|
||||
]
|
||||
}
|
||||
"pos": "testdata/src/calls-json/main.go:12:7",
|
||||
"target": "calls-json.main$1",
|
||||
"callers": [
|
||||
{
|
||||
"pos": "testdata/src/calls-json/main.go:8:3",
|
||||
"desc": "dynamic function call",
|
||||
"caller": "calls-json.call"
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/calls-json/main.go:12:6",
|
||||
"desc": "static function call",
|
||||
"caller": "calls-json.main"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
169
cmd/guru/testdata/src/describe-json/main.golden
vendored
169
cmd/guru/testdata/src/describe-json/main.golden
vendored
@ -1,111 +1,96 @@
|
||||
-------- @describe pkgdecl --------
|
||||
{
|
||||
"mode": "describe",
|
||||
"describe": {
|
||||
"desc": "definition of package \"describe-json\"",
|
||||
"pos": "testdata/src/describe-json/main.go:1:9",
|
||||
"detail": "package",
|
||||
"package": {
|
||||
"path": "describe-json",
|
||||
"members": [
|
||||
{
|
||||
"name": "C",
|
||||
"type": "int",
|
||||
"pos": "testdata/src/describe-json/main.go:25:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (C) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:28:12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "D",
|
||||
"type": "struct{}",
|
||||
"pos": "testdata/src/describe-json/main.go:26:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (*D) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:29:13"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "I",
|
||||
"type": "interface{f()}",
|
||||
"pos": "testdata/src/describe-json/main.go:21:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (I) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:22:2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "main",
|
||||
"type": "func()",
|
||||
"pos": "testdata/src/describe-json/main.go:7:6",
|
||||
"kind": "func"
|
||||
}
|
||||
]
|
||||
}
|
||||
"desc": "definition of package \"describe-json\"",
|
||||
"pos": "testdata/src/describe-json/main.go:1:9",
|
||||
"detail": "package",
|
||||
"package": {
|
||||
"path": "describe-json",
|
||||
"members": [
|
||||
{
|
||||
"name": "C",
|
||||
"type": "int",
|
||||
"pos": "testdata/src/describe-json/main.go:25:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (C) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:28:12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "D",
|
||||
"type": "struct{}",
|
||||
"pos": "testdata/src/describe-json/main.go:26:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (*D) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:29:13"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "I",
|
||||
"type": "interface{f()}",
|
||||
"pos": "testdata/src/describe-json/main.go:21:6",
|
||||
"kind": "type",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (I) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:22:2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "main",
|
||||
"type": "func()",
|
||||
"pos": "testdata/src/describe-json/main.go:7:6",
|
||||
"kind": "func"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @describe desc-val-p --------
|
||||
{
|
||||
"mode": "describe",
|
||||
"describe": {
|
||||
"desc": "identifier",
|
||||
"pos": "testdata/src/describe-json/main.go:9:2",
|
||||
"detail": "value",
|
||||
"value": {
|
||||
"type": "*int",
|
||||
"objpos": "testdata/src/describe-json/main.go:9:2"
|
||||
}
|
||||
"desc": "identifier",
|
||||
"pos": "testdata/src/describe-json/main.go:9:2",
|
||||
"detail": "value",
|
||||
"value": {
|
||||
"type": "*int",
|
||||
"objpos": "testdata/src/describe-json/main.go:9:2"
|
||||
}
|
||||
}
|
||||
-------- @describe desc-val-i --------
|
||||
{
|
||||
"mode": "describe",
|
||||
"describe": {
|
||||
"desc": "identifier",
|
||||
"pos": "testdata/src/describe-json/main.go:16:8",
|
||||
"detail": "value",
|
||||
"value": {
|
||||
"type": "I",
|
||||
"objpos": "testdata/src/describe-json/main.go:12:6"
|
||||
}
|
||||
"desc": "identifier",
|
||||
"pos": "testdata/src/describe-json/main.go:16:8",
|
||||
"detail": "value",
|
||||
"value": {
|
||||
"type": "I",
|
||||
"objpos": "testdata/src/describe-json/main.go:12:6"
|
||||
}
|
||||
}
|
||||
-------- @describe desc-stmt --------
|
||||
{
|
||||
"mode": "describe",
|
||||
"describe": {
|
||||
"desc": "go statement",
|
||||
"pos": "testdata/src/describe-json/main.go:18:2",
|
||||
"detail": "unknown"
|
||||
}
|
||||
"desc": "go statement",
|
||||
"pos": "testdata/src/describe-json/main.go:18:2",
|
||||
"detail": "unknown"
|
||||
}
|
||||
-------- @describe desc-type-C --------
|
||||
{
|
||||
"mode": "describe",
|
||||
"describe": {
|
||||
"desc": "definition of type C (size 8, align 8)",
|
||||
"pos": "testdata/src/describe-json/main.go:25:6",
|
||||
"detail": "type",
|
||||
"type": {
|
||||
"type": "C",
|
||||
"namepos": "testdata/src/describe-json/main.go:25:6",
|
||||
"namedef": "int",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (C) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:28:12"
|
||||
}
|
||||
]
|
||||
}
|
||||
"desc": "definition of type C (size 8, align 8)",
|
||||
"pos": "testdata/src/describe-json/main.go:25:6",
|
||||
"detail": "type",
|
||||
"type": {
|
||||
"type": "C",
|
||||
"namepos": "testdata/src/describe-json/main.go:25:6",
|
||||
"namedef": "int",
|
||||
"methods": [
|
||||
{
|
||||
"name": "method (C) f()",
|
||||
"pos": "testdata/src/describe-json/main.go:28:12"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
252
cmd/guru/testdata/src/implements-json/main.golden
vendored
252
cmd/guru/testdata/src/implements-json/main.golden
vendored
@ -1,159 +1,135 @@
|
||||
-------- @implements E --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-json.E",
|
||||
"pos": "testdata/src/implements-json/main.go:10:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
"type": {
|
||||
"name": "implements-json.E",
|
||||
"pos": "testdata/src/implements-json/main.go:10:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
}
|
||||
-------- @implements F --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-json.C",
|
||||
"pos": "testdata/src/implements-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
{
|
||||
"name": "implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements FG --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements slice --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "[]int",
|
||||
"pos": "-",
|
||||
"kind": "slice"
|
||||
}
|
||||
}
|
||||
}
|
||||
-------- @implements C --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-json.C",
|
||||
"pos": "testdata/src/implements-json/main.go:21:6",
|
||||
"kind": "basic"
|
||||
},
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements starC --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"type": {
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-json.C",
|
||||
"pos": "testdata/src/implements-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements D --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
{
|
||||
"name": "implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements starD --------
|
||||
-------- @implements FG --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"type": {
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements slice --------
|
||||
{
|
||||
"type": {
|
||||
"name": "[]int",
|
||||
"pos": "-",
|
||||
"kind": "slice"
|
||||
}
|
||||
}
|
||||
-------- @implements C --------
|
||||
{
|
||||
"type": {
|
||||
"name": "implements-json.C",
|
||||
"pos": "testdata/src/implements-json/main.go:21:6",
|
||||
"kind": "basic"
|
||||
},
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements starC --------
|
||||
{
|
||||
"type": {
|
||||
"name": "*implements-json.C",
|
||||
"pos": "testdata/src/implements-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements D --------
|
||||
{
|
||||
"type": {
|
||||
"name": "implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements starD --------
|
||||
{
|
||||
"type": {
|
||||
"name": "*implements-json.D",
|
||||
"pos": "testdata/src/implements-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-json.F",
|
||||
"pos": "testdata/src/implements-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
{
|
||||
"name": "implements-json.FG",
|
||||
"pos": "testdata/src/implements-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,290 +1,266 @@
|
||||
-------- @implements F.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.C",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
{
|
||||
"name": "implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (F).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*C) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:24:13"
|
||||
},
|
||||
{
|
||||
"name": "method (D) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:25:12"
|
||||
},
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements FG.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:25:12"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements FG.g --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:18:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:27:13"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements *C.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.C",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*C).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:24:13"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-------- @implements D.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
{
|
||||
"name": "implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (D).f()",
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (F).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*C) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:24:13"
|
||||
},
|
||||
{
|
||||
"name": "method (D) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:25:12"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
],
|
||||
"fromptr_method": [
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements *D.g --------
|
||||
-------- @implements FG.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*D).g() []int",
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:25:12"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements FG.g --------
|
||||
{
|
||||
"type": {
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:18:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:27:13"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements *C.f --------
|
||||
{
|
||||
"type": {
|
||||
"name": "*implements-methods-json.C",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:21:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*C).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:24:13"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements D.f --------
|
||||
{
|
||||
"type": {
|
||||
"name": "implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (D).f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:25:12"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:13:2"
|
||||
}
|
||||
],
|
||||
"fromptr_method": [
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements *D.g --------
|
||||
{
|
||||
"type": {
|
||||
"name": "*implements-methods-json.D",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "implements-methods-json.F",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:12:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
},
|
||||
{
|
||||
"name": "method (FG) g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:18:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "implements-methods-json.FG",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*D).g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:27:13"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
},
|
||||
{
|
||||
"name": "method (FG) g() []int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:18:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements Len --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.sorter",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:29:6",
|
||||
"kind": "slice"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "lib.Sorter",
|
||||
"pos": "testdata/src/lib/lib.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (sorter).Len() int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:31:15"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (lib.Sorter) Len() int",
|
||||
"pos": "testdata/src/lib/lib.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
"type": {
|
||||
"name": "implements-methods-json.sorter",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:29:6",
|
||||
"kind": "slice"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "lib.Sorter",
|
||||
"pos": "testdata/src/lib/lib.go:16:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (sorter).Len() int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:31:15"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (lib.Sorter) Len() int",
|
||||
"pos": "testdata/src/lib/lib.go:17:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @implements I.Method --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "implements-methods-json.I",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:35:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "lib.Type",
|
||||
"pos": "testdata/src/lib/lib.go:3:6",
|
||||
"kind": "basic"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (I).Method(*int) *int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:36:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (lib.Type) Method(x *int) *int",
|
||||
"pos": "testdata/src/lib/lib.go:5:13"
|
||||
}
|
||||
]
|
||||
}
|
||||
"type": {
|
||||
"name": "implements-methods-json.I",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:35:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "lib.Type",
|
||||
"pos": "testdata/src/lib/lib.go:3:6",
|
||||
"kind": "basic"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (I).Method(*int) *int",
|
||||
"pos": "testdata/src/implements-methods-json/main.go:36:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (lib.Type) Method(x *int) *int",
|
||||
"pos": "testdata/src/lib/lib.go:5:13"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
21
cmd/guru/testdata/src/peers-json/main.golden
vendored
21
cmd/guru/testdata/src/peers-json/main.golden
vendored
@ -1,15 +1,12 @@
|
||||
-------- @peers peer-recv-chA --------
|
||||
{
|
||||
"mode": "peers",
|
||||
"peers": {
|
||||
"pos": "testdata/src/peers-json/main.go:11:7",
|
||||
"type": "chan *int",
|
||||
"allocs": [
|
||||
"testdata/src/peers-json/main.go:8:13"
|
||||
],
|
||||
"receives": [
|
||||
"testdata/src/peers-json/main.go:9:2",
|
||||
"testdata/src/peers-json/main.go:11:7"
|
||||
]
|
||||
}
|
||||
"pos": "testdata/src/peers-json/main.go:11:7",
|
||||
"type": "chan *int",
|
||||
"allocs": [
|
||||
"testdata/src/peers-json/main.go:8:13"
|
||||
],
|
||||
"receives": [
|
||||
"testdata/src/peers-json/main.go:9:2",
|
||||
"testdata/src/peers-json/main.go:11:7"
|
||||
]
|
||||
}
|
||||
|
60
cmd/guru/testdata/src/pointsto-json/main.golden
vendored
60
cmd/guru/testdata/src/pointsto-json/main.golden
vendored
@ -1,35 +1,29 @@
|
||||
-------- @pointsto val-p --------
|
||||
{
|
||||
"mode": "pointsto",
|
||||
"pointsto": [
|
||||
{
|
||||
"type": "*int",
|
||||
"labels": [
|
||||
{
|
||||
"pos": "testdata/src/pointsto-json/main.go:8:6",
|
||||
"desc": "s.x[*]"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"type": "*int",
|
||||
"labels": [
|
||||
{
|
||||
"pos": "testdata/src/pointsto-json/main.go:8:6",
|
||||
"desc": "s.x[*]"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
-------- @pointsto val-i --------
|
||||
{
|
||||
"mode": "pointsto",
|
||||
"pointsto": [
|
||||
{
|
||||
"type": "*D",
|
||||
"namepos": "testdata/src/pointsto-json/main.go:24:6",
|
||||
"labels": [
|
||||
{
|
||||
"pos": "testdata/src/pointsto-json/main.go:14:10",
|
||||
"desc": "new"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "C",
|
||||
"namepos": "testdata/src/pointsto-json/main.go:23:6"
|
||||
}
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"type": "*D",
|
||||
"namepos": "testdata/src/pointsto-json/main.go:24:6",
|
||||
"labels": [
|
||||
{
|
||||
"pos": "testdata/src/pointsto-json/main.go:14:10",
|
||||
"desc": "new"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "C",
|
||||
"namepos": "testdata/src/pointsto-json/main.go:23:6"
|
||||
}
|
||||
]
|
||||
|
224
cmd/guru/testdata/src/referrers-json/main.golden
vendored
224
cmd/guru/testdata/src/referrers-json/main.golden
vendored
@ -1,64 +1,184 @@
|
||||
-------- @referrers ref-package --------
|
||||
{
|
||||
"mode": "referrers",
|
||||
"referrers": {
|
||||
"desc": "package lib",
|
||||
"refs": [
|
||||
"testdata/src/describe/main.go:91:8",
|
||||
"testdata/src/imports/main.go:18:12",
|
||||
"testdata/src/imports/main.go:19:2",
|
||||
"testdata/src/imports/main.go:20:2",
|
||||
"testdata/src/imports/main.go:21:8",
|
||||
"testdata/src/imports/main.go:26:8",
|
||||
"testdata/src/referrers-json/main.go:14:8",
|
||||
"testdata/src/referrers-json/main.go:14:19",
|
||||
"testdata/src/referrers/ext_test.go:10:7",
|
||||
"testdata/src/referrers/int_test.go:7:7",
|
||||
"testdata/src/referrers/main.go:16:8",
|
||||
"testdata/src/referrers/main.go:16:19"
|
||||
]
|
||||
}
|
||||
"desc": "package lib"
|
||||
}
|
||||
{
|
||||
"package": "describe",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/describe/main.go:91:8",
|
||||
"text": "\tvar _ lib.Outer // @describe lib-outer \"Outer\""
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "imports",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:18:12",
|
||||
"text": "\tconst c = lib.Const // @describe ref-const \"Const\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:19:2",
|
||||
"text": "\tlib.Func() // @describe ref-func \"Func\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:20:2",
|
||||
"text": "\tlib.Var++ // @describe ref-var \"Var\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:21:8",
|
||||
"text": "\tvar t lib.Type // @describe ref-type \"Type\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:26:8",
|
||||
"text": "\tvar _ lib.Type // @describe ref-pkg \"lib\""
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/int_test.go:7:7",
|
||||
"text": "\t_ = (lib.Type).Method // ref from internal test package"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/main.go:16:8",
|
||||
"text": "\tvar v lib.Type = lib.Const // @referrers ref-package \"lib\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers/main.go:16:19",
|
||||
"text": "\tvar v lib.Type = lib.Const // @referrers ref-package \"lib\""
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers-json",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:14:8",
|
||||
"text": "\tvar v lib.Type = lib.Const // @referrers ref-package \"lib\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:14:19",
|
||||
"text": "\tvar v lib.Type = lib.Const // @referrers ref-package \"lib\""
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers_test",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/ext_test.go:10:7",
|
||||
"text": "\t_ = (lib.Type).Method // ref from external test package"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @referrers ref-method --------
|
||||
{
|
||||
"mode": "referrers",
|
||||
"referrers": {
|
||||
"objpos": "testdata/src/lib/lib.go:5:13",
|
||||
"desc": "func (lib.Type).Method(x *int) *int",
|
||||
"refs": [
|
||||
"testdata/src/imports/main.go:22:9",
|
||||
"testdata/src/referrers-json/main.go:15:8",
|
||||
"testdata/src/referrers-json/main.go:16:8",
|
||||
"testdata/src/referrers/ext_test.go:10:17",
|
||||
"testdata/src/referrers/int_test.go:7:17",
|
||||
"testdata/src/referrers/main.go:17:8",
|
||||
"testdata/src/referrers/main.go:18:8"
|
||||
]
|
||||
}
|
||||
"objpos": "testdata/src/lib/lib.go:5:13",
|
||||
"desc": "func (lib.Type).Method(x *int) *int"
|
||||
}
|
||||
{
|
||||
"package": "imports",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/imports/main.go:22:9",
|
||||
"text": "\tp := t.Method(\u0026a) // @describe ref-method \"Method\""
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/int_test.go:7:17",
|
||||
"text": "\t_ = (lib.Type).Method // ref from internal test package"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/main.go:17:8",
|
||||
"text": "\t_ = v.Method // @referrers ref-method \"Method\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers/main.go:18:8",
|
||||
"text": "\t_ = v.Method"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers-json",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:15:8",
|
||||
"text": "\t_ = v.Method // @referrers ref-method \"Method\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:16:8",
|
||||
"text": "\t_ = v.Method"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"package": "referrers_test",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers/ext_test.go:10:17",
|
||||
"text": "\t_ = (lib.Type).Method // ref from external test package"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @referrers ref-local --------
|
||||
{
|
||||
"mode": "referrers",
|
||||
"referrers": {
|
||||
"objpos": "testdata/src/referrers-json/main.go:14:6",
|
||||
"desc": "var v lib.Type",
|
||||
"refs": [
|
||||
"testdata/src/referrers-json/main.go:15:6",
|
||||
"testdata/src/referrers-json/main.go:16:6",
|
||||
"testdata/src/referrers-json/main.go:17:2",
|
||||
"testdata/src/referrers-json/main.go:18:2"
|
||||
]
|
||||
}
|
||||
"objpos": "testdata/src/referrers-json/main.go:14:6",
|
||||
"desc": "var v lib.Type"
|
||||
}
|
||||
{
|
||||
"package": "referrers-json",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:15:6",
|
||||
"text": "\t_ = v.Method // @referrers ref-method \"Method\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:16:6",
|
||||
"text": "\t_ = v.Method"
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:17:2",
|
||||
"text": "\tv++ //@referrers ref-local \"v\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:18:2",
|
||||
"text": "\tv++"
|
||||
}
|
||||
]
|
||||
}
|
||||
-------- @referrers ref-field --------
|
||||
{
|
||||
"mode": "referrers",
|
||||
"referrers": {
|
||||
"objpos": "testdata/src/referrers-json/main.go:10:2",
|
||||
"desc": "field f int",
|
||||
"refs": [
|
||||
"testdata/src/referrers-json/main.go:20:10",
|
||||
"testdata/src/referrers-json/main.go:23:5"
|
||||
]
|
||||
}
|
||||
"objpos": "testdata/src/referrers-json/main.go:10:2",
|
||||
"desc": "field f int"
|
||||
}
|
||||
{
|
||||
"package": "referrers-json",
|
||||
"refs": [
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:20:10",
|
||||
"text": "\t_ = s{}.f // @referrers ref-field \"f\""
|
||||
},
|
||||
{
|
||||
"pos": "testdata/src/referrers-json/main.go:23:5",
|
||||
"text": "\ts2.f = 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
34
cmd/guru/testdata/src/referrers/main.golden
vendored
34
cmd/guru/testdata/src/referrers/main.golden
vendored
@ -1,50 +1,50 @@
|
||||
-------- @referrers package-decl --------
|
||||
1 references to package main ("referrers")
|
||||
references to package main ("referrers")
|
||||
var _ renamed.T
|
||||
|
||||
-------- @referrers type --------
|
||||
2 references to type s struct{f int}
|
||||
references to type s struct{f int}
|
||||
_ = s{}.f // @referrers ref-field "f"
|
||||
var s2 s
|
||||
|
||||
-------- @referrers ref-package --------
|
||||
12 references to package lib
|
||||
references to package lib
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var _ lib.Outer // @describe lib-outer "Outer"
|
||||
const c = lib.Const // @describe ref-const "Const"
|
||||
lib.Func() // @describe ref-func "Func"
|
||||
lib.Var++ // @describe ref-var "Var"
|
||||
var t lib.Type // @describe ref-type "Type"
|
||||
var _ lib.Type // @describe ref-pkg "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
_ = (lib.Type).Method // ref from external test package
|
||||
_ = (lib.Type).Method // ref from internal test package
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
var v lib.Type = lib.Const // @referrers ref-package "lib"
|
||||
_ = (lib.Type).Method // ref from external test package
|
||||
|
||||
-------- @referrers ref-method --------
|
||||
7 references to func (Type).Method(x *int) *int
|
||||
references to func (Type).Method(x *int) *int
|
||||
_ = v.Method // @referrers ref-method "Method"
|
||||
_ = v.Method
|
||||
_ = v.Method // @referrers ref-method "Method"
|
||||
_ = v.Method
|
||||
p := t.Method(&a) // @describe ref-method "Method"
|
||||
_ = v.Method // @referrers ref-method "Method"
|
||||
_ = v.Method
|
||||
_ = (lib.Type).Method // ref from external test package
|
||||
_ = (lib.Type).Method // ref from internal test package
|
||||
_ = v.Method // @referrers ref-method "Method"
|
||||
_ = v.Method
|
||||
_ = (lib.Type).Method // ref from external test package
|
||||
|
||||
-------- @referrers ref-local --------
|
||||
4 references to var v lib.Type
|
||||
references to var v lib.Type
|
||||
_ = v.Method // @referrers ref-method "Method"
|
||||
_ = v.Method
|
||||
v++ //@referrers ref-local "v"
|
||||
v++
|
||||
|
||||
-------- @referrers ref-field --------
|
||||
2 references to field f int
|
||||
references to field f int
|
||||
_ = s{}.f // @referrers ref-field "f"
|
||||
s2.f = 1
|
||||
|
||||
-------- @referrers ref-type-U --------
|
||||
2 references to type U int
|
||||
references to type U int
|
||||
open testdata/src/referrers/nosuchfile.y: no such file or directory (+ 1 more refs in this file)
|
||||
|
||||
|
93
cmd/guru/testdata/src/what-json/main.golden
vendored
93
cmd/guru/testdata/src/what-json/main.golden
vendored
@ -1,51 +1,48 @@
|
||||
-------- @what call --------
|
||||
{
|
||||
"mode": "what",
|
||||
"what": {
|
||||
"enclosing": [
|
||||
{
|
||||
"desc": "identifier",
|
||||
"start": 175,
|
||||
"end": 176
|
||||
},
|
||||
{
|
||||
"desc": "function call (or conversion)",
|
||||
"start": 175,
|
||||
"end": 178
|
||||
},
|
||||
{
|
||||
"desc": "expression statement",
|
||||
"start": 175,
|
||||
"end": 178
|
||||
},
|
||||
{
|
||||
"desc": "block",
|
||||
"start": 172,
|
||||
"end": 198
|
||||
},
|
||||
{
|
||||
"desc": "function declaration",
|
||||
"start": 160,
|
||||
"end": 198
|
||||
},
|
||||
{
|
||||
"desc": "source file",
|
||||
"start": 0,
|
||||
"end": 198
|
||||
}
|
||||
],
|
||||
"modes": [
|
||||
"callees",
|
||||
"callers",
|
||||
"callstack",
|
||||
"definition",
|
||||
"describe",
|
||||
"freevars",
|
||||
"implements",
|
||||
"pointsto",
|
||||
"referrers"
|
||||
],
|
||||
"srcdir": "testdata/src",
|
||||
"importpath": "what-json"
|
||||
}
|
||||
"enclosing": [
|
||||
{
|
||||
"desc": "identifier",
|
||||
"start": 175,
|
||||
"end": 176
|
||||
},
|
||||
{
|
||||
"desc": "function call (or conversion)",
|
||||
"start": 175,
|
||||
"end": 178
|
||||
},
|
||||
{
|
||||
"desc": "expression statement",
|
||||
"start": 175,
|
||||
"end": 178
|
||||
},
|
||||
{
|
||||
"desc": "block",
|
||||
"start": 172,
|
||||
"end": 198
|
||||
},
|
||||
{
|
||||
"desc": "function declaration",
|
||||
"start": 160,
|
||||
"end": 198
|
||||
},
|
||||
{
|
||||
"desc": "source file",
|
||||
"start": 0,
|
||||
"end": 198
|
||||
}
|
||||
],
|
||||
"modes": [
|
||||
"callees",
|
||||
"callers",
|
||||
"callstack",
|
||||
"definition",
|
||||
"describe",
|
||||
"freevars",
|
||||
"implements",
|
||||
"pointsto",
|
||||
"referrers"
|
||||
],
|
||||
"srcdir": "testdata/src",
|
||||
"importpath": "what-json"
|
||||
}
|
||||
|
@ -29,10 +29,9 @@ func what(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = qpos.fset
|
||||
|
||||
// (ignore errors)
|
||||
srcdir, importPath, _ := guessImportPath(q.Fset.File(qpos.start).Name(), q.Build)
|
||||
srcdir, importPath, _ := guessImportPath(qpos.fset.File(qpos.start).Name(), q.Build)
|
||||
|
||||
// Determine which query modes are applicable to the selection.
|
||||
enable := map[string]bool{
|
||||
@ -129,14 +128,14 @@ func what(q *Query) error {
|
||||
})
|
||||
}
|
||||
|
||||
q.result = &whatResult{
|
||||
q.Output(qpos.fset, &whatResult{
|
||||
path: qpos.path,
|
||||
srcdir: srcdir,
|
||||
importPath: importPath,
|
||||
modes: modes,
|
||||
object: object,
|
||||
sameids: sameids,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -211,7 +210,7 @@ type whatResult struct {
|
||||
sameids []token.Pos
|
||||
}
|
||||
|
||||
func (r *whatResult) display(printf printfFunc) {
|
||||
func (r *whatResult) PrintPlain(printf printfFunc) {
|
||||
for _, n := range r.path {
|
||||
printf(n, "%s", astutil.NodeDescription(n))
|
||||
}
|
||||
@ -223,7 +222,7 @@ func (r *whatResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *whatResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *whatResult) JSON(fset *token.FileSet) []byte {
|
||||
var enclosing []serial.SyntaxNode
|
||||
for _, n := range r.path {
|
||||
enclosing = append(enclosing, serial.SyntaxNode{
|
||||
@ -238,12 +237,12 @@ func (r *whatResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
sameids = append(sameids, fset.Position(pos).String())
|
||||
}
|
||||
|
||||
res.What = &serial.What{
|
||||
return toJSON(&serial.What{
|
||||
Modes: r.modes,
|
||||
SrcDir: r.srcdir,
|
||||
ImportPath: r.importPath,
|
||||
Enclosing: enclosing,
|
||||
Object: r.object,
|
||||
SameIDs: sameids,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ func whicherrs(q *Query) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Fset = lprog.Fset
|
||||
|
||||
qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
|
||||
if err != nil {
|
||||
@ -209,7 +208,7 @@ func whicherrs(q *Query) error {
|
||||
sort.Sort(membersByPosAndString(res.consts))
|
||||
sort.Sort(sorterrorType(res.types))
|
||||
|
||||
q.result = res
|
||||
q.Output(lprog.Fset, res)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -290,7 +289,7 @@ type whicherrsResult struct {
|
||||
types []*errorType
|
||||
}
|
||||
|
||||
func (r *whicherrsResult) display(printf printfFunc) {
|
||||
func (r *whicherrsResult) PrintPlain(printf printfFunc) {
|
||||
if len(r.globals) > 0 {
|
||||
printf(r.qpos, "this error may point to these globals:")
|
||||
for _, g := range r.globals {
|
||||
@ -311,7 +310,7 @@ func (r *whicherrsResult) display(printf printfFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *whicherrsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
func (r *whicherrsResult) JSON(fset *token.FileSet) []byte {
|
||||
we := &serial.WhichErrs{}
|
||||
we.ErrPos = fset.Position(r.errpos).String()
|
||||
for _, g := range r.globals {
|
||||
@ -326,5 +325,5 @@ func (r *whicherrsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
et.Position = fset.Position(t.obj.Pos()).String()
|
||||
we.Types = append(we.Types, et)
|
||||
}
|
||||
res.WhichErrs = we
|
||||
return toJSON(we)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user