go.tools/importer: move PathEnclosingInterval to package astutil.
R=crawshaw CC=golang-dev https://golang.org/cl/38650044
This commit is contained in:
parent
55fb2e8e28
commit
fb3d862cae
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package importer
|
||||
package astutil
|
||||
|
||||
// This file defines utilities for working with source positions.
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ import (
|
|||
//
|
||||
// Precondition: [start, end) both lie within the same file as root.
|
||||
// TODO(adonovan): return (nil, false) in this case and remove precond.
|
||||
// Requires FileSet; see tokenFileContainsPos.
|
||||
// Requires FileSet; see importer.tokenFileContainsPos.
|
||||
//
|
||||
// Postcondition: path is never nil; it always contains at least 'root'.
|
||||
//
|
||||
|
|
@ -623,32 +623,3 @@ func NodeDescription(n ast.Node) string {
|
|||
}
|
||||
panic(fmt.Sprintf("unexpected node type: %T", n))
|
||||
}
|
||||
|
||||
// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
|
||||
func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
|
||||
p := int(pos)
|
||||
base := f.Base()
|
||||
return base <= p && p < base+f.Size()
|
||||
}
|
||||
|
||||
// PathEnclosingInterval returns the PackageInfo and ast.Node that
|
||||
// contain source interval [start, end), and all the node's ancestors
|
||||
// up to the AST root. It searches all ast.Files of all packages in the
|
||||
// Importer imp. exact is defined as for standalone
|
||||
// PathEnclosingInterval.
|
||||
//
|
||||
// The result is (nil, nil, false) if not found.
|
||||
//
|
||||
func (imp *Importer) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
|
||||
for _, info := range imp.allPackages {
|
||||
for _, f := range info.Files {
|
||||
if !tokenFileContainsPos(imp.Fset.File(f.Package), start) {
|
||||
continue
|
||||
}
|
||||
if path, exact := PathEnclosingInterval(f, start, end); path != nil {
|
||||
return info, path, exact
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil, false
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
// 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 astutil_test
|
||||
|
||||
// This file defines tests of PathEnclosingInterval.
|
||||
|
||||
// TODO(adonovan): exhaustive tests that run over the whole input
|
||||
// tree, not just handcrafted examples.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
)
|
||||
|
||||
// pathToString returns a string containing the concrete types of the
|
||||
// nodes in path.
|
||||
func pathToString(path []ast.Node) string {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, "[")
|
||||
for i, n := range path {
|
||||
if i > 0 {
|
||||
fmt.Fprint(&buf, " ")
|
||||
}
|
||||
fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
|
||||
}
|
||||
fmt.Fprint(&buf, "]")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// Common input for following tests.
|
||||
const input = `
|
||||
// Hello.
|
||||
package main
|
||||
import "fmt"
|
||||
func f() {}
|
||||
func main() {
|
||||
z := (x + y) // add them
|
||||
f() // NB: ExprStmt and its CallExpr have same Pos/End
|
||||
}
|
||||
`
|
||||
|
||||
func TestPathEnclosingInterval_Exact(t *testing.T) {
|
||||
// For the exact tests, we check that a substring is mapped to
|
||||
// the canonical string for the node it denotes.
|
||||
tests := []struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
node string // complete text of expected containing node
|
||||
}{
|
||||
{"package",
|
||||
input[11 : len(input)-1]},
|
||||
{"\npack",
|
||||
input[11 : len(input)-1]},
|
||||
{"main",
|
||||
"main"},
|
||||
{"import",
|
||||
"import \"fmt\""},
|
||||
{"\"fmt\"",
|
||||
"\"fmt\""},
|
||||
{"\nfunc f() {}\n",
|
||||
"func f() {}"},
|
||||
{"x ",
|
||||
"x"},
|
||||
{" y",
|
||||
"y"},
|
||||
{"z",
|
||||
"z"},
|
||||
{" + ",
|
||||
"x + y"},
|
||||
{" :=",
|
||||
"z := (x + y)"},
|
||||
{"x + y",
|
||||
"x + y"},
|
||||
{"(x + y)",
|
||||
"(x + y)"},
|
||||
{" (x + y) ",
|
||||
"(x + y)"},
|
||||
{" (x + y) // add",
|
||||
"(x + y)"},
|
||||
{"func",
|
||||
"func f() {}"},
|
||||
{"func f() {}",
|
||||
"func f() {}"},
|
||||
{"\nfun",
|
||||
"func f() {}"},
|
||||
{" f",
|
||||
"f"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
path, exact := astutil.PathEnclosingInterval(f, start, end)
|
||||
if !exact {
|
||||
t.Errorf("PathEnclosingInterval(%q) not exact", test.substr)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
if test.node != "" {
|
||||
t.Errorf("PathEnclosingInterval(%q).path: got [], want %q",
|
||||
test.substr, test.node)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if got := input[path[0].Pos():path[0].End()]; got != test.node {
|
||||
t.Errorf("PathEnclosingInterval(%q): got %q, want %q (path was %s)",
|
||||
test.substr, got, test.node, pathToString(path))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathEnclosingInterval_Paths(t *testing.T) {
|
||||
// For these tests, we check only the path of the enclosing
|
||||
// node, but not its complete text because it's often quite
|
||||
// large when !exact.
|
||||
tests := []struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
path string // the pathToString(),exact of the expected path
|
||||
}{
|
||||
{"// add",
|
||||
"[BlockStmt FuncDecl File],false"},
|
||||
{"(x + y",
|
||||
"[ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"x +",
|
||||
"[BinaryExpr ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"z := (x",
|
||||
"[AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"func f",
|
||||
"[FuncDecl File],false"},
|
||||
{"func f()",
|
||||
"[FuncDecl File],false"},
|
||||
{" f()",
|
||||
"[FuncDecl File],false"},
|
||||
{"() {}",
|
||||
"[FuncDecl File],false"},
|
||||
{"// Hello",
|
||||
"[File],false"},
|
||||
{" f",
|
||||
"[Ident FuncDecl File],true"},
|
||||
{"func ",
|
||||
"[FuncDecl File],true"},
|
||||
{"mai",
|
||||
"[Ident File],true"},
|
||||
{"f() // NB",
|
||||
"[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
path, exact := astutil.PathEnclosingInterval(f, start, end)
|
||||
if got := fmt.Sprintf("%s,%v", pathToString(path), exact); got != test.path {
|
||||
t.Errorf("PathEnclosingInterval(%q): got %q, want %q",
|
||||
test.substr, got, test.path)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
"code.google.com/p/go.tools/go/gcimporter"
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
|
|
@ -531,3 +532,31 @@ func initialPackageFromFiles(fset *token.FileSet, arg string) (*initialPkg, erro
|
|||
files: files,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PathEnclosingInterval returns the PackageInfo and ast.Node that
|
||||
// contain source interval [start, end), and all the node's ancestors
|
||||
// up to the AST root. It searches all ast.Files of all packages in the
|
||||
// Importer imp. exact is defined as for astutil.PathEnclosingInterval.
|
||||
//
|
||||
// The result is (nil, nil, false) if not found.
|
||||
//
|
||||
func (imp *Importer) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
|
||||
for _, info := range imp.allPackages {
|
||||
for _, f := range info.Files {
|
||||
if !tokenFileContainsPos(imp.Fset.File(f.Package), start) {
|
||||
continue
|
||||
}
|
||||
if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
|
||||
return info, path, exact
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
|
||||
func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
|
||||
p := int(pos)
|
||||
base := f.Base()
|
||||
return base <= p && p < base+f.Size()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,37 +6,18 @@ package importer_test
|
|||
|
||||
// This file defines tests of source utilities.
|
||||
|
||||
// TODO(adonovan): exhaustive tests that run over the whole input
|
||||
// tree, not just handcrafted examples.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/importer"
|
||||
"code.google.com/p/go.tools/ssa"
|
||||
)
|
||||
|
||||
// pathToString returns a string containing the concrete types of the
|
||||
// nodes in path.
|
||||
func pathToString(path []ast.Node) string {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, "[")
|
||||
for i, n := range path {
|
||||
if i > 0 {
|
||||
fmt.Fprint(&buf, " ")
|
||||
}
|
||||
fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
|
||||
}
|
||||
fmt.Fprint(&buf, "]")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
@ -59,145 +40,6 @@ func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *a
|
|||
return f, filePos.Pos(i), filePos.Pos(i + len(substr))
|
||||
}
|
||||
|
||||
// Common input for following tests.
|
||||
const input = `
|
||||
// Hello.
|
||||
package main
|
||||
import "fmt"
|
||||
func f() {}
|
||||
func main() {
|
||||
z := (x + y) // add them
|
||||
f() // NB: ExprStmt and its CallExpr have same Pos/End
|
||||
}
|
||||
`
|
||||
|
||||
func TestPathEnclosingInterval_Exact(t *testing.T) {
|
||||
// For the exact tests, we check that a substring is mapped to
|
||||
// the canonical string for the node it denotes.
|
||||
tests := []struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
node string // complete text of expected containing node
|
||||
}{
|
||||
{"package",
|
||||
input[11 : len(input)-1]},
|
||||
{"\npack",
|
||||
input[11 : len(input)-1]},
|
||||
{"main",
|
||||
"main"},
|
||||
{"import",
|
||||
"import \"fmt\""},
|
||||
{"\"fmt\"",
|
||||
"\"fmt\""},
|
||||
{"\nfunc f() {}\n",
|
||||
"func f() {}"},
|
||||
{"x ",
|
||||
"x"},
|
||||
{" y",
|
||||
"y"},
|
||||
{"z",
|
||||
"z"},
|
||||
{" + ",
|
||||
"x + y"},
|
||||
{" :=",
|
||||
"z := (x + y)"},
|
||||
{"x + y",
|
||||
"x + y"},
|
||||
{"(x + y)",
|
||||
"(x + y)"},
|
||||
{" (x + y) ",
|
||||
"(x + y)"},
|
||||
{" (x + y) // add",
|
||||
"(x + y)"},
|
||||
{"func",
|
||||
"func f() {}"},
|
||||
{"func f() {}",
|
||||
"func f() {}"},
|
||||
{"\nfun",
|
||||
"func f() {}"},
|
||||
{" f",
|
||||
"f"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
path, exact := importer.PathEnclosingInterval(f, start, end)
|
||||
if !exact {
|
||||
t.Errorf("PathEnclosingInterval(%q) not exact", test.substr)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
if test.node != "" {
|
||||
t.Errorf("PathEnclosingInterval(%q).path: got [], want %q",
|
||||
test.substr, test.node)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if got := input[path[0].Pos():path[0].End()]; got != test.node {
|
||||
t.Errorf("PathEnclosingInterval(%q): got %q, want %q (path was %s)",
|
||||
test.substr, got, test.node, pathToString(path))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathEnclosingInterval_Paths(t *testing.T) {
|
||||
// For these tests, we check only the path of the enclosing
|
||||
// node, but not its complete text because it's often quite
|
||||
// large when !exact.
|
||||
tests := []struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
path string // the pathToString(),exact of the expected path
|
||||
}{
|
||||
{"// add",
|
||||
"[BlockStmt FuncDecl File],false"},
|
||||
{"(x + y",
|
||||
"[ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"x +",
|
||||
"[BinaryExpr ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"z := (x",
|
||||
"[AssignStmt BlockStmt FuncDecl File],false"},
|
||||
{"func f",
|
||||
"[FuncDecl File],false"},
|
||||
{"func f()",
|
||||
"[FuncDecl File],false"},
|
||||
{" f()",
|
||||
"[FuncDecl File],false"},
|
||||
{"() {}",
|
||||
"[FuncDecl File],false"},
|
||||
{"// Hello",
|
||||
"[File],false"},
|
||||
{" f",
|
||||
"[Ident FuncDecl File],true"},
|
||||
{"func ",
|
||||
"[FuncDecl File],true"},
|
||||
{"mai",
|
||||
"[Ident File],true"},
|
||||
{"f() // NB",
|
||||
"[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
path, exact := importer.PathEnclosingInterval(f, start, end)
|
||||
if got := fmt.Sprintf("%s,%v", pathToString(path), exact); got != test.path {
|
||||
t.Errorf("PathEnclosingInterval(%q): got %q, want %q",
|
||||
test.substr, got, test.path)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------- Tests of source.go -----------------------------------------
|
||||
|
||||
// TODO(adonovan): move this test into ssa.
|
||||
func TestEnclosingFunction(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string // the input file
|
||||
|
|
@ -245,7 +87,7 @@ func TestEnclosingFunction(t *testing.T) {
|
|||
if f == nil {
|
||||
continue
|
||||
}
|
||||
path, exact := importer.PathEnclosingInterval(f, start, end)
|
||||
path, exact := astutil.PathEnclosingInterval(f, start, end)
|
||||
if !exact {
|
||||
t.Errorf("EnclosingFunction(%q) not exact", test.substr)
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
"code.google.com/p/go.tools/importer"
|
||||
|
|
@ -36,7 +37,7 @@ import (
|
|||
func describe(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||
if false { // debugging
|
||||
o.fprintf(os.Stderr, qpos.path[0], "you selected: %s %s",
|
||||
importer.NodeDescription(qpos.path[0]), pathToString2(qpos.path))
|
||||
astutil.NodeDescription(qpos.path[0]), pathToString2(qpos.path))
|
||||
}
|
||||
|
||||
path, action := findInterestingNode(qpos.info, qpos.path)
|
||||
|
|
@ -67,12 +68,12 @@ type describeUnknownResult struct {
|
|||
|
||||
func (r *describeUnknownResult) display(printf printfFunc) {
|
||||
// Nothing much to say about misc syntax.
|
||||
printf(r.node, "%s", importer.NodeDescription(r.node))
|
||||
printf(r.node, "%s", astutil.NodeDescription(r.node))
|
||||
}
|
||||
|
||||
func (r *describeUnknownResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
res.Describe = &serial.Describe{
|
||||
Desc: importer.NodeDescription(r.node),
|
||||
Desc: astutil.NodeDescription(r.node),
|
||||
Pos: fset.Position(r.node.Pos()).String(),
|
||||
}
|
||||
}
|
||||
|
|
@ -496,7 +497,7 @@ func (r *describeValueResult) display(printf printfFunc) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
desc := importer.NodeDescription(r.expr)
|
||||
desc := astutil.NodeDescription(r.expr)
|
||||
if suffix != "" {
|
||||
// constant expression
|
||||
printf(r.expr, "%s%s", desc, suffix)
|
||||
|
|
@ -582,7 +583,7 @@ func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet)
|
|||
}
|
||||
|
||||
res.Describe = &serial.Describe{
|
||||
Desc: importer.NodeDescription(r.expr),
|
||||
Desc: astutil.NodeDescription(r.expr),
|
||||
Pos: fset.Position(r.expr.Pos()).String(),
|
||||
Detail: "value",
|
||||
Value: &serial.DescribeValue{
|
||||
|
|
@ -901,7 +902,7 @@ func describeStmt(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeStmtResu
|
|||
|
||||
default:
|
||||
// Nothing much to say about statements.
|
||||
description = importer.NodeDescription(n)
|
||||
description = astutil.NodeDescription(n)
|
||||
}
|
||||
return &describeStmtResult{o.prog.Fset, path[0], description}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
"code.google.com/p/go.tools/importer"
|
||||
"code.google.com/p/go.tools/oracle/serial"
|
||||
|
|
@ -339,7 +340,7 @@ func ParseQueryPos(imp *importer.Importer, pos string, needExact bool) (*QueryPo
|
|||
return nil, fmt.Errorf("no syntax here")
|
||||
}
|
||||
if needExact && !exact {
|
||||
return nil, fmt.Errorf("ambiguous selection within %s", importer.NodeDescription(path[0]))
|
||||
return nil, fmt.Errorf("ambiguous selection within %s", astutil.NodeDescription(path[0]))
|
||||
}
|
||||
return &QueryPos{start, end, info, path}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ func (lt *ltState) link(v, w *BasicBlock) {
|
|||
//
|
||||
func buildDomTree(f *Function) {
|
||||
// The step numbers refer to the original LT paper; the
|
||||
// reodering is due to Georgiadis.
|
||||
// reordering is due to Georgiadis.
|
||||
|
||||
// Clear any previous domInfo.
|
||||
for _, b := range f.Blocks {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
"code.google.com/p/go.tools/importer"
|
||||
|
|
@ -88,7 +89,7 @@ func TestObjValueLookup(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
if obj, ok := mainInfo.ObjectOf(id).(*types.Var); ok {
|
||||
ref, _ := importer.PathEnclosingInterval(f, id.Pos(), id.Pos())
|
||||
ref, _ := astutil.PathEnclosingInterval(f, id.Pos(), id.Pos())
|
||||
pos := imp.Fset.Position(id.Pos())
|
||||
exp := expectations[fmt.Sprintf("%s:%d", id.Name, pos.Line)]
|
||||
if exp == "" {
|
||||
|
|
@ -240,7 +241,7 @@ func TestValueForExpr(t *testing.T) {
|
|||
e = target.X
|
||||
}
|
||||
|
||||
path, _ := importer.PathEnclosingInterval(f, pos, pos)
|
||||
path, _ := astutil.PathEnclosingInterval(f, pos, pos)
|
||||
if path == nil {
|
||||
t.Errorf("%s: can't find AST path from root to comment: %s", position, text)
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in New Issue