internal Project(Solution solution, ProjectState projectState) { Contract.ThrowIfNull(solution); Contract.ThrowIfNull(projectState); _solution = solution; _projectState = projectState; }
private CompilationTracker( ProjectState project, State state) { Contract.ThrowIfNull(project); this.ProjectState = project; this.stateDoNotAccessDirectly = state; }
// Hand out the same compilation reference for everyone who asks. Use // WeakReference<Compilation> so that if no one is using the MetadataReference, // it can be collected. internal static Compilation GetCompilationForMetadataReference(ProjectState projectState, Compilation compilation) { var weakReference = s_compilationReferenceMap.GetValue(projectState, s_createValue); Compilation reference; lock (s_guard) { if (!weakReference.TryGetTarget(out reference)) { reference = compilation.Clone(); // drop all existing symbols weakReference.SetTarget(reference); } } return reference; }
private static string LogBuildCompilationAsync(ProjectState state) { return string.Join(",", state.AssemblyName, state.DocumentIds.Count); }
private static async Task<Compilation> ReplaceSyntaxTreesWithTreesFromNewProjectStateAsync(Compilation compilation, ProjectState projectState, CancellationToken cancellationToken) { var syntaxTrees = new List<SyntaxTree>(capacity: projectState.DocumentIds.Count); foreach (var documentState in projectState.OrderedDocumentStates) { cancellationToken.ThrowIfCancellationRequested(); syntaxTrees.Add(await documentState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); } return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(syntaxTrees); }
private ImmutableDictionary<string, ImmutableArray<DocumentId>> CreateLinkedFilesMapWithRemovedProject(ProjectState projectState) { return CreateLinkedFilesMapWithRemovedDocuments(projectState, projectState.DocumentIds); }
/// <summary> /// Create a new solution instance that includes a project with the specified project information. /// </summary> public SolutionState AddProject(ProjectInfo projectInfo) { if (projectInfo == null) { throw new ArgumentNullException(nameof(projectInfo)); } var projectId = projectInfo.Id; var language = projectInfo.Language; if (language == null) { throw new ArgumentNullException(nameof(language)); } var displayName = projectInfo.Name; if (displayName == null) { throw new ArgumentNullException(nameof(displayName)); } CheckNotContainsProject(projectId); var languageServices = this.Workspace.Services.GetLanguageServices(language); if (languageServices == null) { throw new ArgumentException(string.Format(WorkspacesResources.The_language_0_is_not_supported, language)); } var newProject = new ProjectState(projectInfo, languageServices, _solutionServices); return this.AddProject(newProject.Id, newProject); }
/// <summary> /// Attempt to get the best readily available compilation for the project. It may be a /// partially built compilation. /// </summary> private MetadataReference GetPartialMetadataReference( ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { // Try to get the compilation state for this project. If it doesn't exist, don't do any // more work. CompilationTracker state; if (!_projectIdToTrackerMap.TryGetValue(projectReference.ProjectId, out state)) { return null; } return state.GetPartialMetadataReference(this, fromProject, projectReference, cancellationToken); }
/// <summary> /// Return reference completeness for the given project and all projects this references. /// </summary> public Task<bool> HasSuccessfullyLoadedAsync(ProjectState project, CancellationToken cancellationToken) { // return HasAllInformation when compilation is not supported. // regardless whether project support compilation or not, if projectInfo is not complete, we can't gurantee its reference completeness return project.SupportsCompilation ? this.GetCompilationTracker(project.Id).HasSuccessfullyLoadedAsync(this, cancellationToken) : project.HasAllInformation ? SpecializedTasks.True : SpecializedTasks.False; }
private void GetPartialCompilationState( SolutionState solution, DocumentId id, out ProjectState inProgressProject, out Compilation inProgressCompilation, CancellationToken cancellationToken) { var state = ReadState(); var compilation = state.Compilation?.GetValueOrNull(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 && compilation != null && inProgressState.IntermediateProjects.All(t => IsTouchDocumentActionForDocument(t.action, id))) { inProgressProject = ProjectState; inProgressCompilation = compilation; SolutionLogger.UseExistingPartialProjectState(); return; } inProgressProject = inProgressState != null?inProgressState.IntermediateProjects.First().state : this.ProjectState; // if we already have a final compilation we are done. if (compilation != null && state is FinalState) { inProgressCompilation = compilation; SolutionLogger.UseExistingFullProjectState(); 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 (compilation == null) { inProgressProject = inProgressProject.RemoveAllDocuments(); inProgressCompilation = CreateEmptyCompilation(); } else { inProgressCompilation = compilation; } // 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); var metadataReferenceToProjectId = new Dictionary <MetadataReference, ProjectId>(); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProjectState(projectReference.ProjectId); if (referencedProject != null) { if (referencedProject.IsSubmission) { var previousScriptCompilation = solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).WaitAndGetResult(cancellationToken); // previous submission project must support compilation: RoslynDebug.Assert(previousScriptCompilation != null); inProgressCompilation = inProgressCompilation.WithScriptCompilationInfo(inProgressCompilation.ScriptCompilationInfo !.WithPreviousScriptCompilation(previousScriptCompilation)); } else { // get the latest metadata for the partial compilation of the referenced project. var metadata = solution.GetPartialMetadataReference(projectReference, this.ProjectState); if (metadata == null) { // if we failed to get the metadata, check to see if we previously had existing metadata and reuse it instead. var inProgressCompilationNotRef = inProgressCompilation; metadata = inProgressCompilationNotRef.ExternalReferences.FirstOrDefault( r => solution.GetProjectState(inProgressCompilationNotRef.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol)?.Id == projectReference.ProjectId); } if (metadata != null) { newProjectReferences.Add(projectReference); metadataReferences.Add(metadata); metadataReferenceToProjectId.Add(metadata, projectReference.ProjectId); } } } } inProgressProject = inProgressProject.AddProjectReferences(newProjectReferences); inProgressCompilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(inProgressCompilation, metadataReferences, metadataReferenceToProjectId); SolutionLogger.CreatePartialProjectState(); }
public ReplaceAllSyntaxTreesAction(ProjectState state) { _state = state; }
public WorkspaceAnalyzerConfigOptionsProvider(ProjectState projectState) { _projectState = projectState; }
public static bool IsSameLanguage(ProjectState project1, ProjectState project2) { return(project1.LanguageServices == project2.LanguageServices); }
/// <summary> /// Creates a tracker for the provided project. The tracker will be in the 'empty' state /// and will have no extra information beyond the project itself. /// </summary> public CompilationTracker(ProjectState project) : this(project, State.Empty) { }
private static string LogBuildCompilationAsync(ProjectState state) { return(string.Join(",", state.AssemblyName, state.DocumentIds.Count)); }
/// <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(); } // 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.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); } }
/// <summary> /// Attempts to get (without waiting) a metadata reference to a possibly in progress /// compilation. Only actual compilation references are returned. Could potentially /// return null if nothing can be provided. /// </summary> public MetadataReference GetPartialMetadataReference(SolutionState solution, ProjectState fromProject, ProjectReference projectReference, CancellationToken cancellationToken) { var state = this.ReadState(); // get compilation in any state it happens to be in right now. if (state.Compilation.TryGetValue(out var 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> /// Get a metadata reference for the project's compilation /// </summary> internal async Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { try { // Get the compilation state for this project. If it's not already created, then this // will create it. Then force that state to completion and get a metadata reference to it. var tracker = this.GetCompilationTracker(projectReference.ProjectId); var mdref = await tracker.GetMetadataReferenceAsync(this, fromProject, projectReference, cancellationToken).ConfigureAwait(false); if (mdref != null) { RecordReferencedProject(mdref, projectReference.ProjectId); } return mdref; } catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } /// <summary> /// Attempt to get the best readily available compilation for the project. It may be a /// partially built compilation. /// </summary> internal MetadataReference GetPartialMetadataReference( ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { // Try to get the compilation state for this project. If it doesn't exist, don't do any // more work. CompilationTracker state; if (!this.projectIdToTrackerMap.TryGetValue(projectReference.ProjectId, out state)) { return null; } var mdref = state.GetPartialMetadataReference(this, fromProject, projectReference, cancellationToken); if (mdref != null) { RecordReferencedProject(mdref, projectReference.ProjectId); } return mdref; }
public static bool IsSameLanguage(ProjectState project1, ProjectState project2) { return project1.LanguageServices == project2.LanguageServices; }
/// <summary> /// Creates a new snapshot with an updated project and an action that will produce a new /// compilation matching the new project out of an old compilation. All dependent projects /// are fixed-up if the change to the new project affects its public metadata, and old /// dependent compilations are forgotten. /// </summary> private Solution ForkProject( ProjectState newProjectState, CompilationTranslationAction translate = null, bool withProjectReferenceChange = false, bool withDocumentListChange = false) { // make sure we are getting only known translate actions CompilationTranslationAction.CheckKnownActions(translate); var projectId = newProjectState.Id; var newStateMap = this.projectIdToProjectStateMap.SetItem(projectId, newProjectState); var newDependencyGraph = withProjectReferenceChange ? CreateDependencyGraph(this.projectIds, newStateMap) : this.dependencyGraph; var newTrackerMap = CreateCompilationTrackerMap(projectId, newDependencyGraph); var newLinkedFilesMap = withDocumentListChange ? CreateLinkedFilesMapWithChangedProject(projectIdToProjectStateMap[projectId], newProjectState) : this.linkedFilesMap; // If we have a tracker for this project, then fork it as well (along with the // translation action and store it in the tracker map. CompilationTracker state; if (newTrackerMap.TryGetValue(projectId, out state)) { newTrackerMap = newTrackerMap.Remove(projectId).Add(projectId, state.Fork(newProjectState, translate)); } var modifiedDocumentOnly = translate is CompilationTranslationAction.TouchDocumentAction; var newLatestProjectVersion = modifiedDocumentOnly ? this.lazyLatestProjectVersion : new Lazy<VersionStamp>(() => newProjectState.Version); return this.Branch( idToProjectStateMap: newStateMap, projectIdToTrackerMap: newTrackerMap, dependencyGraph: newDependencyGraph, linkedFilesMap: newLinkedFilesMap, lazyLatestProjectVersion: newLatestProjectVersion); }
/// <summary> /// Returns the compilation for the specified <see cref="ProjectState"/>. Can return <code>null</code> when the project /// does not support compilations. /// </summary> public Task<Compilation> GetCompilationAsync(ProjectState project, CancellationToken cancellationToken) { return project.SupportsCompilation ? this.GetCompilationTracker(project.Id).GetCompilationAsync(this, cancellationToken) : SpecializedTasks.Default<Compilation>(); }
private ImmutableDictionary<string, ImmutableArray<DocumentId>> CreateLinkedFilesMapWithChangedProject(ProjectState oldProjectState, ProjectState newProjectState) { var oldDocumentIds = oldProjectState.DocumentIds; var newDocumentIds = newProjectState.DocumentIds; var addedDocumentIds = newDocumentIds.ToImmutableArray().RemoveRange(oldDocumentIds); var removedDocumentIds = oldDocumentIds.ToImmutableArray().RemoveRange(newDocumentIds); Debug.Assert(addedDocumentIds.Any() || removedDocumentIds.Any(), "The solution's linkedFilesMap should only be recalculated if its files changed."); var linkedFilesMap = this.linkedFilesMap; linkedFilesMap = addedDocumentIds.Any() ? CreateLinkedFilesMapWithAddedDocuments(newProjectState, addedDocumentIds) : linkedFilesMap; linkedFilesMap = removedDocumentIds.Any() ? CreateLinkedFilesMapWithRemovedDocuments(oldProjectState, removedDocumentIds) : linkedFilesMap; return linkedFilesMap; }
/// <summary> /// Get a metadata reference for the project's compilation /// </summary> public Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { try { // Get the compilation state for this project. If it's not already created, then this // will create it. Then force that state to completion and get a metadata reference to it. var tracker = this.GetCompilationTracker(projectReference.ProjectId); return tracker.GetMetadataReferenceAsync(this, fromProject, projectReference, cancellationToken); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Get a metadata reference for the project's compilation /// </summary> internal async Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { // Get the compilation state for this project. If it's not already created, then this // will create it. Then force that state to completion and get a metadata reference to it. var tracker = this.GetCompilationTracker(projectReference.ProjectId); var mdref = await tracker.GetMetadataReferenceAsync(this, fromProject, projectReference, cancellationToken).ConfigureAwait(false); if (mdref != null) { RecordReferencedProject(mdref, projectReference.ProjectId); } return mdref; }
private SolutionState AddProject(ProjectId projectId, ProjectState projectState) { var newProjectIds = _projectIds.ToImmutableArray().Add(projectId); var newStateMap = _projectIdToProjectStateMap.Add(projectId, projectState); var newDependencyGraph = CreateDependencyGraph(newProjectIds, newStateMap); var newTrackerMap = CreateCompilationTrackerMap(projectId, newDependencyGraph); var newLinkedFilesMap = CreateLinkedFilesMapWithAddedProject(newStateMap[projectId]); return this.Branch( projectIds: newProjectIds, idToProjectStateMap: newStateMap, projectIdToTrackerMap: newTrackerMap, linkedFilesMap: newLinkedFilesMap, dependencyGraph: newDependencyGraph, version: this.Version.GetNewerVersion(), // changed project list so, increment version. lazyLatestProjectVersion: new Lazy<VersionStamp>(() => projectState.Version)); // this is the newest! }
/// <summary> /// Attempt to get the best readily available compilation for the project. It may be a /// partially built compilation. /// </summary> internal MetadataReference GetPartialMetadataReference( ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { // Try to get the compilation state for this project. If it doesn't exist, don't do any // more work. CompilationTracker state; if (!this.projectIdToTrackerMap.TryGetValue(projectReference.ProjectId, out state)) { return null; } var mdref = state.GetPartialMetadataReference(this, fromProject, projectReference, cancellationToken); if (mdref != null) { RecordReferencedProject(mdref, projectReference.ProjectId); } return mdref; }
private ImmutableDictionary<string, ImmutableArray<DocumentId>> CreateLinkedFilesMapWithAddedDocuments(ProjectState projectState, IEnumerable<DocumentId> documentIds) { var builder = _linkedFilesMap.ToBuilder(); foreach (var documentId in documentIds) { var filePath = projectState.GetDocumentState(documentId).FilePath; if (string.IsNullOrEmpty(filePath)) { continue; } ImmutableArray<DocumentId> documentIdsWithPath; builder[filePath] = builder.TryGetValue(filePath, out documentIdsWithPath) ? documentIdsWithPath.Add(documentId) : ImmutableArray.Create(documentId); } return builder.ToImmutable(); }
/// <summary> /// Get a metadata reference for the project's compilation /// </summary> internal async Task<MetadataReference> GetMetadataReferenceAsync(ProjectReference projectReference, ProjectState fromProject, CancellationToken cancellationToken) { try { // Get the compilation state for this project. If it's not already created, then this // will create it. Then force that state to completion and get a metadata reference to it. var tracker = this.GetCompilationTracker(projectReference.ProjectId); var mdref = await tracker.GetMetadataReferenceAsync(this, fromProject, projectReference, cancellationToken).ConfigureAwait(false); if (mdref != null) { RecordReferencedProject(mdref, projectReference.ProjectId); } return mdref; } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private ImmutableDictionary<string, ImmutableArray<DocumentId>> CreateLinkedFilesMapWithRemovedDocuments( ProjectState projectState, IEnumerable<DocumentId> documentIds) { var builder = _linkedFilesMap.ToBuilder(); foreach (var documentId in documentIds) { var filePath = projectState.GetDocumentState(documentId).FilePath; if (string.IsNullOrEmpty(filePath)) { continue; } ImmutableArray<DocumentId> documentIdsWithPath; if (!builder.TryGetValue(filePath, out documentIdsWithPath) || !documentIdsWithPath.Contains(documentId)) { throw new ArgumentException("The given documentId was not found in the linkedFilesMap."); } if (documentIdsWithPath.Length == 1) { builder.Remove(filePath); } else { builder[filePath] = documentIdsWithPath.Remove(documentId); } } return builder.ToImmutable(); }
/// <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); } }
/// <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> /// 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> public async Task<MetadataReference> GetMetadataReferenceAsync( SolutionState solution, ProjectState fromProject, ProjectReference projectReference, CancellationToken cancellationToken) { try { // if we already have the compilation and its right kind then use it. if (this.ProjectState.LanguageServices == fromProject.LanguageServices && this.TryGetCompilation(out var 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) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public static CompilationTranslationAction ProjectParseOptions(ProjectState state) { return(new ProjectParseOptionsAction(state)); }
/// <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) { 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); } }
private static SourceCodeKind GetSourceCodeKind(ProjectState project) { return project.ParseOptions != null ? project.ParseOptions.Kind : SourceCodeKind.Regular; }
/// <summary> /// Creates a new instance of the compilation info, retaining any already built /// compilation state as the now 'old' state /// </summary> public CompilationTracker Fork( ProjectState newProject, CompilationTranslationAction translate = null, CancellationToken cancellationToken = default(CancellationToken), bool clone = false) { var state = this.ReadState(); ValueSource<Compilation> baseCompilationSource = state.Compilation; var baseCompilation = baseCompilationSource.GetValue(cancellationToken); if (baseCompilation != null) { // We have some pre-calculated state to incrementally update var newInProgressCompilationSource = clone ? new WeakConstantValueSource<Compilation>(baseCompilation.Clone()) : baseCompilationSource; var intermediateProjects = state is InProgressState ? ((InProgressState)state).IntermediateProjects : ImmutableList.Create<ValueTuple<ProjectState, CompilationTranslationAction>>(); var newIntermediateProjects = translate == null ? intermediateProjects : intermediateProjects.Add(ValueTuple.Create(this.ProjectState, translate)); var newState = State.Create(newInProgressCompilationSource, newIntermediateProjects); return new CompilationTracker(newProject, newState); } var declarationOnlyCompilation = state.DeclarationOnlyCompilation; if (declarationOnlyCompilation != null) { if (translate != null) { var compilationSource = clone ? (ValueSource<Compilation>)new WeakConstantValueSource<Compilation>(declarationOnlyCompilation) : (ValueSource<Compilation>)new ConstantValueSource<Compilation>(declarationOnlyCompilation); var intermediateProjects = ImmutableList.Create<ValueTuple<ProjectState, CompilationTranslationAction>>(ValueTuple.Create(this.ProjectState, translate)); return new CompilationTracker(newProject, new InProgressState(compilationSource, intermediateProjects)); } return new CompilationTracker(newProject, new LightDeclarationState(declarationOnlyCompilation)); } // We have nothing. Just make a tracker that only points to the new project. We'll have // to rebuild its compilation from scratch if anyone asks for it. return new CompilationTracker(newProject); }
/// <summary> /// Creates a new snapshot with an updated project and an action that will produce a new /// compilation matching the new project out of an old compilation. All dependent projects /// are fixed-up if the change to the new project affects its public metadata, and old /// dependent compilations are forgotten. /// </summary> private SolutionState ForkProject( ProjectState newProjectState, CompilationTranslationAction translate = null, bool withProjectReferenceChange = false, ImmutableDictionary<string, ImmutableArray<DocumentId>> newLinkedFilesMap = null, bool forkTracker = true) { var projectId = newProjectState.Id; var newStateMap = _projectIdToProjectStateMap.SetItem(projectId, newProjectState); var newDependencyGraph = withProjectReferenceChange ? CreateDependencyGraph(_projectIds, newStateMap) : _dependencyGraph; var newTrackerMap = CreateCompilationTrackerMap(projectId, newDependencyGraph); // If we have a tracker for this project, then fork it as well (along with the // translation action and store it in the tracker map. CompilationTracker tracker; if (newTrackerMap.TryGetValue(projectId, out tracker)) { newTrackerMap = newTrackerMap.Remove(projectId); if (forkTracker) { newTrackerMap = newTrackerMap.Add(projectId, tracker.Fork(newProjectState, translate)); } } var modifiedDocumentOnly = translate is CompilationTranslationAction.TouchDocumentAction; var newLatestProjectVersion = modifiedDocumentOnly ? _lazyLatestProjectVersion : new Lazy<VersionStamp>(() => newProjectState.Version); return this.Branch( idToProjectStateMap: newStateMap, projectIdToTrackerMap: newTrackerMap, dependencyGraph: newDependencyGraph, linkedFilesMap: newLinkedFilesMap ?? _linkedFilesMap, lazyLatestProjectVersion: newLatestProjectVersion); }
public static CompilationTranslationAction ProjectParseOptions(ProjectState state) { return new ProjectParseOptionsAction(state); }
private static SourceCodeKind GetSourceCodeKind(ProjectState project) { return(project.ParseOptions != null ? project.ParseOptions.Kind : SourceCodeKind.Regular); }