GoPLS Viewer

Home|gopls/go/callgraph/cha/cha_test.go
1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// No testdata on Android.
6
7//go:build !android
8// +build !android
9
10package cha_test
11
12import (
13    "bytes"
14    "fmt"
15    "go/ast"
16    "go/parser"
17    "go/token"
18    "go/types"
19    "io/ioutil"
20    "sort"
21    "strings"
22    "testing"
23
24    "golang.org/x/tools/go/callgraph"
25    "golang.org/x/tools/go/callgraph/cha"
26    "golang.org/x/tools/go/loader"
27    "golang.org/x/tools/go/ssa"
28    "golang.org/x/tools/go/ssa/ssautil"
29    "golang.org/x/tools/internal/typeparams"
30)
31
32var inputs = []string{
33    "testdata/func.go",
34    "testdata/iface.go",
35    "testdata/recv.go",
36    "testdata/issue23925.go",
37}
38
39func expectation(f *ast.File) (stringtoken.Pos) {
40    for _c := range f.Comments {
41        text := strings.TrimSpace(c.Text())
42        if t := strings.TrimPrefix(text"WANT:\n"); t != text {
43            return tc.Pos()
44        }
45    }
46    return ""token.NoPos
47}
48
49// TestCHA runs CHA on each file in inputs, prints the dynamic edges of
50// the call graph, and compares it with the golden results embedded in
51// the WANT comment at the end of the file.
52func TestCHA(t *testing.T) {
53    for _filename := range inputs {
54        progfmainPkgerr := loadProgInfo(filenamessa.InstantiateGenerics)
55        if err != nil {
56            t.Error(err)
57            continue
58        }
59
60        wantpos := expectation(f)
61        if pos == token.NoPos {
62            t.Error(fmt.Errorf("No WANT: comment in %s"filename))
63            continue
64        }
65
66        cg := cha.CallGraph(prog)
67
68        if got := printGraph(cgmainPkg.Pkg"dynamic""Dynamic calls"); got != want {
69            t.Errorf("%s: got:\n%s\nwant:\n%s",
70                prog.Fset.Position(pos), gotwant)
71        }
72    }
73}
74
75// TestCHAGenerics is TestCHA tailored for testing generics,
76func TestCHAGenerics(t *testing.T) {
77    if !typeparams.Enabled {
78        t.Skip("TestCHAGenerics requires type parameters")
79    }
80
81    filename := "testdata/generics.go"
82    progfmainPkgerr := loadProgInfo(filenamessa.InstantiateGenerics)
83    if err != nil {
84        t.Fatal(err)
85    }
86
87    wantpos := expectation(f)
88    if pos == token.NoPos {
89        t.Fatal(fmt.Errorf("No WANT: comment in %s"filename))
90    }
91
92    cg := cha.CallGraph(prog)
93
94    if got := printGraph(cgmainPkg.Pkg"""All calls"); got != want {
95        t.Errorf("%s: got:\n%s\nwant:\n%s",
96            prog.Fset.Position(pos), gotwant)
97    }
98}
99
100func loadProgInfo(filename stringmode ssa.BuilderMode) (*ssa.Program, *ast.File, *ssa.Packageerror) {
101    contenterr := ioutil.ReadFile(filename)
102    if err != nil {
103        return nilnilnilfmt.Errorf("couldn't read file '%s': %s"filenameerr)
104    }
105
106    conf := loader.Config{
107        ParserModeparser.ParseComments,
108    }
109    ferr := conf.ParseFile(filenamecontent)
110    if err != nil {
111        return nilnilnilerr
112    }
113
114    conf.CreateFromFiles("main"f)
115    iprogerr := conf.Load()
116    if err != nil {
117        return nilnilnilerr
118    }
119
120    prog := ssautil.CreateProgram(iprogmode)
121    prog.Build()
122
123    return progfprog.Package(iprog.Created[0].Pkg), nil
124}
125
126// printGraph returns a string representation of cg involving only edges
127// whose description contains edgeMatch. The string representation is
128// prefixed with a desc line.
129func printGraph(cg *callgraph.Graphfrom *types.PackageedgeMatch stringdesc stringstring {
130    var edges []string
131    callgraph.GraphVisitEdges(cg, func(e *callgraph.Edgeerror {
132        if strings.Contains(e.Description(), edgeMatch) {
133            edges = append(edgesfmt.Sprintf("%s --> %s",
134                e.Caller.Func.RelString(from),
135                e.Callee.Func.RelString(from)))
136        }
137        return nil
138    })
139    sort.Strings(edges)
140
141    var buf bytes.Buffer
142    buf.WriteString(desc + "\n")
143    for _edge := range edges {
144        fmt.Fprintf(&buf"  %s\n"edge)
145    }
146    return strings.TrimSpace(buf.String())
147}
148
MembersX
parser
testing
TestCHA.RangeStmt_1150.BlockStmt.err
expectation.RangeStmt_750.BlockStmt.text
TestCHA.RangeStmt_1150.BlockStmt.want
TestCHA.RangeStmt_1150.BlockStmt.cg
TestCHAGenerics.want
loadProgInfo.content
TestCHAGenerics
loadProgInfo.prog
TestCHAGenerics.err
loadProgInfo.conf
printGraph.edges
fmt
sort
loader
typeparams
TestCHA.RangeStmt_1150.BlockStmt.pos
expectation.f
TestCHA.RangeStmt_1150.BlockStmt.f
expectation
TestCHA.RangeStmt_1150.filename
loadProgInfo.filename
loadProgInfo.iprog
strings
TestCHA.t
printGraph
TestCHAGenerics.mainPkg
loadProgInfo.err
ast
expectation.RangeStmt_750.BlockStmt.t
printGraph.from
token
TestCHA.RangeStmt_1150.BlockStmt.prog
TestCHAGenerics.filename
TestCHAGenerics.f
loadProgInfo.mode
ioutil
TestCHAGenerics.got
loadProgInfo
printGraph.cg
printGraph.RangeStmt_3527.edge
cha
TestCHA
TestCHA.RangeStmt_1150.BlockStmt.got
printGraph.buf
TestCHA.RangeStmt_1150.BlockStmt.mainPkg
TestCHAGenerics.t
expectation.RangeStmt_750.c
printGraph.edgeMatch
printGraph.desc
bytes
TestCHAGenerics.prog
TestCHAGenerics.pos
TestCHAGenerics.cg
loadProgInfo.f
Members
X