summaryrefslogtreecommitdiff
path: root/pylint
diff options
context:
space:
mode:
authorJaehoon Hwang <jaehoonhwang@users.noreply.github.com>2021-10-23 05:52:23 -0700
committerGitHub <noreply@github.com>2021-10-23 14:52:23 +0200
commit8b60e428457fb1125f61bd97296665aef53eefb8 (patch)
tree52d4cfa002f6177870296e4bba13890ec06ae6a3 /pylint
parent772b3dcc0b0770a843653783e5c93b4256e5ec6f (diff)
downloadpylint-git-8b60e428457fb1125f61bd97296665aef53eefb8.tar.gz
Fix use-implicit-booleaness-not-comparison crash (#5176)
* Fix use-implicit-booleaness-not-comparison crash `use-implicit-booleaness-not-comparison` caused a crash due to `target_node` not being an instance of `NodeNG.Name` This fix will allow the checker to have a default handling when it encounters `target_node` other than `Calls`,`Name`, or `Attribute` * Added more comprehensive test for implicit_booealness_checker * Make implicit_booealness_checker to have default `variable_name` * Handle `Calls`,`Name`, or `Attribute` * Fix typing in ImplicitBooleanessChecker.base_classes_of_node * [implicit-booleaness] Add call nodes name in warnings * Use `BaseContainer` to check for empty tuple/list and use `as_string` for `Attribute` and `Name` nodes for message Using `BaseContainer` for checking for empty `tuple` and `list`. In addition, `is_base_container` checks for `FrozenSet` and `Set` as well. * Update test cases with cr concerns * Use `BaseContainer` when checking for empty list or tuple * Update `is_literal_tuple/list` to use `is_base_container` * Use `as_string` when giving out function or variable name for message. * Fix broken baseContainer test * Use safe_infer for inferencing `target_instance` * Swap opreators message * Address CR comments; no more try/catch for infer & Add more test cases * Add more test cases and changed few cases to cover more cases. * Remove `try/catch` from `safe_infer` since `safe_infer` will return `None` when it encounters exceptions. * Comparison from infer to be more explicit; using `None` instead of relying on `bool` Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Diffstat (limited to 'pylint')
-rw-r--r--pylint/checkers/refactoring/implicit_booleaness_checker.py42
-rw-r--r--pylint/checkers/utils.py8
2 files changed, 23 insertions, 27 deletions
diff --git a/pylint/checkers/refactoring/implicit_booleaness_checker.py b/pylint/checkers/refactoring/implicit_booleaness_checker.py
index b5d0b277f..fbcb29536 100644
--- a/pylint/checkers/refactoring/implicit_booleaness_checker.py
+++ b/pylint/checkers/refactoring/implicit_booleaness_checker.py
@@ -145,19 +145,15 @@ class ImplicitBooleanessChecker(checkers.BaseChecker):
self, node: nodes.Compare
) -> None:
"""Check for left side and right side of the node for empty literals"""
- is_left_empty_literal = (
- utils.is_empty_list_literal(node.left)
- or utils.is_empty_tuple_literal(node.left)
- or utils.is_empty_dict_literal(node.left)
- )
+ is_left_empty_literal = utils.is_base_container(
+ node.left
+ ) or utils.is_empty_dict_literal(node.left)
# Check both left hand side and right hand side for literals
for operator, comparator in node.ops:
- is_right_empty_literal = (
- utils.is_empty_list_literal(comparator)
- or utils.is_empty_tuple_literal(comparator)
- or utils.is_empty_dict_literal(comparator)
- )
+ is_right_empty_literal = utils.is_base_container(
+ comparator
+ ) or utils.is_empty_dict_literal(comparator)
# Using Exclusive OR (XOR) to compare between two side.
# If two sides are both literal, it should be different error.
if is_right_empty_literal ^ is_left_empty_literal:
@@ -165,14 +161,12 @@ class ImplicitBooleanessChecker(checkers.BaseChecker):
target_node = node.left if is_right_empty_literal else comparator
literal_node = comparator if is_right_empty_literal else node.left
# Infer node to check
- try:
- target_instance = next(target_node.infer())
- except astroid.InferenceError:
- # Probably undefined-variable, continue with check
+ target_instance = utils.safe_infer(target_node)
+ if target_instance is None:
continue
mother_classes = self.base_classes_of_node(target_instance)
is_base_comprehension_type = any(
- t in mother_classes for t in ("tuple", "list", "dict")
+ t in mother_classes for t in ("tuple", "list", "dict", "set")
)
# Only time we bypass check is when target_node is not inherited by
@@ -183,20 +177,26 @@ class ImplicitBooleanessChecker(checkers.BaseChecker):
continue
# No need to check for operator when visiting compare node
- if operator in ["==", "!=", ">=", ">", "<=", "<"]:
+ if operator in ("==", "!=", ">=", ">", "<=", "<"):
collection_literal = "{}"
if isinstance(literal_node, nodes.List):
collection_literal = "[]"
if isinstance(literal_node, nodes.Tuple):
collection_literal = "()"
- variable_name = target_node.name
+
+ instance_name = "x"
+ if isinstance(target_node, nodes.Call) and target_node.func:
+ instance_name = f"{target_node.func.as_string()}(...)"
+ elif isinstance(target_node, (nodes.Attribute, nodes.Name)):
+ instance_name = target_node.as_string()
+
original_comparison = (
- f"{variable_name} {operator} {collection_literal}"
+ f"{instance_name} {operator} {collection_literal}"
)
suggestion = (
- f"not {variable_name}"
+ f"{instance_name}"
if operator == "!="
- else f"{variable_name}"
+ else f"not {instance_name}"
)
self.add_message(
"use-implicit-booleaness-not-comparison",
@@ -208,7 +208,7 @@ class ImplicitBooleanessChecker(checkers.BaseChecker):
)
@staticmethod
- def base_classes_of_node(instance: nodes.ClassDef) -> List[nodes.Name]:
+ def base_classes_of_node(instance: nodes.ClassDef) -> List[str]:
"""Return all the classes names that a ClassDef inherit from including 'object'."""
try:
return [instance.name] + [x.name for x in instance.ancestors()]
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index 0fee05af9..43157d0f9 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -1626,12 +1626,8 @@ def is_function_body_ellipsis(node: nodes.FunctionDef) -> bool:
)
-def is_empty_list_literal(node: Optional[nodes.NodeNG]) -> bool:
- return isinstance(node, nodes.List) and not node.elts
-
-
-def is_empty_tuple_literal(node: Optional[nodes.NodeNG]) -> bool:
- return isinstance(node, nodes.Tuple) and not node.elts
+def is_base_container(node: Optional[nodes.NodeNG]) -> bool:
+ return isinstance(node, nodes.BaseContainer) and not node.elts
def is_empty_dict_literal(node: Optional[nodes.NodeNG]) -> bool: