mirror of
https://github.com/golang/go
synced 2024-11-18 20:44:45 -07:00
37f76edde8
This CL is mostly a renaming s/json/serial/, abstracting the oracle package away from any particular data syntax. (The encoding/* machinery is very clean; clearly I should have structured it this way from the outset.) Supporting XML then becomes a one-liner in cmd/oracle/main.go. Also: call MarshalIndent(), not Marshall() then Indent(). R=crawshaw CC=golang-dev https://golang.org/cl/13858046
104 lines
3.1 KiB
Go
104 lines
3.1 KiB
Go
// 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.
|
|
|
|
package oracle
|
|
|
|
import (
|
|
"go/token"
|
|
|
|
"code.google.com/p/go.tools/go/types"
|
|
"code.google.com/p/go.tools/oracle/serial"
|
|
)
|
|
|
|
// 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, qpos *QueryPos) (queryResult, error) {
|
|
pkg := qpos.info.Pkg
|
|
|
|
// Compute set of named interface/concrete types at package level.
|
|
var interfaces, concretes []*types.Named
|
|
scope := pkg.Scope()
|
|
for _, name := range scope.Names() {
|
|
mem := scope.Lookup(name)
|
|
if t, ok := mem.(*types.TypeName); 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)
|
|
}
|
|
}
|
|
// TODO(adonovan): sort facts to ensure test nondeterminism.
|
|
|
|
return &implementsResult{o.prog.Fset, facts}, nil
|
|
}
|
|
|
|
type implementsFact struct {
|
|
iface *types.Named
|
|
conc types.Type // Named or Pointer(Named)
|
|
}
|
|
|
|
type implementsResult struct {
|
|
fset *token.FileSet
|
|
facts []implementsFact // facts are grouped by interface
|
|
}
|
|
|
|
func (r *implementsResult) display(printf printfFunc) {
|
|
var prevIface *types.Named
|
|
for _, fact := range r.facts {
|
|
if fact.iface != prevIface {
|
|
printf(fact.iface.Obj(), "\tInterface %s:", fact.iface)
|
|
prevIface = fact.iface
|
|
}
|
|
printf(deref(fact.conc).(*types.Named).Obj(), "\t\t%s", fact.conc)
|
|
}
|
|
}
|
|
|
|
func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
|
var facts []*serial.Implements
|
|
for _, fact := range r.facts {
|
|
facts = append(facts, &serial.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(),
|
|
})
|
|
}
|
|
res.Implements = facts
|
|
}
|