@@ -114,7 +114,9 @@ private static IAnalysisSet ResolveAndAdd(AnalysisUnit unit, IAnalysisSet set, A
114114 }
115115
116116 internal IEnumerable < AnalysisVariable > ToVariables ( IReferenceable referenceable ) {
117- if ( referenceable is VariableDef def ) {
117+ var def = referenceable as VariableDef ;
118+
119+ if ( def != null ) {
118120 foreach ( var type in def . Types . WhereNotNull ( ) ) {
119121 var varType = VariableType . Value ;
120122 if ( type . DeclaringModule == null ) {
@@ -123,22 +125,22 @@ internal IEnumerable<AnalysisVariable> ToVariables(IReferenceable referenceable)
123125 }
124126
125127 foreach ( var loc in type . Locations . WhereNotNull ( ) ) {
126- yield return new AnalysisVariable ( varType , loc ) ;
128+ yield return new AnalysisVariable ( def , varType , loc ) ;
127129 }
128130 }
129131 }
130132
131133 foreach ( var reference in referenceable . Definitions ) {
132134 var loc = reference . GetLocationInfo ( ) ;
133135 if ( loc != null ) {
134- yield return new AnalysisVariable ( VariableType . Definition , loc ) ;
136+ yield return new AnalysisVariable ( def , VariableType . Definition , loc ) ;
135137 }
136138 }
137139
138140 foreach ( var reference in referenceable . References ) {
139141 var loc = reference . GetLocationInfo ( ) ;
140142 if ( loc != null ) {
141- yield return new AnalysisVariable ( VariableType . Reference , loc ) ;
143+ yield return new AnalysisVariable ( def , VariableType . Reference , loc ) ;
142144 }
143145 }
144146 }
@@ -234,23 +236,33 @@ public VariablesResult GetVariables(Expression expr, SourceLocation location, st
234236 if ( ! scope . EnumerateTowardsGlobal . Any ( ) ) {
235237 variables = _unit . State . BuiltinModule . GetDefinitions ( name . Name ) . SelectMany ( ToVariables ) ;
236238 } else {
237- foreach ( var defScope in scope . EnumerateTowardsGlobal
238- . Where ( s => s . ContainsVariable ( name . Name ) && ( s == scope || s . VisibleToChildren || IsFirstLineOfFunction ( scope , s , location ) ) ) ) {
239- var scopeVariables = GetVariablesInScope ( name , defScope ) . Distinct ( ) ;
240- // Filter our definitions that are below the requested location (such as reassignments)
241- var above = scopeVariables . Where ( v => new SourceLocation ( v . Location . StartLine , v . Location . StartColumn ) <= location ) ;
242- variables = variables . Union ( above ) ;
243-
244- // Break at the first definition so we don't spill into global scope
245- // for similarly named function parameters.
246- if ( scopeVariables . Any ( v => v . Type == VariableType . Definition ) ) {
239+ foreach ( var s in scope . EnumerateTowardsGlobal . Where ( s => s . VisibleToChildren ) ) {
240+ var scopeVariables = GetVariablesInScope ( name , s ) . Distinct ( ) ;
241+ var args = scopeVariables . Where ( v => IsFunctionArgument ( v . Variable ) ) ;
242+ if ( args . Any ( ) ) {
243+ variables = variables . Union ( args ) ;
247244 break ;
248245 }
246+ variables = variables . Union ( scopeVariables ) ;
249247 }
248+
249+ // Now take outermost definition and treat inner ones (such as reassignments) as references
250+ var others = variables . Where ( v => v . Type == VariableType . Reference || v . Type == VariableType . Value ) ;
251+ var definitions = variables
252+ . Where ( v => v . Type == VariableType . Definition )
253+ . OrderBy ( v => v . Location . Span . Start )
254+ . ToArray ( ) ;
255+
256+ if ( definitions . Length > 0 ) {
257+ var defsToRefs = definitions . Skip ( 1 ) . Select ( v => new AnalysisVariable ( v . Variable , VariableType . Reference , v . Location ) ) ;
258+ variables = definitions . Take ( 1 ) . Concat ( others . Concat ( defsToRefs ) ) ;
259+ }
250260 }
251- } else if ( expr is MemberExpression member && ! string . IsNullOrEmpty ( member . Name ) ) {
252- var objects = eval . Evaluate ( member . Target ) ;
261+ return new VariablesResult ( variables , unit . Tree ) ;
262+ }
253263
264+ if ( expr is MemberExpression member && ! string . IsNullOrEmpty ( member . Name ) ) {
265+ var objects = eval . Evaluate ( member . Target ) ;
254266 foreach ( var v in objects . OfType < IReferenceableContainer > ( ) ) {
255267 variables = variables . Union ( v . GetDefinitions ( member . Name ) . SelectMany ( ToVariables ) ) ;
256268 }
@@ -259,6 +271,9 @@ public VariablesResult GetVariables(Expression expr, SourceLocation location, st
259271 return new VariablesResult ( variables , unit . Tree ) ;
260272 }
261273
274+ private bool IsFunctionArgument ( IVariableDefinition v )
275+ => v ? . Types ? . MaybeEnumerate ( ) . FirstOrDefault ( ) is ParameterInfo ;
276+
262277 private IEnumerable < IAnalysisVariable > GetVariablesInScope ( NameExpression name , IScope scope ) {
263278 var result = new List < IAnalysisVariable > ( ) ;
264279
@@ -297,19 +312,6 @@ private IEnumerable<IAnalysisVariable> GetVariablesInScope(NameExpression name,
297312 return result ;
298313 }
299314
300- private static bool IsFirstLineOfFunction ( IScope innerScope , IScope outerScope , SourceLocation location ) {
301- if ( innerScope . OuterScope == outerScope && innerScope is FunctionScope ) {
302- var funcScope = ( FunctionScope ) innerScope ;
303- var def = funcScope . Function . FunctionDefinition ;
304-
305- // TODO: Use indexes rather than lines to check location
306- if ( location . Line == def . GetStart ( def . GlobalParent ) . Line ) {
307- return true ;
308- }
309- }
310- return false ;
311- }
312-
313315 private class ErrorWalker : PythonWalker {
314316 public bool HasError { get ; private set ; }
315317
0 commit comments