check_elif.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  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. import tokenize
  6. from tokenize import TokenInfo
  7. from typing import TYPE_CHECKING
  8. from astroid import nodes
  9. from pylint.checkers import BaseTokenChecker
  10. from pylint.checkers.utils import only_required_for_messages
  11. from pylint.interfaces import HIGH
  12. if TYPE_CHECKING:
  13. from pylint.lint import PyLinter
  14. class ElseifUsedChecker(BaseTokenChecker):
  15. """Checks for use of "else if" when an "elif" could be used."""
  16. name = "else_if_used"
  17. msgs = {
  18. "R5501": (
  19. 'Consider using "elif" instead of "else" then "if" to remove one indentation level',
  20. "else-if-used",
  21. "Used when an else statement is immediately followed by "
  22. "an if statement and does not contain statements that "
  23. "would be unrelated to it.",
  24. )
  25. }
  26. def __init__(self, linter: PyLinter) -> None:
  27. super().__init__(linter)
  28. self._init()
  29. def _init(self) -> None:
  30. self._elifs: dict[tokenize._Position, str] = {}
  31. def process_tokens(self, tokens: list[TokenInfo]) -> None:
  32. """Process tokens and look for 'if' or 'elif'."""
  33. self._elifs = {
  34. begin: token for _, token, begin, _, _ in tokens if token in {"elif", "if"}
  35. }
  36. def leave_module(self, _: nodes.Module) -> None:
  37. self._init()
  38. @only_required_for_messages("else-if-used")
  39. def visit_if(self, node: nodes.If) -> None:
  40. """Current if node must directly follow an 'else'."""
  41. if (
  42. isinstance(node.parent, nodes.If)
  43. and node.parent.orelse == [node]
  44. and (node.lineno, node.col_offset) in self._elifs
  45. and self._elifs[(node.lineno, node.col_offset)] == "if"
  46. ):
  47. self.add_message("else-if-used", node=node, confidence=HIGH)
  48. def register(linter: PyLinter) -> None:
  49. linter.register_checker(ElseifUsedChecker(linter))