public void TwoStartingItems(params string[] input) { var edges = input.Select(s => (s[0], (int)s[1] - 0x30, s[2], (int)s[3] - 0x30)); LocationLoopResolver <char> .FindStartingItems(edges).Should().BeEquivalentTo('A', 'C'); }
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); }
public void NoStartingItem(params string[] input) { var edges = input.Select(s => (s[0], (int)s[1] - 0x30, s[2], (int)s[3] - 0x30)); LocationLoopResolver <char> .FindStartingItems(edges).Should().BeEmpty(); }