From 821e0c5789cc75e6f53fabc76a9a5df8f088d19e Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 09:42:45 -0700 Subject: [PATCH 1/7] Remove deque & limit analysis passes --- src/Analysis/Engine/Impl/AnalysisLog.cs | 7 +- src/Analysis/Engine/Impl/AnalysisUnit.cs | 12 +- src/Analysis/Engine/Impl/Analyzer/DDG.cs | 13 +- .../Engine/Impl/Analyzer/DependentKeyValue.cs | 15 +- src/Analysis/Engine/Impl/Deque.cs | 378 ------------------ src/Analysis/Engine/Impl/ModuleAnalysis.cs | 9 +- src/Analysis/Engine/Impl/PythonAnalyzer.cs | 28 +- .../Impl/Implementation/Server.cs | 3 +- 8 files changed, 34 insertions(+), 431 deletions(-) delete mode 100644 src/Analysis/Engine/Impl/Deque.cs diff --git a/src/Analysis/Engine/Impl/AnalysisLog.cs b/src/Analysis/Engine/Impl/AnalysisLog.cs index 7e0a0a067..b5ed3cc92 100644 --- a/src/Analysis/Engine/Impl/AnalysisLog.cs +++ b/src/Analysis/Engine/Impl/AnalysisLog.cs @@ -15,6 +15,7 @@ // permissions and limitations under the License. using System; +using System.Collections.Generic; using Microsoft.PythonTools.Analysis.Values; namespace Microsoft.PythonTools.Analysis { @@ -76,13 +77,13 @@ public static void Reset() { LastDisplayedTime = null; } - public static void Enqueue(Deque deque, AnalysisUnit unit) { + public static void Enqueue(Queue deque, AnalysisUnit unit) { if (Active) { Add("E", IdDispenser.GetId(unit), deque.Count); } } - public static void Dequeue(Deque deque, AnalysisUnit unit) { + public static void Dequeue(Queue deque, AnalysisUnit unit) { if (Active) { Add("D", IdDispenser.GetId(unit), deque.Count); } @@ -108,7 +109,7 @@ public static void ExceedsTypeLimit(string variableDefType, int total, string co Add("X", variableDefType, total, contents); } - public static void Cancelled(Deque queue) { + public static void Cancelled(Queue queue) { Add("Cancel", queue.Count); } diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 4751d5131..24ee5939e 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -109,7 +109,7 @@ public AnalysisUnit CopyForEval() { } internal void Enqueue() { - if (!ForEval && !IsInQueue && !_suppressEnqueue) { + if (!ForEval && !IsInQueue && !_suppressEnqueue && NeedsAnalysis()) { State.Queue.Append(this); AnalysisLog.Enqueue(State.Queue, this); IsInQueue = true; @@ -120,6 +120,10 @@ internal void Enqueue() { } } + private bool NeedsAnalysis() + => _analysisCount == 0 || _scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes); + + /// /// The AST which will be analyzed when this node is analyzed /// @@ -361,8 +365,7 @@ public ClassAnalysisUnit(ClassDefinition node, InterpreterScope declScope, Analy public new ClassDefinition Ast => (ClassDefinition)base.Ast; internal override void AnalyzeWorker(DDG ddg, CancellationToken cancel) { - InterpreterScope scope; - if (!ddg.Scope.TryGetNodeScope(Ast, out scope)) { + if (!ddg.Scope.TryGetNodeScope(Ast, out var scope)) { return; } @@ -418,8 +421,7 @@ private IAnalysisSet ProcessClassDecorators(DDG ddg, ClassInfo classInfo) { foreach (var d in Ast.Decorators.Decorators.ExcludeDefault()) { var decorator = ddg._eval.Evaluate(d); - Expression nextExpr; - if (!_decoratorCalls.TryGetValue(d, out nextExpr)) { + if (!_decoratorCalls.TryGetValue(d, out var nextExpr)) { nextExpr = _decoratorCalls[d] = new CallExpression(d, new[] { new Arg(expr) }); nextExpr.SetLoc(d.IndexSpan); } diff --git a/src/Analysis/Engine/Impl/Analyzer/DDG.cs b/src/Analysis/Engine/Impl/Analyzer/DDG.cs index ed840aa19..1cda6be21 100644 --- a/src/Analysis/Engine/Impl/Analyzer/DDG.cs +++ b/src/Analysis/Engine/Impl/Analyzer/DDG.cs @@ -30,7 +30,7 @@ internal class DDG : PythonWalker { private SuiteStatement _curSuite; public readonly HashSet AnalyzedEntries = new HashSet(); - public void Analyze(Deque queue, CancellationToken cancel, Action reportQueueSize = null, int reportQueueInterval = 1) { + public void Analyze(Queue queue, CancellationToken cancel, Action reportQueueSize = null, int reportQueueInterval = 1) { if (cancel.IsCancellationRequested) { return; } @@ -46,7 +46,7 @@ public void Analyze(Deque queue, CancellationToken cancel, Action< } while (queue.Count > 0 && !cancel.IsCancellationRequested) { - _unit = queue.PopLeft(); + _unit = queue.Dequeue(); if (_unit == endOfQueueMarker) { AnalysisLog.EndOfQueue(queueCountAtStart, queue.Count); @@ -107,10 +107,9 @@ public InterpreterScope Scope { public PythonAnalyzer ProjectState => _unit.State; public override bool Walk(PythonAst node) { - ModuleReference existingRef; Debug.Assert(node == _unit.Ast); - if (!ProjectState.Modules.TryImport(_unit.DeclaringModule.Name, out existingRef)) { + if (!ProjectState.Modules.TryImport(_unit.DeclaringModule.Name, out var existingRef)) { // publish our module ref now so that we don't collect dependencies as we'll be fully processed if (existingRef == null) { ProjectState.Modules[_unit.DeclaringModule.Name] = new ModuleReference(_unit.DeclaringModule, _unit.DeclaringModule.Name); @@ -471,8 +470,7 @@ internal List LookupBaseMethods(string name, IEnumerable projectState.Limits.DictValueTypes) { @@ -163,8 +161,7 @@ public Dictionary KeyValueTypes { } } else { foreach (var keyValue in mod.KeyValues) { - IAnalysisSet existing; - if (!res.TryGetValue(keyValue.Key, out existing)) { + if (!res.TryGetValue(keyValue.Key, out var existing)) { res[keyValue.Key] = keyValue.Value; } else { res[keyValue.Key] = existing.Union(keyValue.Value, canMutate: false); @@ -194,13 +191,11 @@ internal bool CopyFrom(DependentKeyValue dependentKeyValue, bool enqueue = true) } foreach (var keyValue in otherDependency.Value.KeyValues) { - IAnalysisSet union; - if (!deps.KeyValues.TryGetValue(keyValue.Key, out union)) { + if (!deps.KeyValues.TryGetValue(keyValue.Key, out var union)) { deps.KeyValues[keyValue.Key] = union = keyValue.Value; anyAdded = true; } else { - bool added; - deps.KeyValues[keyValue.Key] = union.Union(keyValue.Value, out added, canMutate: false); + deps.KeyValues[keyValue.Key] = union.Union(keyValue.Value, out var added, canMutate: false); anyAdded |= added; } } diff --git a/src/Analysis/Engine/Impl/Deque.cs b/src/Analysis/Engine/Impl/Deque.cs deleted file mode 100644 index a9ac7e037..000000000 --- a/src/Analysis/Engine/Impl/Deque.cs +++ /dev/null @@ -1,378 +0,0 @@ -// Python Tools for Visual Studio -// Copyright(c) Microsoft Corporation -// All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the License); you may not use -// this file except in compliance with the License. You may obtain a copy of the -// License at http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS -// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY -// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -// MERCHANTABLITY OR NON-INFRINGEMENT. -// -// See the Apache Version 2.0 License for specific language governing -// permissions and limitations under the License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using Microsoft.PythonTools.Intellisense; - -namespace Microsoft.PythonTools.Analysis { - class Deque : IEnumerable, ICollection { - private T[] _data; - private int _head, _tail; - private int _itemCnt, _version; - private static IEqualityComparer _comparer = EqualityComparer.Default; - - public Deque() { -#if DEBUG - _scope = AnalysisQueue.Current; -#endif - Clear(); - } - -#if DEBUG - private readonly AnalysisQueue _scope; - private void AssertScope() { - Debug.Assert(_scope == AnalysisQueue.Current); - } -#else - [Conditional("DEBUG")] - private void AssertScope() { } -#endif - - - #region core deque APIs - - public void Append(T x) { - AssertScope(); - - _version++; - - if (_itemCnt == _data.Length) { - GrowArray(); - } - - _itemCnt++; - _data[_tail++] = x; - if (_tail == _data.Length) { - _tail = 0; - } - } - - public void AppendLeft(T x) { - AssertScope(); - - _version++; - - if (_itemCnt == _data.Length) { - GrowArray(); - } - - _itemCnt++; - --_head; - if (_head < 0) { - _head = _data.Length - 1; - } - - _data[_head] = x; - } - - public void Clear() { - _version++; - - _head = _tail = 0; - _itemCnt = 0; - _data = new T[8]; - } - - public T Pop() { - AssertScope(); - - if (_itemCnt == 0) { - throw new InvalidOperationException("pop from an empty deque"); - } - - _version++; - if (_tail != 0) { - _tail--; - } else { - _tail = _data.Length - 1; - } - _itemCnt--; - - T res = _data[_tail]; - _data[_tail] = default(T); - return res; - } - - public T PopLeft() { - AssertScope(); - - if (_itemCnt == 0) { - throw new InvalidOperationException("pop from an empty deque"); - } - - _version++; - T res = _data[_head]; - _data[_head] = default(T); - - if (_head != _data.Length - 1) { - _head++; - } else { - _head = 0; - } - _itemCnt--; - return res; - } - - public void Remove(T value) { - AssertScope(); - - int found = -1; - int startVersion = _version; - WalkDeque(delegate(int index) { - if (_comparer.Equals(_data[index], value)) { - found = index; - return false; - } - return true; - }); - if (_version != startVersion) { - throw new InvalidOperationException("deque mutated during remove()."); - } - - if (found == _head) { - PopLeft(); - } else if (found == (_tail > 0 ? _tail - 1 : _data.Length - 1)) { - Pop(); - } else if (found == -1) { - throw new ArgumentException("deque.remove(value): value not in deque"); - } else { - // otherwise we're removing from the middle and need to slide the values over... - _version++; - - int start; - if (_head >= _tail) { - start = 0; - } else { - start = _head; - } - - bool finished = false; - T copying = _tail != 0 ? _data[_tail - 1] : _data[_data.Length - 1]; - for (int i = _tail - 2; i >= start; i--) { - T tmp = _data[i]; - _data[i] = copying; - if (i == found) { - finished = true; - break; - } - copying = tmp; - } - if (_head >= _tail && !finished) { - for (int i = _data.Length - 1; i >= _head; i--) { - T tmp = _data[i]; - _data[i] = copying; - if (i == found) break; - copying = tmp; - } - } - - // we're one smaller now - _tail--; - _itemCnt--; - if (_tail < 0) { - // and tail just wrapped to the beginning - _tail = _data.Length - 1; - } - } - - } - - public T this[int index] { - get { - - return _data[IndexToSlot(index)]; - } - set { - _version++; - _data[IndexToSlot(index)] = value; - } - } - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() { - return new DequeIterator(this); - } - - private sealed class DequeIterator : IEnumerable, IEnumerator { - private readonly Deque _deque; - private int _curIndex, _moveCnt, _version; - - public DequeIterator(Deque d) { - _deque = d; - _curIndex = d._head - 1; - _version = d._version; - } - - #region IEnumerator Members - - object IEnumerator.Current { - get { - return _deque._data[_curIndex]; - } - } - - bool IEnumerator.MoveNext() { - - if (_version != _deque._version) { - throw new InvalidOperationException("deque mutated during iteration"); - } - - if (_moveCnt < _deque._itemCnt) { - _curIndex++; - _moveCnt++; - if (_curIndex == _deque._data.Length) { - _curIndex = 0; - } - return true; - } - return false; - - } - - void IEnumerator.Reset() { - _moveCnt = 0; - _curIndex = _deque._head - 1; - } - - #endregion - - #region IEnumerable Members - - public IEnumerator GetEnumerator() { - return this; - } - - #endregion - } - - #endregion - - - #region private members - - private void GrowArray() { - T[] newData = new T[_data.Length * 2]; - - // make the array completely sequential again - // by starting head back at 0. - int cnt1, cnt2; - if (_head >= _tail) { - cnt1 = _data.Length - _head; - cnt2 = _data.Length - cnt1; - } else { - cnt1 = _tail - _head; - cnt2 = _data.Length - cnt1; - } - - Array.Copy(_data, _head, newData, 0, cnt1); - Array.Copy(_data, 0, newData, cnt1, cnt2); - - _head = 0; - _tail = _data.Length; - _data = newData; - } - - private int IndexToSlot(int intIndex) { - if (_itemCnt == 0) { - throw new IndexOutOfRangeException("deque index out of range"); - } - - if (intIndex >= 0) { - if (intIndex >= _itemCnt) { - throw new IndexOutOfRangeException("deque index out of range"); - } - - int realIndex = _head + intIndex; - if (realIndex >= _data.Length) { - realIndex -= _data.Length; - } - - return realIndex; - } else { - if ((intIndex * -1) > _itemCnt) { - throw new IndexOutOfRangeException("deque index out of range"); - } - - int realIndex = _tail + intIndex; - if (realIndex < 0) { - realIndex += _data.Length; - } - - return realIndex; - } - } - - private delegate bool DequeWalker(int curIndex); - - /// - /// Walks the queue calling back to the specified delegate for - /// each populated index in the queue. - /// - private void WalkDeque(DequeWalker walker) { - if (_itemCnt != 0) { - int end; - if (_head >= _tail) { - end = _data.Length; - } else { - end = _tail; - } - - for (int i = _head; i < end; i++) { - if (!walker(i)) { - return; - } - } - if (_head >= _tail) { - for (int i = 0; i < _tail; i++) { - if (!walker(i)) { - return; - } - } - } - } - } - - #endregion - - #region ICollection Members - - void ICollection.CopyTo(Array array, int index) { - int i = 0; - foreach (object o in this) { - array.SetValue(o, index + i++); - } - } - - public int Count { - get { return this._itemCnt; } - } - - bool ICollection.IsSynchronized { - get { return false; } - } - - object ICollection.SyncRoot { - get { return this; } - } - - #endregion - } -} diff --git a/src/Analysis/Engine/Impl/ModuleAnalysis.cs b/src/Analysis/Engine/Impl/ModuleAnalysis.cs index 0719bb350..c5b17644b 100644 --- a/src/Analysis/Engine/Impl/ModuleAnalysis.cs +++ b/src/Analysis/Engine/Impl/ModuleAnalysis.cs @@ -483,10 +483,9 @@ ce.Args[0].Expression is ConstantExpression modNameExpr } private static IAnalysisSet ResolveModule(Node node, AnalysisUnit unit, string moduleName) { - ModuleReference modRef; var modules = unit.State.Modules; - if (modules.TryImport(moduleName, out modRef)) { + if (modules.TryImport(moduleName, out var modRef)) { modRef.Module?.Imported(unit); return modRef.AnalysisModule ?? AnalysisSet.Empty; } @@ -948,9 +947,8 @@ GetMemberOptions options // update memberDict foreach (var name in adding) { - IEnumerable values; List valueList; - if (!memberDict.TryGetValue(name, out values)) { + if (!memberDict.TryGetValue(name, out var values)) { memberDict[name] = values = new List(); } if ((valueList = values as List) == null) { @@ -1169,8 +1167,7 @@ private static IEnumerable MemberDictToResultList( var name = GetMemberName(privatePrefix, options, kvp.Key); var completion = name; if (name != null) { - IEnumerable owners; - if (ownerDict != null && ownerDict.TryGetValue(kvp.Key, out owners) && + if (ownerDict != null && ownerDict.TryGetValue(kvp.Key, out var owners) && owners.Any() && owners.Count() < maximumOwners) { // This member came from less than the full set of types. var seenNames = new HashSet(); diff --git a/src/Analysis/Engine/Impl/PythonAnalyzer.cs b/src/Analysis/Engine/Impl/PythonAnalyzer.cs index f1e328edd..020a513e6 100644 --- a/src/Analysis/Engine/Impl/PythonAnalyzer.cs +++ b/src/Analysis/Engine/Impl/PythonAnalyzer.cs @@ -123,8 +123,6 @@ internal PythonAnalyzer(IPythonInterpreterFactory factory, IPythonInterpreter py Limits = AnalysisLimits.GetDefaultLimits(); - Queue = new Deque(); - _defaultContext = _interpreter.CreateModuleContext(); _evalUnit = new AnalysisUnit(null, null, new ModuleInfo("$global", new ProjectEntry(this, "$global", String.Empty, null, null), _defaultContext).Scope, true); @@ -222,8 +220,7 @@ public IPythonProjectEntry AddModule(string moduleName, string filePath, Uri doc /// /// New in 2.1 public void AddModuleAlias(string moduleName, string moduleAlias) { - ModuleReference modRef; - if (Modules.TryImport(moduleName, out modRef)) { + if (Modules.TryImport(moduleName, out var modRef)) { Modules[moduleAlias] = modRef; } } @@ -280,9 +277,8 @@ public void RemoveModule(IProjectEntry entry, Action onImpo /// '__init__'. /// public IEnumerable GetEntriesThatImportModule(string moduleName, bool includeUnresolved) { - ModuleReference modRef; var entries = new List(); - if (_modules.TryImport(moduleName, out modRef) && modRef.HasReferences) { + if (_modules.TryImport(moduleName, out var modRef) && modRef.HasReferences) { entries.AddRange(modRef.References.Select(m => m.ProjectEntry).OfType()); } @@ -366,8 +362,7 @@ public IMemberResult[] GetModules() { } if (moduleRef.IsValid) { - List l; - if (!d.TryGetValue(modName, out l)) { + if (!d.TryGetValue(modName, out var l)) { d[modName] = l = new List(); } if (moduleRef.HasModule) { @@ -530,8 +525,7 @@ private static bool GetPackageNameIfMatch(string name, string fullName, out stri /// /// public IMemberResult[] GetModuleMembers(IModuleContext moduleContext, string[] names, bool includeMembers = false) { - ModuleReference moduleRef; - if (Modules.TryImport(names[0], out moduleRef)) { + if (Modules.TryImport(names[0], out var moduleRef)) { var module = moduleRef.Module as IModule; if (module != null) { return GetModuleMembers(moduleContext, names, includeMembers, module); @@ -697,7 +691,7 @@ internal IKnownClasses ClassInfos { } } - internal Deque Queue { get; } + internal Queue Queue { get; } = new Queue(); /// /// Returns the cached value for the provided key, creating it with @@ -708,8 +702,7 @@ internal IKnownClasses ClassInfos { /// Function to create the value. /// The cached value or null. internal AnalysisValue GetCached(object key, Func maker) { - AnalysisValue result; - if (!_itemCache.TryGetValue(key, out result)) { + if (!_itemCache.TryGetValue(key, out var result)) { // Set the key to prevent recursion _itemCache[key] = null; _itemCache[key] = result = maker(); @@ -815,8 +808,7 @@ internal IDictionary GetAllMembers(IMemberContainer contai var children = (container as IModule)?.GetChildrenPackages(moduleContext); if (children?.Any() ?? false) { foreach (var child in children) { - IAnalysisSet existing; - if (result.TryGetValue(child.Key, out existing)) { + if (result.TryGetValue(child.Key, out var existing)) { result[child.Key] = existing.Add(child.Value); } else { result[child.Key] = child.Value; @@ -832,8 +824,7 @@ internal IDictionary GetAllMembers(IMemberContainer contai internal ConcurrentDictionary ModulesByFilename => _modulesByFilename; public bool TryGetProjectEntryByPath(string path, out IProjectEntry projEntry) { - ModuleInfo modInfo; - if (_modulesByFilename.TryGetValue(path, out modInfo)) { + if (_modulesByFilename.TryGetValue(path, out var modInfo)) { projEntry = modInfo.ProjectEntry; return true; } @@ -1038,8 +1029,7 @@ internal void ClearAggregate(AggregateProjectEntry entry) { } private AggregateProjectEntry GetAggregateWorker(IProjectEntry[] all) { - AggregateProjectEntry agg; - if (!_aggregates.TryGetValue(all, out agg)) { + if (!_aggregates.TryGetValue(all, out var agg)) { _aggregates[all] = agg = new AggregateProjectEntry(new HashSet(all)); foreach (var proj in all) { diff --git a/src/LanguageServer/Impl/Implementation/Server.cs b/src/LanguageServer/Impl/Implementation/Server.cs index fe041a71c..4145e552d 100644 --- a/src/LanguageServer/Impl/Implementation/Server.cs +++ b/src/LanguageServer/Impl/Implementation/Server.cs @@ -579,9 +579,8 @@ private void RemoveDocumentParseCounter(Task t, IDocument doc, VolatileCounter c } private IDisposable GetDocumentParseCounter(IDocument doc, out int count) { - VolatileCounter counter; lock (_pendingParse) { - if (!_pendingParse.TryGetValue(doc, out counter)) { + if (!_pendingParse.TryGetValue(doc, out var counter)) { _pendingParse[doc] = counter = new VolatileCounter(); // Automatically remove counter from the dictionary when it reaches zero. counter.WaitForChangeToZeroAsync().ContinueWith(t => RemoveDocumentParseCounter(t, doc, counter)); From 7bff3f711fa8ba2888fab5b255e682dca977e971 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 09:46:21 -0700 Subject: [PATCH 2/7] Brackets --- src/Analysis/Engine/Impl/AnalysisUnit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 24ee5939e..2d89e9ead 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -121,7 +121,7 @@ internal void Enqueue() { } private bool NeedsAnalysis() - => _analysisCount == 0 || _scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes); + => _analysisCount == 0 || (_scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes)); /// From 3c3a68ad43094b17160262ab773c0d2cdb54001c Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 10:06:45 -0700 Subject: [PATCH 3/7] Revert "Brackets" This reverts commit 7bff3f711fa8ba2888fab5b255e682dca977e971. --- src/Analysis/Engine/Impl/AnalysisUnit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 2d89e9ead..24ee5939e 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -121,7 +121,7 @@ internal void Enqueue() { } private bool NeedsAnalysis() - => _analysisCount == 0 || (_scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes)); + => _analysisCount == 0 || _scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes); /// From 59a3ca953275413020f8d8ed24673323ec35977a Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 10:06:53 -0700 Subject: [PATCH 4/7] Revert "Remove deque & limit analysis passes" This reverts commit 821e0c5789cc75e6f53fabc76a9a5df8f088d19e. --- src/Analysis/Engine/Impl/AnalysisLog.cs | 7 +- src/Analysis/Engine/Impl/AnalysisUnit.cs | 12 +- src/Analysis/Engine/Impl/Analyzer/DDG.cs | 13 +- .../Engine/Impl/Analyzer/DependentKeyValue.cs | 15 +- src/Analysis/Engine/Impl/Deque.cs | 378 ++++++++++++++++++ src/Analysis/Engine/Impl/ModuleAnalysis.cs | 9 +- src/Analysis/Engine/Impl/PythonAnalyzer.cs | 28 +- .../Impl/Implementation/Server.cs | 3 +- 8 files changed, 431 insertions(+), 34 deletions(-) create mode 100644 src/Analysis/Engine/Impl/Deque.cs diff --git a/src/Analysis/Engine/Impl/AnalysisLog.cs b/src/Analysis/Engine/Impl/AnalysisLog.cs index b5ed3cc92..7e0a0a067 100644 --- a/src/Analysis/Engine/Impl/AnalysisLog.cs +++ b/src/Analysis/Engine/Impl/AnalysisLog.cs @@ -15,7 +15,6 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; using Microsoft.PythonTools.Analysis.Values; namespace Microsoft.PythonTools.Analysis { @@ -77,13 +76,13 @@ public static void Reset() { LastDisplayedTime = null; } - public static void Enqueue(Queue deque, AnalysisUnit unit) { + public static void Enqueue(Deque deque, AnalysisUnit unit) { if (Active) { Add("E", IdDispenser.GetId(unit), deque.Count); } } - public static void Dequeue(Queue deque, AnalysisUnit unit) { + public static void Dequeue(Deque deque, AnalysisUnit unit) { if (Active) { Add("D", IdDispenser.GetId(unit), deque.Count); } @@ -109,7 +108,7 @@ public static void ExceedsTypeLimit(string variableDefType, int total, string co Add("X", variableDefType, total, contents); } - public static void Cancelled(Queue queue) { + public static void Cancelled(Deque queue) { Add("Cancel", queue.Count); } diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 24ee5939e..4751d5131 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -109,7 +109,7 @@ public AnalysisUnit CopyForEval() { } internal void Enqueue() { - if (!ForEval && !IsInQueue && !_suppressEnqueue && NeedsAnalysis()) { + if (!ForEval && !IsInQueue && !_suppressEnqueue) { State.Queue.Append(this); AnalysisLog.Enqueue(State.Queue, this); IsInQueue = true; @@ -120,10 +120,6 @@ internal void Enqueue() { } } - private bool NeedsAnalysis() - => _analysisCount == 0 || _scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes); - - /// /// The AST which will be analyzed when this node is analyzed /// @@ -365,7 +361,8 @@ public ClassAnalysisUnit(ClassDefinition node, InterpreterScope declScope, Analy public new ClassDefinition Ast => (ClassDefinition)base.Ast; internal override void AnalyzeWorker(DDG ddg, CancellationToken cancel) { - if (!ddg.Scope.TryGetNodeScope(Ast, out var scope)) { + InterpreterScope scope; + if (!ddg.Scope.TryGetNodeScope(Ast, out scope)) { return; } @@ -421,7 +418,8 @@ private IAnalysisSet ProcessClassDecorators(DDG ddg, ClassInfo classInfo) { foreach (var d in Ast.Decorators.Decorators.ExcludeDefault()) { var decorator = ddg._eval.Evaluate(d); - if (!_decoratorCalls.TryGetValue(d, out var nextExpr)) { + Expression nextExpr; + if (!_decoratorCalls.TryGetValue(d, out nextExpr)) { nextExpr = _decoratorCalls[d] = new CallExpression(d, new[] { new Arg(expr) }); nextExpr.SetLoc(d.IndexSpan); } diff --git a/src/Analysis/Engine/Impl/Analyzer/DDG.cs b/src/Analysis/Engine/Impl/Analyzer/DDG.cs index 1cda6be21..ed840aa19 100644 --- a/src/Analysis/Engine/Impl/Analyzer/DDG.cs +++ b/src/Analysis/Engine/Impl/Analyzer/DDG.cs @@ -30,7 +30,7 @@ internal class DDG : PythonWalker { private SuiteStatement _curSuite; public readonly HashSet AnalyzedEntries = new HashSet(); - public void Analyze(Queue queue, CancellationToken cancel, Action reportQueueSize = null, int reportQueueInterval = 1) { + public void Analyze(Deque queue, CancellationToken cancel, Action reportQueueSize = null, int reportQueueInterval = 1) { if (cancel.IsCancellationRequested) { return; } @@ -46,7 +46,7 @@ public void Analyze(Queue queue, CancellationToken cancel, Action< } while (queue.Count > 0 && !cancel.IsCancellationRequested) { - _unit = queue.Dequeue(); + _unit = queue.PopLeft(); if (_unit == endOfQueueMarker) { AnalysisLog.EndOfQueue(queueCountAtStart, queue.Count); @@ -107,9 +107,10 @@ public InterpreterScope Scope { public PythonAnalyzer ProjectState => _unit.State; public override bool Walk(PythonAst node) { + ModuleReference existingRef; Debug.Assert(node == _unit.Ast); - if (!ProjectState.Modules.TryImport(_unit.DeclaringModule.Name, out var existingRef)) { + if (!ProjectState.Modules.TryImport(_unit.DeclaringModule.Name, out existingRef)) { // publish our module ref now so that we don't collect dependencies as we'll be fully processed if (existingRef == null) { ProjectState.Modules[_unit.DeclaringModule.Name] = new ModuleReference(_unit.DeclaringModule, _unit.DeclaringModule.Name); @@ -470,7 +471,8 @@ internal List LookupBaseMethods(string name, IEnumerable projectState.Limits.DictValueTypes) { @@ -161,7 +163,8 @@ public Dictionary KeyValueTypes { } } else { foreach (var keyValue in mod.KeyValues) { - if (!res.TryGetValue(keyValue.Key, out var existing)) { + IAnalysisSet existing; + if (!res.TryGetValue(keyValue.Key, out existing)) { res[keyValue.Key] = keyValue.Value; } else { res[keyValue.Key] = existing.Union(keyValue.Value, canMutate: false); @@ -191,11 +194,13 @@ internal bool CopyFrom(DependentKeyValue dependentKeyValue, bool enqueue = true) } foreach (var keyValue in otherDependency.Value.KeyValues) { - if (!deps.KeyValues.TryGetValue(keyValue.Key, out var union)) { + IAnalysisSet union; + if (!deps.KeyValues.TryGetValue(keyValue.Key, out union)) { deps.KeyValues[keyValue.Key] = union = keyValue.Value; anyAdded = true; } else { - deps.KeyValues[keyValue.Key] = union.Union(keyValue.Value, out var added, canMutate: false); + bool added; + deps.KeyValues[keyValue.Key] = union.Union(keyValue.Value, out added, canMutate: false); anyAdded |= added; } } diff --git a/src/Analysis/Engine/Impl/Deque.cs b/src/Analysis/Engine/Impl/Deque.cs new file mode 100644 index 000000000..a9ac7e037 --- /dev/null +++ b/src/Analysis/Engine/Impl/Deque.cs @@ -0,0 +1,378 @@ +// Python Tools for Visual Studio +// Copyright(c) Microsoft Corporation +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABLITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.PythonTools.Intellisense; + +namespace Microsoft.PythonTools.Analysis { + class Deque : IEnumerable, ICollection { + private T[] _data; + private int _head, _tail; + private int _itemCnt, _version; + private static IEqualityComparer _comparer = EqualityComparer.Default; + + public Deque() { +#if DEBUG + _scope = AnalysisQueue.Current; +#endif + Clear(); + } + +#if DEBUG + private readonly AnalysisQueue _scope; + private void AssertScope() { + Debug.Assert(_scope == AnalysisQueue.Current); + } +#else + [Conditional("DEBUG")] + private void AssertScope() { } +#endif + + + #region core deque APIs + + public void Append(T x) { + AssertScope(); + + _version++; + + if (_itemCnt == _data.Length) { + GrowArray(); + } + + _itemCnt++; + _data[_tail++] = x; + if (_tail == _data.Length) { + _tail = 0; + } + } + + public void AppendLeft(T x) { + AssertScope(); + + _version++; + + if (_itemCnt == _data.Length) { + GrowArray(); + } + + _itemCnt++; + --_head; + if (_head < 0) { + _head = _data.Length - 1; + } + + _data[_head] = x; + } + + public void Clear() { + _version++; + + _head = _tail = 0; + _itemCnt = 0; + _data = new T[8]; + } + + public T Pop() { + AssertScope(); + + if (_itemCnt == 0) { + throw new InvalidOperationException("pop from an empty deque"); + } + + _version++; + if (_tail != 0) { + _tail--; + } else { + _tail = _data.Length - 1; + } + _itemCnt--; + + T res = _data[_tail]; + _data[_tail] = default(T); + return res; + } + + public T PopLeft() { + AssertScope(); + + if (_itemCnt == 0) { + throw new InvalidOperationException("pop from an empty deque"); + } + + _version++; + T res = _data[_head]; + _data[_head] = default(T); + + if (_head != _data.Length - 1) { + _head++; + } else { + _head = 0; + } + _itemCnt--; + return res; + } + + public void Remove(T value) { + AssertScope(); + + int found = -1; + int startVersion = _version; + WalkDeque(delegate(int index) { + if (_comparer.Equals(_data[index], value)) { + found = index; + return false; + } + return true; + }); + if (_version != startVersion) { + throw new InvalidOperationException("deque mutated during remove()."); + } + + if (found == _head) { + PopLeft(); + } else if (found == (_tail > 0 ? _tail - 1 : _data.Length - 1)) { + Pop(); + } else if (found == -1) { + throw new ArgumentException("deque.remove(value): value not in deque"); + } else { + // otherwise we're removing from the middle and need to slide the values over... + _version++; + + int start; + if (_head >= _tail) { + start = 0; + } else { + start = _head; + } + + bool finished = false; + T copying = _tail != 0 ? _data[_tail - 1] : _data[_data.Length - 1]; + for (int i = _tail - 2; i >= start; i--) { + T tmp = _data[i]; + _data[i] = copying; + if (i == found) { + finished = true; + break; + } + copying = tmp; + } + if (_head >= _tail && !finished) { + for (int i = _data.Length - 1; i >= _head; i--) { + T tmp = _data[i]; + _data[i] = copying; + if (i == found) break; + copying = tmp; + } + } + + // we're one smaller now + _tail--; + _itemCnt--; + if (_tail < 0) { + // and tail just wrapped to the beginning + _tail = _data.Length - 1; + } + } + + } + + public T this[int index] { + get { + + return _data[IndexToSlot(index)]; + } + set { + _version++; + _data[IndexToSlot(index)] = value; + } + } + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() { + return new DequeIterator(this); + } + + private sealed class DequeIterator : IEnumerable, IEnumerator { + private readonly Deque _deque; + private int _curIndex, _moveCnt, _version; + + public DequeIterator(Deque d) { + _deque = d; + _curIndex = d._head - 1; + _version = d._version; + } + + #region IEnumerator Members + + object IEnumerator.Current { + get { + return _deque._data[_curIndex]; + } + } + + bool IEnumerator.MoveNext() { + + if (_version != _deque._version) { + throw new InvalidOperationException("deque mutated during iteration"); + } + + if (_moveCnt < _deque._itemCnt) { + _curIndex++; + _moveCnt++; + if (_curIndex == _deque._data.Length) { + _curIndex = 0; + } + return true; + } + return false; + + } + + void IEnumerator.Reset() { + _moveCnt = 0; + _curIndex = _deque._head - 1; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() { + return this; + } + + #endregion + } + + #endregion + + + #region private members + + private void GrowArray() { + T[] newData = new T[_data.Length * 2]; + + // make the array completely sequential again + // by starting head back at 0. + int cnt1, cnt2; + if (_head >= _tail) { + cnt1 = _data.Length - _head; + cnt2 = _data.Length - cnt1; + } else { + cnt1 = _tail - _head; + cnt2 = _data.Length - cnt1; + } + + Array.Copy(_data, _head, newData, 0, cnt1); + Array.Copy(_data, 0, newData, cnt1, cnt2); + + _head = 0; + _tail = _data.Length; + _data = newData; + } + + private int IndexToSlot(int intIndex) { + if (_itemCnt == 0) { + throw new IndexOutOfRangeException("deque index out of range"); + } + + if (intIndex >= 0) { + if (intIndex >= _itemCnt) { + throw new IndexOutOfRangeException("deque index out of range"); + } + + int realIndex = _head + intIndex; + if (realIndex >= _data.Length) { + realIndex -= _data.Length; + } + + return realIndex; + } else { + if ((intIndex * -1) > _itemCnt) { + throw new IndexOutOfRangeException("deque index out of range"); + } + + int realIndex = _tail + intIndex; + if (realIndex < 0) { + realIndex += _data.Length; + } + + return realIndex; + } + } + + private delegate bool DequeWalker(int curIndex); + + /// + /// Walks the queue calling back to the specified delegate for + /// each populated index in the queue. + /// + private void WalkDeque(DequeWalker walker) { + if (_itemCnt != 0) { + int end; + if (_head >= _tail) { + end = _data.Length; + } else { + end = _tail; + } + + for (int i = _head; i < end; i++) { + if (!walker(i)) { + return; + } + } + if (_head >= _tail) { + for (int i = 0; i < _tail; i++) { + if (!walker(i)) { + return; + } + } + } + } + } + + #endregion + + #region ICollection Members + + void ICollection.CopyTo(Array array, int index) { + int i = 0; + foreach (object o in this) { + array.SetValue(o, index + i++); + } + } + + public int Count { + get { return this._itemCnt; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + #endregion + } +} diff --git a/src/Analysis/Engine/Impl/ModuleAnalysis.cs b/src/Analysis/Engine/Impl/ModuleAnalysis.cs index c5b17644b..0719bb350 100644 --- a/src/Analysis/Engine/Impl/ModuleAnalysis.cs +++ b/src/Analysis/Engine/Impl/ModuleAnalysis.cs @@ -483,9 +483,10 @@ ce.Args[0].Expression is ConstantExpression modNameExpr } private static IAnalysisSet ResolveModule(Node node, AnalysisUnit unit, string moduleName) { + ModuleReference modRef; var modules = unit.State.Modules; - if (modules.TryImport(moduleName, out var modRef)) { + if (modules.TryImport(moduleName, out modRef)) { modRef.Module?.Imported(unit); return modRef.AnalysisModule ?? AnalysisSet.Empty; } @@ -947,8 +948,9 @@ GetMemberOptions options // update memberDict foreach (var name in adding) { + IEnumerable values; List valueList; - if (!memberDict.TryGetValue(name, out var values)) { + if (!memberDict.TryGetValue(name, out values)) { memberDict[name] = values = new List(); } if ((valueList = values as List) == null) { @@ -1167,7 +1169,8 @@ private static IEnumerable MemberDictToResultList( var name = GetMemberName(privatePrefix, options, kvp.Key); var completion = name; if (name != null) { - if (ownerDict != null && ownerDict.TryGetValue(kvp.Key, out var owners) && + IEnumerable owners; + if (ownerDict != null && ownerDict.TryGetValue(kvp.Key, out owners) && owners.Any() && owners.Count() < maximumOwners) { // This member came from less than the full set of types. var seenNames = new HashSet(); diff --git a/src/Analysis/Engine/Impl/PythonAnalyzer.cs b/src/Analysis/Engine/Impl/PythonAnalyzer.cs index 020a513e6..f1e328edd 100644 --- a/src/Analysis/Engine/Impl/PythonAnalyzer.cs +++ b/src/Analysis/Engine/Impl/PythonAnalyzer.cs @@ -123,6 +123,8 @@ internal PythonAnalyzer(IPythonInterpreterFactory factory, IPythonInterpreter py Limits = AnalysisLimits.GetDefaultLimits(); + Queue = new Deque(); + _defaultContext = _interpreter.CreateModuleContext(); _evalUnit = new AnalysisUnit(null, null, new ModuleInfo("$global", new ProjectEntry(this, "$global", String.Empty, null, null), _defaultContext).Scope, true); @@ -220,7 +222,8 @@ public IPythonProjectEntry AddModule(string moduleName, string filePath, Uri doc /// /// New in 2.1 public void AddModuleAlias(string moduleName, string moduleAlias) { - if (Modules.TryImport(moduleName, out var modRef)) { + ModuleReference modRef; + if (Modules.TryImport(moduleName, out modRef)) { Modules[moduleAlias] = modRef; } } @@ -277,8 +280,9 @@ public void RemoveModule(IProjectEntry entry, Action onImpo /// '__init__'. /// public IEnumerable GetEntriesThatImportModule(string moduleName, bool includeUnresolved) { + ModuleReference modRef; var entries = new List(); - if (_modules.TryImport(moduleName, out var modRef) && modRef.HasReferences) { + if (_modules.TryImport(moduleName, out modRef) && modRef.HasReferences) { entries.AddRange(modRef.References.Select(m => m.ProjectEntry).OfType()); } @@ -362,7 +366,8 @@ public IMemberResult[] GetModules() { } if (moduleRef.IsValid) { - if (!d.TryGetValue(modName, out var l)) { + List l; + if (!d.TryGetValue(modName, out l)) { d[modName] = l = new List(); } if (moduleRef.HasModule) { @@ -525,7 +530,8 @@ private static bool GetPackageNameIfMatch(string name, string fullName, out stri /// /// public IMemberResult[] GetModuleMembers(IModuleContext moduleContext, string[] names, bool includeMembers = false) { - if (Modules.TryImport(names[0], out var moduleRef)) { + ModuleReference moduleRef; + if (Modules.TryImport(names[0], out moduleRef)) { var module = moduleRef.Module as IModule; if (module != null) { return GetModuleMembers(moduleContext, names, includeMembers, module); @@ -691,7 +697,7 @@ internal IKnownClasses ClassInfos { } } - internal Queue Queue { get; } = new Queue(); + internal Deque Queue { get; } /// /// Returns the cached value for the provided key, creating it with @@ -702,7 +708,8 @@ internal IKnownClasses ClassInfos { /// Function to create the value. /// The cached value or null. internal AnalysisValue GetCached(object key, Func maker) { - if (!_itemCache.TryGetValue(key, out var result)) { + AnalysisValue result; + if (!_itemCache.TryGetValue(key, out result)) { // Set the key to prevent recursion _itemCache[key] = null; _itemCache[key] = result = maker(); @@ -808,7 +815,8 @@ internal IDictionary GetAllMembers(IMemberContainer contai var children = (container as IModule)?.GetChildrenPackages(moduleContext); if (children?.Any() ?? false) { foreach (var child in children) { - if (result.TryGetValue(child.Key, out var existing)) { + IAnalysisSet existing; + if (result.TryGetValue(child.Key, out existing)) { result[child.Key] = existing.Add(child.Value); } else { result[child.Key] = child.Value; @@ -824,7 +832,8 @@ internal IDictionary GetAllMembers(IMemberContainer contai internal ConcurrentDictionary ModulesByFilename => _modulesByFilename; public bool TryGetProjectEntryByPath(string path, out IProjectEntry projEntry) { - if (_modulesByFilename.TryGetValue(path, out var modInfo)) { + ModuleInfo modInfo; + if (_modulesByFilename.TryGetValue(path, out modInfo)) { projEntry = modInfo.ProjectEntry; return true; } @@ -1029,7 +1038,8 @@ internal void ClearAggregate(AggregateProjectEntry entry) { } private AggregateProjectEntry GetAggregateWorker(IProjectEntry[] all) { - if (!_aggregates.TryGetValue(all, out var agg)) { + AggregateProjectEntry agg; + if (!_aggregates.TryGetValue(all, out agg)) { _aggregates[all] = agg = new AggregateProjectEntry(new HashSet(all)); foreach (var proj in all) { diff --git a/src/LanguageServer/Impl/Implementation/Server.cs b/src/LanguageServer/Impl/Implementation/Server.cs index 4145e552d..fe041a71c 100644 --- a/src/LanguageServer/Impl/Implementation/Server.cs +++ b/src/LanguageServer/Impl/Implementation/Server.cs @@ -579,8 +579,9 @@ private void RemoveDocumentParseCounter(Task t, IDocument doc, VolatileCounter c } private IDisposable GetDocumentParseCounter(IDocument doc, out int count) { + VolatileCounter counter; lock (_pendingParse) { - if (!_pendingParse.TryGetValue(doc, out var counter)) { + if (!_pendingParse.TryGetValue(doc, out counter)) { _pendingParse[doc] = counter = new VolatileCounter(); // Automatically remove counter from the dictionary when it reaches zero. counter.WaitForChangeToZeroAsync().ContinueWith(t => RemoveDocumentParseCounter(t, doc, counter)); From 9f3666a6dfc78e08f70f78cd09cc8a894db03df7 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 10:03:53 -0700 Subject: [PATCH 5/7] Limit analysis --- src/Analysis/Engine/Impl/AnalysisUnit.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 4751d5131..7950c2d4b 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -109,7 +109,7 @@ public AnalysisUnit CopyForEval() { } internal void Enqueue() { - if (!ForEval && !IsInQueue && !_suppressEnqueue) { + if (!ForEval && !IsInQueue && !_suppressEnqueue && NeedsAnalysis()) { State.Queue.Append(this); AnalysisLog.Enqueue(State.Queue, this); IsInQueue = true; @@ -120,6 +120,10 @@ internal void Enqueue() { } } + private bool NeedsAnalysis() + => _analysisCount == 0 || (_scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes)); + + /// /// The AST which will be analyzed when this node is analyzed /// From e9e1a90af33b619234259c39a76399f517287f8b Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 11:14:26 -0700 Subject: [PATCH 6/7] Revert "Limit analysis" This reverts commit 9f3666a6dfc78e08f70f78cd09cc8a894db03df7. --- src/Analysis/Engine/Impl/AnalysisUnit.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Analysis/Engine/Impl/AnalysisUnit.cs b/src/Analysis/Engine/Impl/AnalysisUnit.cs index 7950c2d4b..4751d5131 100644 --- a/src/Analysis/Engine/Impl/AnalysisUnit.cs +++ b/src/Analysis/Engine/Impl/AnalysisUnit.cs @@ -109,7 +109,7 @@ public AnalysisUnit CopyForEval() { } internal void Enqueue() { - if (!ForEval && !IsInQueue && !_suppressEnqueue && NeedsAnalysis()) { + if (!ForEval && !IsInQueue && !_suppressEnqueue) { State.Queue.Append(this); AnalysisLog.Enqueue(State.Queue, this); IsInQueue = true; @@ -120,10 +120,6 @@ internal void Enqueue() { } } - private bool NeedsAnalysis() - => _analysisCount == 0 || (_scope != null && _scope.AllVariables.Select(k => k.Value).Any(v => !v.HasTypes)); - - /// /// The AST which will be analyzed when this node is analyzed /// From 423234f71889d1c0d4d59fea580385641f38dbcb Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 3 Oct 2018 11:15:17 -0700 Subject: [PATCH 7/7] Suppress error --- src/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 25bc515da..d2a6ae077 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -29,7 +29,7 @@ csharp_space_between_parentheses = None csharp_space_after_cast = false -csharp_style_inlined_variable_declaration = true:error +csharp_style_inlined_variable_declaration = true:message csharp_space_before_open_square_brackets = false