Skip to content

Commit 9a5c95f

Browse files
authoredDec 4, 2024
refactor(rule/context-as-argument): replace AST walker by iteration over declarations (#1160)
1 parent c3b541f commit 9a5c95f

File tree

1 file changed

+32
-47
lines changed

1 file changed

+32
-47
lines changed
 

‎rule/context_as_argument.go

+32-47
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
// ContextAsArgumentRule suggests that `context.Context` should be the first argument of a function.
1313
type ContextAsArgumentRule struct {
14-
allowTypesLUT map[string]struct{}
14+
allowTypes map[string]struct{}
1515

1616
configureOnce sync.Once
1717
}
@@ -21,64 +21,49 @@ func (r *ContextAsArgumentRule) Apply(file *lint.File, args lint.Arguments) []li
2121
r.configureOnce.Do(func() { r.configure(args) })
2222

2323
var failures []lint.Failure
24-
walker := lintContextArguments{
25-
allowTypesLUT: r.allowTypesLUT,
26-
onFailure: func(failure lint.Failure) {
27-
failures = append(failures, failure)
28-
},
29-
}
24+
for _, decl := range file.AST.Decls {
25+
fn, ok := decl.(*ast.FuncDecl)
26+
if !ok || len(fn.Type.Params.List) <= 1 {
27+
continue // not a function or a function with less than 2 parameters
28+
}
3029

31-
ast.Walk(walker, file.AST)
30+
fnArgs := fn.Type.Params.List
31+
32+
// A context.Context should be the first parameter of a function.
33+
// Flag any that show up after the first.
34+
isCtxStillAllowed := true
35+
for _, arg := range fnArgs {
36+
argIsCtx := isPkgDot(arg.Type, "context", "Context")
37+
if argIsCtx && !isCtxStillAllowed {
38+
failures = append(failures, lint.Failure{
39+
Node: arg,
40+
Category: "arg-order",
41+
Failure: "context.Context should be the first parameter of a function",
42+
Confidence: 0.9,
43+
})
44+
45+
break // only flag one
46+
}
3247

33-
return failures
34-
}
48+
typeName := gofmt(arg.Type)
49+
// a parameter of type context.Context is still allowed if the current arg type is in the allow types LookUpTable
50+
_, isCtxStillAllowed = r.allowTypes[typeName]
51+
}
52+
}
3553

36-
func (r *ContextAsArgumentRule) configure(arguments lint.Arguments) {
37-
r.allowTypesLUT = getAllowTypesFromArguments(arguments)
54+
return failures
3855
}
3956

4057
// Name returns the rule name.
4158
func (*ContextAsArgumentRule) Name() string {
4259
return "context-as-argument"
4360
}
4461

45-
type lintContextArguments struct {
46-
allowTypesLUT map[string]struct{}
47-
onFailure func(lint.Failure)
48-
}
49-
50-
func (w lintContextArguments) Visit(n ast.Node) ast.Visitor {
51-
fn, ok := n.(*ast.FuncDecl)
52-
if !ok || len(fn.Type.Params.List) <= 1 {
53-
return w
54-
}
55-
56-
fnArgs := fn.Type.Params.List
57-
58-
// A context.Context should be the first parameter of a function.
59-
// Flag any that show up after the first.
60-
isCtxStillAllowed := true
61-
for _, arg := range fnArgs {
62-
argIsCtx := isPkgDot(arg.Type, "context", "Context")
63-
if argIsCtx && !isCtxStillAllowed {
64-
w.onFailure(lint.Failure{
65-
Node: arg,
66-
Category: "arg-order",
67-
Failure: "context.Context should be the first parameter of a function",
68-
Confidence: 0.9,
69-
})
70-
break // only flag one
71-
}
72-
73-
typeName := gofmt(arg.Type)
74-
// a parameter of type context.Context is still allowed if the current arg type is in the LUT
75-
_, isCtxStillAllowed = w.allowTypesLUT[typeName]
76-
}
77-
78-
return nil // avoid visiting the function body
62+
func (r *ContextAsArgumentRule) configure(arguments lint.Arguments) {
63+
r.allowTypes = r.getAllowTypesFromArguments(arguments)
7964
}
8065

81-
func getAllowTypesFromArguments(args lint.Arguments) map[string]struct{} {
66+
func (r *ContextAsArgumentRule) getAllowTypesFromArguments(args lint.Arguments) map[string]struct{} {
8267
allowTypesBefore := []string{}
8368
if len(args) >= 1 {
8469
argKV, ok := args[0].(map[string]any)

0 commit comments

Comments
 (0)
Please sign in to comment.