Ejemplo n.º 1
0
        private async Task <int> AnalyzeAffectedEntriesAsync(Stopwatch stopWatch)
        {
            IDependencyChainNode <PythonAnalyzerEntry> node;
            var remaining = 0;
            var ace       = new AsyncCountdownEvent(0);

            bool isCanceled;

            while ((node = await _walker.GetNextAsync(_analyzerCancellationToken)) != null)
            {
                lock (_syncObj) {
                    isCanceled = _isCanceled;
                }

                if (isCanceled && !node.Value.NotAnalyzed)
                {
                    remaining++;
                    node.MoveNext();
                    continue;
                }

                ActivityTracker.OnEnqueueModule(node.Value.Module.FilePath);

                if (Interlocked.Increment(ref _runningTasks) >= _maxTaskRunning || _walker.Remaining == 1)
                {
                    RunAnalysis(node, stopWatch);
                }
                else
                {
                    ace.AddOne();
                    StartAnalysis(node, ace, stopWatch).DoNotWait();
                }
            }

            await ace.WaitAsync(_analyzerCancellationToken);

            lock (_syncObj) {
                isCanceled = _isCanceled;
            }

            if (_walker.MissingKeys.Count == 0 || _walker.MissingKeys.All(k => k.IsTypeshed))
            {
                Interlocked.Exchange(ref _runningTasks, 0);

                if (!isCanceled)
                {
                    _analysisCompleteEvent.Set();
                }
            }
            else if (!isCanceled && _log != null && _log.LogLevel >= TraceEventType.Verbose)
            {
                _log?.Log(TraceEventType.Verbose, $"Missing keys: {string.Join(", ", _walker.MissingKeys)}");
            }

            return(remaining);
        }
        /// <summary>
        /// Performs analysis of the document. Returns document global scope
        /// with declared variables and inner scopes. Does not analyze chain
        /// of dependencies, it is intended for the single file analysis.
        /// </summary>
        private void Analyze(IDependencyChainSingleNode <PythonAnalyzerEntry> node, Stopwatch stopWatch)
        {
            ActivityTracker.OnEnqueueModule(node.Value.Module.FilePath);
            var entry = node.Value;

            if (!CanUpdateAnalysis(entry, _walker.Version, out var module, out var ast))
            {
                return;
            }
            var startTime = stopWatch.Elapsed;

            AnalyzeEntry(node, entry, module, ast, _walker.Version);

            LogCompleted(node, module, stopWatch, startTime);
        }
        private void AnalyzeLoop(IDependencyChainLoopNode <PythonAnalyzerEntry> loopNode, Stopwatch stopWatch)
        {
            var version         = _walker.Version;
            var entries         = new Dictionary <AnalysisModuleKey, (IPythonModule Module, PythonAnalyzerEntry Entry)>();
            var variables       = new Dictionary <(AnalysisModuleKey Module, string Name), int>();
            var importNames     = new List <(AnalysisModuleKey From, int FromPosition, AnalysisModuleKey To, string ToName)>();
            var cachedVariables = new Dictionary <AnalysisModuleKey, IVariableCollection>();
            var asts            = new Dictionary <AnalysisModuleKey, PythonAst>();
            var startTime       = stopWatch.Elapsed;

            // Note: loop analysis is not cancellable. The reason is that when smaller loop
            // appears inside a larger loop gets canceled, it will not be re-walked during
            // the outer loop analysis. For example, functools <=> _functools loop and
            // the related CircularDependencyFunctools test.
            foreach (var entry in loopNode.Values)
            {
                ActivityTracker.OnEnqueueModule(entry.Module.FilePath);
                if (!CanUpdateAnalysis(entry, Version, out var module, out var ast))
                {
                    _log?.Log(TraceEventType.Verbose, $"Analysis of loop canceled.");
                    return;
                }

                var moduleKey = new AnalysisModuleKey(module);
                entries[moduleKey] = (module, entry);
                var analysis = _analyzer.TryRestoreCachedAnalysis(module);
                if (analysis != null)
                {
                    AddLoopImportsFromCachedAnalysis(importNames, variables, moduleKey, analysis);
                    cachedVariables.Add(moduleKey, analysis.GlobalScope.Variables);
                }
                else
                {
                    AddLoopImportsFromAst(importNames, variables, moduleKey, ast);
                    asts.Add(moduleKey, ast);
                }
            }

            if (asts.Count == 0)
            {
                // Fully cached loop
                if (_log != null && _log.LogLevel == TraceEventType.Verbose)
                {
                    var names = string.Join(", ", cachedVariables.Select(v => v.Key.Name));
                    _log?.Log(TraceEventType.Verbose, $"Fully cached modules cycle: {names}");
                }
                return;
            }

            var imports = new List <(AnalysisModuleKey From, int FromPosition, AnalysisModuleKey To, int ToPosition)>();

            foreach (var(fromModule, fromPosition, toModule, toName) in importNames)
            {
                if (!entries.ContainsKey(toModule))
                {
                    continue;
                }

                if (toName == null)
                {
                    imports.Add((fromModule, fromPosition, toModule, 0));
                }
                else if (variables.TryGetValue((toModule, toName), out var toPosition))
                {
                    imports.Add((fromModule, fromPosition, toModule, toPosition));
                }
            }

            var startingKeys = LocationLoopResolver <AnalysisModuleKey> .FindStartingItems(imports);

            var variableHandler = new LoopImportedVariableHandler(_services, asts, cachedVariables, () => false);

            foreach (var key in startingKeys)
            {
                if (asts.TryGetValue(key, out var startingAst) && entries.TryGetValue(key, out var me))
                {
                    variableHandler.WalkModule(me.Module, startingAst);
                }
            }

            foreach (var walker in variableHandler.Walkers)
            {
                asts.Remove(new AnalysisModuleKey(walker.Module));
            }

            while (asts.Count > 0)
            {
                var(moduleKey, ast) = asts.First();
                variableHandler.WalkModule(entries[moduleKey].Module, ast);

                foreach (var walker in variableHandler.Walkers)
                {
                    asts.Remove(new AnalysisModuleKey(walker.Module));
                }
            }

            foreach (var walker in variableHandler.Walkers)
            {
                var module    = (IDocument)walker.Module;
                var moduleKey = new AnalysisModuleKey(module);
                if (entries.TryGetValue(moduleKey, out var e))
                {
                    var analysis = CreateAnalysis(null, module, walker.Ast, version, walker);
                    CompleteAnalysis(e.Entry, module, version, analysis);
                }
            }

            loopNode.MarkWalked();
            LogCompleted(loopNode, entries.Values.Select(v => v.Module), stopWatch, startTime);
        }