2013-08-27 16:49:13 -06:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2013-08-27 15:58:26 -06:00
|
|
|
package oracle
|
|
|
|
|
|
|
|
import (
|
2013-09-03 13:29:02 -06:00
|
|
|
"go/token"
|
|
|
|
|
2013-08-27 15:58:26 -06:00
|
|
|
"code.google.com/p/go.tools/go/types"
|
2013-09-03 13:29:02 -06:00
|
|
|
"code.google.com/p/go.tools/oracle/json"
|
2013-08-27 15:58:26 -06:00
|
|
|
"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
|
2013-09-03 13:29:02 -06:00
|
|
|
// different packages in the 'implements' relation?
|
2013-08-27 15:58:26 -06:00
|
|
|
// - 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)
|
|
|
|
}
|
|
|
|
}
|
2013-09-03 13:29:02 -06:00
|
|
|
// TODO(adonovan): sort facts to ensure test nondeterminism.
|
2013-08-27 15:58:26 -06:00
|
|
|
|
2013-09-03 13:29:02 -06:00
|
|
|
return &implementsResult{o.prog.Fset, facts}, nil
|
2013-08-27 15:58:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type implementsFact struct {
|
|
|
|
iface *types.Named
|
|
|
|
conc types.Type // Named or Pointer(Named)
|
|
|
|
}
|
|
|
|
|
|
|
|
type implementsResult struct {
|
2013-09-03 13:29:02 -06:00
|
|
|
fset *token.FileSet
|
2013-08-27 15:58:26 -06:00
|
|
|
facts []implementsFact // facts are grouped by interface
|
|
|
|
}
|
|
|
|
|
2013-09-03 13:29:02 -06:00
|
|
|
func (r *implementsResult) display(printf printfFunc) {
|
2013-08-27 15:58:26 -06:00
|
|
|
var prevIface *types.Named
|
|
|
|
for _, fact := range r.facts {
|
|
|
|
if fact.iface != prevIface {
|
2013-09-03 13:29:02 -06:00
|
|
|
printf(fact.iface.Obj(), "\tInterface %s:", fact.iface)
|
2013-08-27 15:58:26 -06:00
|
|
|
prevIface = fact.iface
|
|
|
|
}
|
2013-09-03 13:29:02 -06:00
|
|
|
printf(deref(fact.conc).(*types.Named).Obj(), "\t\t%s", fact.conc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *implementsResult) toJSON(res *json.Result, fset *token.FileSet) {
|
|
|
|
var facts []*json.Implements
|
|
|
|
for _, fact := range r.facts {
|
|
|
|
facts = append(facts, &json.Implements{
|
|
|
|
I: fact.iface.String(),
|
|
|
|
IPos: fset.Position(fact.iface.Obj().Pos()).String(),
|
|
|
|
C: fact.conc.String(),
|
|
|
|
CPos: fset.Position(deref(fact.conc).(*types.Named).Obj().Pos()).String(),
|
|
|
|
})
|
2013-08-27 15:58:26 -06:00
|
|
|
}
|
2013-09-03 13:29:02 -06:00
|
|
|
res.Implements = facts
|
2013-08-27 15:58:26 -06:00
|
|
|
}
|