nolint: gocognit genDecl processes one declaration clause.
(node ast.Node)
| 343 | // nolint: gocognit |
| 344 | // genDecl processes one declaration clause. |
| 345 | func (f *File) genDecl(node ast.Node) bool { |
| 346 | decl, ok := node.(*ast.GenDecl) |
| 347 | if !ok || decl.Tok != token.CONST { |
| 348 | // We only care about const declarations. |
| 349 | return true |
| 350 | } |
| 351 | // The name of the type of the constants we are declaring. |
| 352 | // Can change if this is a multi-element declaration. |
| 353 | typ := "" |
| 354 | // Loop over the elements of the declaration. Each element is a ValueSpec: |
| 355 | // a list of names possibly followed by a type, possibly followed by values. |
| 356 | // If the type and value are both missing, we carry down the type (and value, |
| 357 | // but the "go/types" package takes care of that). |
| 358 | for _, spec := range decl.Specs { |
| 359 | vspec, _ := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST. |
| 360 | if vspec.Type == nil && len(vspec.Values) > 0 { |
| 361 | // "X = 1". With no type but a value. If the constant is untyped, |
| 362 | // skip this vspec and reset the remembered type. |
| 363 | typ = "" |
| 364 | |
| 365 | // If this is a simple type conversion, remember the type. |
| 366 | // We don't mind if this is actually a call; a qualified call won't |
| 367 | // be matched (that will be SelectorExpr, not Ident), and only unusual |
| 368 | // situations will result in a function call that appears to be |
| 369 | // a type conversion. |
| 370 | ce, ok := vspec.Values[0].(*ast.CallExpr) |
| 371 | if !ok { |
| 372 | continue |
| 373 | } |
| 374 | id, ok := ce.Fun.(*ast.Ident) |
| 375 | if !ok { |
| 376 | continue |
| 377 | } |
| 378 | typ = id.Name |
| 379 | } |
| 380 | if vspec.Type != nil { |
| 381 | // "X T". We have a type. Remember it. |
| 382 | ident, ok := vspec.Type.(*ast.Ident) |
| 383 | if !ok { |
| 384 | continue |
| 385 | } |
| 386 | typ = ident.Name |
| 387 | } |
| 388 | if typ != f.typeName { |
| 389 | // This is not the type we're looking for. |
| 390 | continue |
| 391 | } |
| 392 | // We now have a list of names (from one line of source code) all being |
| 393 | // declared with the desired type. |
| 394 | // Grab their names and actual values and store them in f.values. |
| 395 | for _, name := range vspec.Names { |
| 396 | if name.Name == "_" { |
| 397 | continue |
| 398 | } |
| 399 | // This dance lets the type checker find the values for us. It's a |
| 400 | // bit tricky: look up the object declared by the name, find its |
| 401 | // types.Const, and extract its value. |
| 402 | obj, ok := f.pkg.defs[name] |