Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/cmd/guru: implements output is strange when cursor is over the interface keyword #20003

Open
zmb3 opened this issue Apr 16, 2017 · 1 comment
Labels
Milestone

Comments

@zmb3
Copy link
Contributor

@zmb3 zmb3 commented Apr 16, 2017

For a simple main.go file:

package main

type Fooer interface {
	Foo() string
}

type Int int

func (Int) Foo() string {
	return "foo"
}

func main() {
}

When I run an implements query with the cursor over Fooer, I get reasonable output:

$ guru -json implements main.go:#40
{
	"type": {
		"name": "github.com/zmb3/foo.Fooer",
		"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:3:6",
		"kind": "interface"
	},
	"to": [
		{
			"name": "github.com/zmb3/foo.Int",
			"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:7:6",
			"kind": "basic"
		}
	],
	"method": {
		"name": "func (Fooer).Foo() string",
		"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:4:2"
	},
	"to_method": [
		{
			"name": "method (Int) Foo() string",
			"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:9:12"
		}
	]
}

However, when the cursor is moved a few bytes to the right (over interface) the output looks much different:

$ guru -json implements main.go:#50
{
	"type": {
		"name": "interface{Foo() string}",
		"pos": "-",
		"kind": "interface"
	},
	"to": [
		{
			"name": "github.com/zmb3/foo.Fooer",
			"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:3:6",
			"kind": "interface"
		},
		{
			"name": "github.com/zmb3/foo.Int",
			"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:7:6",
			"kind": "basic"
		}
	],
	"from": [
		{
			"name": "github.com/zmb3/foo.Fooer",
			"pos": "/Users/zbergquist/src/github.com/zmb3/foo/main.go:3:6",
			"kind": "interface"
		}
	]
}

It seems like guru is now identifying the selection as an anonymous interface and not the type declaration for the Fooer interface.

I'm finding the behavior in the latter case to be difficult to build tooling around, mostly because:

  1. The type.name field is long and hard to read for anything but the most simple interfaces
  2. The extra to entry makes it seem like there is an extra interface in the program
  3. The type.pos field is no longer populated
@gopherbot gopherbot added this to the Unreleased milestone Apr 17, 2017
@davidrjenni

This comment has been minimized.

Copy link
Contributor

@davidrjenni davidrjenni commented Apr 25, 2017

The guru implements mode calls findInterestingNode to get the selected type. findInterestingNode stops at the type node and does not continue to the type spec (*ast.TypeSpec) (if there is one).


This effect can also be observed with a describe query (describe also calls findInterestingNode):

fun.go:

package main

type Fun func()

func main() {}

Output of guru describe fun.go:#20 (selects the type name):

…/fun.go:3.6-3.8: definition of type Fun (size 8, align 8)
…/fun.go:3.6-3.8: No methods.

Output of guru describe fun.go:#25 (selects the func keyword):

…/fun.go:3.10-3.15: type func()

The fix to your problem would be to continue to the type name, if the type node occurs in an *ast.TypeSpec:

case *ast.ArrayType,
	*ast.StructType,
	*ast.FuncType,
	*ast.InterfaceType,
	*ast.MapType,
	*ast.ChanType:
+	// Continue to type name, if possible.
+	if spec, ok := path[1].(*ast.TypeSpec); ok {
+		path = append([]ast.Node{spec.Name}, path...)
+		continue
+	}
	return path, actionType

For an example, similar to yours:

iface.go:

package main

type Iface interface {
	M()
}

type T int

func (T) M() {}

func main() {}

Output of guru implements iface.go:#30 (selects the interface keyword) after applying the change:

…/iface.go:3.6-3.10: interface type Iface
…/iface.go:7.6-7.6: 	is implemented by basic type T

This change also affects the output of the describe query.
Output of guru describe fun.go:#25 (selects the func keyword) after applying the change:

…/fun.go:3.6-3.8: definition of type Fun (size 8, align 8)
…/fun.go:3.6-3.8: No methods.

If this is not considered problematic, I could submit a CL.
Another possibility would be to introduce a specialized function for the implements mode.

/cc @alandonovan


findInterestingNode is also called by the pointsto mode and the whicherrs mode. The change proposed would not affect the result of those queries. Both, pointsto and whicherrs, abort if findInterestingNode does not return actionExpr as second return value, which is not the case for a path to an *ast.{Array,Struct,Func,Interface,Map,Chan}Type node.

@gopherbot gopherbot added the Tools label Sep 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.