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

explore writing linters for cardboard users #229

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

erdii
Copy link
Member

@erdii erdii commented May 8, 2024

This PR contains a PoC combination of 2 linters: one that identifies calls to manager.SerialDeps and manager.ParallelDeps and validates that self is not inlined in the method call and another one that validates correct receiver/method pairs in calls to run.MethX.

Example run against package ./cmd/sample:

go run ./cmd/cardboard-lint ./cmd/sample
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:53:9: second arg to ParallelDeps call should be identifier "self" but is "this".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:57:9: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:61:2: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:66:5: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:73:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:80:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth(c, c.MethNoArgs)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:87:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(c, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:94:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(empty{}, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:101:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(suspect{}, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:109:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(c, methTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:117:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth(c, meth)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:94:53: method "c.MethTwoArgs" does not belong to type of "empty{}": "run.Meth2(empty{}, c.MethTwoArgs, foo, bar)" *pkg.package-operator.run/cardboard/cmd/sample.coll
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:101:55: method "c.MethTwoArgs" does not belong to type of "suspect{}": "run.Meth2(suspect{}, c.MethTwoArgs, foo, bar)" *pkg.package-operator.run/cardboard/cmd/sample.coll
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:109:47: identifier "methTwoArgs" should be removed and method selector expression inlined: "run.Meth2(c, methTwoArgs, foo, bar)"
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:117:46: identifier "meth" should be removed and method selector expression inlined: "run.Meth(c, meth)"

PoC-Done:

  • Linters: (go run ./cmd/cardboard-lint - behaves likes other linters)
    • cardboardselfident: enforce self arg to be named self - can propose a fix where an inline expression is factored into a prepended self := expression statement
    • cardboardmeth: enforce valid receiver/method combinations in run.MethX arguments

Missing:

  • The Fix for the case where the self argument is correct, but named different. It would probably be better generated by something like gorename? essentially, this is "pls gorename the wrongly named identifier to self"
  • Additional linters:
    • cardboardself: self must actually be a dep wrapped version of the caller!
  • Testing

Apparently if i modify the parentBlock ast node, I should expect other linters to break when running multiple linters from the same binary. So far it seems that the AST fumbling is not breaking the combined linters, but this should assumption should be validated via extensive tests.

Apparently deep cloning a (sub) ast is not part of the go stdlib. I found these libs/implementations: https://github.com/go-toolsmith/astcopy/blob/v1.1.0/astcopy.go https://github.com/google/wire/blob/main/internal/wire/copyast.go

…ter that identifies calls to manager.SerialDeps and manager.ParallelDeps and validates that `self` is not inlined in the method call and another one that validates correct receiver/method pairs in calls to run.MethX

Example run against package ./cmd/sample:

```
go run ./cmd/cardboard-lint ./cmd/sample
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:53:9: second arg to ParallelDeps call should be identifier "self" but is "this".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:57:9: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:61:2: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:66:5: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:73:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth1(c, c.MethTarget, args)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:80:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth(c, c.MethNoArgs)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:87:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(c, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:94:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(empty{}, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:101:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(suspect{}, c.MethTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:109:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth2(c, methTwoArgs, foo, bar)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:117:12: Second arg to ParallelDeps call should be identifier "self" but is expression "run.Meth(c, meth)".
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:94:53: method "c.MethTwoArgs" does not belong to type of "empty{}": "run.Meth2(empty{}, c.MethTwoArgs, foo, bar)" *pkg.package-operator.run/cardboard/cmd/sample.coll
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:101:55: method "c.MethTwoArgs" does not belong to type of "suspect{}": "run.Meth2(suspect{}, c.MethTwoArgs, foo, bar)" *pkg.package-operator.run/cardboard/cmd/sample.coll
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:109:47: identifier "methTwoArgs" should be removed and method selector expression inlined: "run.Meth2(c, methTwoArgs, foo, bar)"
/home/erdii/projects/redhat/github.com/package-operator/cardboard/cmd/sample/main.go:117:46: identifier "meth" should be removed and method selector expression inlined: "run.Meth(c, meth)"
```

PoC-Done:
- Linters: (`go run ./cmd/cardboard-lint` - behaves likes other linters)
  - `cardboardselfident`: enforce self arg to be named `self`
    - can propose a fix where an inline expression is factored into a prepended `self := expression` statement
  - `cardboardmeth`: enforce valid receiver/method combinations in run.MethX arguments

Missing:
- The Fix for the case where the `self` argument is correct, but named different. It would probably be better generated by something like gorename? essentially, this is "pls gorename the wrongly named identifier to `self`"
- Additional linters:
  - `cardboardself`: self must actually be a dep wrapped version of the caller!
- Testing

Apparently if i modify the parentBlock ast node, I should expect other linters to break when running multiple linters from the same binary.
So far it seems that the AST fumbling is not breaking the combined linters, but this should assumption should be validated via extensive tests.

Apparently deep cloning a (sub) ast is not part of the go stdlib. I found these libs/implementations:
https://github.com/go-toolsmith/astcopy/blob/v1.1.0/astcopy.go
https://github.com/google/wire/blob/main/internal/wire/copyast.go

Signed-off-by: erdii <me@erdii.engineering>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant