]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/flow_analysis.py
1 from typing
import Dict
, Optional
3 from jedi
.parser_utils
import get_flow_branch_keyword
, is_scope
, get_parent_scope
4 from jedi
.inference
.recursion
import execution_allowed
5 from jedi
.inference
.helpers
import is_big_annoying_library
9 lookup_table
: Dict
[Optional
[bool], 'Status'] = {}
11 def __init__(self
, value
: Optional
[bool], name
: str) -> None:
14 Status
.lookup_table
[value
] = self
19 elif self
is UNREACHABLE
:
24 def __and__(self
, other
):
25 if UNSURE
in (self
, other
):
28 return REACHABLE
if self
._value
and other
._value
else UNREACHABLE
31 return '<%s: %s>' % (type(self
).__name
__, self
._name
)
34 REACHABLE
= Status(True, 'reachable')
35 UNREACHABLE
= Status(False, 'unreachable')
36 UNSURE
= Status(None, 'unsure')
39 def _get_flow_scopes(node
):
41 node
= get_parent_scope(node
, include_flows
=True)
42 if node
is None or is_scope(node
):
47 def reachability_check(context
, value_scope
, node
, origin_scope
=None):
48 if is_big_annoying_library(context
) \
49 or not context
.inference_state
.flow_analysis_enabled
:
52 first_flow_scope
= get_parent_scope(node
, include_flows
=True)
53 if origin_scope
is not None:
54 origin_flow_scopes
= list(_get_flow_scopes(origin_scope
))
55 node_flow_scopes
= list(_get_flow_scopes(node
))
58 for flow_scope
in origin_flow_scopes
:
59 if flow_scope
in node_flow_scopes
:
60 node_keyword
= get_flow_branch_keyword(flow_scope
, node
)
61 origin_keyword
= get_flow_branch_keyword(flow_scope
, origin_scope
)
62 branch_matches
= node_keyword
== origin_keyword
63 if flow_scope
.type == 'if_stmt':
64 if not branch_matches
:
66 elif flow_scope
.type == 'try_stmt':
67 if not branch_matches
and origin_keyword
== 'else' \
68 and node_keyword
== 'except':
73 # Direct parents get resolved, we filter scopes that are separate
74 # branches. This makes sense for autocompletion and static analysis.
75 # For actual Python it doesn't matter, because we're talking about
76 # potentially unreachable code.
77 # e.g. `if 0:` would cause all name lookup within the flow make
78 # unaccessible. This is not a "problem" in Python, because the code is
79 # never called. In Jedi though, we still want to infer types.
80 while origin_scope
is not None:
81 if first_flow_scope
== origin_scope
and branch_matches
:
83 origin_scope
= origin_scope
.parent
85 return _break_check(context
, value_scope
, first_flow_scope
, node
)
88 def _break_check(context
, value_scope
, flow_scope
, node
):
90 if flow_scope
.type == 'if_stmt':
91 if flow_scope
.is_node_after_else(node
):
92 for check_node
in flow_scope
.get_test_nodes():
93 reachable
= _check_if(context
, check_node
)
94 if reachable
in (REACHABLE
, UNSURE
):
96 reachable
= reachable
.invert()
98 flow_node
= flow_scope
.get_corresponding_test_node(node
)
99 if flow_node
is not None:
100 reachable
= _check_if(context
, flow_node
)
101 elif flow_scope
.type in ('try_stmt', 'while_stmt'):
104 # Only reachable branches need to be examined further.
105 if reachable
in (UNREACHABLE
, UNSURE
):
108 if value_scope
!= flow_scope
and value_scope
!= flow_scope
.parent
:
109 flow_scope
= get_parent_scope(flow_scope
, include_flows
=True)
110 return reachable
& _break_check(context
, value_scope
, flow_scope
, node
)
115 def _check_if(context
, node
):
116 with
execution_allowed(context
.inference_state
, node
) as allowed
:
120 types
= context
.infer_node(node
)
121 values
= set(x
.py__bool__() for x
in types
)
123 return Status
.lookup_table
[values
.pop()]