You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

116 lines
2.1 KiB

  1. package rule
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/token"
  6. "github.com/mgechev/revive/lint"
  7. )
  8. // UnexportedNamingRule lints wrongly named unexported symbols.
  9. type UnexportedNamingRule struct{}
  10. // Apply applies the rule to given file.
  11. func (r *UnexportedNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
  12. var failures []lint.Failure
  13. onFailure := func(failure lint.Failure) {
  14. failures = append(failures, failure)
  15. }
  16. ba := &unexportablenamingLinter{onFailure}
  17. ast.Walk(ba, file.AST)
  18. return failures
  19. }
  20. // Name returns the rule name.
  21. func (r *UnexportedNamingRule) Name() string {
  22. return "unexported-naming"
  23. }
  24. type unexportablenamingLinter struct {
  25. onFailure func(lint.Failure)
  26. }
  27. func (unl unexportablenamingLinter) Visit(node ast.Node) ast.Visitor {
  28. switch n := node.(type) {
  29. case *ast.FuncDecl:
  30. unl.lintFunction(n.Type, n.Body)
  31. return nil
  32. case *ast.FuncLit:
  33. unl.lintFunction(n.Type, n.Body)
  34. return nil
  35. case *ast.AssignStmt:
  36. if n.Tok != token.DEFINE {
  37. return nil
  38. }
  39. ids := []*ast.Ident{}
  40. for _, e := range n.Lhs {
  41. id, ok := e.(*ast.Ident)
  42. if !ok {
  43. continue
  44. }
  45. ids = append(ids, id)
  46. }
  47. unl.lintIDs(ids)
  48. case *ast.DeclStmt:
  49. gd, ok := n.Decl.(*ast.GenDecl)
  50. if !ok {
  51. return nil
  52. }
  53. if len(gd.Specs) < 1 {
  54. return nil
  55. }
  56. vs, ok := gd.Specs[0].(*ast.ValueSpec)
  57. if !ok {
  58. return nil
  59. }
  60. unl.lintIDs(vs.Names)
  61. }
  62. return unl
  63. }
  64. func (unl unexportablenamingLinter) lintFunction(ft *ast.FuncType, body *ast.BlockStmt) {
  65. unl.lintFields(ft.Params)
  66. unl.lintFields(ft.Results)
  67. if body != nil {
  68. ast.Walk(unl, body)
  69. }
  70. }
  71. func (unl unexportablenamingLinter) lintFields(fields *ast.FieldList) {
  72. if fields == nil {
  73. return
  74. }
  75. ids := []*ast.Ident{}
  76. for _, field := range fields.List {
  77. ids = append(ids, field.Names...)
  78. }
  79. unl.lintIDs(ids)
  80. }
  81. func (unl unexportablenamingLinter) lintIDs(ids []*ast.Ident) {
  82. for _, id := range ids {
  83. if id.IsExported() {
  84. unl.onFailure(lint.Failure{
  85. Node: id,
  86. Confidence: 1,
  87. Category: "naming",
  88. Failure: fmt.Sprintf("the symbol %s is local, its name should start with a lowercase letter", id.String()),
  89. })
  90. }
  91. }
  92. }