Using go/types for
Code Comprehension and
Refactoring Tools
$ go list -f '{{.ImportPath}} {{join .GoFiles " "}}' std |
while read dir files; do
echo $(cd $dir && cat $files | wc -l) $dir
done | sort -rn | head
30197 runtime
10464 go/types ←
9049 net
8100 net/http
7741 unicode
6734 math/big
6658 syscall
6283 crypto/tls
4959 math
4952 reflect
$ go list std |
while read pkg; do
echo $(go doc $pkg |
grep -E '^(type|func|var|const)' | wc -l) $pkg
done | sort -rn | head
262 syscall
91 go/ast
91 debug/elf
88 go/types ←
82 net
70 net/http
69 os
65 math
50 bytes
47 strings
Analysis Libraries and Tools
gofmt
SSA IR builder�x/tools/go/ssa
Type checker
go/types
Parser�go/{parser,ast,scanner,token}
Pointer analysis�x/tools/go/pointer
gorename
vet
oracle
godoc
-analysis
llgo
eg
gomvpkg
golint
gofmt
Type checker
go/types
Parser�go/{parser,ast,scanner,token}
gorename
vet
Grok
Kythe
eg
gomvpkg
Analysis Libraries and Tools
and Services
SourceGraph
Demo
$ godoc -analysis=type -http :8000
Demo
oracle definition
referrers
freevars
implements
Demo
gorename
fmt
go/types
fmt
fmt
a.go
mypkg
parsed files
of mypkg
dependency
packages
type-checked
package
expression
information
!
compile errors
name
resolution
var x int
fmt.Println(x)
“What does the name x refer to?”
type
deduction
name
resolution
z := x.f()[0] << y
“What is the type of z?”
type
deduction
name
resolution
constant
evaluation
const KiB = 1 << (10 * (1 + iota))
“What is the value of KiB?”
type
deduction
name
resolution
constant
evaluation
*bytes.Buffer
unsafe.Sizeof(x)
type
deduction
name
resolution
constant
evaluation
*bytes.Buffer
unsafe.Sizeof(x)
T{K: 0}
[C]int
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
Func main
Var i
PkgName fmt imports “fmt”
Const format
Objects
fmt
Func Printf
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
Definitions
Func main
Var i
PkgName fmt imports “fmt”
Const format
fmt
Func Printf
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
Uses
PkgName fmt imports “fmt”
Const format
Var i
fmt
Func Printf
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
Renaming format to foo
Const format
package main
import "fmt"
const foo = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(foo, i)
}
}
Successfully renamed
package main
import "fmt"
const main = "%d green bottles\n"
func main() { // error: main already defined at package level
for i := 10; i >= 0; i-- {
fmt.Printf(main, i)
}
}
Same-level conflict
x
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
Universe
Package mypkg
File a.go
fmt
Printf
Lexical Blocks
a.k.a. “Scopes”
Func Println
Const true
Universe
Func main
Var i
PkgName fmt
Const format
Func Printf
Package fmt
Package mypkg
Const true
File a.go
Func main
for
{}
Tree of Scopes
package main
import "fmt"
const i = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(i, i) // error: i is not a string
}
}
Down-level conflict
x
Func Println
Const true
Universe
Func main
Var i
PkgName fmt
Const format
Func Printf
Package fmt
Package mypkg
Const true
File a.go
Func main
for
{}
Tree of Scopes
renaming “format” to “i”
would cause this reference
to become shadowed by this intervening declaration
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i-- {
fmt.Printf(format, i)
}
}
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for format := 10; format >= 0; format-- {
fmt.Printf(format, format) // error
}
}
Up-level conflict
x
package main
import "fmt"
const format = "%d green bottles\n"
func main() {
for i := 10; i >= 0; i {
fmt.Printf(format, i)
}
}
renaming “i” to “format”
would shadow this reference
to this enclosing declaration
import “go/types”
Thank you. Questions?
Alan Donovan
Google NYC
adonovan@google.com
Available October 30
gopl.io