mirror of
https://github.com/golang/go
synced 2024-11-18 23:54:41 -07:00
go/ssa: acquire TestEnclosingFunction from go/loader package.
Not sure how it ended up there... Change-Id: I0d48025fd6595714b0c52cadf305b3e06e2b9b84 Reviewed-on: https://go-review.googlesource.com/9171 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
41d9a0e7b2
commit
bc61fa75b3
@ -1,127 +0,0 @@
|
|||||||
// 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 loader_test
|
|
||||||
|
|
||||||
// This file defines tests of source utilities.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/ast/astutil"
|
|
||||||
"golang.org/x/tools/go/loader"
|
|
||||||
"golang.org/x/tools/go/ssa"
|
|
||||||
"golang.org/x/tools/go/ssa/ssautil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// findInterval parses input and returns the [start, end) positions of
|
|
||||||
// the first occurrence of substr in input. f==nil indicates failure;
|
|
||||||
// an error has already been reported in that case.
|
|
||||||
//
|
|
||||||
func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
|
|
||||||
f, err := parser.ParseFile(fset, "<input>", input, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("parse error: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
i := strings.Index(input, substr)
|
|
||||||
if i < 0 {
|
|
||||||
t.Errorf("%q is not a substring of input", substr)
|
|
||||||
f = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filePos := fset.File(f.Package)
|
|
||||||
return f, filePos.Pos(i), filePos.Pos(i + len(substr))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnclosingFunction(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string // the input file
|
|
||||||
substr string // first occurrence of this string denotes interval
|
|
||||||
fn string // name of expected containing function
|
|
||||||
}{
|
|
||||||
// We use distinctive numbers as syntactic landmarks.
|
|
||||||
|
|
||||||
// Ordinary function:
|
|
||||||
{`package main
|
|
||||||
func f() { println(1003) }`,
|
|
||||||
"100", "main.f"},
|
|
||||||
// Methods:
|
|
||||||
{`package main
|
|
||||||
type T int
|
|
||||||
func (t T) f() { println(200) }`,
|
|
||||||
"200", "(main.T).f"},
|
|
||||||
// Function literal:
|
|
||||||
{`package main
|
|
||||||
func f() { println(func() { print(300) }) }`,
|
|
||||||
"300", "main.f$1"},
|
|
||||||
// Doubly nested
|
|
||||||
{`package main
|
|
||||||
func f() { println(func() { print(func() { print(350) })})}`,
|
|
||||||
"350", "main.f$1$1"},
|
|
||||||
// Implicit init for package-level var initializer.
|
|
||||||
{"package main; var a = 400", "400", "main.init"},
|
|
||||||
// No code for constants:
|
|
||||||
{"package main; const a = 500", "500", "(none)"},
|
|
||||||
// Explicit init()
|
|
||||||
{"package main; func init() { println(600) }", "600", "main.init#1"},
|
|
||||||
// Multiple explicit init functions:
|
|
||||||
{`package main
|
|
||||||
func init() { println("foo") }
|
|
||||||
func init() { println(800) }`,
|
|
||||||
"800", "main.init#2"},
|
|
||||||
// init() containing FuncLit.
|
|
||||||
{`package main
|
|
||||||
func init() { println(func(){print(900)}) }`,
|
|
||||||
"900", "main.init#1$1"},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
conf := loader.Config{Fset: token.NewFileSet()}
|
|
||||||
f, start, end := findInterval(t, conf.Fset, test.input, test.substr)
|
|
||||||
if f == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
path, exact := astutil.PathEnclosingInterval(f, start, end)
|
|
||||||
if !exact {
|
|
||||||
t.Errorf("EnclosingFunction(%q) not exact", test.substr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.CreateFromFiles("main", f)
|
|
||||||
|
|
||||||
iprog, err := conf.Load()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
prog := ssautil.CreateProgram(iprog, 0)
|
|
||||||
pkg := prog.Package(iprog.Created[0].Pkg)
|
|
||||||
pkg.Build()
|
|
||||||
|
|
||||||
name := "(none)"
|
|
||||||
fn := ssa.EnclosingFunction(pkg, path)
|
|
||||||
if fn != nil {
|
|
||||||
name = fn.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if name != test.fn {
|
|
||||||
t.Errorf("EnclosingFunction(%q in %q) got %s, want %s",
|
|
||||||
test.substr, test.input, name, test.fn)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// While we're here: test HasEnclosingFunction.
|
|
||||||
if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) {
|
|
||||||
t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v",
|
|
||||||
test.substr, test.input, has, fn != nil)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -275,3 +275,110 @@ func TestValueForExpr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findInterval parses input and returns the [start, end) positions of
|
||||||
|
// the first occurrence of substr in input. f==nil indicates failure;
|
||||||
|
// an error has already been reported in that case.
|
||||||
|
//
|
||||||
|
func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
|
||||||
|
f, err := parser.ParseFile(fset, "<input>", input, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("parse error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i := strings.Index(input, substr)
|
||||||
|
if i < 0 {
|
||||||
|
t.Errorf("%q is not a substring of input", substr)
|
||||||
|
f = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePos := fset.File(f.Package)
|
||||||
|
return f, filePos.Pos(i), filePos.Pos(i + len(substr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnclosingFunction(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string // the input file
|
||||||
|
substr string // first occurrence of this string denotes interval
|
||||||
|
fn string // name of expected containing function
|
||||||
|
}{
|
||||||
|
// We use distinctive numbers as syntactic landmarks.
|
||||||
|
|
||||||
|
// Ordinary function:
|
||||||
|
{`package main
|
||||||
|
func f() { println(1003) }`,
|
||||||
|
"100", "main.f"},
|
||||||
|
// Methods:
|
||||||
|
{`package main
|
||||||
|
type T int
|
||||||
|
func (t T) f() { println(200) }`,
|
||||||
|
"200", "(main.T).f"},
|
||||||
|
// Function literal:
|
||||||
|
{`package main
|
||||||
|
func f() { println(func() { print(300) }) }`,
|
||||||
|
"300", "main.f$1"},
|
||||||
|
// Doubly nested
|
||||||
|
{`package main
|
||||||
|
func f() { println(func() { print(func() { print(350) })})}`,
|
||||||
|
"350", "main.f$1$1"},
|
||||||
|
// Implicit init for package-level var initializer.
|
||||||
|
{"package main; var a = 400", "400", "main.init"},
|
||||||
|
// No code for constants:
|
||||||
|
{"package main; const a = 500", "500", "(none)"},
|
||||||
|
// Explicit init()
|
||||||
|
{"package main; func init() { println(600) }", "600", "main.init#1"},
|
||||||
|
// Multiple explicit init functions:
|
||||||
|
{`package main
|
||||||
|
func init() { println("foo") }
|
||||||
|
func init() { println(800) }`,
|
||||||
|
"800", "main.init#2"},
|
||||||
|
// init() containing FuncLit.
|
||||||
|
{`package main
|
||||||
|
func init() { println(func(){print(900)}) }`,
|
||||||
|
"900", "main.init#1$1"},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
conf := loader.Config{Fset: token.NewFileSet()}
|
||||||
|
f, start, end := findInterval(t, conf.Fset, test.input, test.substr)
|
||||||
|
if f == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path, exact := astutil.PathEnclosingInterval(f, start, end)
|
||||||
|
if !exact {
|
||||||
|
t.Errorf("EnclosingFunction(%q) not exact", test.substr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.CreateFromFiles("main", f)
|
||||||
|
|
||||||
|
iprog, err := conf.Load()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prog := ssautil.CreateProgram(iprog, 0)
|
||||||
|
pkg := prog.Package(iprog.Created[0].Pkg)
|
||||||
|
pkg.Build()
|
||||||
|
|
||||||
|
name := "(none)"
|
||||||
|
fn := ssa.EnclosingFunction(pkg, path)
|
||||||
|
if fn != nil {
|
||||||
|
name = fn.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != test.fn {
|
||||||
|
t.Errorf("EnclosingFunction(%q in %q) got %s, want %s",
|
||||||
|
test.substr, test.input, name, test.fn)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// While we're here: test HasEnclosingFunction.
|
||||||
|
if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) {
|
||||||
|
t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v",
|
||||||
|
test.substr, test.input, has, fn != nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user