diff options
author | Sandy Armstrong <sandy@xamarin.com> | 2019-09-06 23:00:22 +0300 |
---|---|---|
committer | Sandy Armstrong <sandy@xamarin.com> | 2019-09-06 23:09:31 +0300 |
commit | baf6a8bc9bd330f82922781f4bc3106339ff1eee (patch) | |
tree | fd0af7fab448274d0398e1ae150da818a8e5447c /main/src/core/MonoDevelop.Ide | |
parent | 17110c9d48c095eef52c97673d5d3ef8e1bc46a4 (diff) |
Workspace: Prevent DocumentIds from changing on configuration change
It's possible for events like device (dis)connect to make several quick
calls to `ActiveConfigurationChanged`, some of which would be canceled,
ultimately causing old `DocumentId` data to get lost during project
reload.
Creating new `DocumentId`s could break multiple Roslyn services such as
intellisense. This change makes the whole process more robust so that
`DocumentId` data does not get lost.
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/915494
Diffstat (limited to 'main/src/core/MonoDevelop.Ide')
3 files changed, 41 insertions, 10 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs index 3d62435d25..52d2088c81 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs @@ -46,11 +46,17 @@ namespace MonoDevelop.Ide.TypeSystem this.projectId = projectId; workspaceRef = new WeakReference<MonoDevelopWorkspace> (ws); DocumentData = new DocumentMap (projectId); - this.metadataReferences = new List<MonoDevelopMetadataReference> (metadataReferences.Length); + this.metadataReferences = new List<MonoDevelopMetadataReference> (metadataReferences); + } + + internal void Connect () + { + if (!workspaceRef.TryGetTarget (out var ws)) + return; - lock (this.metadataReferences) { + lock (metadataReferences) { foreach (var metadataReference in metadataReferences) { - AddMetadataReference_NoLock (metadataReference, ws); + metadataReference.SnapshotUpdated += OnMetadataReferenceUpdated; } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs index bd6fedc593..a9a7bd2d5d 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs @@ -202,14 +202,33 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal ProjectData CreateData (ProjectId id, ImmutableArray<MonoDevelopMetadataReference> metadataReferences) + /// <summary> + /// Construct, connect to, and return a new <see cref="ProjectData"/> based on + /// <paramref name="metadataReferences"/>. This replaces any old <see cref="ProjectData"/> for + /// <paramref name="id"/>. + /// </summary> + internal ProjectData ReplaceData (ProjectId id, ImmutableArray<MonoDevelopMetadataReference> metadataReferences, out ProjectData oldData) + { + var result = new ProjectData (id, metadataReferences, Workspace); + ReplaceData (id, result, out oldData); + return result; + } + + /// <summary> + /// Remove the old <see cref="ProjectData"/> for <paramref name="id"/>, replace it with + /// <paramref name="newData"/>, and and connect to <paramref name="newData"/>. + /// </summary> + internal void ReplaceData (ProjectId id, ProjectData newData, out ProjectData oldData) { lock (updatingProjectDataLock) { - var result = new ProjectData (id, metadataReferences, Workspace); - projectDataMap [id] = result; - return result; + oldData = RemoveData (id); + if (newData != null) { + newData.Connect (); + projectDataMap [id] = newData; + } } } + internal ProjectId[] GetProjectIds () { lock (updatingProjectDataLock) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs index 2399816b3b..b2446f8ac2 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs @@ -144,12 +144,14 @@ namespace MonoDevelop.Ide.TypeSystem try { await workspace.LoadLock.WaitAsync ().ConfigureAwait (false); //when reloading e.g. after a save, preserve document IDs - oldProjectData = projectMap.RemoveData (projectId); - projectData = projectMap.CreateData (projectId, cacheInfo.References); + projectData = projectMap.ReplaceData (projectId, cacheInfo.References, out oldProjectData); var documents = await CreateDocuments (projectData, p, token, cacheInfo.SourceFiles, oldProjectData).ConfigureAwait (false); - if (documents == null) + if (documents == null) { + // Restore old document data if cancellation happens here. + projectMap.ReplaceData (projectId, oldProjectData, out _); return null; + } mainDocuments = documents.Item1; additionalDocuments = documents.Item2; @@ -157,6 +159,10 @@ namespace MonoDevelop.Ide.TypeSystem workspace.LoadLock.Release (); } + if (token.IsCancellationRequested || mainDocuments == null) { + return null; + } + // TODO: Pass in the WorkspaceMetadataFileReferenceResolver var info = ProjectInfo.Create ( projectId, |