summaryrefslogtreecommitdiff
path: root/pylint/checkers/utils.py
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2019-11-27 09:41:04 +0100
committerClaudiu Popa <pcmanticore@gmail.com>2019-11-27 09:43:39 +0100
commit01dfa522195d79217c43065d3d013e2ee31d47b7 (patch)
tree23443eda6546dbb36201da44e92b5437128d0ab7 /pylint/checkers/utils.py
parent114298dccd13e72fe4733034e07ae0f2bf3aaeda (diff)
downloadpylint-git-01dfa522195d79217c43065d3d013e2ee31d47b7.tar.gz
``safe_infer`` can infer a value as long as all the paths share the same type.
This permits finding more errors for functions whose return values use the same type. Until now we were stopping after the first inference result if we detected that a node value had multiple possible results. Close #2503
Diffstat (limited to 'pylint/checkers/utils.py')
-rw-r--r--pylint/checkers/utils.py27
1 files changed, 21 insertions, 6 deletions
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index 4bda9ff78..41b3876cb 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -1075,6 +1075,13 @@ def supports_delitem(value: astroid.node_classes.NodeNG) -> bool:
return _supports_protocol(value, _supports_delitem_protocol)
+def _get_python_type_of_node(node):
+ pytype = getattr(node, "pytype", None)
+ if callable(pytype):
+ return pytype()
+ return None
+
+
@lru_cache(maxsize=1024)
def safe_infer(
node: astroid.node_classes.NodeNG, context=None
@@ -1082,20 +1089,28 @@ def safe_infer(
"""Return the inferred value for the given node.
Return None if inference failed or if there is some ambiguity (more than
- one node has been inferred).
+ one node has been inferred of different types).
"""
+ inferred_types = set()
try:
- inferit = node.infer(context=context)
- value = next(inferit)
+ infer_gen = node.infer(context=context)
+ value = next(infer_gen)
except astroid.InferenceError:
return None
+
+ if value is not astroid.Uninferable:
+ inferred_types.add(_get_python_type_of_node(value))
+
try:
- next(inferit)
- return None # None if there is ambiguity on the inferred node
+ for inferred in infer_gen:
+ inferred_type = _get_python_type_of_node(inferred)
+ if inferred_type not in inferred_types:
+ return None # If there is ambiguity on the inferred node.
except astroid.InferenceError:
- return None # there is some kind of ambiguity
+ return None # There is some kind of ambiguity
except StopIteration:
return value
+ return value if len(inferred_types) <= 1 else None
def has_known_bases(klass: astroid.ClassDef, context=None) -> bool: