Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandy Armstrong <sandy@xamarin.com>2019-09-06 23:00:22 +0300
committerSandy Armstrong <sandy@xamarin.com>2019-09-06 23:09:31 +0300
commitbaf6a8bc9bd330f82922781f4bc3106339ff1eee (patch)
treefd0af7fab448274d0398e1ae150da818a8e5447c /main/src/core/MonoDevelop.Ide
parent17110c9d48c095eef52c97673d5d3ef8e1bc46a4 (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')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs12
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs27
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs12
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,