450 (self.__checkReturn, ("M831", "M832", "M833", "M834")), |
453 (self.__checkReturn, ("M831", "M832", "M833", "M834")), |
451 (self.__checkLineContinuation, ("M841",)), |
454 (self.__checkLineContinuation, ("M841",)), |
452 (self.__checkImplicitStringConcat, ("M851", "M852")), |
455 (self.__checkImplicitStringConcat, ("M851", "M852")), |
453 (self.__checkExplicitStringConcat, ("M853",)), |
456 (self.__checkExplicitStringConcat, ("M853",)), |
454 (self.__checkCommentedCode, ("M891",)), |
457 (self.__checkCommentedCode, ("M891",)), |
|
458 (self.__checkDefaultMatchCase, ("M901", "M902")), |
455 ] |
459 ] |
456 |
460 |
457 # the eradicate whitelist |
461 # the eradicate whitelist |
458 commentedCodeCheckerArgs = self.__args.get( |
462 commentedCodeCheckerArgs = self.__args.get( |
459 "CommentedCodeChecker", |
463 "CommentedCodeChecker", |
1500 for operand in (node.left, node.right) |
1504 for operand in (node.left, node.right) |
1501 ) |
1505 ) |
1502 ): |
1506 ): |
1503 self.__error(node.lineno - 1, node.col_offset, "M853") |
1507 self.__error(node.lineno - 1, node.col_offset, "M853") |
1504 |
1508 |
|
1509 ################################################################################# |
|
1510 ## The following method checks default match cases. |
|
1511 ################################################################################# |
|
1512 |
|
1513 def __checkDefaultMatchCase(self): |
|
1514 """ |
|
1515 Private method to check the default match case. |
|
1516 """ |
|
1517 visitor = DefaultMatchCaseVisitor() |
|
1518 visitor.visit(self.__tree) |
|
1519 for violation in visitor.violations: |
|
1520 node = violation[0] |
|
1521 reason = violation[1] |
|
1522 self.__error(node.lineno - 1, node.col_offset, reason) |
|
1523 |
1505 |
1524 |
1506 class TextVisitor(ast.NodeVisitor): |
1525 class TextVisitor(ast.NodeVisitor): |
1507 """ |
1526 """ |
1508 Class implementing a node visitor for bytes and str instances. |
1527 Class implementing a node visitor for bytes and str instances. |
1509 |
1528 |
4416 self.violations.append((node, "M412")) |
4435 self.violations.append((node, "M412")) |
4417 |
4436 |
4418 self.generic_visit(node) |
4437 self.generic_visit(node) |
4419 |
4438 |
4420 |
4439 |
|
4440 class DefaultMatchCaseVisitor(ast.NodeVisitor): |
|
4441 """ |
|
4442 Class implementing a node visitor to check default match cases. |
|
4443 |
|
4444 Note: This class is modeled after flake8-spm v0.0.1. |
|
4445 """ |
|
4446 |
|
4447 def __init__(self): |
|
4448 """ |
|
4449 Constructor |
|
4450 """ |
|
4451 super().__init__() |
|
4452 |
|
4453 self.violations = [] |
|
4454 |
|
4455 def visit_Match(self, node): |
|
4456 """ |
|
4457 Public method to handle Match nodes. |
|
4458 |
|
4459 @param node reference to the node to be processed |
|
4460 @type ast.Match |
|
4461 """ |
|
4462 for badNode, issueCode in self.__badNodes(node): |
|
4463 self.violations.append((badNode, issueCode)) |
|
4464 |
|
4465 self.generic_visit(node) |
|
4466 |
|
4467 def __badNodes(self, node): |
|
4468 """ |
|
4469 Private method to yield bad match nodes. |
|
4470 |
|
4471 @param node reference to the node to be processed |
|
4472 @type ast.Match |
|
4473 @yield tuple containing a reference to bad match case node and the corresponding |
|
4474 issue code |
|
4475 @ytype tyuple of (ast.AST, str) |
|
4476 """ |
|
4477 for case in node.cases: |
|
4478 if self.__emptyMatchDefault(case): |
|
4479 if self.__lastStatementDoesNotRaise(case): |
|
4480 yield self.__findBadNode(case), "M901" |
|
4481 elif self.__returnPrecedesExceptionRaising(case): |
|
4482 yield self.__findBadNode(case), "M902" |
|
4483 |
|
4484 def __emptyMatchDefault(self, case): |
|
4485 """ |
|
4486 Private method to check for an empty default match case. |
|
4487 |
|
4488 @param case reference to the node to be processed |
|
4489 @type ast.match_case |
|
4490 @return flag indicating an empty default match case |
|
4491 @rtype bool |
|
4492 """ |
|
4493 pattern = case.pattern |
|
4494 return isinstance(pattern, ast.MatchAs) and ( |
|
4495 pattern.pattern is None |
|
4496 or ( |
|
4497 isinstance(pattern.pattern, ast.MatchAs) |
|
4498 and pattern.pattern.pattern is None |
|
4499 ) |
|
4500 ) |
|
4501 |
|
4502 def __lastStatementDoesNotRaise(self, case): |
|
4503 """ |
|
4504 Private method to check that the last case statement does not raise an |
|
4505 exception. |
|
4506 |
|
4507 @param case reference to the node to be processed |
|
4508 @type ast.match_case |
|
4509 @return flag indicating that the last case statement does not raise an |
|
4510 exception |
|
4511 @rtype bool |
|
4512 """ |
|
4513 return not isinstance(case.body[-1], ast.Raise) |
|
4514 |
|
4515 def __returnPrecedesExceptionRaising(self, case): |
|
4516 """ |
|
4517 Private method to check that no return precedes an exception raising. |
|
4518 |
|
4519 @param case reference to the node to be processed |
|
4520 @type ast.match_case |
|
4521 @return flag indicating that a return precedes an exception raising |
|
4522 @rtype bool |
|
4523 """ |
|
4524 returnIndex = -1 |
|
4525 raiseIndex = -1 |
|
4526 for index, body in enumerate(case.body): |
|
4527 if isinstance(body, ast.Return): |
|
4528 returnIndex = index |
|
4529 elif isinstance(body, ast.Raise): |
|
4530 raiseIndex = index |
|
4531 return returnIndex >= 0 and returnIndex < raiseIndex |
|
4532 |
|
4533 def __findBadNode(self, case) -> ast.AST: |
|
4534 """ |
|
4535 Private method returning a reference to the bad node of a case node. |
|
4536 |
|
4537 @param case reference to the node to be processed |
|
4538 @type ast.match_case |
|
4539 @return reference to the bad node |
|
4540 @rtype ast.AST |
|
4541 """ |
|
4542 for body in case.body: |
|
4543 # Handle special case when return precedes exception raising. |
|
4544 # In this case the bad node is that with the return statement. |
|
4545 if isinstance(body, ast.Return): |
|
4546 return body |
|
4547 |
|
4548 return case.body[-1] |
|
4549 |
|
4550 |
4421 # |
4551 # |
4422 # eflag: noqa = M891 |
4552 # eflag: noqa = M891 |