Beispiel #1
0
        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)
 {
 }
Beispiel #4
0
 public CompilationEngineContext(IApplicationEnvironment applicationEnvironment,
                                 IRuntimeEnvironment runtimeEnvironment,
                                 IAssemblyLoadContext defaultLoadContext,
                                 CompilationCache cache) :
     this(applicationEnvironment, runtimeEnvironment, defaultLoadContext, cache, NoopWatcher.Instance)
 {
 }
Beispiel #5
0
        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);
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
            }
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #9
0
        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"));
            }
        }
Beispiel #10
0
        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);
            }
        }
Beispiel #11
0
        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);
        }
Beispiel #13
0
 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();
 }
Beispiel #14
0
        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;
                }
            }
        }
Beispiel #15
0
        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");
            }
        }
Beispiel #16
0
        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");
            }
        }
Beispiel #17
0
        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);
        }
Beispiel #19
0
        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);
        }
Beispiel #23
0
        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);
                }
            }
        }
Beispiel #26
0
 public CompilationEngineFactory(CompilationCache cache)
 {
     CompilationCache = cache;
 }
Beispiel #27
0
        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;
            }));
        }
Beispiel #28
0
        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>());
        }