From cb86fde105aecedb879baba82665fcaff713c9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Karlas=CC=8C?= Date: Tue, 10 Apr 2018 09:14:04 +0200 Subject: Fix 594883: Goto Declaration is not available when creating an Android project Main fix for this bug is in `LoadProject` method, problem was that if multiple calls to `LoadProject` were made, 1st call called `GetProjectData` and `CreateProjectData` and when second call called `GetProjectData` to set `oldProjectData` it was empty because 1st call didn't call `CreateDocuments` yet, resulting in `documentIdMap` being empty, hence documentIds were totally different after project reload, causing issues with GoToDefinition command... While working on this I also noticed that OnProjectModified is called ~10 times when restoring NuGets for Android project and none of this is canceled, in theory it could happen that older version finishes after latest version and cause project references list to be outdated, hence I added logic to cancel old requests... --- .../MonoDevelopWorkspace.cs | 64 +++++++++++++--------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'main/src/core') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs index 1378da5b17..6397d0370f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs @@ -65,6 +65,7 @@ namespace MonoDevelop.Ide.TypeSystem readonly MonoDevelop.Projects.Solution monoDevelopSolution; object addLock = new object(); bool added; + object updatingProjectDataLock = new object (); public MonoDevelop.Projects.Solution MonoDevelopSolution { get { @@ -470,10 +471,6 @@ namespace MonoDevelop.Ide.TypeSystem var projectId = GetOrCreateProjectId (p); - //when reloading e.g. after a save, preserve document IDs - var oldProjectData = GetProjectData (projectId); - var projectData = CreateProjectData (projectId); - var references = await CreateMetadataReferences (p, projectId, token).ConfigureAwait (false); if (token.IsCancellationRequested) return null; @@ -485,29 +482,39 @@ namespace MonoDevelop.Ide.TypeSystem if (fileName.IsNullOrEmpty) fileName = new FilePath (p.Name + ".dll"); + var projectReferences = await CreateProjectReferences (p, token); if (token.IsCancellationRequested) return null; + var sourceFiles = await p.GetSourceFilesAsync (config != null ? config.Selector : null).ConfigureAwait (false); - var documents = CreateDocuments (projectData, p, token, sourceFiles, oldProjectData); - if (documents == null) + if (token.IsCancellationRequested) return null; - var info = ProjectInfo.Create ( - projectId, - VersionStamp.Create (), - p.Name, - fileName.FileNameWithoutExtension, - LanguageNames.CSharp, - p.FileName, - fileName, - cp != null ? cp.CreateCompilationOptions () : null, - cp != null ? cp.CreateParseOptions (config) : null, - documents.Item1, - await CreateProjectReferences (p, token), - references, - additionalDocuments: documents.Item2 - ); - projectData.Info = info; - return info; + + lock (updatingProjectDataLock) { + //when reloading e.g. after a save, preserve document IDs + var oldProjectData = GetProjectData (projectId); + var projectData = CreateProjectData (projectId); + var documents = CreateDocuments (projectData, p, token, sourceFiles, oldProjectData); + if (documents == null) + return null; + var info = ProjectInfo.Create ( + projectId, + VersionStamp.Create (), + p.Name, + fileName.FileNameWithoutExtension, + LanguageNames.CSharp, + p.FileName, + fileName, + cp != null ? cp.CreateCompilationOptions () : null, + cp != null ? cp.CreateParseOptions (config) : null, + documents.Item1, + projectReferences, + references, + additionalDocuments: documents.Item2 + ); + projectData.Info = info; + return info; + } } internal void UpdateProjectionEntry (MonoDevelop.Projects.ProjectFile projectFile, IReadOnlyList projections) @@ -1496,6 +1503,7 @@ namespace MonoDevelop.Ide.TypeSystem List modifiedProjects = new List (); object projectModifyLock = new object (); bool freezeProjectModify; + Dictionary projectModifiedCts = new Dictionary (); void OnProjectModified (object sender, MonoDevelop.Projects.SolutionItemModifiedEventArgs args) { lock (projectModifyLock) { @@ -1508,14 +1516,20 @@ namespace MonoDevelop.Ide.TypeSystem if (project == null) return; var projectId = GetProjectId (project); + if (projectModifiedCts.TryGetValue (project, out var cts)) + cts.Cancel (); + cts = new CancellationTokenSource (); + projectModifiedCts [project] = cts; if (CurrentSolution.ContainsProject (projectId)) { - var projectInfo = LoadProject (project, CancellationToken.None, null).ContinueWith (t => { + var projectInfo = LoadProject (project, cts.Token, null).ContinueWith (t => { + if (t.IsCanceled) + return; if (t.IsFaulted) { LoggingService.LogError ("Failed to reload project", t.Exception); return; } OnProjectReloaded (t.Result); - }); + }, cts.Token); } else { modifiedProjects.Add (project); } -- cgit v1.2.3