public async void CompileSolution() { var _ = typeof(Microsoft.CodeAnalysis.CSharp.Formatting.CSharpFormattingOptions); string solutionFileName = "C:\\MSBuildProjects-beta\\VStudio.sln"; VSSolutionLoader rw = new VSSolutionLoader(); System.Windows.Forms.TreeView vv = rw.LoadProject(solutionFileName); VSSolution vs = vv.Tag as VSSolution; MessageBox.Show("VSolution loaded.." + vs.Name); comp = new Dictionary <string, Compilation>(); named = new Dictionary <string, List <INamespaceOrTypeSymbol> >(); workspace = null; ProjectDependencyGraph projectGraph = null; Microsoft.CodeAnalysis.Solution solution = null; workspace = MSBuildWorkspace.Create(); solution = await workspace.OpenSolutionAsync(solutionFileName); projectGraph = solution.GetProjectDependencyGraph(); foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects()) { Stopwatch sw = Stopwatch.StartNew(); Compilation projectCompilation = solution.GetProject(projectId).GetCompilationAsync().Result; sw.Stop(); System.Diagnostics.Debug.WriteLine("Time taken compilation creation: {0}ms", sw.Elapsed.TotalMilliseconds); Microsoft.CodeAnalysis.Project project = solution.GetProject(projectId); comp.Add(project.FilePath, projectCompilation); // List<INamespaceOrTypeSymbol> ns = GetAllTypes(project.FilePath); // named.Add(project.FilePath, ns); } }
public async Task<Target> FindTarget(Solution solution) { if (solution == null) { return new Target(); } var classDeclarationSyntaxes = solution.GetProjectDependencyGraph().GetTopologicallySortedProjects() .Select(async projectId => { var project = solution.GetProject(projectId); var compilation = (await project.GetCompilationAsync()); return compilation; }) .Select(compilationTask => compilationTask.Result) .Where(compilation => GetClassDeclarationSyntaxes(compilation).Any()) .Select(compilation => new Target() { Compilation = compilation, Node = GetClassDeclarationSyntaxes(compilation).First() }); var foundNamespaceDeclarationSyntax = new Target(); if (classDeclarationSyntaxes.Any()) { foundNamespaceDeclarationSyntax = classDeclarationSyntaxes.First(); } return foundNamespaceDeclarationSyntax; }
async internal static Task<ProjectCodeProvider> ProjectCodeProviderByNameAsync(Solution solution, string name) { foreach (var id in solution.ProjectIds) { var project = solution.GetProject(id); if (project.Name.Equals(name)) { return new ProjectCodeProvider(project, await project.GetCompilationAsync()); } } Contract.Assert(false, "Can't find project named = " + name); return null; }
// Almost there, I think, but not currently working. public static async Task <(bool OverallSuccess, EmitResult?TriggeringFailure)> CompileWithRosyln(string solutionUrl, string outputDir, CancellationToken cancel) { MSBuildWorkspace workspace = MSBuildWorkspace.Create(); Microsoft.CodeAnalysis.Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph(); foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects()) { Compilation?compilation = await solution.GetProject(projectId) !.GetCompilationAsync().ConfigureAwait(false); if (compilation == null || string.IsNullOrEmpty(compilation.AssemblyName)) { return(false, default);
public async Task<SyntaxNode> FindSource(Solution solution, string activeDocument, int cursorPosition) { if (solution == null || string.IsNullOrEmpty(activeDocument) || cursorPosition < 0) { return null; } var compilationTasks = solution.GetProjectDependencyGraph().GetTopologicallySortedProjects() .Select(projectId => { var project = solution.GetProject(projectId); var compilation = project.GetCompilationAsync(); return compilation; }); foreach (var task in compilationTasks) { task.Wait(); } var invocationExpressions = compilationTasks .Select(task => task.Result) .SelectMany(compilation => compilation.SyntaxTrees) .Where(compilation => FileNameComparer.SameFile(compilation.FilePath, activeDocument)) .Select(syntaxTree => syntaxTree.GetRoot()) .SelectMany(root => root.DescendantNodesAndSelf()) .Where(syntaxNode => syntaxNode.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.MethodDeclaration)) .SelectMany(methodDeclaration => methodDeclaration.DescendantNodesAndSelf()) .Where(IsSource) .Where(syntaxNode => syntaxNode.Span.Contains(cursorPosition)); SyntaxNode foundInvocationExpression = null; if (invocationExpressions.Any()) { foundInvocationExpression = invocationExpressions.First(); } return foundInvocationExpression; }
private async Task <bool> ComputeHasSuccessfullyLoadedTransitivelyAsync(Solution solution, bool hasSuccessfullyLoaded, CancellationToken cancellationToken) { if (!hasSuccessfullyLoaded) { return(false); } foreach (var projectReference in this.ProjectState.ProjectReferences) { var project = solution.GetProject(projectReference.ProjectId); if (project == null) { return(false); } if (!await solution.HasSuccessfullyLoadedAsync(project, cancellationToken).ConfigureAwait(false)) { return(false); } } return(true); }
private async Task<IProjectMetric> InnerCalculate(Project project, Task<Compilation> compilationTask, Solution solution) { if (project == null) { return null; } var compilation = await compilationTask.ConfigureAwait(false); var metricsTask = _metricsCalculator.Calculate(project, solution); IEnumerable<string> dependencies; if (solution != null) { var dependencyGraph = solution.GetProjectDependencyGraph(); dependencies = dependencyGraph.GetProjectsThatThisProjectTransitivelyDependsOn(project.Id) .Select<ProjectId, Project>(id => solution.GetProject(id)) .SelectMany(x => x.MetadataReferences.Select(y => y.Display).Concat(new[] { x.AssemblyName })); } else { dependencies = project.AllProjectReferences.SelectMany(x => x.Aliases) .Concat(project.MetadataReferences.Select(y => y.Display)); } var assemblyTypes = compilation.Assembly.TypeNames; var metrics = (await metricsTask.ConfigureAwait(false)).AsArray(); var internalTypesUsed = from metric in metrics from coupling in metric.ClassCouplings where coupling.Assembly == project.AssemblyName select coupling; var relationalCohesion = (internalTypesUsed.Count() + 1.0) / assemblyTypes.Count; return new ProjectMetric(project.Name, metrics, dependencies, relationalCohesion); }
private ObjectReference GetObservedCompilation(Solution solution, ProjectId projectId) { var observed = solution.GetProject(projectId).GetCompilationAsync().Result; return new ObjectReference(observed); }
private static bool IsIdentifierValid_Worker(Solution solution, string replacementText, IEnumerable<ProjectId> projectIds, CancellationToken cancellationToken) { foreach (var language in projectIds.Select(p => solution.GetProject(p).Language).Distinct()) { var languageServices = solution.Workspace.Services.GetLanguageServices(language); var renameRewriterLanguageService = languageServices.GetService<IRenameRewriterLanguageService>(); var syntaxFactsLanguageService = languageServices.GetService<ISyntaxFactsService>(); if (!renameRewriterLanguageService.IsIdentifierValid(replacementText, syntaxFactsLanguageService)) { return false; } } return true; }
// Updates all projects to properly reference other existing projects via project references instead of using references to built metadata. private Solution UpdateReferencesAfterAdd(Solution solution) { // Build map from output assembly path to ProjectId // Use explicit loop instead of ToDictionary so we don't throw if multiple projects have same output assembly path. var outputAssemblyToProjectIdMap = new Dictionary<string, ProjectId>(); foreach (var p in solution.Projects) { if (!string.IsNullOrEmpty(p.OutputFilePath)) { outputAssemblyToProjectIdMap[p.OutputFilePath] = p.Id; } } // now fix each project if necessary foreach (var pid in solution.ProjectIds) { var project = solution.GetProject(pid); // convert metadata references to project references if the metadata reference matches some project's output assembly. foreach (var meta in project.MetadataReferences) { var pemeta = meta as PortableExecutableReference; if (pemeta != null) { ProjectId matchingProjectId; // check both Display and FilePath. FilePath points to the actually bits, but Display should match output path if // the metadata reference is shadow copied. if ((!string.IsNullOrEmpty(pemeta.Display) && outputAssemblyToProjectIdMap.TryGetValue(pemeta.Display, out matchingProjectId)) || (!string.IsNullOrEmpty(pemeta.FilePath) && outputAssemblyToProjectIdMap.TryGetValue(pemeta.FilePath, out matchingProjectId))) { var newProjRef = new ProjectReference(matchingProjectId, pemeta.Properties.Aliases, pemeta.Properties.EmbedInteropTypes); if (!project.ProjectReferences.Contains(newProjRef)) { project = project.WithProjectReferences(project.ProjectReferences.Concat(newProjRef)); } project = project.WithMetadataReferences(project.MetadataReferences.Where(mr => mr != meta)); } } } solution = project.Solution; } return solution; }
private static Solution RemoveNonExistingFiles(Solution solution) { foreach (var projectId in solution.ProjectIds.ToArray()) { var project = solution.GetProject(projectId); solution = RemoveNonExistingDocuments(project); project = solution.GetProject(projectId); solution = RemoveNonExistingReferences(project); } return solution; }
private static ImmutableDictionary<Project, ImmutableArray<Diagnostic>> GetProjectDiagnosticsMappedToNewSolution(ImmutableDictionary<Project, ImmutableArray<Diagnostic>> projectDiagnosticsToFixMap, Solution newSolution, string language) { ImmutableDictionary<Project, ImmutableArray<Diagnostic>>.Builder projectDiagsBuilder = null; foreach (var kvp in projectDiagnosticsToFixMap) { if (kvp.Key.Language != language) { continue; } var project = newSolution.GetProject(kvp.Key.Id); if (project != null) { projectDiagsBuilder = projectDiagsBuilder ?? ImmutableDictionary.CreateBuilder<Project, ImmutableArray<Diagnostic>>(); projectDiagsBuilder.Add(project, kvp.Value); } } return projectDiagsBuilder != null ? projectDiagsBuilder.ToImmutable() : ImmutableDictionary<Project, ImmutableArray<Diagnostic>>.Empty; }
/// <summary> /// Add all appropriate references to the compilation and set it as our final compilation /// state. /// </summary> private async Task <CompilationInfo> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { try { // if HasAllInformation is false, then this project is always not completed. bool hasSuccessfullyLoaded = this.ProjectState.HasAllInformation; var newReferences = new List <MetadataReference>(); var metadataReferenceToProjectId = new Dictionary <MetadataReference, ProjectId>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithScriptCompilationInfo( compilation.ScriptCompilationInfo.WithPreviousScriptCompilation(previousSubmissionCompilation)); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // A reference can fail to be created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); metadataReferenceToProjectId.Add(metadataReference, projectReference.ProjectId); } else { hasSuccessfullyLoaded = false; } } } } compilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(compilation, newReferences, metadataReferenceToProjectId); bool hasSuccessfullyLoadedTransitively = !HasMissingReferences(compilation, this.ProjectState.MetadataReferences) && await ComputeHasSuccessfullyLoadedTransitivelyAsync(solution, hasSuccessfullyLoaded, cancellationToken).ConfigureAwait(false); this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasSuccessfullyLoadedTransitively), solution); return(new CompilationInfo(compilation, hasSuccessfullyLoadedTransitively)); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private static Solution DisambiguateSameNameLinkedFiles(Solution solution) { foreach (var projectId in solution.ProjectIds.ToArray()) { var project = solution.GetProject(projectId); solution = DisambiguateSameNameLinkedFiles(project); } return solution; }
/// <summary> /// Tries to get the latest snapshot of the compilation without waiting for it to be /// fully built. This method takes advantage of the progress side-effect produced during /// BuildCompilation. It will either return the already built compilation, any /// in-progress compilation or any known old compilation in that order of preference. /// The compilation state that is returned will have a compilation that is retained so /// that it cannot disappear. /// </summary> private void GetPartialCompilationState( Solution solution, DocumentId id, out ProjectState inProgressProject, out Compilation inProgressCompilation, CancellationToken cancellationToken) { var state = this.ReadState(); inProgressCompilation = state.Compilation.GetValue(cancellationToken); // check whether we can bail out quickly for typing case var inProgressState = state as InProgressState; // all changes left for this document is modifying the given document. // we can use current state as it is since we will replace the document with latest document anyway. if (inProgressState != null && inProgressCompilation != null && inProgressState.IntermediateProjects.All(t => TouchDocumentActionForDocument(t, id))) { inProgressProject = this.ProjectState; return; } inProgressProject = inProgressState != null ? inProgressState.IntermediateProjects.First().Item1 : this.ProjectState; // if we already have a final compilation we are done. if (inProgressCompilation != null && state is FinalState) { return; } // 1) if we have an in-progress compilation use it. // 2) If we don't, then create a simple empty compilation/project. // 3) then, make sure that all it's p2p refs and whatnot are correct. if (inProgressCompilation == null) { inProgressProject = inProgressProject.RemoveAllDocuments(); inProgressCompilation = this.CreateEmptyCompilation(solution); } // first remove all project from the project and compilation. inProgressProject = inProgressProject.WithProjectReferences(ImmutableList.Create<ProjectReference>()); // Now add in back a consistent set of project references. For project references // try to get either a CompilationReference or a SkeletonReference. This ensures // that the in-progress project only reports a reference to another project if it // could actually get a reference to that project's metadata. var metadataReferences = new List<MetadataReference>(); var newProjectReferences = new List<ProjectReference>(); metadataReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); if (referencedProject != null) { if (referencedProject.IsSubmission) { var compilation = solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).WaitAndGetResult(cancellationToken); inProgressCompilation = inProgressCompilation.WithPreviousSubmission(compilation); } else { // get the latest metadata for the partial compilation of the referenced project. var metadata = solution.GetPartialMetadataReference(projectReference, this.ProjectState, cancellationToken); if (metadata == null) { // if we failed to get the metadata, check to see if we previously had existing metadata and reuse it instead. metadata = inProgressCompilation.References.FirstOrDefault(r => solution.GetProjectId(r) == projectReference.ProjectId); } if (metadata != null) { newProjectReferences.Add(projectReference); metadataReferences.Add(metadata); } } } } inProgressProject = inProgressProject.AddProjectReferences(newProjectReferences); if (!Enumerable.SequenceEqual(inProgressCompilation.References, metadataReferences)) { inProgressCompilation = inProgressCompilation.WithReferences(metadataReferences); } }
private Project CreateSubmissionProject(Solution solution) { string name = "Program" + _documentNumber++; ProjectId id = ProjectId.CreateNewId(name); solution = solution.AddProject(ProjectInfo.Create(id, VersionStamp.Create(), name, name, LanguageNames.CSharp, parseOptions: _parseOptions, compilationOptions: _compilationOptions.WithScriptClassName(name), metadataReferences: _references)); //if (_previousProjectId != null) //{ // solution = solution.AddProjectReference(id, new ProjectReference(_previousProjectId)); //} return solution.GetProject(id); }
/// <summary> /// Add all appropriate references to the compilation and set it as our final compilation /// state. /// </summary> private async Task<CompilationInfo> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { try { bool hasCompleteReferences = true; var newReferences = new List<MetadataReference>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithScriptCompilationInfo( compilation.ScriptCompilationInfo.WithPreviousScriptCompilation(previousSubmissionCompilation)); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // A reference can fail to be created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); } else { hasCompleteReferences = false; } } } } if (!Enumerable.SequenceEqual(compilation.ExternalReferences, newReferences)) { compilation = compilation.WithReferences(newReferences); } this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasCompleteReferences), solution); return new CompilationInfo(compilation, hasCompleteReferences); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Tries to get the latest snapshot of the compilation without waiting for it to be /// fully built. This method takes advantage of the progress side-effect produced during /// <see cref="BuildCompilationInfoAsync(Solution, CancellationToken)"/>. It will either return the already built compilation, any /// in-progress compilation or any known old compilation in that order of preference. /// The compilation state that is returned will have a compilation that is retained so /// that it cannot disappear. /// </summary> private void GetPartialCompilationState( Solution solution, DocumentId id, out ProjectState inProgressProject, out Compilation inProgressCompilation, CancellationToken cancellationToken) { var state = this.ReadState(); inProgressCompilation = state.Compilation.GetValue(cancellationToken); // check whether we can bail out quickly for typing case var inProgressState = state as InProgressState; // all changes left for this document is modifying the given document. // we can use current state as it is since we will replace the document with latest document anyway. if (inProgressState != null && inProgressCompilation != null && inProgressState.IntermediateProjects.All(t => IsTouchDocumentActionForDocument(t, id))) { inProgressProject = this.ProjectState; return; } inProgressProject = inProgressState != null?inProgressState.IntermediateProjects.First().Item1 : this.ProjectState; // if we already have a final compilation we are done. if (inProgressCompilation != null && state is FinalState) { return; } // 1) if we have an in-progress compilation use it. // 2) If we don't, then create a simple empty compilation/project. // 3) then, make sure that all it's p2p refs and whatnot are correct. if (inProgressCompilation == null) { inProgressProject = inProgressProject.RemoveAllDocuments(); inProgressCompilation = this.CreateEmptyCompilation(); } // first remove all project from the project and compilation. inProgressProject = inProgressProject.WithProjectReferences(ImmutableArray.Create <ProjectReference>()); // Now add in back a consistent set of project references. For project references // try to get either a CompilationReference or a SkeletonReference. This ensures // that the in-progress project only reports a reference to another project if it // could actually get a reference to that project's metadata. var metadataReferences = new List <MetadataReference>(); var newProjectReferences = new List <ProjectReference>(); metadataReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); if (referencedProject != null) { if (referencedProject.IsSubmission) { var compilation = solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).WaitAndGetResult(cancellationToken); inProgressCompilation = inProgressCompilation.WithScriptCompilationInfo(inProgressCompilation.ScriptCompilationInfo.WithPreviousScriptCompilation(compilation)); } else { // get the latest metadata for the partial compilation of the referenced project. var metadata = solution.GetPartialMetadataReference(projectReference, this.ProjectState, cancellationToken); if (metadata == null) { // if we failed to get the metadata, check to see if we previously had existing metadata and reuse it instead. metadata = inProgressCompilation.References.FirstOrDefault(r => solution.GetProjectId(r) == projectReference.ProjectId); } if (metadata != null) { newProjectReferences.Add(projectReference); metadataReferences.Add(metadata); } } } } inProgressProject = inProgressProject.AddProjectReferences(newProjectReferences); if (!Enumerable.SequenceEqual(inProgressCompilation.References, metadataReferences)) { inProgressCompilation = inProgressCompilation.WithReferences(metadataReferences); } }
/// <summary> /// Remove the added table preprocessor symbol. Don't want that saved into the project /// file as a change. /// </summary> private Solution RemoveTablePreprocessorSymbol(Solution newSolution, Solution oldSolution) { var projectIds = newSolution.ProjectIds; foreach (var projectId in projectIds) { var oldProject = oldSolution.GetProject(projectId); var newProject = newSolution.GetProject(projectId); newSolution = newProject.WithParseOptions(oldProject.ParseOptions).Solution; } return newSolution; }
private Solution AddTablePreprocessorSymbol(Solution solution) { var projectIds = solution.ProjectIds; foreach (var projectId in projectIds) { var project = solution.GetProject(projectId); var parseOptions = project.ParseOptions as CSharpParseOptions; if (parseOptions != null) { var list = new List<string>(); list.AddRange(parseOptions.PreprocessorSymbolNames); list.Add(TablePreprocessorSymbolName); parseOptions = parseOptions.WithPreprocessorSymbols(list); solution = project.WithParseOptions(parseOptions).Solution; } } return solution; }
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)); }
private void ValidateSolutionAndCompilations(Solution solution) { foreach (var project in solution.Projects) { Assert.True(solution.ContainsProject(project.Id), "Solution was expected to have project " + project.Id); Assert.Equal(project, solution.GetProject(project.Id)); // these won't always be unique in real-world but should be for these tests Assert.Equal(project, solution.GetProjectsByName(project.Name).FirstOrDefault()); var compilation = project.GetCompilationAsync().Result; Assert.NotNull(compilation); // check that the options are the same Assert.Equal(project.CompilationOptions, compilation.Options); // check that all known metadata references are present in the compilation foreach (var meta in project.MetadataReferences) { Assert.True(compilation.References.Contains(meta), "Compilation references were expected to contain " + meta); } // check that all project-to-project reference metadata is present in the compilation foreach (var referenced in project.ProjectReferences) { if (solution.ContainsProject(referenced.ProjectId)) { var referencedMetadata = solution.GetMetadataReferenceAsync(referenced, solution.GetProjectState(project.Id), CancellationToken.None).Result; Assert.NotNull(referencedMetadata); var compilationReference = referencedMetadata as CompilationReference; if (compilationReference != null) { compilation.References.Single(r => { var cr = r as CompilationReference; return cr != null && cr.Compilation == compilationReference.Compilation; }); } } } // check that the syntax trees are the same var docs = project.Documents.ToList(); var trees = compilation.SyntaxTrees.ToList(); Assert.Equal(docs.Count, trees.Count); foreach (var doc in docs) { Assert.True(trees.Contains(doc.GetSyntaxTreeAsync().Result), "trees list was expected to contain the syntax tree of doc"); } } }
private static bool TryGetCompilation( ISymbol symbol, Solution solution, out Compilation definingCompilation, CancellationToken cancellationToken) { var definitionProject = solution.GetProject(symbol.ContainingAssembly, cancellationToken); if (definitionProject == null) { definingCompilation = null; return false; } // compilation from definition project must already exist. if (!definitionProject.TryGetCompilation(out definingCompilation)) { Contract.Requires(false, "How can compilation not exist?"); return false; } return true; }
public IEnumerable<Project> GetProjectsWithInstalledPackage(Solution solution, string packageName, string version) { ThisCanBeCalledOnAnyThread(); var result = new List<Project>(); foreach (var kvp in this._projectToInstalledPackageAndVersion) { var installedPackageAndVersion = kvp.Value; if (installedPackageAndVersion != null) { string installedVersion; if (installedPackageAndVersion.TryGetValue(packageName, out installedVersion) && installedVersion == version) { var project = solution.GetProject(kvp.Key); if (project != null) { result.Add(project); } } } } return result; }
internal static async Task<Tuple<ProjectCodeProvider, IMethodSymbol, SyntaxTree>> GetProviderContainingEntryPointAsync(Solution solution, CancellationToken cancellationToken = default(CancellationToken)) { var projectIDs = solution.GetProjectDependencyGraph().GetTopologicallySortedProjects(cancellationToken); var continuations = new BlockingCollection<Task<Tuple<ProjectCodeProvider, IMethodSymbol>>>(); foreach (var projectId in projectIDs) { var project = solution.GetProject(projectId); var pair = await ProjectCodeProvider.GetProviderContainingEntryPointAsync(project); if (pair != null) { return pair; } } //foreach (var continuation in continuations) { // var pair = await continuation; // if (pair != null) // { // return pair; // } //} return null; }
private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(Solution solution, CancellationToken cancellationToken) { try { cancellationToken.ThrowIfCancellationRequested(); using (await this.buildLock.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { var state = this.ReadState(); // we are already in the final stage. just return it. var compilation = state.FinalCompilation.GetValue(cancellationToken); if (compilation != null) { return compilation; } compilation = state.Compilation.GetValue(cancellationToken); if (compilation == null) { // let's see whether we have declaration only compilation if (state.DeclarationOnlyCompilation != null) { // okay, move to full declaration state. do this so that declaration only compilation never // realize symbols. this.WriteState(new FullDeclarationState(this.Retain(solution, state.DeclarationOnlyCompilation))); return state.DeclarationOnlyCompilation; } // We've got nothing. Build it from scratch :( return await BuildDeclarationCompilationFromScratchAsync(solution, cancellationToken).ConfigureAwait(false); } else if (state is FullDeclarationState) { // we have full declaration, just use it. return state.Compilation.GetValue(cancellationToken); } else if (state is InProgressState) { // We have an in progress compilation. Build off of that. return await BuildDeclarationCompilationFromInProgressAsync(solution, state as InProgressState, compilation, cancellationToken).ConfigureAwait(false); } else { throw Contract.Unreachable; } } } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } private async Task<Compilation> GetOrBuildCompilationAsync( Solution solution, bool lockGate, CancellationToken cancellationToken) { try { using (Logger.LogBlock(FunctionId.Workspace_Project_CompilationTracker_BuildCompilationAsync, logBuildCompilationAsync, this.ProjectState, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var state = this.ReadState(); // Try to get the built compilation. If it exists, then we can just return that. var finalCompilation = state.FinalCompilation.GetValue(cancellationToken); if (finalCompilation != null) { return finalCompilation; } // Otherwise, we actually have to build it. Ensure that only one thread is trying to // build this compilation at a time. if (lockGate) { using (await this.buildLock.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { return await BuildCompilationAsync(solution, cancellationToken).ConfigureAwait(false); } } else { return await BuildCompilationAsync(solution, cancellationToken).ConfigureAwait(false); } } } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } /// <summary> /// Builds the compilation matching the project state. In the process of building, also /// produce in progress snapshots that can be accessed from other threads. /// </summary> private Task<Compilation> BuildCompilationAsync( Solution solution, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var state = this.ReadState(); // if we already have a compilation, we must be already done! This can happen if two // threads were waiting to build, and we came in after the other succeeded. var compilation = state.FinalCompilation.GetValue(cancellationToken); if (compilation != null) { return SpecializedTasks.FromResult(compilation); } compilation = state.Compilation.GetValue(cancellationToken); if (compilation == null) { // this can happen if compilation is already kicked out from the cache. // check whether the state we have support declaration only compilation if (state.DeclarationOnlyCompilation != null) { // we have declaration only compilation. build final one from it. return FinalizeCompilationAsync(solution, state.DeclarationOnlyCompilation, cancellationToken); } // We've got nothing. Build it from scratch :( return BuildCompilationFromScratchAsync(solution, state, cancellationToken); } else if (state is FullDeclarationState) { // We have a declaration compilation, use it to reconstruct the final compilation return this.FinalizeCompilationAsync(solution, compilation, cancellationToken); } else if (state is InProgressState) { // We have an in progress compilation. Build off of that. return BuildFinalStateFromInProgressStateAsync(solution, state as InProgressState, compilation, cancellationToken); } else { throw Contract.Unreachable; } } private async Task<Compilation> BuildCompilationFromScratchAsync( Solution solution, State state, CancellationToken cancellationToken) { try { var compilation = await BuildDeclarationCompilationFromScratchAsync(solution, cancellationToken).ConfigureAwait(false); return await FinalizeCompilationAsync(solution, compilation, cancellationToken).ConfigureAwait(false); } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } private async Task<Compilation> BuildDeclarationCompilationFromScratchAsync( Solution solution, CancellationToken cancellationToken) { try { var compilation = CreateEmptyCompilation(solution); foreach (var document in this.ProjectState.OrderedDocumentStates) { cancellationToken.ThrowIfCancellationRequested(); compilation = compilation.AddSyntaxTrees(await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); } this.WriteState(new FullDeclarationState(this.Retain(solution, compilation))); return compilation; } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } private Compilation CreateEmptyCompilation(Solution solution) { var compilationFactory = this.ProjectState.LanguageServices.GetService<ICompilationFactoryService>(); if (this.ProjectState.IsSubmission) { return compilationFactory.CreateSubmissionCompilation( this.ProjectState.AssemblyName, this.ProjectState.CompilationOptions, this.ProjectState.HostObjectType); } else { return compilationFactory.CreateCompilation( this.ProjectState.AssemblyName, this.ProjectState.CompilationOptions); } } private async Task<Compilation> BuildFinalStateFromInProgressStateAsync( Solution solution, InProgressState state, Compilation inProgressCompilation, CancellationToken cancellationToken) { try { var compilation = await BuildDeclarationCompilationFromInProgressAsync(solution, state, inProgressCompilation, cancellationToken).ConfigureAwait(false); return await FinalizeCompilationAsync(solution, compilation, cancellationToken).ConfigureAwait(false); } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } private async Task<Compilation> BuildDeclarationCompilationFromInProgressAsync( Solution solution, InProgressState state, Compilation inProgressCompilation, CancellationToken cancellationToken) { try { Contract.Requires(inProgressCompilation != null); var intermediateProjects = state.IntermediateProjects; while (intermediateProjects.Length > 0) { cancellationToken.ThrowIfCancellationRequested(); var intermediateProject = intermediateProjects[0]; var inProgressProject = intermediateProject.Item1; var action = intermediateProject.Item2; inProgressCompilation = await action.InvokeAsync(inProgressCompilation, cancellationToken).ConfigureAwait(false); intermediateProjects = intermediateProjects.RemoveAt(0); this.WriteState(State.Create( this.Retain(solution, inProgressCompilation), intermediateProjects)); } return inProgressCompilation; } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } // Add all appropriate references to the compilation and set it as our final compilation // state. private async Task<Compilation> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { try { var newReferences = new List<MetadataReference>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithPreviousSubmission(previousSubmissionCompilation); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // The compilation doesn't want to receive a null entry in the set // of references it is constructed with. A reference can fail to be // created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); } } } } if (!Enumerable.SequenceEqual(compilation.References, newReferences)) { compilation = compilation.WithReferences(newReferences); } this.WriteState(new FinalState(this.Retain(solution, compilation))); return compilation; } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } /// <summary> /// Get a metadata reference to this compilation info's compilation with respect to /// another project. For cross language references produce a skeletal assembly. If the /// compilation is not available, it is built. If a skeletal assembly reference is /// needed and does not exist, it is also built. /// </summary> internal async Task<MetadataReference> GetMetadataReferenceAsync( Solution solution, ProjectState fromProject, ProjectReference projectReference, CancellationToken cancellationToken) { try { Compilation compilation; // if we already have the compilation and its right kind then use it. if (this.ProjectState.LanguageServices == fromProject.LanguageServices && this.TryGetCompilation(out compilation)) { return compilation.ToMetadataReference(projectReference.Aliases, projectReference.EmbedInteropTypes); } // If same language then we can wrap the other project's compilation into a compilation reference if (this.ProjectState.LanguageServices == fromProject.LanguageServices) { // otherwise, base it off the compilation by building it first. compilation = await this.GetCompilationAsync(solution, cancellationToken).ConfigureAwait(false); return compilation.ToMetadataReference(projectReference.Aliases, projectReference.EmbedInteropTypes); } else { // otherwise get a metadata only image reference that is built by emitting the metadata from the referenced project's compilation and re-importing it. return await this.GetMetadataOnlyImageReferenceAsync(solution, projectReference, cancellationToken).ConfigureAwait(false); } } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } /// <summary> /// Attempts to get (without waiting) a metadata reference to a possibly in progress /// compilation. Actual compilation references are preferred over skeletal assembly /// references. Could potentially return null if nothing can be provided. /// </summary> internal MetadataReference GetPartialMetadataReference(Solution solution, ProjectState fromProject, ProjectReference projectReference, CancellationToken cancellationToken) { var state = this.ReadState(); // get compilation in any state it happens to be in right now. Compilation compilation; if (state.Compilation.TryGetValue(out compilation) && compilation != null && this.ProjectState.LanguageServices == fromProject.LanguageServices) { // if we have a compilation and its the correct language, use a simple compilation reference return compilation.ToMetadataReference(projectReference.Aliases, projectReference.EmbedInteropTypes); } return null; } /// <summary> /// Gets a metadata reference to the metadata-only-image corresponding to the compilation. /// </summary> private async Task<MetadataReference> GetMetadataOnlyImageReferenceAsync( Solution solution, ProjectReference projectReference, CancellationToken cancellationToken) { try { using (Logger.LogBlock(FunctionId.Workspace_SkeletonAssembly_GetMetadataOnlyImage, cancellationToken)) { var projectId = this.ProjectState.Id; var version = await this.GetDependentSemanticVersionAsync(solution, cancellationToken).ConfigureAwait(false); // get or build compilation up to decleration state. this compilation will be used to provide live xml doc comment var declarationCompilation = await this.GetOrBuildDeclarationCompilationAsync(solution, cancellationToken: cancellationToken).ConfigureAwait(false); MetadataReference reference; if (!MetadataOnlyReference.TryGetReference(solution, projectReference, declarationCompilation, version, out reference)) { // using async build lock so we don't get multiple consumers attempting to build metadata-only images for the same compilation. using (await this.buildLock.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { // okay, we still don't have one. bring the compilation to final state since we are going to use it to create skeleton assembly var compilation = await this.GetOrBuildCompilationAsync(solution, lockGate: false, cancellationToken: cancellationToken).ConfigureAwait(false); reference = MetadataOnlyReference.GetOrBuildReference(solution, projectReference, compilation, version, cancellationToken); } } return reference; } } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } /// <summary> /// Converts a compilation into a ValueSource employing an external compilation retention policy. /// </summary> private ValueSource<Compilation> Retain(Solution solution, Compilation compilation) { var cache = solution.Services.CompilationCacheService; if (cache != null) { return new CachedObjectSource<Compilation>(compilation, cache); } else { return new ConstantValueSource<Compilation>(compilation); } } #region Versions // Dependent Versions are stored on compilation tracker so they are more likely to survive when unrelated solution branching occurs. private AsyncLazy<VersionStamp> lazyDependentVersion; private AsyncLazy<VersionStamp> lazyDependentSemanticVersion; internal async Task<VersionStamp> GetDependentVersionAsync(Solution solution, CancellationToken cancellationToken) { if (this.lazyDependentVersion == null) { // note: solution is captured here, but it will go away once GetValueAsync executes. Interlocked.CompareExchange(ref this.lazyDependentVersion, new AsyncLazy<VersionStamp>(c => ComputeDependentVersionAsync(solution, c), cacheResult: true), null); } return await this.lazyDependentVersion.GetValueAsync(cancellationToken).ConfigureAwait(false); }
private static async Task<Uri> GetAssemblyFullPathAsync(IAssemblySymbol containingAssembly, Solution solution, CancellationToken cancellationToken) { if (containingAssembly == null) { return null; } Project foundProject = solution.GetProject(containingAssembly, cancellationToken); if (foundProject != null) { var workspace = solution.Workspace as VisualStudioWorkspaceImpl; if (workspace != null) { var vsProject = workspace.ProjectTracker.GetProject(foundProject.Id); if (vsProject != null) { var output = vsProject.BinOutputPath; if (!string.IsNullOrWhiteSpace(output)) { return new Uri(output, UriKind.RelativeOrAbsolute); } } return null; } } else { // This symbol is not present in the source code, we need to resolve it from the references! // If a MetadataReference returned by Compilation.GetMetadataReference(AssemblySymbol) has a path, we could use it. foreach (var project in solution.Projects) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (compilation != null) { var reference = compilation.GetMetadataReference(containingAssembly) as PortableExecutableReference; if (reference != null && !string.IsNullOrEmpty(reference.FilePath)) { return new Uri(reference.FilePath, UriKind.RelativeOrAbsolute); } } } } // If we are not in VS, return project.OutputFilePath as a reasonable fallback. // For an example, it could be AdhocWorkspace for unit tests. if (foundProject != null && !string.IsNullOrEmpty(foundProject.OutputFilePath)) { return new Uri(foundProject.OutputFilePath, UriKind.Absolute); } return null; }
/// <summary> /// Add all appropriate references to the compilation and set it as our final compilation /// state. /// </summary> private async Task <CompilationInfo> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { try { bool hasCompleteReferences = true; var newReferences = new List <MetadataReference>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithScriptCompilationInfo( compilation.ScriptCompilationInfo.WithPreviousScriptCompilation(previousSubmissionCompilation)); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // A reference can fail to be created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); } else { hasCompleteReferences = false; } } } } if (!Enumerable.SequenceEqual(compilation.References, newReferences)) { compilation = compilation.WithReferences(newReferences); } this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasCompleteReferences), solution); return(new CompilationInfo(compilation, hasCompleteReferences)); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Add all appropriate references to the compilation and set it as our final compilation /// state. /// </summary> private async Task<CompilationInfo> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { try { // if HasAllInformation is false, then this project is always not completed. bool hasSuccessfullyLoaded = this.ProjectState.HasAllInformation; var newReferences = new List<MetadataReference>(); var metadataReferenceToProjectId = new Dictionary<MetadataReference, ProjectId>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithScriptCompilationInfo( compilation.ScriptCompilationInfo.WithPreviousScriptCompilation(previousSubmissionCompilation)); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // A reference can fail to be created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); metadataReferenceToProjectId.Add(metadataReference, projectReference.ProjectId); } else { hasSuccessfullyLoaded = false; } } } } compilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(compilation, newReferences, metadataReferenceToProjectId); bool hasSuccessfullyLoadedTransitively = !HasMissingReferences(compilation, this.ProjectState.MetadataReferences) && await ComputeHasSuccessfullyLoadedTransitivelyAsync(solution, hasSuccessfullyLoaded, cancellationToken).ConfigureAwait(false); this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasSuccessfullyLoadedTransitively), solution); return new CompilationInfo(compilation, hasSuccessfullyLoadedTransitively); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
// Add all appropriate references to the compilation and set it as our final compilation // state. private async Task<Compilation> FinalizeCompilationAsync( Solution solution, Compilation compilation, CancellationToken cancellationToken) { var newReferences = new List<MetadataReference>(); newReferences.AddRange(this.ProjectState.MetadataReferences); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProject(projectReference.ProjectId); // Even though we're creating a final compilation (vs. an in progress compilation), // it's possible that the target project has been removed. if (referencedProject != null) { // If both projects are submissions, we'll count this as a previous submission link // instead of a regular metadata reference if (referencedProject.IsSubmission) { // if the referenced project is a submission project must be a submission as well: Debug.Assert(this.ProjectState.IsSubmission); var previousSubmissionCompilation = await solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).ConfigureAwait(false); compilation = compilation.WithPreviousSubmission(previousSubmissionCompilation); } else { var metadataReference = await solution.GetMetadataReferenceAsync( projectReference, this.ProjectState, cancellationToken).ConfigureAwait(false); // The compilation doesn't want to receive a null entry in the set // of references it is constructed with. A reference can fail to be // created if a skeleton assembly could not be constructed. if (metadataReference != null) { newReferences.Add(metadataReference); } } } } if (!Enumerable.SequenceEqual(compilation.References, newReferences)) { compilation = compilation.WithReferences(newReferences); } this.WriteState(new FinalState(this.Retain(solution, compilation))); return compilation; }
private async Task<bool> ComputeHasSuccessfullyLoadedTransitivelyAsync(Solution solution, bool hasSuccessfullyLoaded, CancellationToken cancellationToken) { if (!hasSuccessfullyLoaded) { return false; } foreach (var projectReference in this.ProjectState.ProjectReferences) { var project = solution.GetProject(projectReference.ProjectId); if (project == null) { return false; } if (!await solution.HasSuccessfullyLoadedAsync(project, cancellationToken).ConfigureAwait(false)) { return false; } } return true; }