Class: Solargraph::Parser::FlowSensitiveTyping
- Inherits:
-
Object
- Object
- Solargraph::Parser::FlowSensitiveTyping
- Extended by:
- Logging
- Includes:
- Logging, ParserGem::NodeMethods
- Defined in:
- lib/solargraph/parser/flow_sensitive_typing.rb
Constant Summary
Constants included from Logging
Logging::DEFAULT_LOG_LEVEL, Logging::LOG_LEVELS
Constants included from ParserGem::NodeMethods
ParserGem::NodeMethods::NIL_NODE
Instance Method Summary collapse
-
#initialize(locals, ivars, enclosing_breakable_pin, enclosing_compound_statement_pin) ⇒ FlowSensitiveTyping
constructor
A new instance of FlowSensitiveTyping.
- #process_and(and_node, true_ranges = [], false_ranges = []) ⇒ void
- #process_calls(node, true_presences, false_presences) ⇒ void
- #process_if(if_node, true_ranges = [], false_ranges = []) ⇒ void
- #process_or(or_node, true_ranges = [], false_ranges = []) ⇒ void
- #process_while(while_node, true_ranges = [], false_ranges = []) ⇒ void
Methods included from Logging
Methods included from ParserGem::NodeMethods
any_splatted_call?, call_nodes_from, const_nodes_from, convert_hash, drill_signature, find_recipient_node, get_node_end_position, get_node_start_position, infer_literal_node_type, pack_name, repaired_find_recipient_node, returns_from_method_body, splatted_call?, splatted_hash?, unpack_name, value_position_nodes_only
Constructor Details
#initialize(locals, ivars, enclosing_breakable_pin, enclosing_compound_statement_pin) ⇒ FlowSensitiveTyping
Returns a new instance of FlowSensitiveTyping.
12 13 14 15 16 17 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 12 def initialize locals, ivars, enclosing_breakable_pin, enclosing_compound_statement_pin @locals = locals @ivars = ivars @enclosing_breakable_pin = enclosing_breakable_pin @enclosing_compound_statement_pin = enclosing_compound_statement_pin end |
Instance Method Details
#process_and(and_node, true_ranges = [], false_ranges = []) ⇒ void
This method returns an undefined value.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 24 def process_and and_node, true_ranges = [], false_ranges = [] return unless and_node.type == :and # @type [Parser::AST::Node] lhs = and_node.children[0] # @type [Parser::AST::Node] rhs = and_node.children[1] before_rhs_loc = rhs.location.expression.adjust(begin_pos: -1) before_rhs_pos = Position.new(before_rhs_loc.line, before_rhs_loc.column) rhs_presence = Range.new(before_rhs_pos, get_node_end_position(rhs)) # can't assume if an and is false that every single condition # is false, so don't provide any false ranges to assert facts # on process_expression(lhs, true_ranges + [rhs_presence], []) process_expression(rhs, true_ranges, []) end |
#process_calls(node, true_presences, false_presences) ⇒ void
This method returns an undefined value.
79 80 81 82 83 84 85 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 79 def process_calls node, true_presences, false_presences return unless node.type == :send process_isa(node, true_presences, false_presences) process_nilp(node, true_presences, false_presences) process_bang(node, true_presences, false_presences) end |
#process_if(if_node, true_ranges = [], false_ranges = []) ⇒ void
This method returns an undefined value.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 92 def process_if if_node, true_ranges = [], false_ranges = [] return if if_node.type != :if # # See if we can refine a type based on the result of 'if foo.nil?' # # [3] pry(main)> require 'parser/current'; Parser::CurrentRuby.parse("if foo.is_a? Baz; then foo; else bar; end") # => s(:if, # s(:send, # s(:send, nil, :foo), :is_a?, # s(:const, nil, :Baz)), # s(:send, nil, :foo), # s(:send, nil, :bar)) # [4] pry(main)> conditional_node = if_node.children[0] # @type [Parser::AST::Node, nil] then_clause = if_node.children[1] # @type [Parser::AST::Node, nil] else_clause = if_node.children[2] unless enclosing_breakable_pin.nil? rest_of_breakable_body = Range.new(get_node_end_position(if_node), get_node_end_position(enclosing_breakable_pin.node)) false_ranges << rest_of_breakable_body if always_breaks?(then_clause) true_ranges << rest_of_breakable_body if always_breaks?(else_clause) end unless enclosing_compound_statement_pin.node.nil? rest_of_returnable_body = Range.new(get_node_end_position(if_node), get_node_end_position(enclosing_compound_statement_pin.node)) # # if one of the clauses always leaves the compound # statement, we can assume things about the rest of the # compound statement # false_ranges << rest_of_returnable_body if always_leaves_compound_statement?(then_clause) true_ranges << rest_of_returnable_body if always_leaves_compound_statement?(else_clause) end unless then_clause.nil? # # If the condition is true we can assume things about the then clause # before_then_clause_loc = then_clause.location.expression.adjust(begin_pos: -1) before_then_clause_pos = Position.new(before_then_clause_loc.line, before_then_clause_loc.column) true_ranges << Range.new(before_then_clause_pos, get_node_end_position(then_clause)) end unless else_clause.nil? # # If the condition is true we can assume things about the else clause # before_else_clause_loc = else_clause.location.expression.adjust(begin_pos: -1) before_else_clause_pos = Position.new(before_else_clause_loc.line, before_else_clause_loc.column) false_ranges << Range.new(before_else_clause_pos, get_node_end_position(else_clause)) end process_expression(conditional_node, true_ranges, false_ranges) end |
#process_or(or_node, true_ranges = [], false_ranges = []) ⇒ void
This method returns an undefined value.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 50 def process_or or_node, true_ranges = [], false_ranges = [] return unless or_node.type == :or # @type [Parser::AST::Node] lhs = or_node.children[0] # @type [Parser::AST::Node] rhs = or_node.children[1] before_rhs_loc = rhs.location.expression.adjust(begin_pos: -1) before_rhs_pos = Position.new(before_rhs_loc.line, before_rhs_loc.column) rhs_presence = Range.new(before_rhs_pos, get_node_end_position(rhs)) # can assume if an or is false that every single condition is # false, so provide false ranges to assert facts on # can't assume if an or is true that every single condition is # true, so don't provide true ranges to assert facts on process_expression(lhs, [], false_ranges + [rhs_presence]) process_expression(rhs, [], false_ranges) end |
#process_while(while_node, true_ranges = [], false_ranges = []) ⇒ void
This method returns an undefined value.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/solargraph/parser/flow_sensitive_typing.rb', line 163 def process_while while_node, true_ranges = [], false_ranges = [] return if while_node.type != :while # # See if we can refine a type based on the result of 'if foo.nil?' # # [3] pry(main)> Parser::CurrentRuby.parse("while a; b; c; end") # => s(:while, # s(:send, nil, :a), # s(:begin, # s(:send, nil, :b), # s(:send, nil, :c))) # [4] pry(main)> conditional_node = while_node.children[0] # @type [Parser::AST::Node, nil] do_clause = while_node.children[1] unless do_clause.nil? # # If the condition is true we can assume things about the do clause # before_do_clause_loc = do_clause.location.expression.adjust(begin_pos: -1) before_do_clause_pos = Position.new(before_do_clause_loc.line, before_do_clause_loc.column) true_ranges << Range.new(before_do_clause_pos, get_node_end_position(do_clause)) end process_expression(conditional_node, true_ranges, false_ranges) end |