From 8bca56b1fa4ab8b282ae6491de25525c90aa9efe Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Fri, 1 Mar 2019 09:51:05 -0800 Subject: [PATCH 01/11] Fix #668 (partial) --- .../Analyzer/Handlers/ConditionalHandler.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs b/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs index cb41801b9..b104acb94 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs @@ -66,24 +66,6 @@ public bool HandleIf(IfStatement node) { someRecognized = true; } } - - // Handle basic check such as - // if isinstance(value, type): - // return value - // by assigning type to the value unless clause is raising exception. - var ce = node.Tests.FirstOrDefault()?.Test as CallExpression; - if (ce?.Target is NameExpression ne && ne.Name == @"isinstance" && ce.Args.Count == 2) { - var nex = ce.Args[0].Expression as NameExpression; - var name = nex?.Name; - var typeName = (ce.Args[1].Expression as NameExpression)?.Name; - if (name != null && typeName != null) { - var typeId = typeName.GetTypeId(); - if (typeId != BuiltinTypeId.Unknown) { - var t = new PythonType(typeName, Module, string.Empty, LocationInfo.Empty, typeId); - Eval.DeclareVariable(name, t, VariableSource.Declaration, nex); - } - } - } return !someRecognized; } From 7ffc9db4f0807314d4d36a8540380b988c26ee2e Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Mon, 4 Mar 2019 16:43:30 -0800 Subject: [PATCH 02/11] Tests --- src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 10 ++++++++-- src/Analysis/Ast/Impl/Modules/PythonModule.cs | 12 ++++-------- src/Analysis/Ast/Test/BasicTests.cs | 14 ++++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index 205e64d01..a30c5a97b 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -227,8 +227,14 @@ private async Task AnalyzeAffectedEntriesAsync(IDependencyChainWalker<ModuleKey, StartAnalysis(node, walker.Version, stopWatch, cancellationToken); } } - - if (walker.MissingKeys.Where(k => !k.IsTypeshed).Count == 0) { + + var count = walker.MissingKeys.Where(k => !k.IsTypeshed).Count; + _log?.Log(TraceEventType.Verbose, $"Walker count is {count}, missing keys:"); + foreach (var key in walker.MissingKeys) { + _log?.Log(TraceEventType.Verbose, $" Name: {key.Name}, Path: {key.FilePath}"); + } + + if (count == 0) { Interlocked.Exchange(ref _runningTasks, 0); _analysisCompleteEvent.Set(); } diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index 7be31275e..ce6949fc5 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -111,6 +111,7 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s ContentState = State.Analyzed; } InitializeContent(creationOptions.Content); + Log?.Log(TraceEventType.Verbose, $"Created module: {Name} {FilePath}"); } #region IPythonType @@ -385,21 +386,16 @@ private void Parse(CancellationToken cancellationToken) { _diagnosticsService?.Replace(Uri, _parseErrors); } - ContentState = State.Parsed; - } - - NewAst?.Invoke(this, EventArgs.Empty); - - if (ContentState < State.Analyzing) { ContentState = State.Analyzing; + Log?.Log(TraceEventType.Verbose, $"Enqueue: {Name} {FilePath}"); var analyzer = Services.GetService<IPythonAnalyzer>(); analyzer.EnqueueDocumentForAnalysis(this, ast, version, _allProcessingCts.Token); - } - lock (AnalysisLock) { _parsingTask = null; } + + NewAst?.Invoke(this, EventArgs.Empty); } private class CollectingErrorSink : ErrorSink { diff --git a/src/Analysis/Ast/Test/BasicTests.cs b/src/Analysis/Ast/Test/BasicTests.cs index 47d47b8cd..c8b64e2f2 100644 --- a/src/Analysis/Ast/Test/BasicTests.cs +++ b/src/Analysis/Ast/Test/BasicTests.cs @@ -75,12 +75,14 @@ public async Task ImportTest() { import sys x = sys.path "; - var analysis = await GetAnalysisAsync(code); - analysis.GlobalScope.Variables.Count.Should().Be(2); - - analysis.Should() - .HaveVariable("sys").OfType(BuiltinTypeId.Module) - .And.HaveVariable("x").OfType(BuiltinTypeId.List); + for (var i = 0; i < 20; i++) { + var analysis = await GetAnalysisAsync(code); + analysis.GlobalScope.Variables.Count.Should().Be(2); + + analysis.Should() + .HaveVariable("sys").OfType(BuiltinTypeId.Module) + .And.HaveVariable("x").OfType(BuiltinTypeId.List); + } } [TestMethod, Priority(0)] From 6303c45f234ba1c40058520c8700f6815c303035 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov <mikhaila@microsoft.com> Date: Mon, 4 Mar 2019 18:11:48 -0800 Subject: [PATCH 03/11] Revert "Tests" This reverts commit 7ffc9db4f0807314d4d36a8540380b988c26ee2e. --- src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 10 ++-------- src/Analysis/Ast/Impl/Modules/PythonModule.cs | 12 ++++++++---- src/Analysis/Ast/Test/BasicTests.cs | 14 ++++++-------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index a30c5a97b..205e64d01 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -227,14 +227,8 @@ private async Task AnalyzeAffectedEntriesAsync(IDependencyChainWalker<ModuleKey, StartAnalysis(node, walker.Version, stopWatch, cancellationToken); } } - - var count = walker.MissingKeys.Where(k => !k.IsTypeshed).Count; - _log?.Log(TraceEventType.Verbose, $"Walker count is {count}, missing keys:"); - foreach (var key in walker.MissingKeys) { - _log?.Log(TraceEventType.Verbose, $" Name: {key.Name}, Path: {key.FilePath}"); - } - - if (count == 0) { + + if (walker.MissingKeys.Where(k => !k.IsTypeshed).Count == 0) { Interlocked.Exchange(ref _runningTasks, 0); _analysisCompleteEvent.Set(); } diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index ce6949fc5..7be31275e 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -111,7 +111,6 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s ContentState = State.Analyzed; } InitializeContent(creationOptions.Content); - Log?.Log(TraceEventType.Verbose, $"Created module: {Name} {FilePath}"); } #region IPythonType @@ -386,16 +385,21 @@ private void Parse(CancellationToken cancellationToken) { _diagnosticsService?.Replace(Uri, _parseErrors); } + ContentState = State.Parsed; + } + + NewAst?.Invoke(this, EventArgs.Empty); + + if (ContentState < State.Analyzing) { ContentState = State.Analyzing; - Log?.Log(TraceEventType.Verbose, $"Enqueue: {Name} {FilePath}"); var analyzer = Services.GetService<IPythonAnalyzer>(); analyzer.EnqueueDocumentForAnalysis(this, ast, version, _allProcessingCts.Token); + } + lock (AnalysisLock) { _parsingTask = null; } - - NewAst?.Invoke(this, EventArgs.Empty); } private class CollectingErrorSink : ErrorSink { diff --git a/src/Analysis/Ast/Test/BasicTests.cs b/src/Analysis/Ast/Test/BasicTests.cs index c8b64e2f2..47d47b8cd 100644 --- a/src/Analysis/Ast/Test/BasicTests.cs +++ b/src/Analysis/Ast/Test/BasicTests.cs @@ -75,14 +75,12 @@ public async Task ImportTest() { import sys x = sys.path "; - for (var i = 0; i < 20; i++) { - var analysis = await GetAnalysisAsync(code); - analysis.GlobalScope.Variables.Count.Should().Be(2); - - analysis.Should() - .HaveVariable("sys").OfType(BuiltinTypeId.Module) - .And.HaveVariable("x").OfType(BuiltinTypeId.List); - } + var analysis = await GetAnalysisAsync(code); + analysis.GlobalScope.Variables.Count.Should().Be(2); + + analysis.Should() + .HaveVariable("sys").OfType(BuiltinTypeId.Module) + .And.HaveVariable("x").OfType(BuiltinTypeId.List); } [TestMethod, Priority(0)] From 01781c0417b836768708eebaad825330d0b8c987 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Wed, 27 Mar 2019 16:03:02 -0700 Subject: [PATCH 04/11] Exp --- .../Ast/Impl/Analyzer/PythonAnalyzer.cs | 48 +++++++++++++++++-- .../Ast/Impl/Documents/DocumentBuffer.cs | 16 +++---- src/LanguageServer/Impl/Program.cs | 2 +- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index b627aa4f7..674dbe877 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -14,6 +14,7 @@ // permissions and limitations under the License. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -55,6 +56,7 @@ public PythonAnalyzer(IServiceManager services) { _analysisRunningEvent.Set(); _progress = new ProgressReporter(services.GetService<IProgressService>()); + Task.Run(() => Worker()).DoNotWait(); } public void Dispose() { @@ -137,7 +139,7 @@ public void EnqueueDocumentForAnalysis(IPythonModule module, ImmutableArray<IPyt } if (entry.Invalidate(analysisDependencies, version, out var dependencies)) { - AnalyzeDocumentAsync(key, entry, dependencies, default).DoNotWait(); + AnalyzeDocument(key, entry, dependencies, default); } } @@ -159,7 +161,7 @@ public void EnqueueDocumentForAnalysis(IPythonModule module, PythonAst ast, int } if (entry.Invalidate(module, ast, bufferVersion, version, out var dependencies)) { - AnalyzeDocumentAsync(key, entry, dependencies, cancellationToken).DoNotWait(); + AnalyzeDocument(key, entry, dependencies, cancellationToken); } } @@ -177,8 +179,44 @@ public IReadOnlyList<DiagnosticsEntry> LintModule(IPythonModule module) { return linter.Lint(module.Analysis, _services); } + private readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>(); + private readonly ManualResetEventSlim _workAvailable = new ManualResetEventSlim(false); + private readonly ManualResetEventSlim _workerAvailable = new ManualResetEventSlim(true); + private readonly object _lock = new object(); + private int _workerCount; - private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) { + private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) { + lock (_lock) { + _queue.Enqueue(() => DoAnalyzeDocument(key, entry, dependencies, cancellationToken)); + _workAvailable.Set(); + } + } + + private void Worker() { + while(true) { + _workAvailable.Wait(); + if (_queue.TryDequeue(out var action)) { + _workerAvailable.Wait(); + lock (_lock) { + _workerCount++; + if (_workerCount > 4) { + _workerAvailable.Reset(); + } + } + + Task.Run(action).ContinueWith(t => { + lock (_lock) { + _workerCount--; + _workerAvailable.Set(); + } + }); + } else { + _workAvailable.Reset(); + } + } + } + + private void DoAnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) { _analysisCompleteEvent.Reset(); _log?.Log(TraceEventType.Verbose, $"Analysis of {entry.Module.Name}({entry.Module.ModuleType}) queued"); @@ -213,7 +251,7 @@ private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEnt StartAnalysis(entry, walker.Version, cancellationToken); } - await waitForAnalysisTask; + waitForAnalysisTask.Wait(cancellationToken); } int version; @@ -239,7 +277,7 @@ private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEnt var remaining = originalRemaining; try { _log?.Log(TraceEventType.Verbose, $"Analysis version {walker.Version} of {originalRemaining} entries has started."); - remaining = await AnalyzeAffectedEntriesAsync(walker, stopWatch, analysisToken); + remaining = AnalyzeAffectedEntriesAsync(walker, stopWatch, analysisToken).GetAwaiter().GetResult(); } finally { _analysisRunningEvent.Set(); stopWatch.Stop(); diff --git a/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs b/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs index 7e042c1a3..4a386d6ba 100644 --- a/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs +++ b/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs @@ -21,22 +21,21 @@ namespace Microsoft.Python.Analysis.Documents { internal sealed class DocumentBuffer { - private readonly StringBuilder _sb = new StringBuilder(); - private string _cachedText; + private StringBuilder _sb; + private string _content; public int Version { get; private set; } - public string Text => _cachedText ?? (_cachedText = _sb.ToString()); + public string Text => _content ?? (_content = _sb.ToString()); public void Reset(int version, string content) { Version = version; - _sb.Clear(); - if (!string.IsNullOrEmpty(content)) { - _sb.Append(content); - } - _cachedText = null; + _sb = null; + _content = content; } public void Update(IEnumerable<DocumentChange> changes) { + _sb = _sb ?? new StringBuilder(_content); + _content = null; var lastStart = int.MaxValue; var lineLoc = SplitLines(_sb).ToArray(); @@ -57,7 +56,6 @@ public void Update(IEnumerable<DocumentChange> changes) { } } Version++; - _cachedText = null; } private static IEnumerable<NewLineLocation> SplitLines(StringBuilder text) { diff --git a/src/LanguageServer/Impl/Program.cs b/src/LanguageServer/Impl/Program.cs index 11348f518..2fefa03ba 100644 --- a/src/LanguageServer/Impl/Program.cs +++ b/src/LanguageServer/Impl/Program.cs @@ -13,7 +13,7 @@ // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. -// #define WAIT_FOR_DEBUGGER +#define WAIT_FOR_DEBUGGER using System; using System.Diagnostics; From f544f8a19eeee582bd13c46e90f9b5f3985f88b8 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov <mikhaila@microsoft.com> Date: Wed, 27 Mar 2019 19:30:18 -0700 Subject: [PATCH 05/11] Limit concurrency --- src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 5 +++-- src/LanguageServer/Impl/Program.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index 674dbe877..14d4c9a4d 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -193,13 +193,14 @@ private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, I } private void Worker() { - while(true) { + ThreadPool.GetMaxThreads(out var max, out _); + while (true) { _workAvailable.Wait(); if (_queue.TryDequeue(out var action)) { _workerAvailable.Wait(); lock (_lock) { _workerCount++; - if (_workerCount > 4) { + if (_workerCount >= Environment.ProcessorCount) { _workerAvailable.Reset(); } } diff --git a/src/LanguageServer/Impl/Program.cs b/src/LanguageServer/Impl/Program.cs index 2fefa03ba..11348f518 100644 --- a/src/LanguageServer/Impl/Program.cs +++ b/src/LanguageServer/Impl/Program.cs @@ -13,7 +13,7 @@ // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. -#define WAIT_FOR_DEBUGGER +// #define WAIT_FOR_DEBUGGER using System; using System.Diagnostics; From 01bd7196838a7a614bf59cbec0709c8cf300bdb5 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov <mikhaila@microsoft.com> Date: Wed, 27 Mar 2019 19:56:57 -0700 Subject: [PATCH 06/11] Concurrency limit --- src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index 14d4c9a4d..0671135ca 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -193,14 +193,14 @@ private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, I } private void Worker() { - ThreadPool.GetMaxThreads(out var max, out _); + var maxConcurrent = Math.Max(Environment.ProcessorCount / 2, 4); while (true) { _workAvailable.Wait(); if (_queue.TryDequeue(out var action)) { _workerAvailable.Wait(); lock (_lock) { _workerCount++; - if (_workerCount >= Environment.ProcessorCount) { + if (_workerCount >= maxConcurrent) { _workerAvailable.Reset(); } } @@ -377,7 +377,7 @@ private void Analyze(IDependencyChainNode<PythonAnalyzerEntry> node, IDependency node.Commit(); _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) failed."); } finally { - if(_version == walker.Version) { + if (_version == walker.Version) { _progress.ReportRemaining(walker.Remaining); } Interlocked.Decrement(ref _runningTasks); From 2f8e564e3bb1529c0349f88e37483e5e25e3f189 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov <mikhaila@microsoft.com> Date: Thu, 28 Mar 2019 07:20:20 -0700 Subject: [PATCH 07/11] Drop cache after analysis --- src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs | 2 ++ src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs index 123afc63f..c1e7a455f 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs @@ -164,6 +164,8 @@ public IMember GetValueFromExpression(Expression expr, LookupOptions options) { return m; } + internal void ClearCache() => _scopeLookupCache.Clear(); + private IMember GetValueFromFormatSpecifier(FormatSpecifier formatSpecifier) { return new PythonFString(formatSpecifier.Unparsed, Interpreter, GetLoc(formatSpecifier)); } diff --git a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs index b8aa5144c..83b91e9eb 100644 --- a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs +++ b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs @@ -105,6 +105,8 @@ public void Complete() { .Where(s => !string.IsNullOrEmpty(s)) .ToImmutableArray(); } + + Eval.ClearCache(); } public IGlobalScope GlobalScope => Eval.GlobalScope; From 4ad56bbdf1cf3cbe78a8b0b888b5cf2a976cbe03 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Thu, 28 Mar 2019 16:47:16 -0700 Subject: [PATCH 08/11] Fix regression --- src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs b/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs index 536075e0d..34d7b85c3 100644 --- a/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs +++ b/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs @@ -212,6 +212,9 @@ private DocumentEntry CreateDocument(ModuleCreationOptions mco) { document = new CompiledBuiltinPythonModule(mco.ModuleName, mco.Stub, _services); break; case ModuleType.User: + TryAddModulePath(mco); + document = new PythonModule(mco, _services); + break; case ModuleType.Library when TryAddModulePath(mco): document = new PythonModule(mco, _services); break; From 2a50eb9c158342810cca7a20755d3bc297130106 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Wed, 10 Apr 2019 11:00:35 -0700 Subject: [PATCH 09/11] Fix test --- src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs index cda525e89..e04c4192f 100644 --- a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs +++ b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs @@ -120,7 +120,7 @@ private void HandleAllAppendExtend(CallExpression node) { return; } - ExtendAll(node, values); + ExtendAll(me.Target, values); } private void ExtendAll(Node location, IPythonCollection values) { From c94d37555c25849e67f789566c797236f2255105 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Wed, 1 May 2019 09:50:54 -0700 Subject: [PATCH 10/11] Add null check --- src/Analysis/Ast/Impl/Types/Location.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Ast/Impl/Types/Location.cs b/src/Analysis/Ast/Impl/Types/Location.cs index d875216ca..db4d0d442 100644 --- a/src/Analysis/Ast/Impl/Types/Location.cs +++ b/src/Analysis/Ast/Impl/Types/Location.cs @@ -28,9 +28,15 @@ public Location(IPythonModule module, IndexSpan indexSpan) { public IPythonModule Module { get; } public IndexSpan IndexSpan { get; } - public LocationInfo LocationInfo => Module?.Analysis?.Ast != null - ? new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(Module.Analysis?.Ast)) - : LocationInfo.Empty; + public LocationInfo LocationInfo { + get { + var ast = Module?.Analysis.Ast; + if (ast != null && !string.IsNullOrEmpty(Module.FilePath) && Module.Uri != null) { + return new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(ast)); + } + return LocationInfo.Empty; + } + } public bool IsValid => Module != null; From 0607ab40bc7b998c3d4058ac254c60bc6984957d Mon Sep 17 00:00:00 2001 From: MikhailArkhipov <mikhaila@microsoft.com> Date: Wed, 1 May 2019 09:52:50 -0700 Subject: [PATCH 11/11] Null check --- src/Analysis/Ast/Impl/Types/Location.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Ast/Impl/Types/Location.cs b/src/Analysis/Ast/Impl/Types/Location.cs index db4d0d442..8cc2540bf 100644 --- a/src/Analysis/Ast/Impl/Types/Location.cs +++ b/src/Analysis/Ast/Impl/Types/Location.cs @@ -31,7 +31,7 @@ public Location(IPythonModule module, IndexSpan indexSpan) { public LocationInfo LocationInfo { get { var ast = Module?.Analysis.Ast; - if (ast != null && !string.IsNullOrEmpty(Module.FilePath) && Module.Uri != null) { + if (ast != null && !string.IsNullOrEmpty(Module?.FilePath) && Module?.Uri != null) { return new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(ast)); } return LocationInfo.Empty;