1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:54:42 -07:00
go/oracle/implements.go
Alan Donovan e08d89f3ed go.tools/oracle: an oracle that answers questions about Go source code.
+ Tests.
+ Emacs integration.
+ Emacs integration test.
+ very rudimentary Vim integration.  Needs some love from a Vim user.

TODO (in follow-ups):
- More tests would be good.
  We'll need to make the output order deterministic in more places.
- Documentation.

R=gri, crawshaw, dominik.honnef
CC=golang-dev
https://golang.org/cl/9502043
2013-08-27 17:58:26 -04:00

85 lines
2.5 KiB
Go

package oracle
import (
"code.google.com/p/go.tools/go/types"
"code.google.com/p/go.tools/ssa"
)
// Implements displays the 'implements" relation among all
// package-level named types in the package containing the query
// position.
//
// TODO(adonovan): more features:
// - should we include pairs of types belonging to
// different packages in the 'implements' relation?//
// - should we restrict the query to the type declaration identified
// by the query position, if any, and use all types in the package
// otherwise?
// - should we show types that are local to functions?
// They can only have methods via promotion.
// - abbreviate the set of concrete types implementing the empty
// interface.
// - should we scan the instruction stream for MakeInterface
// instructions and report which concrete->interface conversions
// actually occur, with examples? (NB: this is not a conservative
// answer due to ChangeInterface, i.e. subtyping among interfaces.)
//
func implements(o *oracle) (queryResult, error) {
pkg := o.prog.Package(o.queryPkgInfo.Pkg)
if pkg == nil {
return nil, o.errorf(o.queryPath[0], "no SSA package")
}
// Compute set of named interface/concrete types at package level.
var interfaces, concretes []*types.Named
for _, mem := range pkg.Members {
if t, ok := mem.(*ssa.Type); ok {
nt := t.Type().(*types.Named)
if _, ok := nt.Underlying().(*types.Interface); ok {
interfaces = append(interfaces, nt)
} else {
concretes = append(concretes, nt)
}
}
}
// For each interface, show the concrete types that implement it.
var facts []implementsFact
for _, iface := range interfaces {
fact := implementsFact{iface: iface}
for _, conc := range concretes {
if types.IsAssignableTo(conc, iface) {
fact.conc = conc
} else if ptr := types.NewPointer(conc); types.IsAssignableTo(ptr, iface) {
fact.conc = ptr
} else {
continue
}
facts = append(facts, fact)
}
}
return &implementsResult{facts}, nil
}
type implementsFact struct {
iface *types.Named
conc types.Type // Named or Pointer(Named)
}
type implementsResult struct {
facts []implementsFact // facts are grouped by interface
}
func (r *implementsResult) display(o *oracle) {
// TODO(adonovan): sort to ensure test nondeterminism.
var prevIface *types.Named
for _, fact := range r.facts {
if fact.iface != prevIface {
o.printf(fact.iface.Obj(), "\tInterface %s:", fact.iface)
prevIface = fact.iface
}
o.printf(deref(fact.conc).(*types.Named).Obj(), "\t\t%s", fact.conc)
}
}