public async Task When_Display_Graph_Two_Roots_No_Extension() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var compilation = await project.GetCompilationAsync(); var someClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeClass.cs"); var someCircularClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeCircularClass.cs"); var roots = new[] { (await someClassTree.GetRootAsync()).GetAllDeclaredTypes(compilation.GetSemanticModel(someClassTree)).First(), (await someCircularClassTree.GetRootAsync()).GetAllDeclaredTypes(compilation.GetSemanticModel(someCircularClassTree)).First() }; var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var displayGraph = fullGraph.GetDisplaySubgraph(roots); Assert.AreEqual(2, displayGraph.VertexCount); var simpleEdges = displayGraph.Edges.OfType <SimpleDisplayEdge>().ToArray(); var multiEdges = displayGraph.Edges.OfType <MultiDependencyDisplayEdge>().ToArray(); Assert.AreEqual(0, simpleEdges.Length); Assert.AreEqual(1, multiEdges.Length); } }
public async Task When_Two_Roots() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var someClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass")]; var someCircularClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeCircularClass")]; var roots = new HashSet <Node>(); roots.Add(someClassNode); roots.Add(someCircularClassNode); var paths = NodeGraphExtensions.GetMultiDependencyRootPaths(graph, roots).ToArray(); var path = paths.Single(); Assert.AreEqual(someClassNode, path.Source); Assert.AreEqual(someCircularClassNode, path.Target); Assert.AreEqual(2, path.Intermediates.Count); Assert.AreEqual("SomeOtherClass", (path.Intermediates[0] as TypeNode).Identifier.Name); Assert.AreEqual("SomeDeeperClass", (path.Intermediates[1] as TypeNode).Identifier.Name); } }
public CompilationEngineContext(IApplicationEnvironment applicationEnvironment, IAssemblyLoadContext defaultLoadContext, CompilationCache cache, IProjectGraphProvider projectGraphProvider) : this(applicationEnvironment, defaultLoadContext, cache, NoopWatcher.Instance, projectGraphProvider) { }
public CompilationEngineContext(IApplicationEnvironment applicationEnvironment, IRuntimeEnvironment runtimeEnvironment, IAssemblyLoadContext defaultLoadContext, CompilationCache cache) : this(applicationEnvironment, runtimeEnvironment, defaultLoadContext, cache, NoopWatcher.Instance) { }
public async Task When_Implemented_Interface() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var implementingClassNode = fullGraph.Nodes.Values.Single(n => (n as TypeNode)?.Identifier.Name == "SomeBaseClass"); AssertImplements(implementingClassNode, "ISomeInheritedInterface"); AssertImplements(implementingClassNode, "ISomeStillOtherInterface"); AssertImplements(implementingClassNode, "ISomeGenericInterface<T>"); void AssertImplements(Node implementer, string interfaceName) { var interfaceLink = AssertEx.ContainsSingle(implementer.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == interfaceName); Assert.AreEqual(LinkType.ImplementsInterface, interfaceLink.LinkType); } ; //var baseClassLink = AssertEx.ContainsSingle(inheritedClassNode.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == "SomeBaseClass"); //Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType); //var derivedClassLink = AssertEx.ContainsSingle(inheritedClassNode.BackLinks, l => (l.Dependent as TypeNode)?.Identifier.Name == "SomeInheritedClassDepth2"); //Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType); } }
public CompilationEngine( CompilationCache compilationCache, CompilationEngineContext context) { _context = context; RootLibraryExporter = new LibraryExporter(_context.LibraryManager, this, _context.TargetFramework, _context.Configuration); _compilerLoadContext = new Lazy <IAssemblyLoadContext>(() => { var factory = (IAssemblyLoadContextFactory)_context.Services.GetService(typeof(IAssemblyLoadContextFactory)); // Ensure this compilation engine is in the service provider var services = new ServiceProvider(_context.Services); services.Add(typeof(ICompilationEngine), this); return(factory.Create(services)); }); CompilationCache = compilationCache; // Register compiler services // TODO(anurse): Switch to project factory model to avoid needing to do this. _context.AddService(typeof(ICache), CompilationCache.Cache); _context.AddService(typeof(ICacheContextAccessor), CompilationCache.CacheContextAccessor); _context.AddService(typeof(INamedCacheDependencyProvider), CompilationCache.NamedCacheDependencyProvider); _context.AddService(typeof(IFileWatcher), context.FileWatcher); }
public async Task When_Building_From_Subject() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var compilation = await project.GetCompilationAsync(); var someClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeClass.cs"); var rootNode = await someClassTree.GetRootAsync(); var model = compilation.GetSemanticModel(someClassTree); var classSymbol = rootNode.GetAllDeclaredTypes(model).First(); Assert.AreEqual("SomeClass", classSymbol.Name); var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var root = graph.GetNodeForType(classSymbol); Assert.AreEqual(classSymbol.ToIdentifier(), root.Identifier); Assert.AreEqual(4, root.ForwardLinks.Count); AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeEnumeratedClass"); AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeClassCore"); var someOtherClassNode = AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeOtherClass") as TypeNode; CollectionAssert.Contains(someOtherClassNode.BackLinkNodes, root); AssertEx.Contains(someOtherClassNode.BackLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeCircularClass"); AssertEx.Contains(someOtherClassNode.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeClassInArray"); AssertEx.Contains(someOtherClassNode.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeDeeperClass"); AssertConsistentState(graph); } }
public async Task When_Root_With_BackLinks() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var compilation = await project.GetCompilationAsync(); var someClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeOtherClass.cs"); var rootNode = await someClassTree.GetRootAsync(); var model = compilation.GetSemanticModel(someClassTree); var classSymbol = rootNode.GetAllDeclaredTypes(model).First(); Assert.AreEqual("SomeOtherClass", classSymbol.Name); var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var root = graph.GetNodeForType(classSymbol); Assert.AreEqual(classSymbol.ToIdentifier(), root.Identifier); Assert.AreEqual(3, root.ForwardLinks.Count); Assert.AreEqual(2, root.BackLinks.Count); AssertConsistentState(graph); } }
public async Task When_MultiDependency_Edge() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var someClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass")]; var deepClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClassDepth5")]; var roots = new HashSet <Node>(); roots.Add(someClassNode); roots.Add(deepClassNode); var paths = NodeGraphExtensions.GetMultiDependencyRootPaths(graph, roots).ToArray(); var path = paths.Single(); var displayGraph = graph.GetDisplaySubgraph(subgraphNodes: roots, pinnedNodes: SetUtils.GetEmpty <NodeKey>()); var multiEdges = displayGraph.Edges.OfType <MultiDependencyDisplayEdge>(); AssertEx.ContainsSingle(multiEdges, m => m.Source.DisplayString.EndsWith("SomeClass") && m.Target.DisplayString.EndsWith("SomeClassDepth5")); } }
public async Task When_Inherited_Class_Generic() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var inheritedClassNode = fullGraph.Nodes.Values.Single(n => (n as TypeNode)?.Identifier.Name == "SomeInheritedConcretifiedClass"); var baseClassLink = AssertEx.ContainsSingle(inheritedClassNode.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == "SomeBaseGenericClass<T>"); Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType); } }
private async Task UpdateForDocument(DocumentId documentId, CompilationCache compilationCache, CancellationToken ct) { var document = compilationCache.GetDocument(documentId); if (document == null) { return; } var filePath = document.FilePath; var associatedExistingNodes = GetAssociatedNodes(filePath); var syntaxRoot = await document.GetSyntaxRootAsync(ct); if (ct.IsCancellationRequested) { return; } if (syntaxRoot == null) { return; } var model = await compilationCache.GetSemanticModel(syntaxRoot, document.Project.ToIdentifier(), ct); if (ct.IsCancellationRequested) { return; } if (model == null) { return; } var declaredSymbols = GetIncludedSymbolsFromSyntaxRoot(syntaxRoot, model); // For each symbol, get existing or new node, and invalidate it so it will be reevaluated in the next part of the Update pass. var declaredSymbolNodes = declaredSymbols.Select(s => GetOrCreateNode(s, compilationCache)).ToHashSet(); foreach (var node in declaredSymbolNodes) { InvalidateNode(node); } // If any associatedExistingNode is no longer found in this document, invalidate it for reevaluation. foreach (var node in associatedExistingNodes) { if (!declaredSymbolNodes.Contains(node)) { InvalidateNode(node); } } }
private TypeNode GetOrCreateNode(ITypeSymbol symbol, CompilationCache cache) { var identifier = symbol.ToIdentifier(); var key = new TypeNodeKey(identifier); if (!_nodes.TryGetValue(key, out var node)) { node = CreateTypeNodeForSymbol(symbol, key, cache); AddNode(node); } return((TypeNode)node); }
public ConnectionContext(IDictionary <int, ApplicationContext> contexts, IServiceProvider services, ProcessingQueue queue, ProtocolManager protocolManager, string hostId) { _contexts = contexts; _services = services; _queue = queue; _hostId = hostId; _protocolManager = protocolManager; _cache = new CompilationCache(); }
public async Task <ICollection <Node> > Update(CompilationCache compilationCache, IEnumerable <DocumentId> invalidatedDocuments, CancellationToken ct) { // TODO: documents with compilation errors - should probably be reevaluated on every update? lock (_gate) { if (_isUpdating) { throw new InvalidOperationException("Update already in process."); } _isUpdating = true; } try { foreach (var doc in invalidatedDocuments) { if (ct.IsCancellationRequested) { return(ArrayUtils.GetEmpty <Node>()); } await UpdateForDocument(doc, compilationCache, ct); } var allModified = new HashSet <Node>(); while (_invalidatedNodes.Count > 0) { if (ct.IsCancellationRequested) { return(allModified); } var node = _invalidatedNodes.Dequeue(); var modifiedNodes = await UpdateNode(node, compilationCache, ct); allModified.UnionWith(modifiedNodes); } return(allModified); } finally { _alreadyInvalidatedNodes.Clear(); lock (_gate) { _isUpdating = false; } } }
public async Task When_Purely_Generated_Excluded() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeGeneratedClass"); AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomePartiallyGeneratedClass"); var graphWithGeneratedExcluded = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), excludePureGenerated : true); AssertEx.None(graphWithGeneratedExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeGeneratedClass"); AssertEx.Contains(graphWithGeneratedExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomePartiallyGeneratedClass"); } }
public async Task When_Project_Excluded() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeClassCore"); var mainProject = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var graphWithCoreExcluded = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), new[] { mainProject.ToIdentifier() }); AssertEx.None(graphWithCoreExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeClassCore"); } }
public CompilationEngineContext(IApplicationEnvironment applicationEnvironment, IRuntimeEnvironment runtimeEnvironment, IAssemblyLoadContext defaultLoadContext, CompilationCache cache) { ApplicationEnvironment = applicationEnvironment; RuntimeEnvironment = runtimeEnvironment; DefaultLoadContext = defaultLoadContext; CompilationCache = cache; // Register compiler services AddCompilationService(typeof(IApplicationEnvironment), ApplicationEnvironment); AddCompilationService(typeof(ICache), CompilationCache.Cache); AddCompilationService(typeof(ICacheContextAccessor), CompilationCache.CacheContextAccessor); AddCompilationService(typeof(INamedCacheDependencyProvider), CompilationCache.NamedCacheDependencyProvider); }
public static async Task <NodeGraph?> BuildGraph(CompilationCache compilationCache, IEnumerable <ProjectIdentifier>?includedProjects = null, bool excludePureGenerated = false, CancellationToken ct = default) { var projects = includedProjects ?? compilationCache.GetAllProjects(); var includedAssemblies = projects.Select(p => compilationCache.GetAssemblyName(p)).Trim(); var graph = new NodeGraph(excludePureGenerated, includedAssemblies); await BuildGraph(graph, compilationCache, projects, ct); if (ct.IsCancellationRequested) { return(null); } return(graph); }
public async Task When_Link_External_Assembly() { using (var workspace = WorkspaceUtils.GetSubjectSolution()) { var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var someClassKey = TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass"); var someClassNode = graph.Nodes[someClassKey]; var someClassCoreKey = TypeNodeKey.GetFromFullName("SubjectSolution.Core.SomeClassCore"); var someClassCoreNode = graph.Nodes[someClassCoreKey]; var forwardLink = AssertEx.Contains(someClassNode.ForwardLinkNodes, n => n.Key.Equals(someClassCoreKey)); Assert.AreEqual(someClassCoreNode, forwardLink); var backLink = AssertEx.Contains(someClassCoreNode.BackLinkNodes, n => n.Key.Equals(someClassKey)); Assert.AreEqual(someClassNode, backLink); } }
public async Task When_Updated_Reference_Added() { using var workspace = WorkspaceUtils.GetSubjectSolution(); var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var mutableClassKey = TypeNodeKey.GetFromFullName("SubjectSolution.Mutable.SomeMutableClass"); var mutableClassNode = (TypeNode)fullGraph.Nodes[mutableClassKey]; Assert.AreEqual(1, mutableClassNode.ForwardLinks.Count); var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution"); var mutableDoc = project.Documents.Single(d => d.FilePath.EndsWith("SomeMutableClass.cs")); var mutableRoot = await mutableDoc.GetSyntaxRootAsync(); var replaceableMethod = mutableRoot.DescendantNodes().OfType <MethodDeclarationSyntax>().Single(m => m.Identifier.Text == "MightBeReplaced"); var replacementText = @" public void MightBeReplaced() { var replacement = new SomeClassAddableReference(); } "; var mutableDocText = await mutableDoc.GetTextAsync(); var mutatedMutableDocText = mutableDocText.Replace(replaceableMethod.Span, replacementText); var mutatedMutableDoc = mutableDoc.WithText(mutatedMutableDocText); Assert.AreEqual(mutableDoc.Id, mutatedMutableDoc.Id); var mutatedSolution = mutatedMutableDoc.Project.Solution; await fullGraph.Update(CompilationCache.CacheWithSolution(mutatedSolution), new[] { mutableDoc.Id }, default); var mutatedmutableClassNode = (TypeNode)fullGraph.Nodes[mutableClassKey]; // For now this is reference-equal to mutableClassNode, but let's try not to rely on it Assert.AreEqual(2, mutableClassNode.ForwardLinks.Count); AssertEx.Contains(mutableClassNode.ForwardLinkNodes, n => (n as TypeNode).Identifier.Name == "SomeClassAddableReference"); AssertConsistentState(fullGraph); }
public CompilationEngineContext(IApplicationEnvironment applicationEnvironment, IAssemblyLoadContext defaultLoadContext, CompilationCache cache, IFileWatcher fileWatcher, IProjectGraphProvider projectGraphProvider) { ApplicationEnvironment = applicationEnvironment; DefaultLoadContext = defaultLoadContext; ProjectGraphProvider = projectGraphProvider; CompilationCache = cache; FileWatcher = fileWatcher; // Register compiler services AddCompilationService(typeof(IFileWatcher), FileWatcher); AddCompilationService(typeof(IApplicationEnvironment), ApplicationEnvironment); AddCompilationService(typeof(ICache), CompilationCache.Cache); AddCompilationService(typeof(ICacheContextAccessor), CompilationCache.CacheContextAccessor); AddCompilationService(typeof(INamedCacheDependencyProvider), CompilationCache.NamedCacheDependencyProvider); }
public async Task When_Updated_Invariant() { using var workspace = WorkspaceUtils.GetSubjectSolution(); var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default); var initialState = fullGraph.Nodes.ToDictionary(kvp => kvp.Key, kvp => (kvp.Value.BackLinks.ToList(), kvp.Value.ForwardLinks.ToList())); await fullGraph.Update(CompilationCache.CacheWithSolution(workspace.CurrentSolution), workspace.CurrentSolution.GetAllDocumentIds(), default); Assert.AreEqual(initialState.Count, fullGraph.Nodes.Count); foreach (var kvp in fullGraph.Nodes) { Assert.IsTrue(initialState.ContainsKey(kvp.Key)); var initialNodeState = initialState[kvp.Key]; var node = kvp.Value; CollectionAssert.AreEqual(initialNodeState.Item1, node.BackLinks); CollectionAssert.AreEqual(initialNodeState.Item2, node.ForwardLinks); } AssertConsistentState(fullGraph); }
public static async IAsyncEnumerable <ITypeSymbol> GetTypeDependencies(this ISymbol symbol, CompilationCache compilationCache, ProjectIdentifier containingProject, bool includeExternalMetadata = true, [EnumeratorCancellation] CancellationToken ct = default) { foreach (var syntaxRef in symbol.DeclaringSyntaxReferences) { if (ct.IsCancellationRequested) { yield break; } var root = await syntaxRef.GetSyntaxAsync(ct); var model = await compilationCache.GetSemanticModel(syntaxRef.SyntaxTree, containingProject, ct); if (model == null) { continue; } foreach (var referenced in root.GetAllReferencedTypeSymbols(model, includeExternalMetadata)) { yield return(referenced); } } }
private static TypeNode CreateTypeNodeForSymbol(ITypeSymbol symbol, TypeNodeKey key, CompilationCache cache) { var associatedFiles = GetAssociatedFiles(symbol); return(new TypeNode(key, symbol.GetPreferredDeclaration(), associatedFiles, symbol.GetFullMetadataName(), isNestedType: symbol.ContainingType != null, cache.GetContainingProject(associatedFiles)?.ToIdentifier())); }
private static async Task BuildGraph(NodeGraph graph, CompilationCache compilationCache, IEnumerable <ProjectIdentifier> projects, CancellationToken ct) { var knownNodes = new Dictionary <TypeIdentifier, TypeNode>(); foreach (var project in projects) { var syntaxTrees = await compilationCache.GetSyntaxTreesForProject(project, ct); // We use a hashset here because different SyntaxTrees may declare the same symbol (eg partial definitions) // Note: it's safe to hash by ITypeSymbol because they're all coming from the same Compilation var declaredSymbols = new HashSet <ITypeSymbol>(); foreach (var syntaxTree in syntaxTrees) { if (ct.IsCancellationRequested) { return; } var root = await syntaxTree.GetRootAsync(ct); var semanticModel = await compilationCache.GetSemanticModel(syntaxTree, project, ct); if (semanticModel == null) { continue; } declaredSymbols.UnionWith(graph.GetIncludedSymbolsFromSyntaxRoot(root, semanticModel)); } foreach (var symbol in declaredSymbols) { if (ct.IsCancellationRequested) { return; } var node = GetFromKnownNodes(symbol, compilationCache); await foreach (var dependency in symbol.GetTypeDependencies(compilationCache, project, includeExternalMetadata: false, ct)) { if (graph.IsSymbolIncluded(dependency)) { var dependencyNode = GetFromKnownNodes(dependency, compilationCache); if (node != dependencyNode) { node.AddForwardLink(dependencyNode, GetLinkType(dependency, symbol)); } } } } TypeNode GetFromKnownNodes(ITypeSymbol symbol, CompilationCache cache) { var identifier = symbol.ToIdentifier(); if (!knownNodes.TryGetValue(identifier, out var node)) { var key = new TypeNodeKey(identifier); node = CreateTypeNodeForSymbol(symbol, key, cache); knownNodes[identifier] = node; graph.AddNode(node); } return(node); } } }
public CompilationEngineFactory(CompilationCache cache) { CompilationCache = cache; }
private ApplicationHostContext GetApplicationHostContext(Runtime.Project project, FrameworkName targetFramework, string configuration, CompilationCache cache) { var cacheKey = Tuple.Create("ApplicationContext", project.Name, configuration, targetFramework); return(cache.Cache.Get <ApplicationHostContext>(cacheKey, ctx => { var applicationHostContext = new ApplicationHostContext(hostServices: _hostServices, projectDirectory: project.ProjectDirectory, packagesDirectory: null, configuration: configuration, targetFramework: targetFramework, loadContextFactory: GetRuntimeLoadContextFactory(project)); applicationHostContext.DependencyWalker.Walk(project.Name, project.Version, targetFramework); return applicationHostContext; })); }
private async Task <ICollection <Node> > UpdateNode(Node node, CompilationCache compilationCache, CancellationToken ct) { var(symbol, project) = await compilationCache.GetSymbolForNode(node, ct); if (symbol == null) { // It's gone! Clear node (remove all its forward links and back links). Back links need to be invalidated. var dirtied = new HashSet <Node>(); var lp = new LoopProtection(); while (node.ForwardLinks.Count > 0) { lp.Iterate(); var forwardLink = node.ForwardLinks.First(); dirtied.Add(forwardLink.Dependency); node.RemoveForwardLink(forwardLink); } while (node.BackLinks.Count > 0) { lp.Iterate(); var backLink = node.BackLinks.First(); var backLinkNode = backLink.Dependent; dirtied.Add(backLinkNode); backLinkNode.RemoveForwardLink(node); InvalidateNode(backLinkNode); } return(dirtied); } // Reconcile AssociatedFiles (including _nodesByDocument) var associated = GetAssociatedFiles(symbol); var fileDiffs = associated.GetUnorderedDiff(node.AssociatedFiles); if (fileDiffs.IsDifferent) { foreach (var added in fileDiffs.Added) { AddAssociatedFile(node, added); } foreach (var removed in fileDiffs.Removed) { RemoveAssociatedFile(node, removed); } } var dependencySymbols = await symbol.GetTypeDependencies(compilationCache, project, includeExternalMetadata : false, ct) .Where(IsSymbolIncluded) .ToListAsync(); var symbolsForDependencies = dependencySymbols.ToDictionary(s => (Node)GetOrCreateNode(s, compilationCache)); var dependencies = symbolsForDependencies.Keys; if (ct.IsCancellationRequested) { return(ArrayUtils.GetEmpty <Node>()); } var diffs = dependencies.GetUnorderedDiff(node.ForwardLinkNodes); if (diffs.IsDifferent) { var dirtied = new HashSet <Node>(); dirtied.Add(node); foreach (var removedItem in diffs.Removed) { node.RemoveForwardLink(removedItem); dirtied.Add(removedItem); } foreach (var addedItem in diffs.Added) { if (addedItem != node) { var linkType = GetLinkType(symbolsForDependencies[addedItem], symbol); node.AddForwardLink(addedItem, linkType); } dirtied.Add(addedItem); } return(dirtied); } return(ArrayUtils.GetEmpty <Node>()); }