@@ -35,12 +35,35 @@ func (mr *mapRanging) ID() string {
35
35
return mr .MetaData .ID
36
36
}
37
37
38
+ func extractIdent (call ast.Expr ) * ast.Ident {
39
+ switch n := call .(type ) {
40
+ case * ast.Ident :
41
+ return n
42
+
43
+ case * ast.SelectorExpr :
44
+ if ident , ok := n .X .(* ast.Ident ); ok {
45
+ return ident
46
+ }
47
+ if n .Sel != nil {
48
+ return extractIdent (n .Sel )
49
+ }
50
+ return extractIdent (n .X )
51
+
52
+ default :
53
+ panic (fmt .Sprintf ("Unhandled type: %T" , call ))
54
+ }
55
+ }
56
+
38
57
func (mr * mapRanging ) Match (node ast.Node , ctx * gosec.Context ) (* gosec.Issue , error ) {
39
58
rangeStmt , ok := node .(* ast.RangeStmt )
40
59
if ! ok {
41
60
return nil , nil
42
61
}
43
62
63
+ if rangeStmt .X == nil {
64
+ return nil , nil
65
+ }
66
+
44
67
// Algorithm:
45
68
// 1. Ensure that right hand side's eventual type is a map.
46
69
// 2. Ensure that only the form:
@@ -61,14 +84,44 @@ func (mr *mapRanging) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, er
61
84
case * ast.CallExpr :
62
85
// Synthesize the declaration to be an *ast.FuncType from
63
86
// either function declarations or function literals.
64
- idecl := rangeRHS .Fun .(* ast.Ident ).Obj .Decl
87
+ ident := extractIdent (rangeRHS .Fun )
88
+ if ident == nil {
89
+ panic (fmt .Sprintf ("Couldn't find ident: %#v\n " , rangeRHS .Fun ))
90
+ }
91
+ if ident .Obj == nil {
92
+ sel , ok := rangeRHS .Fun .(* ast.SelectorExpr )
93
+ if ok && sel .Sel != nil {
94
+ ident = extractIdent (sel .Sel )
95
+ }
96
+ }
97
+ if ident .Obj == nil {
98
+ return nil , nil
99
+ }
100
+
101
+ idecl := ident .Obj .Decl
65
102
switch idecl := idecl .(type ) {
66
103
case * ast.FuncDecl :
67
104
decl = idecl .Type
68
105
69
106
case * ast.AssignStmt :
70
- decl = idecl .Rhs [0 ].(* ast.FuncLit ).Type
107
+ var err error
108
+ decl , err = typeOf (idecl .Rhs [0 ])
109
+ if err != nil {
110
+ return nil , err
111
+ }
112
+
71
113
}
114
+
115
+ case * ast.SelectorExpr :
116
+ if ident := extractIdent (rangeRHS .X ); ident != nil {
117
+ decl = ident .Obj .Decl
118
+ } else {
119
+ panic (fmt .Sprintf ("%#v\n " , rangeRHS .X .(* ast.Ident )))
120
+ }
121
+ }
122
+
123
+ if decl == nil {
124
+ return nil , fmt .Errorf ("failed to extract decl from: %T" , rangeStmt .X )
72
125
}
73
126
74
127
switch decl := decl .(type ) {
@@ -83,8 +136,7 @@ func (mr *mapRanging) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, er
83
136
}
84
137
85
138
case * ast.AssignStmt :
86
- rhs0 := decl .Rhs [0 ].(* ast.CompositeLit )
87
- if _ , ok := rhs0 .Type .(* ast.MapType ); ! ok {
139
+ if skip := mapHandleAssignStmt (decl ); skip {
88
140
return nil , nil
89
141
}
90
142
@@ -135,7 +187,12 @@ func (mr *mapRanging) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, er
135
187
if ! ok {
136
188
return nil , fmt .Errorf ("expecting an identifier for an append call to a slice, got %T" , stmt .Lhs [0 ])
137
189
}
138
- if _ , ok := typeOf (lhs0 .Obj ).(* ast.ArrayType ); ! ok {
190
+
191
+ typ , err := typeOf (lhs0 .Obj )
192
+ if err != nil {
193
+ return nil , err
194
+ }
195
+ if _ , ok := typ .(* ast.ArrayType ); ! ok {
139
196
return nil , fmt .Errorf ("expecting an array/slice being used to retrieve keys, got %T" , lhs0 .Obj )
140
197
}
141
198
@@ -154,7 +211,24 @@ func (mr *mapRanging) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, er
154
211
}
155
212
}
156
213
157
- func eitherAppendOrDeleteCall (callExpr * ast.CallExpr ) (string , bool ) {
214
+ func mapHandleAssignStmt (decl * ast.AssignStmt ) (skip bool ) {
215
+ switch rhs0 := decl .Rhs [0 ].(type ) {
216
+ case * ast.CompositeLit :
217
+ if _ , ok := rhs0 .Type .(* ast.MapType ); ! ok {
218
+ return true
219
+ }
220
+ return false
221
+
222
+ case * ast.CallExpr :
223
+ return true
224
+
225
+ default :
226
+ // TODO: handle other types.
227
+ return true
228
+ }
229
+ }
230
+
231
+ func eitherAppendOrDeleteCall (callExpr * ast.CallExpr ) (fnName string , ok bool ) {
158
232
fn , ok := callExpr .Fun .(* ast.Ident )
159
233
if ! ok {
160
234
return "" , false
@@ -167,7 +241,7 @@ func eitherAppendOrDeleteCall(callExpr *ast.CallExpr) (string, bool) {
167
241
}
168
242
}
169
243
170
- func typeOf (value interface {}) ast.Node {
244
+ func typeOf (value interface {}) ( ast.Node , error ) {
171
245
switch typ := value .(type ) {
172
246
case * ast.Object :
173
247
return typeOf (typ .Decl )
@@ -178,15 +252,31 @@ func typeOf(value interface{}) ast.Node {
178
252
if _ , ok := rhs .(* ast.CallExpr ); ok {
179
253
return typeOf (rhs )
180
254
}
255
+ if _ , ok := rhs .(* ast.CompositeLit ); ok {
256
+ return typeOf (rhs )
257
+ }
258
+
259
+ panic (fmt .Sprintf ("Non-CallExpr: %#v\n " , rhs ))
181
260
182
261
case * ast.CallExpr :
183
262
decl := typ
184
263
fn := decl .Fun .(* ast.Ident )
185
264
if fn .Name == "make" {
186
265
// We can infer the type from the first argument.
187
- return decl .Args [0 ]
266
+ return decl .Args [0 ], nil
188
267
}
189
268
return typeOf (decl .Args [0 ])
269
+
270
+ case * ast.CompositeLit :
271
+ return typ .Type , nil
272
+ panic (fmt .Sprintf ("Non-CallExpr: %#v\n " , typ ))
273
+
274
+ case * ast.FuncLit :
275
+ returns := typ .Type .Results
276
+ if g , w := len (returns .List ), 1 ; g != w {
277
+ return nil , fmt .Errorf ("returns %d arguments, want %d" , g , w )
278
+ }
279
+ return returns .List [0 ].Type , nil
190
280
}
191
281
192
282
panic (fmt .Sprintf ("Unexpected type: %T" , value ))
0 commit comments