+++ /dev/null
-// Copyright 2014 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.
-
-// No testdata on Android.
-
-// +build !android
-
-package rta_test
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "go/types"
- "io/ioutil"
- "sort"
- "strings"
- "testing"
-
- "golang.org/x/tools/go/callgraph"
- "golang.org/x/tools/go/callgraph/rta"
- "golang.org/x/tools/go/loader"
- "golang.org/x/tools/go/ssa"
- "golang.org/x/tools/go/ssa/ssautil"
-)
-
-var inputs = []string{
- "testdata/func.go",
- "testdata/rtype.go",
- "testdata/iface.go",
-}
-
-func expectation(f *ast.File) (string, token.Pos) {
- for _, c := range f.Comments {
- text := strings.TrimSpace(c.Text())
- if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
- return t, c.Pos()
- }
- }
- return "", token.NoPos
-}
-
-// TestRTA runs RTA on each file in inputs, prints the results, and
-// compares it with the golden results embedded in the WANT comment at
-// the end of the file.
-//
-// The results string consists of two parts: the set of dynamic call
-// edges, "f --> g", one per line, and the set of reachable functions,
-// one per line. Each set is sorted.
-//
-func TestRTA(t *testing.T) {
- for _, filename := range inputs {
- content, err := ioutil.ReadFile(filename)
- if err != nil {
- t.Errorf("couldn't read file '%s': %s", filename, err)
- continue
- }
-
- conf := loader.Config{
- ParserMode: parser.ParseComments,
- }
- f, err := conf.ParseFile(filename, content)
- if err != nil {
- t.Error(err)
- continue
- }
-
- want, pos := expectation(f)
- if pos == token.NoPos {
- t.Errorf("No WANT: comment in %s", filename)
- continue
- }
-
- conf.CreateFromFiles("main", f)
- iprog, err := conf.Load()
- if err != nil {
- t.Error(err)
- continue
- }
-
- prog := ssautil.CreateProgram(iprog, 0)
- mainPkg := prog.Package(iprog.Created[0].Pkg)
- prog.Build()
-
- res := rta.Analyze([]*ssa.Function{
- mainPkg.Func("main"),
- mainPkg.Func("init"),
- }, true)
-
- if got := printResult(res, mainPkg.Pkg); got != want {
- t.Errorf("%s: got:\n%s\nwant:\n%s",
- prog.Fset.Position(pos), got, want)
- }
- }
-}
-
-func printResult(res *rta.Result, from *types.Package) string {
- var buf bytes.Buffer
-
- writeSorted := func(ss []string) {
- sort.Strings(ss)
- for _, s := range ss {
- fmt.Fprintf(&buf, " %s\n", s)
- }
- }
-
- buf.WriteString("Dynamic calls\n")
- var edges []string
- callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
- if strings.Contains(e.Description(), "dynamic") {
- edges = append(edges, fmt.Sprintf("%s --> %s",
- e.Caller.Func.RelString(from),
- e.Callee.Func.RelString(from)))
- }
- return nil
- })
- writeSorted(edges)
-
- buf.WriteString("Reachable functions\n")
- var reachable []string
- for f := range res.Reachable {
- reachable = append(reachable, f.RelString(from))
- }
- writeSorted(reachable)
-
- buf.WriteString("Reflect types\n")
- var rtypes []string
- res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
- if value == false { // accessible to reflection
- rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
- }
- })
- writeSorted(rtypes)
-
- return strings.TrimSpace(buf.String())
-}