Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit 71e70f4

Browse files
author
Mikhail Arkhipov
committed
Scopes
1 parent 08d4995 commit 71e70f4

5 files changed

Lines changed: 1618 additions & 1593 deletions

File tree

src/Analysis/Engine/Impl/AnalysisVariable.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,18 @@
1616

1717
namespace Microsoft.PythonTools.Analysis {
1818
class AnalysisVariable : IAnalysisVariable {
19-
public AnalysisVariable(VariableType type, ILocationInfo location, int? version = null) {
19+
public AnalysisVariable(IVariableDefinition variable, VariableType type, ILocationInfo location, int? version = null) {
20+
Variable = variable;
2021
Location = location;
2122
Type = type;
2223
Version = version;
2324
}
2425

2526
#region IAnalysisVariable Members
26-
2727
public ILocationInfo Location { get; }
28-
2928
public VariableType Type { get; }
30-
3129
public int? Version { get; }
32-
30+
public IVariableDefinition Variable { get; }
3331
#endregion
3432

3533
public override bool Equals(object obj) {

src/Analysis/Engine/Impl/Definitions/IAnalysisVariable.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@ public interface IAnalysisVariable {
2222
ILocationInfo Location { get; }
2323

2424
VariableType Type { get; }
25+
26+
IVariableDefinition Variable { get; }
2527
}
2628
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Python Tools for Visual Studio
2+
// Copyright(c) Microsoft Corporation
3+
// All rights reserved.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the License); you may not use
6+
// this file except in compliance with the License. You may obtain a copy of the
7+
// License at http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
10+
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
11+
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
12+
// MERCHANTABLITY OR NON-INFRINGEMENT.
13+
//
14+
// See the Apache Version 2.0 License for specific language governing
15+
// permissions and limitations under the License.
16+
17+
using System.Collections.Generic;
18+
19+
namespace Microsoft.PythonTools.Analysis.Infrastructure {
20+
static class HashSetExtensions {
21+
public static void Add<T>(this HashSet<T> set, IEnumerable<T> source) {
22+
foreach(var e in source) {
23+
set.Add(e);
24+
}
25+
}
26+
}
27+
}

src/Analysis/Engine/Impl/ModuleAnalysis.cs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)