public static async Task <ProjectDependencyGraph> GetDependencyGraphAsync(Solution solution, CancellationToken cancellationToken) { var tracker = TrackWorkspace(solution.Workspace); var oldGraph = await tracker.GetGraphAsync(cancellationToken).ConfigureAwait(false); return(ProjectDependencyGraph.From(solution, oldGraph, cancellationToken)); }
private SolutionState( BranchId branchId, int workspaceVersion, SolutionServices solutionServices, SolutionId id, string filePath, IEnumerable<ProjectId> projectIds, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap, ImmutableDictionary<string, ImmutableArray<DocumentId>> linkedFilesMap, ProjectDependencyGraph dependencyGraph, VersionStamp version, Lazy<VersionStamp> lazyLatestProjectVersion) { _branchId = branchId; _workspaceVersion = workspaceVersion; _id = id; _filePath = filePath; _solutionServices = solutionServices; _projectIds = projectIds.ToImmutableReadOnlyListOrEmpty(); _projectIdToProjectStateMap = idToProjectStateMap; _projectIdToTrackerMap = projectIdToTrackerMap; _linkedFilesMap = linkedFilesMap; _dependencyGraph = dependencyGraph; _version = version; _lazyLatestProjectVersion = lazyLatestProjectVersion; CheckInvariants(); }
private SolutionState( BranchId branchId, int workspaceVersion, SolutionServices solutionServices, SolutionInfo solutionInfo, IEnumerable<ProjectId> projectIds, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap, ImmutableDictionary<string, ImmutableArray<DocumentId>> linkedFilesMap, ProjectDependencyGraph dependencyGraph, Lazy<VersionStamp> lazyLatestProjectVersion) { _branchId = branchId; _workspaceVersion = workspaceVersion; _solutionServices = solutionServices; _solutionInfo = solutionInfo; _projectIds = projectIds.ToImmutableReadOnlyListOrEmpty(); _projectIdToProjectStateMap = idToProjectStateMap; _projectIdToTrackerMap = projectIdToTrackerMap; _linkedFilesMap = linkedFilesMap; _dependencyGraph = dependencyGraph; _lazyLatestProjectVersion = lazyLatestProjectVersion; // when solution state is changed, we re-calcuate its checksum _lazyChecksums = new AsyncLazy<SolutionStateChecksums>(ComputeChecksumsAsync, cacheResult: true); CheckInvariants(); }
private async Task <ProjectDependencyGraph> LoadOrComputeGraphAsync(Solution solution, CancellationToken cancellationToken) { Contract.ThrowIfFalse(solution.BranchId == solution.Workspace.PrimaryBranchId); // TODO: make this async too var persistenceService = WorkspaceService.GetService <IPersistentStorageService>(solution.Workspace); ProjectDependencyGraph graph; using (var storage = persistenceService.GetStorage(solution)) using (var stream = await storage.ReadStreamAsync(PersistenceName, cancellationToken).ConfigureAwait(false)) { if (stream != null) { using (var reader = new ObjectReader(stream)) { graph = ProjectDependencyGraph.From(solution, reader, cancellationToken); if (graph != null) { return(graph); } } } } cancellationToken.ThrowIfCancellationRequested(); // do it the hard way! graph = ProjectDependencyGraph.From(solution, cancellationToken); // since we built it, we may as well save it for next time await SaveGraphAsync(graph, cancellationToken).ConfigureAwait(false); return(graph); }
private Solution( BranchId branchId, int workspaceVersion, SolutionServices solutionServices, SolutionId id, string filePath, ImmutableList<ProjectId> projectIds, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap, ProjectDependencyGraph dependencyGraph, VersionStamp version, Lazy<VersionStamp> lazyLatestProjectVersion) { this.branchId = branchId; this.workspaceVersion = workspaceVersion; this.id = id; this.filePath = filePath; this.solutionServices = solutionServices; this.projectIds = projectIds; this.projectIdToProjectStateMap = idToProjectStateMap; this.projectIdToTrackerMap = projectIdToTrackerMap; this.dependencyGraph = dependencyGraph; this.projectIdToProjectMap = ImmutableHashMap<ProjectId, Project>.Empty; this.version = version; this.lazyLatestProjectVersion = lazyLatestProjectVersion; CheckInvariants(); }
private async Task SaveGraphAsync(ProjectDependencyGraph graph, CancellationToken cancellationToken) { Contract.ThrowIfFalse(graph.Solution.BranchId == graph.Solution.Workspace.PrimaryBranchId); using (var stream = SerializableBytes.CreateWritableStream()) using (var writer = new ObjectWriter(stream)) { graph.WriteTo(writer); stream.Position = 0; var persistenceService = WorkspaceService.GetService <IPersistentStorageService>(graph.Solution.Workspace); using (var storage = persistenceService.GetStorage(graph.Solution)) { await storage.WriteStreamAsync(PersistenceName, stream, cancellationToken).ConfigureAwait(false); } } }
/// <summary> /// Build solution and call specified action on syntax tree and semantic model of a particular file. /// </summary> /// <param name="solutionPath"></param> /// <param name="solutionExplorer"></param> public static void BuildSolution(string solutionPath, Action <SyntaxTree, SemanticModel> solutionExplorer) { var workspace = CreateMSBuildWorkspace(); Solution solution = OpenSolution(workspace, solutionPath); // Set Parser options CSharpParseOptions options = CSharpParseOptions.Default .WithFeatures(new[] { new KeyValuePair <string, string>("flow-analysis", "") }); var seenProjects = new ConcurrentDictionary <string, bool>(); Microsoft.CodeAnalysis.ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph(); foreach (var projectId in projectGraph.GetTopologicallySortedProjects()) { if (!seenProjects.TryAdd(solution.GetProject(projectId).FilePath, true)) { continue; } Compilation projectCompilation; try { var solutionWithOptions = solution.WithProjectParseOptions(projectId, options); // Get project compilation projectCompilation = GetCompilation(solutionWithOptions, projectId); } catch (Exception ex) { Console.WriteLine($"Exception occured while compiling project {projectId}. {ex.Message}: {ex.StackTrace}"); continue; } switch (projectCompilation) { case CSharpCompilation cSharpCompilation: foreach (SyntaxTree syntaxTree in projectCompilation.SyntaxTrees) { var semanticModel = projectCompilation.GetSemanticModel(syntaxTree); solutionExplorer(syntaxTree, semanticModel); } break; } } }
private SolutionState Branch( IEnumerable<ProjectId> projectIds = null, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap = null, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap = null, ImmutableDictionary<string, ImmutableArray<DocumentId>> linkedFilesMap = null, ProjectDependencyGraph dependencyGraph = null, VersionStamp? version = default(VersionStamp?), Lazy<VersionStamp> lazyLatestProjectVersion = null) { var branchId = GetBranchId(); projectIds = projectIds ?? _projectIds; idToProjectStateMap = idToProjectStateMap ?? _projectIdToProjectStateMap; projectIdToTrackerMap = projectIdToTrackerMap ?? _projectIdToTrackerMap; linkedFilesMap = linkedFilesMap ?? _linkedFilesMap; dependencyGraph = dependencyGraph ?? _dependencyGraph; version = version.HasValue ? version.Value : _version; lazyLatestProjectVersion = lazyLatestProjectVersion ?? _lazyLatestProjectVersion; if (branchId == _branchId && projectIds == _projectIds && idToProjectStateMap == _projectIdToProjectStateMap && projectIdToTrackerMap == _projectIdToTrackerMap && linkedFilesMap == _linkedFilesMap && dependencyGraph == _dependencyGraph && version == _version && lazyLatestProjectVersion == _lazyLatestProjectVersion) { return this; } return new SolutionState( branchId, _workspaceVersion, _solutionServices, _id, _filePath, projectIds, idToProjectStateMap, projectIdToTrackerMap, linkedFilesMap, dependencyGraph, version.Value, lazyLatestProjectVersion); }
private ImmutableDictionary<ProjectId, CompilationTracker> CreateCompilationTrackerMap(ProjectId projectId, ProjectDependencyGraph dependencyGraph) { var builder = ImmutableDictionary.CreateBuilder<ProjectId, CompilationTracker>(); var dependencies = dependencyGraph.GetProjectsThatTransitivelyDependOnThisProject(projectId); foreach (var projectIdAndTracker in _projectIdToTrackerMap) { var id = projectIdAndTracker.Key; var tracker = projectIdAndTracker.Value; if (!tracker.HasCompilation) { continue; } var canReuse = id == projectId || !dependencies.Contains(id); builder.Add(id, canReuse ? tracker : tracker.Fork(tracker.ProjectState)); } return builder.ToImmutable(); }
/// <summary> /// Links the solution project assemblies to the given P# project. /// </summary> /// <param name="project">Project</param> /// <param name="graph">ProjectDependencyGraph</param> private void LinkSolutionAssembliesToProject(Project project, ProjectDependencyGraph graph) { var projectPath = this.OutputDirectoryMap[project.AssemblyName]; foreach (var projectId in graph.GetProjectsThatThisProjectTransitivelyDependsOn(project.Id)) { var requiredProject = this.CompilationContext.GetSolution().GetProject(projectId); var assemblyPath = this.ProjectAssemblyPathMap[requiredProject.AssemblyName]; var fileName = projectPath + Path.DirectorySeparatorChar + requiredProject.AssemblyName + ".dll"; this.CopyAssembly(assemblyPath, fileName); } }
private SolutionState Branch( SolutionInfo solutionInfo = null, IEnumerable<ProjectId> projectIds = null, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap = null, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap = null, ImmutableDictionary<string, ImmutableArray<DocumentId>> linkedFilesMap = null, ProjectDependencyGraph dependencyGraph = null, Lazy<VersionStamp> lazyLatestProjectVersion = null) { var branchId = GetBranchId(); solutionInfo = solutionInfo ?? _solutionInfo; projectIds = projectIds ?? _projectIds; idToProjectStateMap = idToProjectStateMap ?? _projectIdToProjectStateMap; projectIdToTrackerMap = projectIdToTrackerMap ?? _projectIdToTrackerMap; linkedFilesMap = linkedFilesMap ?? _linkedFilesMap; dependencyGraph = dependencyGraph ?? _dependencyGraph; lazyLatestProjectVersion = lazyLatestProjectVersion ?? _lazyLatestProjectVersion; if (branchId == _branchId && solutionInfo == _solutionInfo && projectIds == _projectIds && idToProjectStateMap == _projectIdToProjectStateMap && projectIdToTrackerMap == _projectIdToTrackerMap && linkedFilesMap == _linkedFilesMap && dependencyGraph == _dependencyGraph && lazyLatestProjectVersion == _lazyLatestProjectVersion) { return this; } return new SolutionState( branchId, _workspaceVersion, _solutionServices, solutionInfo, projectIds, idToProjectStateMap, projectIdToTrackerMap, linkedFilesMap, dependencyGraph, lazyLatestProjectVersion); }
/// <summary> /// Links the external references to the given P# compilation. /// </summary> /// <param name="project">Project</param> /// <param name="graph">ProjectDependencyGraph</param> private void LinkExternalAssembliesToProject(Project project, ProjectDependencyGraph graph) { var projectPath = this.OutputDirectoryMap[project.AssemblyName]; foreach (var projectId in graph.GetProjectsThatThisProjectTransitivelyDependsOn(project.Id)) { var requiredProject = this.CompilationContext.GetSolution().GetProject(projectId); foreach (var reference in requiredProject.MetadataReferences) { //if (!(reference is PortableExecutableReference)) //{ // continue; //} var fileName = Path.Combine(projectPath, Path.GetFileName(reference.Display)); this.CopyAssembly(reference.Display, fileName); } } }
private Solution Branch( ImmutableList<ProjectId> projectIds = null, ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap = null, ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap = null, ProjectDependencyGraph dependencyGraph = null, VersionStamp? version = default(VersionStamp?), Lazy<VersionStamp> lazyLatestProjectVersion = null) { var branchId = GetBranchId(); projectIds = projectIds ?? this.projectIds; idToProjectStateMap = idToProjectStateMap ?? this.projectIdToProjectStateMap; projectIdToTrackerMap = projectIdToTrackerMap ?? this.projectIdToTrackerMap; dependencyGraph = dependencyGraph ?? this.dependencyGraph; version = version.HasValue ? version.Value : this.version; lazyLatestProjectVersion = lazyLatestProjectVersion ?? this.lazyLatestProjectVersion; if (branchId == this.branchId && projectIds == this.projectIds && idToProjectStateMap == this.projectIdToProjectStateMap && projectIdToTrackerMap == this.projectIdToTrackerMap && dependencyGraph == this.dependencyGraph && version == this.version && lazyLatestProjectVersion == this.lazyLatestProjectVersion) { return this; } return new Solution( branchId, this.workspaceVersion, this.solutionServices, this.id, this.filePath, projectIds, idToProjectStateMap, projectIdToTrackerMap, dependencyGraph, version.Value, lazyLatestProjectVersion); }
public void RecomputeGraphLazily(Solution solution) { SetLazyGraph(new AsyncLazy <ProjectDependencyGraph>(c => Task.FromResult(ProjectDependencyGraph.From(solution, c)), cacheResult: true)); }
public TestAccessor(ProjectDependencyGraph instance) { _instance = instance; }
/// <summary> /// Links the solution project assemblies to the given P# project. /// </summary> /// <param name="project">Project</param> /// <param name="graph">ProjectDependencyGraph</param> private static void LinkSolutionAssembliesToProject(Project project, ProjectDependencyGraph graph) { var projectPath = CompilationEngine.OutputDirectoryMap[project.AssemblyName]; foreach (var projectId in graph.GetProjectsThatThisProjectTransitivelyDependsOn(project.Id)) { var requiredProject = ProgramInfo.Solution.GetProject(projectId); var assemblyPath = CompilationEngine.ProjectAssemblyPathMap[requiredProject.AssemblyName]; var fileName = projectPath + Path.DirectorySeparatorChar + requiredProject.AssemblyName + ".dll"; File.Delete(fileName); File.Copy(assemblyPath, fileName); } }
internal static ProjectDependencyGraph From(Solution newSolution, ProjectDependencyGraph oldGraph, CancellationToken cancellationToken) { var oldSolution = oldGraph.Solution; if (oldSolution == newSolution) { return(oldGraph); } // in case old and new are incompatible just build it the hard way if (oldSolution.Id != newSolution.Id) { return(From(newSolution, cancellationToken)); } var map = oldGraph.projectToProjectsItReferencesMap; var reverseMap = oldGraph.projectToProjectsThatReferenceItMap; var differences = newSolution.GetChanges(oldSolution); // remove projects that no longer occur in new solution foreach (var project in differences.GetRemovedProjects()) { cancellationToken.ThrowIfCancellationRequested(); ImmutableHashSet <ProjectId> referencedProjectIds; if (oldGraph.projectToProjectsItReferencesMap.TryGetValue(project.Id, out referencedProjectIds)) { map = map.Remove(project.Id); reverseMap = reverseMap.RemoveAll(referencedProjectIds, project.Id); } } // add projects that don't occur in old solution foreach (var project in differences.GetAddedProjects()) { cancellationToken.ThrowIfCancellationRequested(); var referencedProjectIds = project.ProjectReferences.Select(p => p.ProjectId); map = map.Add(project.Id, ImmutableHashSet.CreateRange <ProjectId>(referencedProjectIds)); reverseMap = reverseMap.AddAll(referencedProjectIds, project.Id); } // update projects that are changed. foreach (var projectChanges in differences.GetProjectChanges().Where(pc => pc.OldProject.AllProjectReferences != pc.NewProject.AllProjectReferences)) { var projectId = projectChanges.ProjectId; cancellationToken.ThrowIfCancellationRequested(); ImmutableHashSet <ProjectId> oldReferencedProjectIds; if (oldGraph.projectToProjectsItReferencesMap.TryGetValue(projectId, out oldReferencedProjectIds)) { map = map.Remove(projectId); reverseMap = reverseMap.RemoveAll(oldReferencedProjectIds, projectId); } var newReferencedProjectIds = newSolution.GetProject(projectId).ProjectReferences.Select(p => p.ProjectId); map = map.Add(projectId, ImmutableHashSet.CreateRange <ProjectId>(newReferencedProjectIds)); reverseMap = reverseMap.AddAll(newReferencedProjectIds, projectId); } var version = newSolution.GetLatestProjectVersion(); return(new ProjectDependencyGraph(newSolution, version, map, reverseMap)); }