Skip to content

Commit cc38f09

Browse files
authored
Adjust local variable presence to start after assignment, not before (#864)
* Adjust local variable presence to start after assignment, not before * Add regression test around assignment in return position * Fix assignment visibility code, which relied on bad asgn semantics
1 parent 076fba9 commit cc38f09

File tree

4 files changed

+74
-17
lines changed

4 files changed

+74
-17
lines changed

lib/solargraph/parser/parser_gem/node_chainer.rb

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,21 @@ def generate_links n
8989
elsif n.type == :const
9090
const = unpack_name(n)
9191
result.push Chain::Constant.new(const)
92-
elsif [:lvar, :lvasgn].include?(n.type)
92+
elsif [:lvasgn, :ivasgn, :gvasgn, :cvasgn].include?(n.type)
93+
result.concat generate_links(n.children[1])
94+
elsif n.type == :lvar
9395
result.push Chain::Call.new(n.children[0].to_s)
94-
elsif [:ivar, :ivasgn].include?(n.type)
95-
result.push Chain::InstanceVariable.new(n.children[0].to_s)
96-
elsif [:cvar, :cvasgn].include?(n.type)
97-
result.push Chain::ClassVariable.new(n.children[0].to_s)
98-
elsif [:gvar, :gvasgn].include?(n.type)
99-
result.push Chain::GlobalVariable.new(n.children[0].to_s)
96+
elsif n.type == :ivar
97+
result.push Chain::InstanceVariable.new(n.children[0].to_s)
98+
elsif n.type == :cvar
99+
result.push Chain::ClassVariable.new(n.children[0].to_s)
100+
elsif n.type == :gvar
101+
result.push Chain::GlobalVariable.new(n.children[0].to_s)
100102
elsif n.type == :or_asgn
103+
# @todo: Need a new Link class here that evaluates the
104+
# existing variable type with the RHS, and generates a
105+
# union type of the LHS alone if never nil, or minus nil +
106+
# RHS if it is nilable.
101107
result.concat generate_links n.children[1]
102108
elsif [:class, :module, :def, :defs].include?(n.type)
103109
# @todo Undefined or what?

lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ class LvasgnNode < Parser::NodeProcessor::Base
88
include ParserGem::NodeMethods
99

1010
def process
11-
here = get_node_start_position(node)
12-
presence = Range.new(here, region.closure.location.range.ending)
11+
# variable not visible until next statement
12+
presence = Range.new(get_node_end_position(node), region.closure.location.range.ending)
1313
loc = get_node_location(node)
1414
locals.push Solargraph::Pin::LocalVariable.new(
1515
location: loc,

spec/parser/node_chainer_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,9 @@ class Foo
111111
foo = [1, 2]
112112
))
113113
chain = Solargraph::Parser.chain(source.node)
114-
expect(chain.links.map(&:word)).to eq(['foo'])
114+
expect(chain.links.map(&:word)).to eq(['<::Array>'])
115115
foo_link = chain.links.first
116-
expect(foo_link.class).to eq(Solargraph::Source::Chain::Call)
117-
expect(foo_link.arguments).to eq([])
116+
expect(foo_link.class).to eq(Solargraph::Source::Chain::Array)
118117
end
119118

120119
it 'tracks complex lhs' do

spec/source_map/clip_spec.rb

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,11 @@ def bar
361361
# @return [String, Array]
362362
def foo; end
363363
var = foo
364+
var
364365
), 'test.rb')
365366
map = Solargraph::ApiMap.new
366367
map.map source
367-
clip = map.clip_at('test.rb', Solargraph::Position.new(3, 7))
368+
clip = map.clip_at('test.rb', Solargraph::Position.new(4, 6))
368369
type = clip.infer
369370
expect(type.to_s).to eq('String, Array')
370371
end
@@ -731,10 +732,11 @@ def self.new
731732
end
732733
end
733734
value = Value.new
735+
value
734736
), 'test.rb')
735737
api_map = Solargraph::ApiMap.new
736738
api_map.map source
737-
clip = api_map.clip_at('test.rb', [6, 11])
739+
clip = api_map.clip_at('test.rb', [7, 11])
738740
expect(clip.infer.tag).to eq('Class')
739741
end
740742

@@ -1252,6 +1254,7 @@ class Foo
12521254
class Mod
12531255
def meth
12541256
arr = []
1257+
arr
12551258
1.times do
12561259
arr
12571260
end
@@ -1261,11 +1264,11 @@ def meth
12611264
), 'test.rb')
12621265
api_map = Solargraph::ApiMap.new
12631266
api_map.map source
1264-
clip = api_map.clip_at('test.rb', [3, 11])
1267+
clip = api_map.clip_at('test.rb', [4, 11])
12651268
expect(clip.infer.tag).to eq('Array')
1266-
clip = api_map.clip_at('test.rb', [5, 12])
1269+
clip = api_map.clip_at('test.rb', [6, 12])
12671270
expect(clip.infer.tag).to eq('Array')
1268-
clip = api_map.clip_at('test.rb', [7, 10])
1271+
clip = api_map.clip_at('test.rb', [8, 10])
12691272
expect(clip.infer.tag).to eq('Array')
12701273
end
12711274

@@ -2267,6 +2270,55 @@ def blah
22672270
expect(clip.infer.to_s).to eq('nil')
22682271
end
22692272

2273+
it 'can infer assignments-in-return-position from complex expressions' do
2274+
source = Solargraph::Source.load_string(%(
2275+
class A
2276+
def foo
2277+
blah = ['foo'].map { 456 }
2278+
end
2279+
2280+
def bar
2281+
nah ||= ['foo'].map { 456 }
2282+
end
2283+
2284+
def foo1
2285+
@blah = ['foo'].map { 456 }
2286+
end
2287+
2288+
def bar1
2289+
@nah2 ||= ['foo'].map { 456 }
2290+
end
2291+
2292+
def baz
2293+
a = foo
2294+
a
2295+
b = bar
2296+
b
2297+
a1 = foo1
2298+
a1
2299+
b2 = bar1
2300+
b2
2301+
end
2302+
end
2303+
), 'test.rb')
2304+
2305+
api_map = Solargraph::ApiMap.new.map(source)
2306+
2307+
clip = api_map.clip_at('test.rb', [20, 10])
2308+
expect(clip.infer.to_s).to eq('Array<Integer>')
2309+
2310+
# @todo pending https://github.com/castwide/solargraph/pull/888
2311+
# clip = api_map.clip_at('test.rb', [22, 10])
2312+
# expect(clip.infer.to_s).to eq('Array<Integer>')
2313+
2314+
clip = api_map.clip_at('test.rb', [24, 10])
2315+
expect(clip.infer.to_s).to eq('Array<Integer>')
2316+
2317+
# @todo pending https://github.com/castwide/solargraph/pull/888
2318+
# clip = api_map.clip_at('test.rb', [26, 10])
2319+
# expect(clip.infer.to_s).to eq('Array<Integer>')
2320+
end
2321+
22702322
xit 'resolves overloads based on kwarg existence' do
22712323
source = Solargraph::Source.load_string(%(
22722324
class Blah

0 commit comments

Comments
 (0)