Example #1
0
        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);
 }
Example #5
0
        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);
        }
Example #6
0
 private ImmutableDictionary<string, ImmutableArray<DocumentId>> CreateLinkedFilesMapWithRemovedProject(ProjectState projectState)
 {
     return CreateLinkedFilesMapWithRemovedDocuments(projectState, projectState.DocumentIds);
 }
Example #7
0
        /// <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);
        }
Example #8
0
        /// <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);
        }
Example #9
0
 /// <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;
 }
Example #10
0
            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();
            }
Example #11
0
 public ReplaceAllSyntaxTreesAction(ProjectState state)
 {
     _state = state;
 }
Example #12
0
 public WorkspaceAnalyzerConfigOptionsProvider(ProjectState projectState)
 {
     _projectState = projectState;
 }
Example #13
0
 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);
                }
            }
Example #17
0
            /// <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);
            }
Example #18
0
        /// <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;
        }
Example #19
0
 public static bool IsSameLanguage(ProjectState project1, ProjectState project2)
 {
     return project1.LanguageServices == project2.LanguageServices;
 }
Example #20
0
        /// <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);
        }
Example #21
0
 /// <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>();
 }
Example #22
0
        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;
        }
Example #23
0
 /// <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;
     }
 }
Example #24
0
        /// <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;
        }
Example #25
0
        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!
        }
Example #26
0
        /// <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;
        }
Example #27
0
        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();
        }
Example #28
0
        /// <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;
            }
        }
Example #29
0
        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>
 /// 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)
 {
 }
            /// <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);
                }
            }
Example #36
0
 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);
            }
Example #38
0
        /// <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);
 }
Example #40
0
 private static SourceCodeKind GetSourceCodeKind(ProjectState project)
 {
     return(project.ParseOptions != null ? project.ParseOptions.Kind : SourceCodeKind.Regular);
 }