confusing_elif.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
  3. # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
  4. from __future__ import annotations
  5. from typing import TYPE_CHECKING
  6. from astroid import nodes
  7. from pylint.checkers import BaseChecker
  8. from pylint.checkers.utils import only_required_for_messages
  9. if TYPE_CHECKING:
  10. from pylint.lint import PyLinter
  11. class ConfusingConsecutiveElifChecker(BaseChecker):
  12. """Checks if "elif" is used right after an indented block that finishes with "if" or
  13. "elif" itself.
  14. """
  15. name = "confusing_elif"
  16. msgs = {
  17. "R5601": (
  18. "Consecutive elif with differing indentation level, consider creating a function to separate the inner"
  19. " elif",
  20. "confusing-consecutive-elif",
  21. "Used when an elif statement follows right after an indented block which itself ends with if or elif. "
  22. "It may not be ovious if the elif statement was willingly or mistakenly unindented. "
  23. "Extracting the indented if statement into a separate function might avoid confusion and prevent "
  24. "errors.",
  25. )
  26. }
  27. @only_required_for_messages("confusing-consecutive-elif")
  28. def visit_if(self, node: nodes.If) -> None:
  29. body_ends_with_if = isinstance(
  30. node.body[-1], nodes.If
  31. ) and self._has_no_else_clause(node.body[-1])
  32. if node.has_elif_block() and body_ends_with_if:
  33. self.add_message("confusing-consecutive-elif", node=node.orelse[0])
  34. @staticmethod
  35. def _has_no_else_clause(node: nodes.If) -> bool:
  36. orelse = node.orelse
  37. while orelse and isinstance(orelse[0], nodes.If):
  38. orelse = orelse[0].orelse
  39. if not orelse or isinstance(orelse[0], nodes.If):
  40. return True
  41. return False
  42. def register(linter: PyLinter) -> None:
  43. linter.register_checker(ConfusingConsecutiveElifChecker(linter))