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.

indent-error-flow.go 1.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package rule
  2. import (
  3. "go/ast"
  4. "go/token"
  5. "github.com/mgechev/revive/lint"
  6. )
  7. // IndentErrorFlowRule lints given else constructs.
  8. type IndentErrorFlowRule struct{}
  9. // Apply applies the rule to given file.
  10. func (r *IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
  11. var failures []lint.Failure
  12. onFailure := func(failure lint.Failure) {
  13. failures = append(failures, failure)
  14. }
  15. w := lintElse{make(map[*ast.IfStmt]bool), onFailure}
  16. ast.Walk(w, file.AST)
  17. return failures
  18. }
  19. // Name returns the rule name.
  20. func (r *IndentErrorFlowRule) Name() string {
  21. return "indent-error-flow"
  22. }
  23. type lintElse struct {
  24. ignore map[*ast.IfStmt]bool
  25. onFailure func(lint.Failure)
  26. }
  27. func (w lintElse) Visit(node ast.Node) ast.Visitor {
  28. ifStmt, ok := node.(*ast.IfStmt)
  29. if !ok || ifStmt.Else == nil {
  30. return w
  31. }
  32. if w.ignore[ifStmt] {
  33. if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
  34. w.ignore[elseif] = true
  35. }
  36. return w
  37. }
  38. if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
  39. w.ignore[elseif] = true
  40. return w
  41. }
  42. if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
  43. // only care about elses without conditions
  44. return w
  45. }
  46. if len(ifStmt.Body.List) == 0 {
  47. return w
  48. }
  49. shortDecl := false // does the if statement have a ":=" initialization statement?
  50. if ifStmt.Init != nil {
  51. if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
  52. shortDecl = true
  53. }
  54. }
  55. lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
  56. if _, ok := lastStmt.(*ast.ReturnStmt); ok {
  57. extra := ""
  58. if shortDecl {
  59. extra = " (move short variable declaration to its own line if necessary)"
  60. }
  61. w.onFailure(lint.Failure{
  62. Confidence: 1,
  63. Node: ifStmt.Else,
  64. Category: "indent",
  65. Failure: "if block ends with a return statement, so drop this else and outdent its block" + extra,
  66. })
  67. }
  68. return w
  69. }