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

refactor (rule/receiver-naming): replace AST walker by iteration over declarations #1169

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 54 additions & 68 deletions rule/receiver_naming.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,63 @@ func (r *ReceiverNamingRule) configure(arguments lint.Arguments) {
func (r *ReceiverNamingRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
r.configureOnce.Do(func() { r.configure(args) })

typeReceiver := map[string]string{}
var failures []lint.Failure
for _, decl := range file.AST.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 {
continue
}

fileAst := file.AST
walker := lintReceiverName{
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
typeReceiver: map[string]string{},
receiverNameMaxLength: r.receiverNameMaxLength,
}
names := fn.Recv.List[0].Names
if len(names) < 1 {
continue
}
name := names[0].Name

if name == "_" {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
continue
}

if name == "this" || name == "self" {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
continue
}
Comment on lines +64 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use a switch

You are checking the same variable three times, also it would allow to remove the two continue, as they will be useless

Suggested change
if name == "_" {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
continue
}
if name == "this" || name == "self" {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
continue
}
switch name {
case "_":
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
case "this", "self":
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch on name will cope with the first two conditions for failure, the other conditions are not just on name thus IMO, adding a switch will not help in clarity (further, even with a switch continue is needed after adding a failure to do not evaluate the not-in-the-switch conditions)


ast.Walk(walker, fileAst)
if r.receiverNameMaxLength > 0 && len([]rune(name)) > r.receiverNameMaxLength {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, r.receiverNameMaxLength),
})
continue
}

recv := typeparams.ReceiverType(fn)
if prev, ok := typeReceiver[recv]; ok && prev != name {
failures = append(failures, lint.Failure{
Node: decl,
Confidence: 1,
Category: "naming",
Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv),
})
continue
}

typeReceiver[recv] = name
}

return failures
}
Expand All @@ -67,62 +112,3 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, args lint.Arguments) []lint.
func (*ReceiverNamingRule) Name() string {
return "receiver-naming"
}

type lintReceiverName struct {
onFailure func(lint.Failure)
typeReceiver map[string]string
receiverNameMaxLength int
}

func (w lintReceiverName) Visit(n ast.Node) ast.Visitor {
fn, ok := n.(*ast.FuncDecl)
if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 {
return w
}
names := fn.Recv.List[0].Names
if len(names) < 1 {
return w
}
name := names[0].Name
if name == "_" {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Failure: "receiver name should not be an underscore, omit the name if it is unused",
})
return w
}
if name == "this" || name == "self" {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`,
})
return w
}

if w.receiverNameMaxLength > 0 && len([]rune(name)) > w.receiverNameMaxLength {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, w.receiverNameMaxLength),
})
return w
}

recv := typeparams.ReceiverType(fn)
if prev, ok := w.typeReceiver[recv]; ok && prev != name {
w.onFailure(lint.Failure{
Node: n,
Confidence: 1,
Category: "naming",
Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv),
})
return w
}
w.typeReceiver[recv] = name
return w
}
Loading