diff --git a/oracle/freevars.go b/oracle/freevars.go index 1540f0bd..211e4818 100644 --- a/oracle/freevars.go +++ b/oracle/freevars.go @@ -28,6 +28,8 @@ import ( // func freevars(o *oracle) (queryResult, error) { file := o.queryPath[len(o.queryPath)-1] // the enclosing file + fileScope := o.queryPkgInfo.Scopes[file] + pkgScope := fileScope.Parent() // The id and sel functions return non-nil if they denote an // object o or selection o.x.y that is referenced by the @@ -61,11 +63,12 @@ func freevars(o *oracle) (queryResult, error) { if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) { return nil // not defined in this file } - if obj.Parent() == nil { - return nil // e.g. interface method TODO(adonovan): what else? + scope := obj.Parent() + if scope == nil { + return nil // e.g. interface method, struct field } - if obj.Parent() == o.queryPkgInfo.Scopes[file] { - return nil // defined at file scope + if scope == fileScope || scope == pkgScope { + return nil // defined at file or package scope } if o.startPos <= obj.Pos() && obj.Pos() <= o.endPos { return nil // defined within selection => not free diff --git a/oracle/testdata/src/main/freevars.go b/oracle/testdata/src/main/freevars.go index 82633d5a..1ce0ae6b 100644 --- a/oracle/testdata/src/main/freevars.go +++ b/oracle/testdata/src/main/freevars.go @@ -15,6 +15,8 @@ type S struct { t T } +func f(int) {} + func main() { type C int x := 1 @@ -29,6 +31,8 @@ func main() { println(s.x + s.t.a + s.t.b + x + int(y)) // @freevars fv2 "print.*y." } + f(x) // @freevars fv3 "f.x." + // TODO(adonovan): enable when go/types supports labels. loop: // #@freevars fv-def-label "loop:" for { diff --git a/oracle/testdata/src/main/freevars.golden b/oracle/testdata/src/main/freevars.golden index 030d3a6b..4b29fa45 100644 --- a/oracle/testdata/src/main/freevars.golden +++ b/oracle/testdata/src/main/freevars.golden @@ -12,3 +12,7 @@ var s.x int var x int var y int32 +-------- @freevars fv3 -------- +Free identifers: +var x int +