util/codegen: add NamedTypes

And use it in cmd/cloner.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
josh/immutable-views
Josh Bleecher Snyder 3 years ago committed by Josh Bleecher Snyder
parent 367a973dc2
commit d8a8f70000

@ -17,8 +17,6 @@ import (
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
"go/ast"
"go/token"
"go/types" "go/types"
"log" "log"
"os" "os"
@ -62,33 +60,13 @@ func main() {
pkg := pkgs[0] pkg := pkgs[0]
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
imports := make(map[string]struct{}) imports := make(map[string]struct{})
namedTypes := codegen.NamedTypes(pkg)
for _, typeName := range typeNames { for _, typeName := range typeNames {
found := false typ, ok := namedTypes[typeName]
for _, file := range pkg.Syntax {
for _, d := range file.Decls {
decl, ok := d.(*ast.GenDecl)
if !ok || decl.Tok != token.TYPE {
continue
}
for _, s := range decl.Specs {
spec, ok := s.(*ast.TypeSpec)
if !ok || spec.Name.Name != typeName {
continue
}
typeNameObj := pkg.TypesInfo.Defs[spec.Name]
typ, ok := typeNameObj.Type().(*types.Named)
if !ok { if !ok {
continue
}
pkg := typeNameObj.Pkg()
gen(buf, imports, typ, pkg)
found = true
}
}
}
if !found {
log.Fatalf("could not find type %s", typeName) log.Fatalf("could not find type %s", typeName)
} }
gen(buf, imports, typ, pkg.Types)
} }
w := func(format string, args ...interface{}) { w := func(format string, args ...interface{}) {

@ -8,9 +8,13 @@ package codegen
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"go/ast"
"go/format" "go/format"
"go/token"
"go/types" "go/types"
"os" "os"
"golang.org/x/tools/go/packages"
) )
// WriteFormatted writes code to path. // WriteFormatted writes code to path.
@ -41,6 +45,32 @@ func WriteFormatted(code []byte, path string) error {
return nil return nil
} }
// NamedTypes returns all named types in pkg, keyed by their type name.
func NamedTypes(pkg *packages.Package) map[string]*types.Named {
nt := make(map[string]*types.Named)
for _, file := range pkg.Syntax {
for _, d := range file.Decls {
decl, ok := d.(*ast.GenDecl)
if !ok || decl.Tok != token.TYPE {
continue
}
for _, s := range decl.Specs {
spec, ok := s.(*ast.TypeSpec)
if !ok {
continue
}
typeNameObj := pkg.TypesInfo.Defs[spec.Name]
typ, ok := typeNameObj.Type().(*types.Named)
if !ok {
continue
}
nt[spec.Name.Name] = typ
}
}
}
return nt
}
// AssertStructUnchanged generates code that asserts at compile time that type t is unchanged. // AssertStructUnchanged generates code that asserts at compile time that type t is unchanged.
// tname is the named type corresponding to t. // tname is the named type corresponding to t.
// ctx is a single-word context for this assertion, such as "Clone". // ctx is a single-word context for this assertion, such as "Clone".

Loading…
Cancel
Save