@@ -246,39 +246,66 @@ private static VariablesResult GetVariablesFromCallExpression(AnalysisUnit unit,
246246 return null ;
247247 }
248248
249+ private class VariableScopePair : Tuple < IAnalysisVariable , int > {
250+ public VariableScopePair ( IAnalysisVariable v , int scopeLevel ) : base ( v , scopeLevel ) { }
251+ public IAnalysisVariable Variable => Item1 ;
252+ public int ScopeLevel => Item2 ;
253+ public VariableType VariableType => Variable . Type ;
254+ public ILocationInfo Location => Variable . Location ;
255+ }
256+
249257 private VariablesResult GetVariablesFromNameExpression ( Expression expr , AnalysisUnit unit , IScope scope ) {
250258 if ( ! ( expr is NameExpression name ) ) {
251259 return null ;
252260 }
253261
254- var variables = Enumerable . Empty < IAnalysisVariable > ( ) ;
255262 if ( ! scope . EnumerateTowardsGlobal . Any ( ) ) {
256- variables = _unit . State . BuiltinModule . GetDefinitions ( name . Name ) . SelectMany ( ToVariables ) ;
257- return new VariablesResult ( variables , unit . Tree ) ;
263+ var v = _unit . State . BuiltinModule . GetDefinitions ( name . Name ) . SelectMany ( ToVariables ) ;
264+ return new VariablesResult ( v , unit . Tree ) ;
258265 }
259266
267+ var variables = Enumerable . Empty < VariableScopePair > ( ) ;
268+ VariableScopePair mainDefinition = null ;
269+ var scopeLevel = 0 ;
260270 foreach ( var s in scope . EnumerateTowardsGlobal ) {
261- var scopeVariables = GetVariablesInScope ( name , s ) . Distinct ( ) ;
271+ var scopeVariables = GetVariablesInScope ( name , s )
272+ . Distinct ( )
273+ . Select ( v => new VariableScopePair ( v , scopeLevel ) )
274+ . ToArray ( ) ;
275+
262276 variables = variables . Union ( scopeVariables ) ;
263- var args = scopeVariables . Where ( v => IsFunctionArgument ( s , v ) ) ;
264- if ( args . Any ( ) ) {
277+
278+ // If we already have definition and it is a function argument, then stop
279+ // since function argument wins over definitions in the outer scope
280+ mainDefinition = scopeVariables . FirstOrDefault ( v => v . VariableType == VariableType . Definition && IsFunctionArgument ( s , v . Variable ) ) ;
281+ if ( mainDefinition != null ) {
265282 break ;
266283 }
284+ scopeLevel ++ ;
267285 }
268286
269- // Now take outermost definition and treat inner ones (such as reassignments) as references
270- var others = variables . Where ( v => v . Type == VariableType . Reference || v . Type == VariableType . Value ) ;
287+ // Now take innermost definition and treat inner ones (such as reassignments) as references
271288 var definitions = variables
272- . Where ( v => v . Type == VariableType . Definition )
289+ . Where ( v => v . VariableType == VariableType . Definition )
273290 . OrderBy ( v => v . Location . Span . Start )
291+ . Reverse ( )
274292 . ToArray ( ) ;
275293
276- if ( definitions . Length > 0 ) {
277- var defsToRefs = definitions . Skip ( 1 ) . Select ( v => new AnalysisVariable ( v . Variable , VariableType . Reference , v . Location ) ) ;
278- variables = definitions . Take ( 1 ) . Concat ( others . Concat ( defsToRefs ) ) ;
294+ mainDefinition = mainDefinition ?? definitions . FirstOrDefault ( ) ;
295+ if ( mainDefinition != null ) {
296+ // Drop definitions in outer scopes and convert those in inner scopes to references.
297+ // Scope levels are numbered in reverse (X == main definition level, x+1 == one up).
298+ var defsToRefs = definitions
299+ . Where ( d => d != mainDefinition && d . ScopeLevel <= mainDefinition . ScopeLevel )
300+ . Select ( v => new VariableScopePair ( new AnalysisVariable ( v . Variable . Variable , VariableType . Reference , v . Location ) , v . ScopeLevel ) ) ;
301+
302+ var others = variables
303+ . Where ( v => ( v . VariableType == VariableType . Reference || v . VariableType == VariableType . Value ) &&
304+ v . ScopeLevel <= mainDefinition . ScopeLevel ) ;
305+ variables = new [ ] { mainDefinition } . Concat ( others . Concat ( defsToRefs ) ) ;
279306 }
280307
281- return new VariablesResult ( variables , unit . Tree ) ;
308+ return new VariablesResult ( variables . Select ( v => v . Variable ) , unit . Tree ) ;
282309 }
283310
284311 private VariablesResult GetVariablesFromMemberExpression ( Expression expr , AnalysisUnit unit , ExpressionEvaluator eval ) {
0 commit comments