mirror of
https://github.com/golang/go
synced 2024-11-18 23:54:41 -07:00
e08d89f3ed
+ 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
85 lines
2.5 KiB
Go
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)
|
|
}
|
|
}
|