-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add gofactory linter
#4196
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
Add gofactory linter
#4196
Conversation
Hey, thank you for opening your first Pull Request !
CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.
7799b5c to
14c0aba
Compare
gofactory linter (削除ここまで)gofactory linter (追記ここまで)
gofactory linter (削除ここまで)gofactory linter (追記ここまで)
gofactory linter (削除ここまで)gofactory linter (追記ここまで)
In order for a pull request adding a linter to be reviewed, the linter and the PR must follow some requirements.
- The CLA must be signed
Pull Request Description
- It must have a link to the linter repository.
- It must provide a short description of the linter.
Linter
- It must not be a duplicate of another linter or a rule of a linter. (the team will help to verify that)
- It must have a valid license (AGPL is not allowed) and the file must contain the required information by the license, ex: author, year, etc.
- The linter repository must have a CI and tests.
- It must use
go/analysis. - It must have a valid tag, ex:
v1.0.0,v0.1.0. - It must not contain
init(). - It must not contain
panic(). - It must not contain
log.fatal(),os.exit(), or similar. - It must not modify the AST.
- It must not have false positives/negatives. (the team will help to verify that)
- It must have tests inside golangci-lint.
The Linter Tests Inside Golangci-lint
- They must have at least one std lib import.
- They must work with
T=<name of the linter test file>.go make test_linters. (the team will help to verify that)
.golangci.reference.yml
- The linter must be added to the list of available linters (alphabetical case-insensitive order).
enableanddisableoptions
- If the linter has a configuration, the exhaustive configuration of the linter must be added (alphabetical case-insensitive order)
- The values must be different from the default ones.
- The default values must be defined in a comment.
- The option must have a short description.
Others Requirements
- The files (tests and linter) inside golangci-lint must have the same name as the linter.
- The
.golangci.ymlof golangci-lint itself must not be edited and the linter must not be added to this file. - The linters must be sorted in the alphabetical order (case-insensitive) in the
Manager.GetAllSupportedLinterConfigs(...)and.golangci.reference.yml. - The load mode (
WithLoadMode(...)):- if the linter doesn't use types:
goanalysis.LoadModeSyntax goanalysis.LoadModeTypesInforequiredWithLoadForGoAnalysis()in theManager.GetAllSupportedLinterConfigs(...)
- if the linter doesn't use types:
- The version in
WithSince(...)must be the next minor version (v1.X.0) of golangci-lint. -
WithURL()must contain the URL of the repository.
Recommendations
- The linter should not use SSA. (SSA can be a problem with generics)
- The linter repository should have a readme and linting.
- The linter should be published as a binary. (useful to diagnose bug origins)
The golangci-lint team will edit this comment to check the boxes before and during the review.
The code review will start after the completion of those checkboxes (except for the specific items that the team will help to verify).
If the author of the PR is a member of the golangci-lint team, he should not edit this message.
This checklist does not imply that we will accept the linter.
Maybe to combine with check from #3488?
Maybe to combine with check from #3488?
I don't want to combine constructor and gofactory because the DDD factory can be a function or separate struct method, not only a constructor.
Also, I think that IssueLoan is more descriptive than NewLoan.
2. Added tests 3. Added config 4. Added linter
14c0aba to
70cd3e5
Compare
Is there anything else that I can do to get the PR be approved and merged?
bf7fb06 to
5a86fb8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the linter!
In addition to review comments:
TestdataDir()->analysistest.TestData()- Case like
type OtherStruct struct {} type Struct struct { Other OtherStruct } func NewStruct() Struct { return Struct{ Other: OtherStruct{}, // warning? } }
Type assertion, type declaration and type underlying, tests <- Broken link
- Struct with type params?
type Struct[T any] struct { // type params could be many (this is different ast node) } _ = Struct[T]{} // Warning
- Import alias (and affect on report warning?).
- You covered slice, but not map, channel, func call, etc. places where obj could be constructed.
2. Added test with options
# golangci/golangci-lint#4196 1. TestdataDir() -> analysistest.TestData() 2. Described False-Negative cases as testcases and in README.md 3. Fixed link for type_nested.go.skip in README.md 4. Added testcase with generic 5. Added testcase with alias 6. Added testcase with map, chan, array, func # golangci/golangci-lint#4196 7. Added glob syntax for pkgs 8. Renamed options 9. Extended unexpected code message 10. Added unimplemented testcases
Could I resolve the case on Winter Weekends, not now?)
I added unimplemented testcases for the case and also for chan, var declaration, named returned.
- Case like
type OtherStruct struct {} type Struct struct { Other OtherStruct } func NewStruct() Struct { return Struct{ Other: OtherStruct{}, // warning? } }
Just a reminder for the maintainers: before reviewing the code, the checklist should be handled.
The use of the tests dedicated to linters that need dependencies is not the right way.
The tests should handled as simple linters.
I'm not sure about the pertinence of this linter because Go doesn't require constructors, and data structure is a good pattern, I think this will lead to a lot of false positives.
The use of the tests dedicated to linters that need dependencies is not the right way.
The tests should handled as simple linters.
Do you mean tests should be like this and remove subdirectories?
package gofactory import "net/http" func local() { _ = http.Request{} // want... _, _ = http.NewRequest("GET", "http://example.com", nil) }
I'm not sure about the pertinence of this linter because Go doesn't require constructors, and data structure is a good pattern, I think this will lead to a lot of false positives.
My motivation was to create the linter for the domain layer with business logic in the factories, which cannot be skipped and where any structures should always be valid.
I agree that using the go-factory-lint in any place is not a good idea, so I added options packageGlobs and onlyPackageGlobs to set domain packages to use the linter only for them.
Should I force set onlyPackageGlobs as true by default and ask to set packageGlobs to run linter?
2. Removed nested directory in test
The use of the tests dedicated to linters that need dependencies is not the right way.
The tests should handled as simple linters.
I removed subdirectories in tests. I'm not sure what you mean.
If not, then you mean that I should remove the use of the WithLoadForGoAnasis option.
I can't because the linter needs this to determine whether it is a function or a type when we cast types like this.
package casting import ( "factory/unimplemented/casting/nested" ) func ToNestedMyInt() { _ = nested.MyInt(1) // want `Use factory for nested.Struct` }
2. renamed options 3. changed linter version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope that is correct solution to pass tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
your tests are not in the right places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean I should move test/testdata/gofactory/blocked.go to test/testdata/gofactory/gofactory_package_globs_only.go?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, your tests must be inside test/testdata/ and not a dedicated folder.
and your linter should be removed from test/linters_test.go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this change relate to PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I return, can I add -D gofactory to fix linter error Use factory for unsafe.Pointer.
Or is solution from comment is better?
#4196 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be reverted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to rollback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added because of linter error Use factory for unsafe.Pointer.
Should I add option to exclude checking of std libraries in gofactory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I add option to exclude checking of std libraries in gofactory?
Nice idea, but I think in case of exclude-std=false we will receive false positive anyway, because a lot of std types could be (or must be) used without factory by design. Like unsafe.Pointer or sync.Mutex.
Zero value is useful 🙂
Look at
$ cd $GOROOT/src
$ gofactory -json ./... | jq '.[] | .[] | .[] .message' | sort | uniq
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cosmetic question: why not Use factory for alias_blocked.Request?
at fist time I was confused, but cannot decide what option is better 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idk too)
Could you decide how to better based on your experience?
I checked wrapcheck, go-reassign. They both used different printing way for package names.
I don't find another linter which uses package names.
wrapcheck: error returned from external package is unwrapped: sig: func encoding/json.Marshal(v any) ([]byte, error)
go-reassign: reassigning variable EOF in other package alias
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, the option that is better for grep and common understanding – to keep the source code and warnings for it consistent:
_ = neturl.URL{} // want `Use factory for neturl.URL` _ = &url.URL{} // want `Use factory for url.URL`
Uh oh!
There was an error while loading. Please reload this page.
The linter checks that the structures are created by the factory, and not directly.
The checking helps to provide invariants without exclusion and helps avoid creating an invalid object.
related to #2708