Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1180)

Side by Side Diff: oracle/describe.go

Issue 13270045: code review 13270045: go.tools/oracle: add option to output results in JSON s... (Closed)
Patch Set: diff -r 07183b5c385c https://code.google.com/p/go.tools Created 10 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « oracle/callstack.go ('k') | oracle/freevars.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Go Authors. All rights reserved. 1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package oracle 5 package oracle
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "go/ast" 10 "go/ast"
11 "go/token" 11 "go/token"
12 "os"
12 "sort" 13 "sort"
13 "strconv" 14 "strconv"
14 "strings" 15 "strings"
15 16
17 "code.google.com/p/go.tools/go/exact"
16 "code.google.com/p/go.tools/go/types" 18 "code.google.com/p/go.tools/go/types"
17 "code.google.com/p/go.tools/importer" 19 "code.google.com/p/go.tools/importer"
20 "code.google.com/p/go.tools/oracle/json"
18 "code.google.com/p/go.tools/pointer" 21 "code.google.com/p/go.tools/pointer"
19 "code.google.com/p/go.tools/ssa" 22 "code.google.com/p/go.tools/ssa"
20 ) 23 )
21 24
22 // TODO(adonovan): all printed sets must be sorted to ensure test determinism.
23
24 // describe describes the syntax node denoted by the query position, 25 // describe describes the syntax node denoted by the query position,
25 // including: 26 // including:
26 // - its syntactic category 27 // - its syntactic category
27 // - the location of the definition of its referent (for identifiers) 28 // - the location of the definition of its referent (for identifiers)
28 // - its type and method set (for an expression or type expression) 29 // - its type and method set (for an expression or type expression)
29 // - its points-to set (for a pointer-like expression) 30 // - its points-to set (for a pointer-like expression)
30 // - its concrete types (for an interface expression) and their points-to sets. 31 // - its concrete types (for an interface expression) and their points-to sets.
31 // 32 //
33 // All printed sets are sorted to ensure determinism.
34 //
32 func describe(o *oracle) (queryResult, error) { 35 func describe(o *oracle) (queryResult, error) {
33 if false { // debugging 36 if false { // debugging
34 » » o.printf(o.queryPath[0], "you selected: %s %s", 37 » » o.fprintf(os.Stderr, o.queryPath[0], "you selected: %s %s",
35 importer.NodeDescription(o.queryPath[0]), pathToString2( o.queryPath)) 38 importer.NodeDescription(o.queryPath[0]), pathToString2( o.queryPath))
36 } 39 }
37 40
38 path, action := findInterestingNode(o.queryPkgInfo, o.queryPath) 41 path, action := findInterestingNode(o.queryPkgInfo, o.queryPath)
39 switch action { 42 switch action {
40 case actionExpr: 43 case actionExpr:
41 return describeValue(o, path) 44 return describeValue(o, path)
42 45
43 case actionType: 46 case actionType:
44 return describeType(o, path) 47 return describeType(o, path)
45 48
46 case actionPackage: 49 case actionPackage:
47 return describePackage(o, path) 50 return describePackage(o, path)
48 51
49 case actionStmt: 52 case actionStmt:
50 return describeStmt(o, path) 53 return describeStmt(o, path)
51 54
52 case actionUnknown: 55 case actionUnknown:
53 return &describeUnknownResult{path[0]}, nil 56 return &describeUnknownResult{path[0]}, nil
54 57
55 default: 58 default:
56 panic(action) // unreachable 59 panic(action) // unreachable
57 } 60 }
58 } 61 }
59 62
60 type describeUnknownResult struct { 63 type describeUnknownResult struct {
61 node ast.Node 64 node ast.Node
62 } 65 }
63 66
64 func (r *describeUnknownResult) display(o *oracle) { 67 func (r *describeUnknownResult) display(printf printfFunc) {
65 // Nothing much to say about misc syntax. 68 // Nothing much to say about misc syntax.
66 » o.printf(r.node, "%s", importer.NodeDescription(r.node)) 69 » printf(r.node, "%s", importer.NodeDescription(r.node))
70 }
71
72 func (r *describeUnknownResult) toJSON(res *json.Result, fset *token.FileSet) {
73 » res.Describe = &json.Describe{
74 » » Desc: importer.NodeDescription(r.node),
75 » » Pos: fset.Position(r.node.Pos()).String(),
76 » }
67 } 77 }
68 78
69 type action int 79 type action int
70 80
71 const ( 81 const (
72 actionUnknown action = iota // None of the below 82 actionUnknown action = iota // None of the below
73 actionExpr // FuncDecl, true Expr or Ident(types.{Const ,Var}) 83 actionExpr // FuncDecl, true Expr or Ident(types.{Const ,Var})
74 actionType // type Expr or Ident(types.TypeName). 84 actionType // type Expr or Ident(types.TypeName).
75 actionStmt // Stmt or Ident(types.Label) 85 actionStmt // Stmt or Ident(types.Label)
76 actionPackage // Ident(types.Package) or ImportSpec 86 actionPackage // Ident(types.Package) or ImportSpec
(...skipping 15 matching lines...) Expand all
92 // doesn't crash. 102 // doesn't crash.
93 103
94 // TODO(adonovan): audit for ParenExpr safety, esp. since we 104 // TODO(adonovan): audit for ParenExpr safety, esp. since we
95 // traverse up and down. 105 // traverse up and down.
96 106
97 // TODO(adonovan): if the users selects the "." in 107 // TODO(adonovan): if the users selects the "." in
98 // "fmt.Fprintf()", they'll get an ambiguous selection error; 108 // "fmt.Fprintf()", they'll get an ambiguous selection error;
99 // we won't even reach here. Can we do better? 109 // we won't even reach here. Can we do better?
100 110
101 // TODO(adonovan): describing a field within 'type T struct {...}' 111 // TODO(adonovan): describing a field within 'type T struct {...}'
102 » // describes the (anonymous) struct type and concludes "no methods". Fi x. 112 » // describes the (anonymous) struct type and concludes "no methods".
113 » // We should ascend to the enclosing type decl, if any.
103 114
104 for len(path) > 0 { 115 for len(path) > 0 {
105 switch n := path[0].(type) { 116 switch n := path[0].(type) {
106 case *ast.GenDecl: 117 case *ast.GenDecl:
107 if len(n.Specs) == 1 { 118 if len(n.Specs) == 1 {
108 // Descend to sole {Import,Type,Value}Spec child . 119 // Descend to sole {Import,Type,Value}Spec child .
109 path = append([]ast.Node{n.Specs[0]}, path...) 120 path = append([]ast.Node{n.Specs[0]}, path...)
110 continue 121 continue
111 } 122 }
112 return path, actionUnknown // uninteresting 123 return path, actionUnknown // uninteresting
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 return nil, o.errorf(n, "multiple value specification") 348 return nil, o.errorf(n, "multiple value specification")
338 case ast.Expr: 349 case ast.Expr:
339 expr = n 350 expr = n
340 default: 351 default:
341 // Is this reachable? 352 // Is this reachable?
342 return nil, o.errorf(n, "unexpected AST for expr: %T", n) 353 return nil, o.errorf(n, "unexpected AST for expr: %T", n)
343 } 354 }
344 355
345 // From this point on, we cannot fail with an error. 356 // From this point on, we cannot fail with an error.
346 // Failure to run the pointer analysis will be reported later. 357 // Failure to run the pointer analysis will be reported later.
358 //
359 // Our disposition to pointer analysis may be one of the following:
360 // - ok: ssa.Value was const or func.
361 // - error: no ssa.Value for expr (e.g. trivially dead code)
362 // - ok: ssa.Value is non-pointerlike
363 // - error: no Pointer for ssa.Value (e.g. analytically unreachable)
364 // - ok: Pointer has empty points-to set
365 // - ok: Pointer has non-empty points-to set
366 // ptaErr is non-nil only in the "error:" cases.
347 367
348 var value ssa.Value 368 var value ssa.Value
349 var ptaErr error 369 var ptaErr error
350 var obj types.Object 370 var obj types.Object
351 371
352 // Determine the ssa.Value for the expression. 372 // Determine the ssa.Value for the expression.
353 if id, ok := expr.(*ast.Ident); ok { 373 if id, ok := expr.(*ast.Ident); ok {
354 // def/ref of func/var/const object 374 // def/ref of func/var/const object
355 obj = o.queryPkgInfo.ObjectOf(id) 375 obj = o.queryPkgInfo.ObjectOf(id)
356 value, ptaErr = ssaValueForIdent(o, obj, path) 376 value, ptaErr = ssaValueForIdent(o, obj, path)
357 } else { 377 } else {
358 // any other expression 378 // any other expression
359 if o.queryPkgInfo.ValueOf(expr) == nil { // non-constant? 379 if o.queryPkgInfo.ValueOf(expr) == nil { // non-constant?
360 value, ptaErr = ssaValueForExpr(o, path) 380 value, ptaErr = ssaValueForExpr(o, path)
361 } 381 }
362 } 382 }
363 383
364 // Don't run pointer analysis on non-pointerlike types. 384 // Don't run pointer analysis on non-pointerlike types.
365 if value != nil && !pointer.CanPoint(value.Type()) { 385 if value != nil && !pointer.CanPoint(value.Type()) {
366 value = nil 386 value = nil
367 } 387 }
368 388
369 // Run pointer analysis of the selected SSA value. 389 // Run pointer analysis of the selected SSA value.
370 » var ptrs []pointer.Pointer 390 » var ptrs []pointerResult
371 if value != nil { 391 if value != nil {
372 buildSSA(o) 392 buildSSA(o)
373 393
374 o.config.QueryValues = map[ssa.Value][]pointer.Pointer{value: ni l} 394 o.config.QueryValues = map[ssa.Value][]pointer.Pointer{value: ni l}
375 ptrAnalysis(o) 395 ptrAnalysis(o)
376 » » ptrs = o.config.QueryValues[value] 396
397 » » // Combine the PT sets from all contexts.
398 » » pointers := o.config.QueryValues[value]
399 » » if pointers == nil {
400 » » » ptaErr = fmt.Errorf("PTA did not encounter this expressi on (dead code?)")
401 » » }
402 » » pts := pointer.PointsToCombined(pointers)
403
404 » » if _, ok := value.Type().Underlying().(*types.Interface); ok {
405 » » » // Show concrete types for interface expression.
406 » » » if concs := pts.ConcreteTypes(); concs.Len() > 0 {
407 » » » » concs.Iterate(func(conc types.Type, pta interfac e{}) {
408 » » » » » combined := pointer.PointsToCombined(pta .([]pointer.Pointer))
409 » » » » » labels := combined.Labels()
410 » » » » » sort.Sort(byPosAndString(labels)) // to ensure determinism
411 » » » » » ptrs = append(ptrs, pointerResult{conc, labels})
412 » » » » })
413 » » » }
414 » » } else {
415 » » » // Show labels for other expressions.
416 » » » labels := pts.Labels()
417 » » » sort.Sort(byPosAndString(labels)) // to ensure determini sm
418 » » » ptrs = append(ptrs, pointerResult{value.Type(), labels})
419 » » }
377 } 420 }
421 sort.Sort(byTypeString(ptrs)) // to ensure determinism
422
423 typ := o.queryPkgInfo.TypeOf(expr)
424 constVal := o.queryPkgInfo.ValueOf(expr)
378 425
379 return &describeValueResult{ 426 return &describeValueResult{
380 » » expr: expr, 427 » » expr: expr,
381 » » obj: obj, 428 » » typ: typ,
382 » » value: value, 429 » » constVal: constVal,
383 » » ptaErr: ptaErr, 430 » » obj: obj,
384 » » ptrs: ptrs, 431 » » ptaErr: ptaErr,
432 » » ptrs: ptrs,
385 }, nil 433 }, nil
386 } 434 }
387 435
388 type describeValueResult struct { 436 type pointerResult struct {
389 » expr ast.Expr // query node 437 » typ types.Type // type of the pointer (always concrete)
390 » obj types.Object // var/func/const object, if expr was Ident 438 » labels []*pointer.Label
391 » value ssa.Value // ssa.Value for pointer analysis query
392 » ptaErr error // explanation of why we couldn't run pointer a nalysis
393 » ptrs []pointer.Pointer // result of pointer analysis query
394 } 439 }
395 440
396 func (r *describeValueResult) display(o *oracle) { 441 type describeValueResult struct {
442 » expr ast.Expr // query node
443 » typ types.Type // type of expression
444 » constVal exact.Value // value of expression, if constant
445 » obj types.Object // var/func/const object, if expr was Ident
446 » ptaErr error // reason why pointer analysis couldn't be run, or failed
447 » ptrs []pointerResult // pointer info (typ is concrete => len==1)
448 }
449
450 func (r *describeValueResult) display(printf printfFunc) {
397 suffix := "" 451 suffix := ""
398 » if val := o.queryPkgInfo.ValueOf(r.expr); val != nil { 452 » if r.constVal != nil {
399 » » suffix = fmt.Sprintf(" of constant value %s", val) 453 » » suffix = fmt.Sprintf(" of constant value %s", r.constVal)
400 } 454 }
401 455
402 // Describe the expression. 456 // Describe the expression.
403 if r.obj != nil { 457 if r.obj != nil {
404 if r.obj.Pos() == r.expr.Pos() { 458 if r.obj.Pos() == r.expr.Pos() {
405 // defining ident 459 // defining ident
406 » » » o.printf(r.expr, "definition of %s%s", r.obj, suffix) 460 » » » printf(r.expr, "definition of %s%s", r.obj, suffix)
407 } else { 461 } else {
408 // referring ident 462 // referring ident
409 » » » o.printf(r.expr, "reference to %s%s", r.obj, suffix) 463 » » » printf(r.expr, "reference to %s%s", r.obj, suffix)
410 if def := r.obj.Pos(); def != token.NoPos { 464 if def := r.obj.Pos(); def != token.NoPos {
411 » » » » o.printf(def, "defined here") 465 » » » » printf(def, "defined here")
412 } 466 }
413 } 467 }
414 } else { 468 } else {
415 desc := importer.NodeDescription(r.expr) 469 desc := importer.NodeDescription(r.expr)
416 if suffix != "" { 470 if suffix != "" {
417 // constant expression 471 // constant expression
418 » » » o.printf(r.expr, "%s%s", desc, suffix) 472 » » » printf(r.expr, "%s%s", desc, suffix)
419 } else { 473 } else {
420 // non-constant expression 474 // non-constant expression
421 » » » o.printf(r.expr, "%s of type %s", desc, o.queryPkgInfo.T ypeOf(r.expr)) 475 » » » printf(r.expr, "%s of type %s", desc, r.typ)
422 } 476 }
423 } 477 }
424 478
425 » if r.value == nil { 479 » // pointer analysis could not be run
426 » » // pointer analysis was not run 480 » if r.ptaErr != nil {
427 » » if r.ptaErr != nil { 481 » » printf(r.expr, "no points-to information: %s", r.ptaErr)
428 » » » o.printf(r.expr, "no pointer analysis: %s", r.ptaErr)
429 » » }
430 return 482 return
431 } 483 }
432 484
433 if r.ptrs == nil { 485 if r.ptrs == nil {
434 » » o.printf(r.expr, "pointer analysis did not analyze this expressi on (dead code?)") 486 » » return // PTA was not invoked (not an error)
435 » » return
436 } 487 }
437 488
438 // Display the results of pointer analysis. 489 // Display the results of pointer analysis.
439 490 » if _, ok := r.typ.Underlying().(*types.Interface); ok {
440 » // Combine the PT sets from all contexts.
441 » pts := pointer.PointsToCombined(r.ptrs)
442
443 » // Report which make(chan) labels the query's channel can alias.
444 » if _, ok := r.value.Type().Underlying().(*types.Interface); ok {
445 // Show concrete types for interface expression. 491 // Show concrete types for interface expression.
446 » » if concs := pts.ConcreteTypes(); concs.Len() > 0 { 492 » » if len(r.ptrs) > 0 {
447 » » » o.printf(o, "interface may contain these concrete types: ") 493 » » » printf(false, "interface may contain these concrete type s:")
448 » » » // TODO(adonovan): must sort to ensure deterministic tes t behaviour. 494 » » » for _, ptr := range r.ptrs {
449 » » » concs.Iterate(func(conc types.Type, ptrs interface{}) {
450 var obj types.Object 495 var obj types.Object
451 » » » » if nt, ok := deref(conc).(*types.Named); ok { 496 » » » » if nt, ok := deref(ptr.typ).(*types.Named); ok {
452 obj = nt.Obj() 497 obj = nt.Obj()
453 } 498 }
454 499 » » » » if len(ptr.labels) > 0 {
455 » » » » pts := pointer.PointsToCombined(ptrs.([]pointer. Pointer)) 500 » » » » » printf(obj, "\t%s, may point to:", ptr.t yp)
456 » » » » if labels := pts.Labels(); len(labels) > 0 { 501 » » » » » printLabels(printf, ptr.labels, "\t\t")
457 » » » » » o.printf(obj, "\t%s, may point to:", con c)
458 » » » » » printLabels(o, labels, "\t\t")
459 } else { 502 } else {
460 » » » » » o.printf(obj, "\t%s", conc) 503 » » » » » printf(obj, "\t%s", ptr.typ)
461 } 504 }
462 » » » }) 505 » » » }
463 } else { 506 } else {
464 » » » o.printf(o, "interface cannot contain any concrete value s.") 507 » » » printf(false, "interface cannot contain any concrete val ues.")
465 } 508 }
466 } else { 509 } else {
467 // Show labels for other expressions. 510 // Show labels for other expressions.
468 » » if labels := pts.Labels(); len(labels) > 0 { 511 » » if ptr := r.ptrs[0]; len(ptr.labels) > 0 {
469 » » » o.printf(o, "value may point to these labels:") 512 » » » printf(false, "value may point to these labels:")
470 » » » printLabels(o, labels, "\t") 513 » » » printLabels(printf, ptr.labels, "\t")
471 } else { 514 } else {
472 » » » o.printf(o, "value cannot point to anything.") 515 » » » printf(false, "value cannot point to anything.")
473 } 516 }
474 } 517 }
475 } 518 }
476 519
520 func (r *describeValueResult) toJSON(res *json.Result, fset *token.FileSet) {
521 var value, objpos, ptaerr string
522 if r.constVal != nil {
523 value = r.constVal.String()
524 }
525 if r.obj != nil {
526 objpos = fset.Position(r.obj.Pos()).String()
527 }
528 if r.ptaErr != nil {
529 ptaerr = r.ptaErr.Error()
530 }
531
532 var pts []*json.DescribePointer
533 for _, ptr := range r.ptrs {
534 var namePos string
535 if nt, ok := deref(ptr.typ).(*types.Named); ok {
536 namePos = fset.Position(nt.Obj().Pos()).String()
537 }
538 var labels []json.DescribePTALabel
539 for _, l := range ptr.labels {
540 labels = append(labels, json.DescribePTALabel{
541 Pos: fset.Position(l.Pos()).String(),
542 Desc: l.String(),
543 })
544 }
545 pts = append(pts, &json.DescribePointer{
546 Type: ptr.typ.String(),
547 NamePos: namePos,
548 Labels: labels,
549 })
550 }
551
552 res.Describe = &json.Describe{
553 Desc: importer.NodeDescription(r.expr),
554 Pos: fset.Position(r.expr.Pos()).String(),
555 Detail: "value",
556 Value: &json.DescribeValue{
557 Type: r.typ.String(),
558 Value: value,
559 ObjPos: objpos,
560 PTAErr: ptaerr,
561 PTS: pts,
562 },
563 }
564 }
565
566 type byTypeString []pointerResult
567
568 func (a byTypeString) Len() int { return len(a) }
569 func (a byTypeString) Less(i, j int) bool { return a[i].typ.String() < a[j].typ. String() }
570 func (a byTypeString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
571
477 type byPosAndString []*pointer.Label 572 type byPosAndString []*pointer.Label
478 573
479 func (a byPosAndString) Len() int { return len(a) } 574 func (a byPosAndString) Len() int { return len(a) }
480 func (a byPosAndString) Less(i, j int) bool { 575 func (a byPosAndString) Less(i, j int) bool {
481 cmp := a[i].Pos() - a[j].Pos() 576 cmp := a[i].Pos() - a[j].Pos()
482 return cmp < 0 || (cmp == 0 && a[i].String() < a[j].String()) 577 return cmp < 0 || (cmp == 0 && a[i].String() < a[j].String())
483 } 578 }
484 func (a byPosAndString) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 579 func (a byPosAndString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
485 580
486 func printLabels(o *oracle, labels []*pointer.Label, prefix string) { 581 func printLabels(printf printfFunc, labels []*pointer.Label, prefix string) {
487 » // Sort, to ensure deterministic test behaviour.
488 » sort.Sort(byPosAndString(labels))
489 // TODO(adonovan): due to context-sensitivity, many of these 582 // TODO(adonovan): due to context-sensitivity, many of these
490 // labels may differ only by context, which isn't apparent. 583 // labels may differ only by context, which isn't apparent.
491 for _, label := range labels { 584 for _, label := range labels {
492 » » o.printf(label, "%s%s", prefix, label) 585 » » printf(label, "%s%s", prefix, label)
493 } 586 }
494 } 587 }
495 588
496 // ---- TYPE ------------------------------------------------------------ 589 // ---- TYPE ------------------------------------------------------------
497 590
498 func describeType(o *oracle, path []ast.Node) (*describeTypeResult, error) { 591 func describeType(o *oracle, path []ast.Node) (*describeTypeResult, error) {
499 var description string 592 var description string
500 var t types.Type 593 var t types.Type
501 switch n := path[0].(type) { 594 switch n := path[0].(type) {
502 case *ast.Ident: 595 case *ast.Ident:
(...skipping 13 matching lines...) Expand all
516 609
517 case ast.Expr: 610 case ast.Expr:
518 t = o.queryPkgInfo.TypeOf(n) 611 t = o.queryPkgInfo.TypeOf(n)
519 description = "type " + t.String() 612 description = "type " + t.String()
520 613
521 default: 614 default:
522 // Unreachable? 615 // Unreachable?
523 return nil, o.errorf(n, "unexpected AST for type: %T", n) 616 return nil, o.errorf(n, "unexpected AST for type: %T", n)
524 } 617 }
525 618
526 » return &describeTypeResult{path[0], description, t}, nil 619 » return &describeTypeResult{
620 » » node: path[0],
621 » » description: description,
622 » » typ: t,
623 » » methods: accessibleMethods(t, o.queryPkgInfo.Pkg),
624 » }, nil
527 } 625 }
528 626
529 type describeTypeResult struct { 627 type describeTypeResult struct {
530 node ast.Node 628 node ast.Node
531 description string 629 description string
532 typ types.Type 630 typ types.Type
631 methods []*types.Selection
533 } 632 }
534 633
535 func (r *describeTypeResult) display(o *oracle) { 634 func (r *describeTypeResult) display(printf printfFunc) {
536 » o.printf(r.node, "%s", r.description) 635 » printf(r.node, "%s", r.description)
537 636
538 // Show the underlying type for a reference to a named type. 637 // Show the underlying type for a reference to a named type.
539 if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() { 638 if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
540 » » o.printf(nt.Obj(), "defined as %s", nt.Underlying()) 639 » » printf(nt.Obj(), "defined as %s", nt.Underlying())
541 } 640 }
542 641
543 // Print the method set, if the type kind is capable of bearing methods. 642 // Print the method set, if the type kind is capable of bearing methods.
544 switch r.typ.(type) { 643 switch r.typ.(type) {
545 case *types.Interface, *types.Struct, *types.Named: 644 case *types.Interface, *types.Struct, *types.Named:
546 » » // TODO(adonovan): don't show unexported methods if 645 » » if len(r.methods) > 0 {
547 » » // r.typ belongs to a package other than the query 646 » » » printf(r.node, "Method set:")
548 » » // package. 647 » » » for _, meth := range r.methods {
549 » » if m := ssa.IntuitiveMethodSet(r.typ); m != nil { 648 » » » » printf(meth.Obj(), "\t%s", meth)
550 » » » o.printf(r.node, "Method set:")
551 » » » for _, meth := range m {
552 » » » » o.printf(meth.Obj(), "\t%s", meth)
553 } 649 }
554 } else { 650 } else {
555 » » » o.printf(r.node, "No methods.") 651 » » » printf(r.node, "No methods.")
556 } 652 }
557 } 653 }
558 } 654 }
559 655
656 func (r *describeTypeResult) toJSON(res *json.Result, fset *token.FileSet) {
657 var namePos, nameDef string
658 if nt, ok := r.typ.(*types.Named); ok {
659 namePos = fset.Position(nt.Obj().Pos()).String()
660 nameDef = nt.Underlying().String()
661 }
662 res.Describe = &json.Describe{
663 Desc: r.description,
664 Pos: fset.Position(r.node.Pos()).String(),
665 Detail: "type",
666 Type: &json.DescribeType{
667 Type: r.typ.String(),
668 NamePos: namePos,
669 NameDef: nameDef,
670 Methods: methodsToJSON(r.methods, fset),
671 },
672 }
673 }
674
560 // ---- PACKAGE ------------------------------------------------------------ 675 // ---- PACKAGE ------------------------------------------------------------
561 676
562 func describePackage(o *oracle, path []ast.Node) (*describePackageResult, error) { 677 func describePackage(o *oracle, path []ast.Node) (*describePackageResult, error) {
563 var description string 678 var description string
564 var importPath string 679 var importPath string
565 switch n := path[0].(type) { 680 switch n := path[0].(type) {
566 case *ast.ImportSpec: 681 case *ast.ImportSpec:
567 // importPath = o.queryPkgInfo.ObjectOf(n.Name).(*types.Package) .Path() 682 // importPath = o.queryPkgInfo.ObjectOf(n.Name).(*types.Package) .Path()
568 // description = "import of package " + importPath 683 // description = "import of package " + importPath
569 // TODO(gri): o.queryPkgInfo.ObjectOf(n.Name) may be nil. 684 // TODO(gri): o.queryPkgInfo.ObjectOf(n.Name) may be nil.
(...skipping 12 matching lines...) Expand all
582 if importPath == "" { 697 if importPath == "" {
583 // TODO(gri): fix. 698 // TODO(gri): fix.
584 return nil, o.errorf(n, "types.Package.Path() returned \ "\"\n") 699 return nil, o.errorf(n, "types.Package.Path() returned \ "\"\n")
585 } 700 }
586 701
587 default: 702 default:
588 // Unreachable? 703 // Unreachable?
589 return nil, o.errorf(n, "unexpected AST for package: %T", n) 704 return nil, o.errorf(n, "unexpected AST for package: %T", n)
590 } 705 }
591 706
592 » pkg := o.prog.PackagesByPath[importPath] 707 » var members []*describeMember
708 » // NB: package "unsafe" has no object.
709 » if pkg := o.prog.PackagesByPath[importPath]; pkg != nil {
710 » » // Compute set of exported package members in lexicographic orde r.
711 » » var names []string
712 » » for name := range pkg.Members {
713 » » » if pkg.Object == o.queryPkgInfo.Pkg || ast.IsExported(na me) {
714 » » » » names = append(names, name)
715 » » » }
716 » » }
717 » » sort.Strings(names)
593 718
594 » return &describePackageResult{path[0], description, pkg}, nil 719 » » // Enumerate the package members.
720 » » for _, name := range names {
721 » » » mem := pkg.Members[name]
722 » » » var methods []*types.Selection
723 » » » if mem, ok := mem.(*ssa.Type); ok {
724 » » » » methods = accessibleMethods(mem.Type(), o.queryP kgInfo.Pkg)
725 » » » }
726 » » » members = append(members, &describeMember{
727 » » » » mem,
728 » » » » methods,
729 » » » })
730 » » }
731 » }
732
733 » return &describePackageResult{o.prog.Fset, path[0], description, importP ath, members}, nil
595 } 734 }
596 735
597 type describePackageResult struct { 736 type describePackageResult struct {
737 fset *token.FileSet
598 node ast.Node 738 node ast.Node
599 description string 739 description string
600 » pkg *ssa.Package 740 » path string
741 » members []*describeMember // in lexicographic name order
601 } 742 }
602 743
603 func (r *describePackageResult) display(o *oracle) { 744 type describeMember struct {
604 » o.printf(r.node, "%s", r.description) 745 » mem ssa.Member
605 » // TODO(adonovan): factor this into a testable utility function. 746 » methods []*types.Selection // in types.MethodSet order
606 » if p := r.pkg; p != nil { 747 }
607 » » samePkg := p.Object == o.queryPkgInfo.Pkg
608 748
609 » » // Describe exported package members, in lexicographic order. 749 func (r *describePackageResult) display(printf printfFunc) {
750 » printf(r.node, "%s", r.description)
610 751
611 » » // Compute max width of name "column". 752 » // Compute max width of name "column".
612 » » var names []string 753 » maxname := 0
613 » » maxname := 0 754 » for _, mem := range r.members {
614 » » for name := range p.Members { 755 » » if l := len(mem.mem.Name()); l > maxname {
615 » » » if samePkg || ast.IsExported(name) { 756 » » » maxname = l
616 » » » » if l := len(name); l > maxname {
617 » » » » » maxname = l
618 » » » » }
619 » » » » names = append(names, name)
620 » » » }
621 } 757 }
758 }
622 759
623 » » sort.Strings(names) 760 » for _, mem := range r.members {
624 761 » » printf(mem.mem, "\t%s", formatMember(mem.mem, maxname))
625 » » // Print the members. 762 » » for _, meth := range mem.methods {
626 » » for _, name := range names { 763 » » » printf(meth.Obj(), "\t\t%s", meth)
627 » » » mem := p.Members[name]
628 » » » o.printf(mem, "%s", formatMember(mem, maxname))
629 » » » // Print method set.
630 » » » if mem, ok := mem.(*ssa.Type); ok {
631 » » » » for _, meth := range ssa.IntuitiveMethodSet(mem. Type()) {
632 » » » » » if samePkg || ast.IsExported(meth.Obj(). Name()) {
633 » » » » » » o.printf(meth.Obj(), "\t\t%s", m eth)
634 » » » » » }
635 » » » » }
636 » » » }
637 } 764 }
638 } 765 }
639 } 766 }
640 767
641 func formatMember(mem ssa.Member, maxname int) string { 768 func formatMember(mem ssa.Member, maxname int) string {
642 var buf bytes.Buffer 769 var buf bytes.Buffer
643 » fmt.Fprintf(&buf, "\t%-5s %-*s", mem.Token(), maxname, mem.Name()) 770 » fmt.Fprintf(&buf, "%-5s %-*s", mem.Token(), maxname, mem.Name())
644 switch mem := mem.(type) { 771 switch mem := mem.(type) {
645 case *ssa.NamedConst: 772 case *ssa.NamedConst:
646 fmt.Fprintf(&buf, " %s = %s", mem.Type(), mem.Value.Name()) 773 fmt.Fprintf(&buf, " %s = %s", mem.Type(), mem.Value.Name())
647 774
648 case *ssa.Function: 775 case *ssa.Function:
649 fmt.Fprintf(&buf, " %s", mem.Type()) 776 fmt.Fprintf(&buf, " %s", mem.Type())
650 777
651 case *ssa.Type: 778 case *ssa.Type:
652 // Abbreviate long aggregate type names. 779 // Abbreviate long aggregate type names.
653 var abbrev string 780 var abbrev string
(...skipping 12 matching lines...) Expand all
666 } else { 793 } else {
667 fmt.Fprintf(&buf, " %s", abbrev) 794 fmt.Fprintf(&buf, " %s", abbrev)
668 } 795 }
669 796
670 case *ssa.Global: 797 case *ssa.Global:
671 fmt.Fprintf(&buf, " %s", deref(mem.Type())) 798 fmt.Fprintf(&buf, " %s", deref(mem.Type()))
672 } 799 }
673 return buf.String() 800 return buf.String()
674 } 801 }
675 802
803 func (r *describePackageResult) toJSON(res *json.Result, fset *token.FileSet) {
804 var members []*json.DescribeMember
805 for _, mem := range r.members {
806 typ := mem.mem.Type()
807 var val string
808 switch mem := mem.mem.(type) {
809 case *ssa.NamedConst:
810 val = mem.Value.Value.String()
811 case *ssa.Type:
812 typ = typ.Underlying()
813 case *ssa.Global:
814 typ = deref(typ)
815 }
816 members = append(members, &json.DescribeMember{
817 Name: mem.mem.Name(),
818 Type: typ.String(),
819 Value: val,
820 Pos: fset.Position(mem.mem.Pos()).String(),
821 Kind: mem.mem.Token().String(),
822 Methods: methodsToJSON(mem.methods, fset),
823 })
824 }
825 res.Describe = &json.Describe{
826 Desc: r.description,
827 Pos: fset.Position(r.node.Pos()).String(),
828 Detail: "package",
829 Package: &json.DescribePackage{
830 Path: r.path,
831 Members: members,
832 },
833 }
834 }
835
676 // ---- STATEMENT ------------------------------------------------------------ 836 // ---- STATEMENT ------------------------------------------------------------
677 837
678 func describeStmt(o *oracle, path []ast.Node) (*describeStmtResult, error) { 838 func describeStmt(o *oracle, path []ast.Node) (*describeStmtResult, error) {
679 var description string 839 var description string
680 switch n := path[0].(type) { 840 switch n := path[0].(type) {
681 case *ast.Ident: 841 case *ast.Ident:
682 if o.queryPkgInfo.ObjectOf(n).Pos() == n.Pos() { 842 if o.queryPkgInfo.ObjectOf(n).Pos() == n.Pos() {
683 description = "labelled statement" 843 description = "labelled statement"
684 } else { 844 } else {
685 description = "reference to labelled statement" 845 description = "reference to labelled statement"
686 } 846 }
687 847
688 default: 848 default:
689 // Nothing much to say about statements. 849 // Nothing much to say about statements.
690 description = importer.NodeDescription(n) 850 description = importer.NodeDescription(n)
691 } 851 }
692 » return &describeStmtResult{path[0], description}, nil 852 » return &describeStmtResult{o.prog.Fset, path[0], description}, nil
693 } 853 }
694 854
695 type describeStmtResult struct { 855 type describeStmtResult struct {
856 fset *token.FileSet
696 node ast.Node 857 node ast.Node
697 description string 858 description string
698 } 859 }
699 860
700 func (r *describeStmtResult) display(o *oracle) { 861 func (r *describeStmtResult) display(printf printfFunc) {
701 » o.printf(r.node, "%s", r.description) 862 » printf(r.node, "%s", r.description)
863 }
864
865 func (r *describeStmtResult) toJSON(res *json.Result, fset *token.FileSet) {
866 » res.Describe = &json.Describe{
867 » » Desc: r.description,
868 » » Pos: fset.Position(r.node.Pos()).String(),
869 » » Detail: "unknown",
870 » }
702 } 871 }
703 872
704 // ------------------- Utilities ------------------- 873 // ------------------- Utilities -------------------
705 874
706 // pathToString returns a string containing the concrete types of the 875 // pathToString returns a string containing the concrete types of the
707 // nodes in path. 876 // nodes in path.
708 func pathToString2(path []ast.Node) string { 877 func pathToString2(path []ast.Node) string {
709 var buf bytes.Buffer 878 var buf bytes.Buffer
710 fmt.Fprint(&buf, "[") 879 fmt.Fprint(&buf, "[")
711 for i, n := range path { 880 for i, n := range path {
712 if i > 0 { 881 if i > 0 {
713 fmt.Fprint(&buf, " ") 882 fmt.Fprint(&buf, " ")
714 } 883 }
715 fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast. ")) 884 fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast. "))
716 } 885 }
717 fmt.Fprint(&buf, "]") 886 fmt.Fprint(&buf, "]")
718 return buf.String() 887 return buf.String()
719 } 888 }
889
890 func accessibleMethods(t types.Type, from *types.Package) []*types.Selection {
891 var methods []*types.Selection
892 for _, meth := range ssa.IntuitiveMethodSet(t) {
893 if isAccessibleFrom(meth.Obj(), from) {
894 methods = append(methods, meth)
895 }
896 }
897 return methods
898 }
899
900 func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
901 return ast.IsExported(obj.Name()) || obj.Pkg() == pkg
902 }
903
904 func methodsToJSON(methods []*types.Selection, fset *token.FileSet) []json.Descr ibeMethod {
905 var jmethods []json.DescribeMethod
906 for _, meth := range methods {
907 jmethods = append(jmethods, json.DescribeMethod{
908 Name: meth.String(),
909 Pos: fset.Position(meth.Obj().Pos()).String(),
910 })
911 }
912 return jmethods
913 }
OLDNEW
« no previous file with comments | « oracle/callstack.go ('k') | oracle/freevars.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b