|
16 | 16 |
|
17 | 17 | using System;
|
18 | 18 | using System.Collections.Generic;
|
| 19 | +using System.Diagnostics; |
19 | 20 | using System.Linq;
|
20 | 21 | using Microsoft.PythonTools.Analysis.Infrastructure;
|
21 | 22 | using Microsoft.PythonTools.Parsing.Ast;
|
22 | 23 |
|
23 | 24 | namespace Microsoft.PythonTools.Interpreter.Ast {
|
| 25 | + [DebuggerDisplay("{Target.Name}")] |
24 | 26 | class AstAnalysisFunctionWalker : PythonWalker {
|
25 | 27 | private readonly NameLookupContext _scope;
|
26 | 28 | private readonly AstPythonFunctionOverload _overload;
|
@@ -64,14 +66,24 @@ public void Walk() {
|
64 | 66 | _selfType = (self as AstPythonConstant)?.Type as AstPythonType;
|
65 | 67 |
|
66 | 68 | _overload.ReturnTypes.AddRange(_scope.GetTypesFromAnnotation(Target.ReturnAnnotation).ExcludeDefault());
|
67 |
| - |
68 | 69 | _scope.PushScope();
|
| 70 | + |
| 71 | + // Declare self, if any |
| 72 | + var skip = 0; |
69 | 73 | if (self != null) {
|
70 | 74 | var p0 = Target.Parameters.FirstOrDefault();
|
71 | 75 | if (p0 != null && !string.IsNullOrEmpty(p0.Name)) {
|
72 | 76 | _scope.SetInScope(p0.Name, self);
|
| 77 | + skip++; |
73 | 78 | }
|
74 | 79 | }
|
| 80 | + |
| 81 | + // Declare parameters in scope |
| 82 | + foreach(var p in Target.Parameters.Skip(skip).Where(p => !string.IsNullOrEmpty(p.Name))) { |
| 83 | + var value = _scope.GetValueFromExpression(p.DefaultValue); |
| 84 | + _scope.SetInScope(p.Name, value ?? _scope.UnknownType); |
| 85 | + } |
| 86 | + |
75 | 87 | Target.Walk(this);
|
76 | 88 | _scope.PopScope();
|
77 | 89 | }
|
@@ -161,19 +173,28 @@ public override bool Walk(IfStatement node) {
|
161 | 173 | }
|
162 | 174 |
|
163 | 175 | public override bool Walk(ReturnStatement node) {
|
164 |
| - foreach (var type in _scope.GetTypesFromValue(_scope.GetValueFromExpression(node.Expression)).ExcludeDefault()) { |
| 176 | + var types = _scope.GetTypesFromValue(_scope.GetValueFromExpression(node.Expression)).ExcludeDefault(); |
| 177 | + foreach (var type in types) { |
165 | 178 | _overload.ReturnTypes.Add(type);
|
166 | 179 | }
|
| 180 | + |
| 181 | + // Clean up: if there are None or Unknown types along with real ones, remove them. |
| 182 | + var realTypes = _overload.ReturnTypes |
| 183 | + .Where(t => t.TypeId != BuiltinTypeId.Unknown && t.TypeId != BuiltinTypeId.NoneType) |
| 184 | + .ToList(); |
| 185 | + |
| 186 | + if (realTypes.Count > 0) { |
| 187 | + _overload.ReturnTypes.Clear(); |
| 188 | + _overload.ReturnTypes.AddRange(realTypes); |
| 189 | + } |
167 | 190 | return true; // We want to evaluate all code so all private variables in __new__ get defined
|
168 | 191 | }
|
169 | 192 |
|
170 | 193 | private IMember GetSelf() {
|
171 |
| - bool classmethod, staticmethod; |
172 |
| - GetMethodType(Target, out classmethod, out staticmethod); |
| 194 | + GetMethodType(Target, out var classmethod, out var staticmethod); |
173 | 195 | var self = _scope.LookupNameInScopes("__class__", NameLookupContext.LookupOptions.Local);
|
174 | 196 | if (!staticmethod && !classmethod) {
|
175 |
| - var cls = self as IPythonType; |
176 |
| - if (cls == null) { |
| 197 | + if (!(self is IPythonType cls)) { |
177 | 198 | self = null;
|
178 | 199 | } else {
|
179 | 200 | self = new AstPythonConstant(cls, ((cls as ILocatedMember)?.Locations).MaybeEnumerate().ToArray());
|
|
0 commit comments