From 1e73f3abd6cd037ff1e9a10bc0cdc090a561cc46 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Thu, 9 May 2019 00:03:04 -0500 Subject: Catch exception from having a bad LangVersion setting in .csproj If LangVersion is an invalid value and throws an exception, the general page fails to load. So now we catch this exception and display the error on the page so the user can correct it. Fixes VSTS #802073 --- .../CSharpCompilerParameters.cs | 8 +++++--- .../CompilerOptionsPanelWidget.cs | 24 ++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs index 9d30f7a21c..ef73cbd84e 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs @@ -227,9 +227,11 @@ namespace MonoDevelop.CSharp.Project return val; } set { - if (LangVersion == value) { - return; - } + try { + if (LangVersion == value) { + return; + } + } catch (Exception) { } langVersion = LanguageVersionToString (value); NotifyChange (); diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 396dc158c6..2085650193 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -101,10 +101,14 @@ namespace MonoDevelop.CSharp.Project var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion)); foreach (var (text, version) in CSharpLanguageVersionHelper.GetKnownLanguageVersions ()) { - if (unsupportedLanguageVersions.Contains (version) && compilerParameters.LangVersion != version) { - // Mono's MSBuild does not currently support C# 8. - } else { - langVerStore.AppendValues (text, version); + try { + if (unsupportedLanguageVersions.Contains (version) && compilerParameters.LangVersion != version) { + // Mono's MSBuild does not currently support C# 8. + } else { + langVerStore.AppendValues (text, version); + } + } catch (Exception ex) { + label2.Markup = GettextCatalog.GetString ("C# Language Version ({0}):", ex.Message); } } langVerCombo.Model = langVerStore; @@ -112,10 +116,14 @@ namespace MonoDevelop.CSharp.Project TreeIter iter; if (langVerStore.GetIterFirst (out iter)) { do { - var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); - if (val == compilerParameters.LangVersion) { - langVerCombo.SetActiveIter (iter); - break; + try { + var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); + if (val == compilerParameters.LangVersion) { + langVerCombo.SetActiveIter (iter); + break; + } + } catch (Exception ex) { + label2.Markup = GettextCatalog.GetString ("C# Language Version ({0}):", ex.Message); } } while (langVerStore.IterNext (ref iter)); } -- cgit v1.2.3 From 55466a66c0df58b3f47da73e3e1e4aa8d753cccd Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Wed, 15 May 2019 16:19:24 -0500 Subject: UI updates and improvements. Bug #802073 --- ...noDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs | 12 ++++++++++-- .../CompilerOptionsPanelWidget.cs | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs index 232893c387..5e43198b9d 100644 --- a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs @@ -47,6 +47,8 @@ namespace MonoDevelop.CSharp.Project private global::Gtk.VBox vbox3; private global::Gtk.Table table2; + + private global::Gtk.Image langVersionWarningIcon; private global::Gtk.Label label2; @@ -254,12 +256,18 @@ namespace MonoDevelop.CSharp.Project this.table2.RowSpacing = ((uint)(6)); this.table2.ColumnSpacing = ((uint)(6)); // Container child table2.Gtk.Table+TableChild + this.langVersionWarningIcon = new global::Gtk.Image (); + this.langVersionWarningIcon.SetFromStock (Gtk.Stock.DialogWarning, Gtk.IconSize.Menu); + var langVersionHbox = new global::Gtk.HBox (false, 0); + langVersionHbox.Name = "langVersionHbox"; + langVersionHbox.PackStart (this.langVersionWarningIcon, false, false, 0); this.label2 = new global::Gtk.Label (); this.label2.Name = "label2"; this.label2.Xalign = 0F; this.label2.LabelProp = global::Mono.Unix.Catalog.GetString ("C# Language Version:"); - this.table2.Add (this.label2); - global::Gtk.Table.TableChild w19 = ((global::Gtk.Table.TableChild)(this.table2 [this.label2])); + langVersionHbox.PackStart (this.label2, false, false, 0); + this.table2.Add (langVersionHbox); + global::Gtk.Table.TableChild w19 = ((global::Gtk.Table.TableChild)(this.table2 [langVersionHbox])); w19.XOptions = ((global::Gtk.AttachOptions)(4)); w19.YOptions = ((global::Gtk.AttachOptions)(4)); // Container child table2.Gtk.Table+TableChild diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 2085650193..2552c41170 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -29,6 +29,7 @@ using System; using System.Linq; +using System.Text.RegularExpressions; using Gtk; using MonoDevelop.Components; @@ -55,6 +56,13 @@ namespace MonoDevelop.CSharp.Project LanguageVersion.LatestMajor, LanguageVersion.Preview }; + + readonly Regex BadVersionRegex = new Regex (@"'(?.*)'"); + + string ExtractBadVersion (string badValue) + { + return BadVersionRegex.Match (badValue).Groups ["value"].Value; + } public CompilerOptionsPanelWidget (DotNetProject project) { @@ -108,7 +116,9 @@ namespace MonoDevelop.CSharp.Project langVerStore.AppendValues (text, version); } } catch (Exception ex) { - label2.Markup = GettextCatalog.GetString ("C# Language Version ({0}):", ex.Message); + var badVersion = ExtractBadVersion (ex.Message); + label2.Markup = GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]:", badVersion); + langVerStore.AppendValues (ExtractBadVersion (ex.Message), LanguageVersion.Preview); } } langVerCombo.Model = langVerStore; @@ -123,7 +133,8 @@ namespace MonoDevelop.CSharp.Project break; } } catch (Exception ex) { - label2.Markup = GettextCatalog.GetString ("C# Language Version ({0}):", ex.Message); + var badVersion = ExtractBadVersion (ex.Message); + label2.Markup = GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]:", badVersion); } } while (langVerStore.IterNext (ref iter)); } -- cgit v1.2.3 From 10ad025918cd1ec9fa113256f522103797d8abfe Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Tue, 21 May 2019 14:05:30 -0500 Subject: Improvements and UI fixes. Use configuration properties instead of regex --- ...op.CSharp.Project.CompilerOptionsPanelWidget.cs | 1 + .../CompilerOptionsPanelWidget.cs | 52 ++++++++++++---------- 2 files changed, 29 insertions(+), 24 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs index 5e43198b9d..80442aa053 100644 --- a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs @@ -258,6 +258,7 @@ namespace MonoDevelop.CSharp.Project // Container child table2.Gtk.Table+TableChild this.langVersionWarningIcon = new global::Gtk.Image (); this.langVersionWarningIcon.SetFromStock (Gtk.Stock.DialogWarning, Gtk.IconSize.Menu); + this.langVersionWarningIcon.Visible = false; var langVersionHbox = new global::Gtk.HBox (false, 0); langVersionHbox.Name = "langVersionHbox"; langVersionHbox.PackStart (this.langVersionWarningIcon, false, false, 0); diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 2552c41170..37bf9cfd44 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -29,6 +29,7 @@ using System; using System.Linq; +using System.Collections.Generic; using System.Text.RegularExpressions; using Gtk; @@ -57,13 +58,6 @@ namespace MonoDevelop.CSharp.Project LanguageVersion.Preview }; - readonly Regex BadVersionRegex = new Regex (@"'(?.*)'"); - - string ExtractBadVersion (string badValue) - { - return BadVersionRegex.Match (badValue).Groups ["value"].Value; - } - public CompilerOptionsPanelWidget (DotNetProject project) { this.Build(); @@ -106,9 +100,13 @@ namespace MonoDevelop.CSharp.Project iconEntry.DefaultPath = project.BaseDirectory; allowUnsafeCodeCheckButton.Active = compilerParameters.UnsafeCode; noStdLibCheckButton.Active = compilerParameters.NoStdLib; + langVersionWarningIcon.Visible = false; var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion)); - foreach (var (text, version) in CSharpLanguageVersionHelper.GetKnownLanguageVersions ()) { + var langVersions = CSharpLanguageVersionHelper.GetKnownLanguageVersions (); + var badSet = new HashSet (); + + foreach (var (text, version) in langVersions) { try { if (unsupportedLanguageVersions.Contains (version) && compilerParameters.LangVersion != version) { // Mono's MSBuild does not currently support C# 8. @@ -116,27 +114,33 @@ namespace MonoDevelop.CSharp.Project langVerStore.AppendValues (text, version); } } catch (Exception ex) { - var badVersion = ExtractBadVersion (ex.Message); - label2.Markup = GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]:", badVersion); - langVerStore.AppendValues (ExtractBadVersion (ex.Message), LanguageVersion.Preview); + var badVersion = configuration.Properties.GetProperty ("LangVersion").Value; + badSet.Add (GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]", badVersion)); } } + langVerCombo.Model = langVerStore; - TreeIter iter; - if (langVerStore.GetIterFirst (out iter)) { - do { - try { - var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); - if (val == compilerParameters.LangVersion) { - langVerCombo.SetActiveIter (iter); - break; + if (badSet.Any ()) { + langVersionWarningIcon.Visible = true; + foreach (var s in badSet) { + var badIter = langVerStore.AppendValues (s, LanguageVersion.Default); + langVerCombo.SetActiveIter (badIter); + } + } else { + TreeIter iter; + if (langVerStore.GetIterFirst (out iter)) { + do { + try { + var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); + if (val == compilerParameters.LangVersion) { + langVerCombo.SetActiveIter (iter); + break; + } + } catch (Exception ex) { } - } catch (Exception ex) { - var badVersion = ExtractBadVersion (ex.Message); - label2.Markup = GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]:", badVersion); - } - } while (langVerStore.IterNext (ref iter)); + } while (langVerStore.IterNext (ref iter)); + } } SetupAccessibility (); -- cgit v1.2.3 From 9b2f52ce8fc73acc6d2802659ed5e0c1c1e98d7e Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 29 May 2019 14:14:30 +0100 Subject: [NuGet] Add tests for restore command handlers being enabled Added tests for existing logic before changing it to fix some bugs where the restore menu is not enabled when it should be. --- .../PackagesCommandHandler.cs | 24 ++- .../FakeNuGetAwareProject.cs | 5 + .../TestableRestorePackagesHandler.cs | 54 ++++++ .../TestableRestorePackagesInProjectHandler.cs | 54 ++++++ .../MonoDevelop.PackageManagement.Tests.csproj | 3 + .../DotNetProjectExtensionsTests.cs | 6 + .../PackagesCommandHandlerTests.cs | 188 +++++++++++++++++++++ 7 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesHandler.cs create mode 100644 main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesInProjectHandler.cs create mode 100644 main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs index 8c3540eacd..c10cd3c8b9 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs @@ -56,7 +56,7 @@ namespace MonoDevelop.PackageManagement.Commands protected DotNetProject GetSelectedDotNetProject () { - return IdeApp.ProjectOperations.CurrentSelectedProject as DotNetProject; + return CurrentSelectedProject as DotNetProject; } protected bool SelectedDotNetProjectHasPackages () @@ -67,12 +67,12 @@ namespace MonoDevelop.PackageManagement.Commands protected bool IsDotNetSolutionSelected () { - return IdeApp.ProjectOperations.CurrentSelectedSolution != null; + return CurrentSelectedSolution != null; } protected bool SelectedDotNetSolutionHasPackages () { - Solution solution = IdeApp.ProjectOperations.CurrentSelectedSolution; + Solution solution = CurrentSelectedSolution; if (solution == null) { return false; } @@ -96,7 +96,7 @@ namespace MonoDevelop.PackageManagement.Commands if (project != null) { return project.ParentSolution; } - return IdeApp.ProjectOperations.CurrentSelectedSolution; + return CurrentSelectedSolution; } protected bool CanUpdatePackagesForSelectedDotNetProject () @@ -107,7 +107,7 @@ namespace MonoDevelop.PackageManagement.Commands bool CanUpdatePackagesForSelectedDotNetSolution () { - Solution solution = IdeApp.ProjectOperations.CurrentSelectedSolution; + Solution solution = CurrentSelectedSolution; return solution?.CanUpdatePackages () == true; } @@ -120,5 +120,19 @@ namespace MonoDevelop.PackageManagement.Commands } return false; } + + /// + /// Used by unit tests to avoid having to initialize the IDE workspace. + /// + protected virtual Solution CurrentSelectedSolution { + get { return IdeApp.ProjectOperations.CurrentSelectedSolution; } + } + + /// + /// Used by unit tests to avoid having to initialize the IDE workspace. + /// + protected virtual Project CurrentSelectedProject { + get { return IdeApp.ProjectOperations.CurrentSelectedProject; } + } } } diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/FakeNuGetAwareProject.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/FakeNuGetAwareProject.cs index abe4cce276..33cd30fbb5 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/FakeNuGetAwareProject.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/FakeNuGetAwareProject.cs @@ -33,6 +33,11 @@ namespace MonoDevelop.PackageManagement.Tests.Helpers { class FakeNuGetAwareProject : DummyDotNetProject, INuGetAwareProject { + public FakeNuGetAwareProject () + { + Initialize (this); + } + public NuGetProject CreateNuGetProject () { throw new NotImplementedException (); diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesHandler.cs new file mode 100644 index 0000000000..dfb6272a16 --- /dev/null +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesHandler.cs @@ -0,0 +1,54 @@ +// +// TestableRestorePackagesHandler.cs +// +// Author: +// Matt Ward +// +// Copyright (c) 2019 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using MonoDevelop.Components.Commands; +using MonoDevelop.PackageManagement.Commands; +using MonoDevelop.Projects; + +namespace MonoDevelop.PackageManagement.Tests.Helpers +{ + class TestableRestorePackagesHandler : RestorePackagesHandler + { + CommandInfo info = new CommandInfo (); + Project project; + Solution solution; + + public bool Enabled { + get { return info.Enabled; } + } + + public void RunUpdate (Solution solution, Project project) + { + this.solution = solution; + this.project = project; + + base.Update (info); + } + + protected override Project CurrentSelectedProject => project; + protected override Solution CurrentSelectedSolution => solution; + } +} diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesInProjectHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesInProjectHandler.cs new file mode 100644 index 0000000000..64304cb624 --- /dev/null +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.Helpers/TestableRestorePackagesInProjectHandler.cs @@ -0,0 +1,54 @@ +// +// TestableRestorePackagesInProjectHandler.cs +// +// Author: +// Matt Ward +// +// Copyright (c) 2019 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using MonoDevelop.Components.Commands; +using MonoDevelop.PackageManagement.Commands; +using MonoDevelop.Projects; + +namespace MonoDevelop.PackageManagement.Tests.Helpers +{ + class TestableRestorePackagesInProjectHandler : RestorePackagesInProjectHandler + { + CommandInfo info = new CommandInfo (); + Project project; + Solution solution; + + public bool Enabled { + get { return info.Enabled; } + } + + public void RunUpdate (Solution solution, Project project) + { + this.solution = solution; + this.project = project; + + base.Update (info); + } + + protected override Project CurrentSelectedProject => project; + protected override Solution CurrentSelectedSolution => solution; + } +} diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj index 56d4affa52..03a065a5cc 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests.csproj @@ -151,6 +151,9 @@ + + + diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetProjectExtensionsTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetProjectExtensionsTests.cs index 422d599e35..4843451775 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetProjectExtensionsTests.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetProjectExtensionsTests.cs @@ -49,6 +49,12 @@ namespace MonoDevelop.PackageManagement.Tests DotNetProjectExtensions.FileExists = existingFiles.Contains; } + [TearDown] + public void TearDown () + { + DotNetProjectExtensions.FileExists = File.Exists; + } + void CreateProject (string fileName, string projectName) { project = new FakeDotNetProject (fileName.ToNativePath ()) { diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs new file mode 100644 index 0000000000..3dc515e75f --- /dev/null +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs @@ -0,0 +1,188 @@ +// +// PackagesCommandHandlerTests.cs +// +// Author: +// Matt Ward +// +// Copyright (c) 2019 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MonoDevelop.Core; +using MonoDevelop.PackageManagement.Tests.Helpers; +using MonoDevelop.Projects; +using NUnit.Framework; +using UnitTests; + +namespace MonoDevelop.PackageManagement.Tests +{ + [TestFixture] + public class PackagesCommandHandlerTests : RestoreTestBase + { + TestableRestorePackagesHandler restorePackagesHandler; + TestableRestorePackagesInProjectHandler restorePackagesInProjectHandler; + + [SetUp] + public void Init () + { + restorePackagesHandler = new TestableRestorePackagesHandler (); + restorePackagesInProjectHandler = new TestableRestorePackagesInProjectHandler (); + } + + [Test] + public async Task ProjectWithNoPackages () + { + FilePath solutionFileName = Util.GetSampleProject ("csharp-console", "csharp-console.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsFalse (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled); + } + + [Test] + public async Task ProjectWithPackagesConfig () + { + FilePath solutionFileName = Util.GetSampleProject ("csharp-console", "csharp-console.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + var packagesConfigFileName = project.BaseDirectory.Combine ("packages.config"); + File.WriteAllText (packagesConfigFileName, ""); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + + [Test] + public async Task SdkProject_PackageReference () + { + FilePath solutionFileName = Util.GetSampleProject ("NetStandardXamarinForms", "NetStandardXamarinForms.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + + [Test] + public async Task PackageReferenceProject_NonSdk () + { + FilePath solutionFileName = Util.GetSampleProject ("package-reference", "package-reference.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + + [Test] + public void NuGetAwareProject () + { + var project = new FakeNuGetAwareProject (); + var solution = new Solution (); + solution.RootFolder.AddItem (project); + + // No packages in project. + project.HasPackagesReturnValue = false; + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsFalse (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + + // Project has packages. + project.HasPackagesReturnValue = true; + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + } +} -- cgit v1.2.3 From c047dcc2c545a607007733140e22f8bd39da8b62 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 29 May 2019 15:32:54 +0100 Subject: [NuGet] Fix restore menu incorrectly disabled. The restore menu when right clicking a solution or the packages folder is no longer disabled when an SDK style project targets .NET Framework or when the project has RestoreProjectStyle set to PackageReference but has no PackageReferences. Fixes VSTS #764063 - NuGet extension ignores RestoreProjectStyle Fixes VSTS #814579 - Restore NuGet packages menu disabled for sdk style project targeting net47 --- .../PackagesCommandHandler.cs | 34 +++++------ .../RestorePackagesHandler.cs | 2 +- .../RestorePackagesInProjectHandler.cs | 2 +- .../PackagesCommandHandlerTests.cs | 69 ++++++++++++++++++++++ .../DotNetProjectExtensions.cs | 11 ++++ .../SolutionExtensions.cs | 12 ++-- 6 files changed, 104 insertions(+), 26 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs index c10cd3c8b9..be0378ce09 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs @@ -59,35 +59,31 @@ namespace MonoDevelop.PackageManagement.Commands return CurrentSelectedProject as DotNetProject; } - protected bool SelectedDotNetProjectHasPackages () - { - DotNetProject project = GetSelectedDotNetProject (); - return (project != null) && project.HasPackages (); - } - protected bool IsDotNetSolutionSelected () { return CurrentSelectedSolution != null; } - protected bool SelectedDotNetSolutionHasPackages () - { - Solution solution = CurrentSelectedSolution; - if (solution == null) { - return false; + protected bool CanRestoreSelectedDotNetProjectOrSolution () + { + if (IsDotNetProjectSelected ()) { + return CanRestorePackagesForSelectedDotNetProject (); + } else if (IsDotNetSolutionSelected ()) { + return CanRestorePackagesForSelectedSolution (); } + return false; + } - return solution.HasAnyProjectWithPackages (); + protected bool CanRestorePackagesForSelectedDotNetProject () + { + DotNetProject project = GetSelectedDotNetProject (); + return project?.CanRestorePackages () == true; } - protected bool SelectedDotNetProjectOrSolutionHasPackages () + bool CanRestorePackagesForSelectedSolution () { - if (IsDotNetProjectSelected ()) { - return SelectedDotNetProjectHasPackages (); - } else if (IsDotNetSolutionSelected ()) { - return SelectedDotNetSolutionHasPackages (); - } - return false; + Solution solution = CurrentSelectedSolution; + return solution?.CanRestorePackages () == true; } protected Solution GetSelectedSolution () diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesHandler.cs index de29788d4b..0264cae53e 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesHandler.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesHandler.cs @@ -42,7 +42,7 @@ namespace MonoDevelop.PackageManagement.Commands protected override void Update (CommandInfo info) { - info.Enabled = SelectedDotNetProjectOrSolutionHasPackages (); + info.Enabled = CanRestoreSelectedDotNetProjectOrSolution (); } public static void Run (Solution solution) diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesInProjectHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesInProjectHandler.cs index 73731d3bc4..93dadeff7e 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesInProjectHandler.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/RestorePackagesInProjectHandler.cs @@ -40,7 +40,7 @@ namespace MonoDevelop.PackageManagement.Commands protected override void Update (CommandInfo info) { - info.Enabled = SelectedDotNetProjectHasPackages (); + info.Enabled = CanRestorePackagesForSelectedDotNetProject (); } public static void Run (DotNetProject project) diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs index 3dc515e75f..7cec48b14d 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs @@ -120,6 +120,52 @@ namespace MonoDevelop.PackageManagement.Tests Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); } + [Test] + public async Task SdkProject_NoPackageReferences () + { + FilePath solutionFileName = Util.GetSampleProject ("netstandard-sdk", "netstandard-sdk.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + + [Test] + public async Task SdkProject_NetFramework472 () + { + FilePath solutionFileName = Util.GetSampleProject ("netframework-sdk", "netframework-sdk.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + [Test] public async Task PackageReferenceProject_NonSdk () { @@ -143,6 +189,29 @@ namespace MonoDevelop.PackageManagement.Tests Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); } + [Test] + public async Task RestoreProjectStyle_NoPackageReferences () + { + FilePath solutionFileName = Util.GetSampleProject ("RestoreStylePackageReference", "RestoreStylePackageReference.sln"); + + solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName); + var project = solution.GetAllDotNetProjects ().Single (); + + // Project selected. + restorePackagesHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project); + Assert.IsTrue (restorePackagesInProjectHandler.Enabled); + + // Solution only selected + restorePackagesHandler.RunUpdate (solution, project: null); + Assert.IsTrue (restorePackagesHandler.Enabled); + + restorePackagesInProjectHandler.RunUpdate (solution, project: null); + Assert.IsFalse (restorePackagesInProjectHandler.Enabled, "Should be false - no project selected"); + } + [Test] public void NuGetAwareProject () { diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/DotNetProjectExtensions.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/DotNetProjectExtensions.cs index dcc1d5a80b..1954713237 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/DotNetProjectExtensions.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/DotNetProjectExtensions.cs @@ -312,5 +312,16 @@ namespace MonoDevelop.PackageManagement return HasPackages (project.BaseDirectory, project.Name) || project.Items.OfType ().Any (); } + + public static bool CanRestorePackages (this DotNetProject project) + { + var nugetAwareProject = project as INuGetAwareProject; + if (nugetAwareProject != null) + return nugetAwareProject.HasPackages (); + + return HasPackages (project.BaseDirectory, project.Name) || + DotNetCoreNuGetProject.CanCreate (project) || + PackageReferenceNuGetProject.CanCreate (project); + } } } diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/SolutionExtensions.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/SolutionExtensions.cs index d63b3831f6..717a1b1e2a 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/SolutionExtensions.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement/SolutionExtensions.cs @@ -48,16 +48,18 @@ namespace MonoDevelop.PackageManagement .Where (project => project.HasPackages ()); } - public static bool HasAnyProjectWithPackages (this Solution solution) - { - return solution.GetAllProjectsWithPackages ().Any (); - } - public static bool CanUpdatePackages (this Solution solution) { return solution .GetAllDotNetProjects () .Any (project => project.CanUpdatePackages ()); } + + public static bool CanRestorePackages (this Solution solution) + { + return solution + .GetAllDotNetProjects () + .Any (project => project.CanRestorePackages ()); + } } } -- cgit v1.2.3 From 099b6584ecafade3047e650d4477f49fb06fcdd2 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Thu, 30 May 2019 14:58:40 -0500 Subject: Remove the HashSet and iteration, just assume one bad value. --- .../CompilerOptionsPanelWidget.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 37bf9cfd44..2489477fe2 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -104,7 +104,7 @@ namespace MonoDevelop.CSharp.Project var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion)); var langVersions = CSharpLanguageVersionHelper.GetKnownLanguageVersions (); - var badSet = new HashSet (); + string badVersion = null; foreach (var (text, version) in langVersions) { try { @@ -114,19 +114,16 @@ namespace MonoDevelop.CSharp.Project langVerStore.AppendValues (text, version); } } catch (Exception ex) { - var badVersion = configuration.Properties.GetProperty ("LangVersion").Value; - badSet.Add (GettextCatalog.GetString ("C# Language Version [{0} (Unknown Version)]", badVersion)); + badVersion = configuration.Properties.GetProperty ("LangVersion").Value; } } langVerCombo.Model = langVerStore; - if (badSet.Any ()) { + if (badVersion != null) { + var badIter = langVerStore.AppendValues (badVersion, LanguageVersion.Default); + langVerCombo.SetActiveIter (badIter); langVersionWarningIcon.Visible = true; - foreach (var s in badSet) { - var badIter = langVerStore.AppendValues (s, LanguageVersion.Default); - langVerCombo.SetActiveIter (badIter); - } } else { TreeIter iter; if (langVerStore.GetIterFirst (out iter)) { -- cgit v1.2.3 From 7229412b6efbf7143e286478be3fd63337abeed6 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Thu, 30 May 2019 15:03:28 -0500 Subject: Remove unnecessary try/catch. --- .../MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 2489477fe2..89aa4f425a 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -128,13 +128,10 @@ namespace MonoDevelop.CSharp.Project TreeIter iter; if (langVerStore.GetIterFirst (out iter)) { do { - try { - var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); - if (val == compilerParameters.LangVersion) { - langVerCombo.SetActiveIter (iter); - break; - } - } catch (Exception ex) { + var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); + if (val == compilerParameters.LangVersion) { + langVerCombo.SetActiveIter (iter); + break; } } while (langVerStore.IterNext (ref iter)); } -- cgit v1.2.3 From ac1c76bf642242fd729d99920a688f7f130b3a66 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Thu, 30 May 2019 15:46:55 -0500 Subject: Fix combo label to use GettextCatalog. --- .../MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 89aa4f425a..ff6063c620 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -121,7 +121,7 @@ namespace MonoDevelop.CSharp.Project langVerCombo.Model = langVerStore; if (badVersion != null) { - var badIter = langVerStore.AppendValues (badVersion, LanguageVersion.Default); + var badIter = langVerStore.AppendValues (GettextCatalog.GetString ("{0} (Unknown Version)", badVersion), LanguageVersion.Default); langVerCombo.SetActiveIter (badIter); langVersionWarningIcon.Visible = true; } else { -- cgit v1.2.3 From d2251933173908782589fe7a2464dabfee3ea819 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Fri, 31 May 2019 11:35:47 -0500 Subject: More fixes for handling bad LangVersion Don't append values to the list store from within try/catch or it's possible they won't get added correctly. Add a third column to the listv store to mark whether a row is a bad value. Then when we are storing, check that value and don't store the LangVersion if we have a bad value. This prevents us from switching back to Default when the user hits the "Ok" button. --- .../CompilerOptionsPanelWidget.cs | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index ff6063c620..5535b0cf8c 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -102,26 +102,29 @@ namespace MonoDevelop.CSharp.Project noStdLibCheckButton.Active = compilerParameters.NoStdLib; langVersionWarningIcon.Visible = false; - var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion)); + var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion), typeof (bool)); var langVersions = CSharpLanguageVersionHelper.GetKnownLanguageVersions (); string badVersion = null; + LanguageVersion langVersion; + + try { + langVersion = compilerParameters.LangVersion; + } catch (Exception) { + badVersion = configuration.Properties.GetProperty ("LangVersion").Value; + } foreach (var (text, version) in langVersions) { - try { - if (unsupportedLanguageVersions.Contains (version) && compilerParameters.LangVersion != version) { - // Mono's MSBuild does not currently support C# 8. - } else { - langVerStore.AppendValues (text, version); - } - } catch (Exception ex) { - badVersion = configuration.Properties.GetProperty ("LangVersion").Value; + if (unsupportedLanguageVersions.Contains (version)) { + // Mono's MSBuild does not currently support C# 8. + } else { + langVerStore.AppendValues (text, version, false); } } langVerCombo.Model = langVerStore; if (badVersion != null) { - var badIter = langVerStore.AppendValues (GettextCatalog.GetString ("{0} (Unknown Version)", badVersion), LanguageVersion.Default); + var badIter = langVerStore.AppendValues (GettextCatalog.GetString ("{0} (Unknown Version)", badVersion), LanguageVersion.Default, true); langVerCombo.SetActiveIter (badIter); langVersionWarningIcon.Visible = true; } else { @@ -192,11 +195,13 @@ namespace MonoDevelop.CSharp.Project public void Store (ItemConfigurationCollection configs) { int codePage; + bool isBadVersion = false; var langVersion = LanguageVersion.Default; TreeIter iter; if (langVerCombo.GetActiveIter (out iter)) { langVersion = (LanguageVersion)langVerCombo.Model.GetValue (iter, 1); + isBadVersion = (bool)langVerCombo.Model.GetValue (iter, 2); } if (codepageEntry.Entry.Text.Length > 0) { @@ -235,7 +240,8 @@ namespace MonoDevelop.CSharp.Project CSharpCompilerParameters compilerParameters = (CSharpCompilerParameters) configuration.CompilationParameters; compilerParameters.UnsafeCode = allowUnsafeCodeCheckButton.Active; compilerParameters.NoStdLib = noStdLibCheckButton.Active; - compilerParameters.LangVersion = langVersion; + if (!isBadVersion) + compilerParameters.LangVersion = langVersion; } } -- cgit v1.2.3 From 543123359ea90ae9606816f1023f92abf095cc65 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Mon, 3 Jun 2019 14:18:41 -0500 Subject: Fixes for handling C# 8.0 --- .../MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs index 5535b0cf8c..99525f77db 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -105,7 +105,7 @@ namespace MonoDevelop.CSharp.Project var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion), typeof (bool)); var langVersions = CSharpLanguageVersionHelper.GetKnownLanguageVersions (); string badVersion = null; - LanguageVersion langVersion; + LanguageVersion? langVersion = null; try { langVersion = compilerParameters.LangVersion; @@ -115,7 +115,14 @@ namespace MonoDevelop.CSharp.Project foreach (var (text, version) in langVersions) { if (unsupportedLanguageVersions.Contains (version)) { - // Mono's MSBuild does not currently support C# 8. + if (langVersion == version) { + if (badVersion == null) + badVersion = text; + } else { + // Otherwise if it's an unsupported language but it's not the current project's + // version then it must be an unsupported version of Mono. Let's not add that to + // the list store. + } } else { langVerStore.AppendValues (text, version, false); } -- cgit v1.2.3 From 68e5f0a34d09b1d4c42de3ff279d9f7eedd39e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 3 Jun 2019 14:12:28 +0200 Subject: Fixes VSTS Bug 904321: [Feedback] Xamarin Android Breakpoint not work in debug https://devdiv.visualstudio.com/DevDiv/_workitems/edit/904321 Exception from feedback ticket : https://devdiv.visualstudio.com/DevDiv/_workitems/edit/896686 Produces many out of range exceptions in text segment marker. This checks now for empty lines - can happen during an edit session when a line is cleared. Exceptions in that case prevent further drawing in that line. This is now changed and the drawing code is hardened against exceptions in line markers. --- .../Mono.TextEditor/Gui/TextViewMargin.cs | 35 +++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs index 6754d0b0ce..6fb760ace8 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/Mono.TextEditor/Gui/TextViewMargin.cs @@ -1957,7 +1957,7 @@ namespace Mono.TextEditor } } - var metrics = new LineMetrics { + var metrics = new LineMetrics { LineSegment = line, Layout = layout, @@ -1980,18 +1980,26 @@ namespace Mono.TextEditor if (!marker.IsVisible) continue; - if (marker.DrawBackground (textEditor, cr, metrics)) { - isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection; + try { + if (marker.DrawBackground (textEditor, cr, metrics)) { + isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection; + } + } catch (Exception e) { + LoggingService.LogInternalError ("Error while drawing backround marker " + marker, e); } } var textSegmentMarkers = TextDocument.OrderTextSegmentMarkersByInsertion (Document.GetVisibleTextSegmentMarkersAt (line)).ToList (); foreach (var marker in textSegmentMarkers) { - if (layout.Layout != null) + if (layout.Layout == null) + continue; + try { marker.DrawBackground (textEditor, cr, metrics, offset, offset + length); + } catch (Exception e) { + LoggingService.LogInternalError ("Error while drawing backround marker " + marker, e); + } } - if (DecorateLineBg != null) DecorateLineBg (cr, layout, offset, length, xPos, y, selectionStartOffset, selectionEndOffset); @@ -2175,17 +2183,24 @@ namespace Mono.TextEditor } } } - foreach (TextLineMarker marker in textEditor.Document.GetMarkers (line)) { - if (!marker.IsVisible) + foreach (var marker in textEditor.Document.GetMarkers (line)) { + if (!marker.IsVisible || layout.Layout == null) continue; - - if (layout.Layout != null) + try { marker.Draw (textEditor, cr, metrics); + } catch (Exception e) { + LoggingService.LogInternalError ("Error while drawing line marker " + marker, e); + } } foreach (var marker in textSegmentMarkers) { - if (layout.Layout != null) + if (layout.Layout == null) + continue; + try { marker.Draw (textEditor, cr, metrics, offset, offset + length); + } catch (Exception e) { + LoggingService.LogInternalError ("Error while drawing segment marker " + marker, e); + } } position += System.Math.Floor (layout.LastLineWidth); -- cgit v1.2.3 From 3b30f60ac8f05cf72ba26b2832a7c85f21faa98f Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Tue, 4 Jun 2019 09:30:33 -0500 Subject: Fix the warning icon. --- .../Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs index 80442aa053..ca2443dade 100644 --- a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs @@ -1,5 +1,7 @@ // This file has been generated by the GUI designer. Do not modify. +using MonoDevelop.Ide.Gui; + namespace MonoDevelop.CSharp.Project { partial class CompilerOptionsPanelWidget @@ -48,7 +50,7 @@ namespace MonoDevelop.CSharp.Project private global::Gtk.Table table2; - private global::Gtk.Image langVersionWarningIcon; + private MonoDevelop.Components.ImageView langVersionWarningIcon; private global::Gtk.Label label2; @@ -256,8 +258,7 @@ namespace MonoDevelop.CSharp.Project this.table2.RowSpacing = ((uint)(6)); this.table2.ColumnSpacing = ((uint)(6)); // Container child table2.Gtk.Table+TableChild - this.langVersionWarningIcon = new global::Gtk.Image (); - this.langVersionWarningIcon.SetFromStock (Gtk.Stock.DialogWarning, Gtk.IconSize.Menu); + this.langVersionWarningIcon = new MonoDevelop.Components.ImageView (Stock.Warning, Gtk.IconSize.LargeToolbar); this.langVersionWarningIcon.Visible = false; var langVersionHbox = new global::Gtk.HBox (false, 0); langVersionHbox.Name = "langVersionHbox"; -- cgit v1.2.3 From a94aba185efcb7fd3aa2f977ba241623a4197dc9 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Tue, 4 Jun 2019 16:25:35 -0400 Subject: [Debugger] Added new breakpoint span resolver for C# Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/887700/ --- main/src/addins/CSharpBinding/CSharpBinding.csproj | 1 + .../CSharpBreakpointSpanResolver.cs | 58 ++++++++++++++++++++++ .../BreakpointManager.cs | 43 ++++++++++------ .../MonoDevelop.Debugger.csproj | 2 + .../MonoDevelop.Debugger/DebuggingService.cs | 25 +++++++++- .../DefaultBreakpointSpanResolver.cs | 47 ++++++++++++++++++ .../IBreakpointSpanResolver.cs | 48 ++++++++++++++++++ 7 files changed, 206 insertions(+), 18 deletions(-) create mode 100644 main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs create mode 100644 main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DefaultBreakpointSpanResolver.cs create mode 100644 main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/IBreakpointSpanResolver.cs (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/CSharpBinding.csproj b/main/src/addins/CSharpBinding/CSharpBinding.csproj index 2027c0db24..3766cbf2b2 100644 --- a/main/src/addins/CSharpBinding/CSharpBinding.csproj +++ b/main/src/addins/CSharpBinding/CSharpBinding.csproj @@ -291,6 +291,7 @@ + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs new file mode 100644 index 0000000000..992f77529d --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs @@ -0,0 +1,58 @@ +// +// CSharpBreakpointSpanResolver.cs +// +// Author: +// Jeffrey Stedfast +// +// Copyright (c) 2019 Microsoft Corp. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; +using Microsoft.CodeAnalysis.CSharp.EditAndContinue; + +using MonoDevelop.Debugger; +using MonoDevelop.Ide.Gui.Documents; + +namespace MonoDevelop.CSharp.Debugger +{ + [ExportDocumentControllerExtension (MimeType = "text/x-csharp")] + public class CSharpBreakpointSpanResolver : DocumentControllerExtension, IBreakpointSpanResolver + { + public override Task SupportsController (DocumentController controller) + { + return Task.FromResult (controller.GetContent () != null); + } + + public async Task GetBreakpointSpanAsync (ITextBuffer buffer, int position, CancellationToken cancellationToken) + { + var document = buffer.AsTextContainer ().GetOpenDocumentInCurrentContext (); + var tree = await document.GetSyntaxTreeAsync (cancellationToken); + + BreakpointSpans.TryGetBreakpointSpan (tree, position, cancellationToken, out var span); + + return new Span (span.Start, span.Length); + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/BreakpointManager.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/BreakpointManager.cs index f3f690e450..93058fe629 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/BreakpointManager.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/BreakpointManager.cs @@ -37,15 +37,17 @@ namespace MonoDevelop.Debugger void TextBuffer_Changed (object sender, TextContentChangedEventArgs e) { foreach (var breakpoint in breakpoints.Values) { - var newSpan = breakpoint.TrackingSpan.GetSpan (e.After); - if (newSpan.IsEmpty) { + var span = breakpoint.TrackingSpan.GetSpan (e.After); + + if (span.IsEmpty || string.IsNullOrWhiteSpace (span.GetText ())) { DebuggingService.Breakpoints.Remove (breakpoint.Breakpoint); continue; } - var newLineNumber = e.After.GetLineFromPosition (newSpan.Start).LineNumber + 1; - if (breakpoint.Breakpoint.Line != newLineNumber) { + + var newLineNumber = e.After.GetLineFromPosition (span.Start).LineNumber + 1; + + if (breakpoint.Breakpoint.Line != newLineNumber) DebuggingService.Breakpoints.UpdateBreakpointLine (breakpoint.Breakpoint, newLineNumber); - } } } @@ -58,38 +60,47 @@ namespace MonoDevelop.Debugger private Dictionary breakpoints = new Dictionary (); - private void OnBreakpointsChanged (object sender, EventArgs eventArgs) + private async void OnBreakpointsChanged (object sender, EventArgs eventArgs) { - var snapshot = textBuffer.CurrentSnapshot; var newBreakpoints = new Dictionary (); - bool needsUpdate = false; + var snapshot = textBuffer.CurrentSnapshot; + var needsUpdate = false; + foreach (var breakpoint in DebuggingService.Breakpoints.GetBreakpointsAtFile (textDocument.FilePath)) { if (breakpoint.Line > snapshot.LineCount) continue; + if (eventArgs is BreakpointEventArgs breakpointEventArgs && breakpointEventArgs.Breakpoint == breakpoint) needsUpdate = true; - var newSpan = snapshot.GetLineFromLineNumber (breakpoint.Line - 1).Extent; + + var line = snapshot.GetLineFromLineNumber (breakpoint.Line - 1); + var position = line.Start.Position + breakpoint.Column; + var span = await DebuggingService.GetBreakpointSpanAsync (textDocument, position); + if (breakpoints.TryGetValue (breakpoint, out var existingBreakpoint)) { newBreakpoints.Add (breakpoint, existingBreakpoint); - if (existingBreakpoint.Span != newSpan.Span) { - // Update if anything was modifed + if (existingBreakpoint.Span != span) { + // Update if anything was modified + existingBreakpoint.Span = span; needsUpdate = true; - existingBreakpoint.Span = newSpan.Span; } } else { // Update if anything was added - needsUpdate = true; - newBreakpoints.Add (breakpoint, new ManagerBreakpoint () { + newBreakpoints.Add (breakpoint, new ManagerBreakpoint { Breakpoint = breakpoint, - TrackingSpan = snapshot.CreateTrackingSpan (newSpan, SpanTrackingMode.EdgeExclusive), - Span = newSpan.Span + TrackingSpan = snapshot.CreateTrackingSpan (span, SpanTrackingMode.EdgeExclusive), + Span = span }); + needsUpdate = true; } } + // Update if anything was removed if (needsUpdate || breakpoints.Keys.Except (newBreakpoints.Keys).Any ()) needsUpdate = true; + breakpoints = newBreakpoints; + if (needsUpdate) BreakpointsChanged?.Invoke (this, new SnapshotSpanEventArgs (new SnapshotSpan (snapshot, 0, snapshot.Length))); } diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.csproj b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.csproj index 12b7e203fb..bdecc781e7 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.csproj +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.csproj @@ -174,6 +174,8 @@ + + diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs index 950385ee18..9e19487fc4 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs @@ -1331,11 +1331,19 @@ namespace MonoDevelop.Debugger static void OnLineCountChanged (object ob, LineCountEventArgs a) { lock (breakpoints) { - foreach (Breakpoint bp in breakpoints.GetBreakpoints ()) { + foreach (var bp in breakpoints.GetBreakpoints ()) { if (bp.FileName == a.TextFile.Name) { if (bp.Line > a.LineNumber) { + var startIndex = a.TextFile.GetPositionFromLineColumn (bp.Line, bp.Column); + var endIndex = a.TextFile.GetPositionFromLineColumn (bp.Line + 1, 0) - 1; + + if (endIndex < startIndex) + endIndex = startIndex; + + var text = a.TextFile.GetText (startIndex, endIndex); + // If the line that has the breakpoint is deleted, delete the breakpoint, otherwise update the line #. - if (bp.Line + a.LineCount >= a.LineNumber) + if (bp.Line + a.LineCount >= a.LineNumber && !string.IsNullOrWhiteSpace (text)) breakpoints.UpdateBreakpointLine (bp, bp.Line + a.LineCount); else breakpoints.Remove (bp); @@ -1482,6 +1490,19 @@ namespace MonoDevelop.Debugger return result; return frame.GetExpressionCompletionData (exp); } + + public static Task GetBreakpointSpanAsync (ITextDocument document, int position, CancellationToken cancellationToken = default (CancellationToken)) + { + var doc = IdeApp.Workbench.GetDocument (document.FilePath); + IBreakpointSpanResolver resolver = null; + + if (doc != null) + resolver = doc.GetContent (); + + resolver = resolver ?? new DefaultBreakpointSpanResolver (); + + return resolver.GetBreakpointSpanAsync (document.TextBuffer, position, cancellationToken); + } } class FeatureCheckerHandlerFactory : IExecutionHandler diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DefaultBreakpointSpanResolver.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DefaultBreakpointSpanResolver.cs new file mode 100644 index 0000000000..19c245fafb --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DefaultBreakpointSpanResolver.cs @@ -0,0 +1,47 @@ +// +// DefaultBreakpointSpanResolver.cs +// +// Author: +// Jeffrey Stedfast +// +// Copyright (c) 2019 Microsoft Corp. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.VisualStudio.Text; + +namespace MonoDevelop.Debugger +{ + public class DefaultBreakpointSpanResolver : IBreakpointSpanResolver + { + public Task GetBreakpointSpanAsync (ITextBuffer buffer, int position, CancellationToken cancellationToken) + { + try { + var line = buffer.CurrentSnapshot.GetLineFromPosition (position); + + return Task.FromResult (Span.FromBounds (line.Start.Position, line.End.Position)); + } catch { + return Task.FromResult (default (Span)); + } + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/IBreakpointSpanResolver.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/IBreakpointSpanResolver.cs new file mode 100644 index 0000000000..25f337ac54 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/IBreakpointSpanResolver.cs @@ -0,0 +1,48 @@ +// +// IBreakpointSpanResolver.cs +// +// Author: +// Jeffrey Stedfast +// +// Copyright (c) 2019 Microsoft Corp. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.VisualStudio.Text; + +namespace MonoDevelop.Debugger +{ + /// + /// An interface for resolving the span of a breakpoint. + /// + public interface IBreakpointSpanResolver + { + /// + /// Resolve the span of a breakpoint. + /// + /// The text buffer. + /// The cursor position. + /// The cancellation token. + /// The span of the breakpoint. + Task GetBreakpointSpanAsync (ITextBuffer buffer, int position, CancellationToken cancellationToken); + } +} -- cgit v1.2.3 From be6983fa1ea90c82333bebad090bf3858634b086 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Wed, 5 Jun 2019 15:51:46 -0500 Subject: Icon size and padding fixes. --- .../Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs index ca2443dade..15aaf60a49 100644 --- a/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/Gui/MonoDevelop.CSharp.Project.CompilerOptionsPanelWidget.cs @@ -258,7 +258,7 @@ namespace MonoDevelop.CSharp.Project this.table2.RowSpacing = ((uint)(6)); this.table2.ColumnSpacing = ((uint)(6)); // Container child table2.Gtk.Table+TableChild - this.langVersionWarningIcon = new MonoDevelop.Components.ImageView (Stock.Warning, Gtk.IconSize.LargeToolbar); + this.langVersionWarningIcon = new MonoDevelop.Components.ImageView (Stock.Warning, Gtk.IconSize.Menu); this.langVersionWarningIcon.Visible = false; var langVersionHbox = new global::Gtk.HBox (false, 0); langVersionHbox.Name = "langVersionHbox"; @@ -267,11 +267,12 @@ namespace MonoDevelop.CSharp.Project this.label2.Name = "label2"; this.label2.Xalign = 0F; this.label2.LabelProp = global::Mono.Unix.Catalog.GetString ("C# Language Version:"); - langVersionHbox.PackStart (this.label2, false, false, 0); + langVersionHbox.PackStart (this.label2, false, false, 6); this.table2.Add (langVersionHbox); global::Gtk.Table.TableChild w19 = ((global::Gtk.Table.TableChild)(this.table2 [langVersionHbox])); w19.XOptions = ((global::Gtk.AttachOptions)(4)); w19.YOptions = ((global::Gtk.AttachOptions)(4)); + w19.XPadding = 6; // Container child table2.Gtk.Table+TableChild this.langVerCombo = global::Gtk.ComboBox.NewText (); this.langVerCombo.Name = "langVerCombo"; -- cgit v1.2.3 From 405ffee00487d7e1f53e04fada859b5f06cc858f Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Thu, 6 Jun 2019 12:30:29 +0300 Subject: Make CSharpBreakpointSpanResolver internal (#7799) --- .../MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src/addins') diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs index 992f77529d..f21971dc9f 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs @@ -38,7 +38,7 @@ using MonoDevelop.Ide.Gui.Documents; namespace MonoDevelop.CSharp.Debugger { [ExportDocumentControllerExtension (MimeType = "text/x-csharp")] - public class CSharpBreakpointSpanResolver : DocumentControllerExtension, IBreakpointSpanResolver + class CSharpBreakpointSpanResolver : DocumentControllerExtension, IBreakpointSpanResolver { public override Task SupportsController (DocumentController controller) { -- cgit v1.2.3 From ef5ea322347547cb6d971b6097b41965312178e6 Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Thu, 6 Jun 2019 14:07:07 +0300 Subject: [IDE] Overall energy consumption and UI hang improvements (#7695) * Misc perf improvements immediately after project load * Use ImmutableDictionary, CWT won't work - the strings are collected * Dump * Use DefaultScheduler via Task.Run, Task.Factory is context dependent * [AssemblyBrowser] Cleanups, mostly related to task usage * [Debugger, VCS] Some Task.Factory fixes Fixes VSTS #900427 - Review usage of Task.Factory.StartNew * Use ordinal comparisons here * [ASsemblyBrowser] Fix child nodes not appearing in the list * [VCS] Fix improper usage of cancellation token source * Remove unneeded string ordering * [AsssemblyBrowser] Fix workspace leak and delay project loading. It's not common to get to a project item from the IDE, so we can delay loading that while we get everything else setup * [MSBuild] Switch this to Task.Run, so we don't accidentally parse on the UI thread * Add doc comment * [AssemblyBrowser] Massively improve time it takes to open and a couple of fixes Reuse the typesystem created for decompilation. No need to create a new one just to load the treeview. Prefer using AddChildren everywhere rather than Add. This helps not sort the tree every time we're adding an element. Don't bother gathering all the types in an assembly. Most likely we will only need to gather types from just one assembly, so defer that to the namespace node builder. Fix multiple iteration of a type's members when trying to load a project metadata view. And fix nested types to appear in the tree. * Optimize this a bit more * Minor refactors to avoid extra Funcs * Reuse typesystem for loader, add new feature transform to prevent language breaking --- .../AssemblyBrowserViewContent.cs | 69 ++++---- .../AssemblyBrowserWidget.cs | 196 ++++++++++----------- .../MonoDevelop.AssemblyBrowser/AssemblyLoader.cs | 33 +--- .../MetadataExtensions.cs | 5 + .../TreeNodes/AssemblyBrowserTypeNodeBuilder.cs | 12 ++ .../TreeNodes/AssemblyReferenceNodeBuilder.cs | 2 +- .../TreeNodes/BaseTypeFolderNodeBuilder.cs | 4 +- .../TreeNodes/Cecil/AssemblyNodeBuilder.cs | 35 ++-- .../TreeNodes/Cecil/MethodDefinitionNodeBuilder.cs | 4 +- .../TreeNodes/Cecil/TypeDefinitionNodeBuilder.cs | 44 ++--- .../TreeNodes/ModuleReferenceNodeBuilder.cs | 2 +- .../TreeNodes/NamespaceBuilder.cs | 14 +- .../TreeNodes/NamespaceData.cs | 49 ++++-- .../TreeNodes/Roslyn/ProjectNodeBuilder.cs | 38 ++-- .../TreeNodes/Roslyn/RoslynMemberNodeBuilder.cs | 47 ++--- .../TreeNodes/Roslyn/RoslynTypeNodeBuilder.cs | 36 ++-- .../MonoDevelop.Debugger/ObjectValueTreeView.cs | 8 +- .../DotNetCoreProjectExtension.cs | 20 ++- .../GitRepository.cs | 8 +- .../GitSelectRevisionDialog.cs | 8 +- .../MonoDevelop.VersionControl/Repository.cs | 2 +- 21 files changed, 301 insertions(+), 335 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserViewContent.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserViewContent.cs index 15a38cfc9f..c4afa8c1b6 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserViewContent.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserViewContent.cs @@ -40,6 +40,7 @@ using System.Collections.Immutable; using MonoDevelop.Ide; using Microsoft.CodeAnalysis.CodeRefactorings; using MonoDevelop.Ide.Gui.Documents; +using System.Threading; namespace MonoDevelop.AssemblyBrowser { @@ -47,7 +48,8 @@ namespace MonoDevelop.AssemblyBrowser { readonly static string[] defaultAssemblies = new string[] { "mscorlib", "System", "System.Core", "System.Xml" }; AssemblyBrowserWidget widget; - + CancellationTokenSource cts = new CancellationTokenSource (); + protected override Control OnGetViewControl (DocumentViewContent view) { widget.SetToolbar (view.GetToolbar ()); @@ -67,11 +69,13 @@ namespace MonoDevelop.AssemblyBrowser FillWidget (); } - protected override async Task OnInitialize (ModelDescriptor modelDescriptor, Properties status) + protected override Task OnInitialize (ModelDescriptor modelDescriptor, Properties status) { if (modelDescriptor is FileDescriptor fileDescriptor) { Load (fileDescriptor.FilePath); } + + return Task.CompletedTask; } protected override bool OnTryReuseDocument (ModelDescriptor modelDescriptor) @@ -92,9 +96,9 @@ namespace MonoDevelop.AssemblyBrowser { var loader = widget.AddReferenceByFileName (filePath); if (loader != null) { - loader.LoadingTask.ContinueWith (delegate { - widget.SelectAssembly (loader); - }); + loader.LoadingTask + .ContinueWith (t => widget.SelectAssembly (t.Result), Runtime.MainTaskScheduler) + .Ignore (); } } @@ -105,12 +109,14 @@ namespace MonoDevelop.AssemblyBrowser protected override void OnDispose () { - if (currentWs != null) - currentWs.WorkspaceLoaded -= Handle_WorkspaceLoaded; + if (cts != null) { + cts.Cancel (); + cts.Dispose (); + cts = null; + } widget = null; - if (Disposed != null) - Disposed (this, EventArgs.Empty); + Disposed?.Invoke (this, EventArgs.Empty); base.OnDispose (); } @@ -162,40 +168,29 @@ namespace MonoDevelop.AssemblyBrowser //FindDerivedClassesHandler.FindDerivedClasses (type); } - void Handle_WorkspaceLoaded (object sender, EventArgs e) - { - foreach (var project in Ide.IdeApp.ProjectOperations.CurrentSelectedSolution.GetAllProjects ()) { - var nav = Widget.TreeView.GetNodeAtObject (project); - if (nav != null) - Widget.TreeView.RefreshNode (nav); - } - } - - Ide.TypeSystem.MonoDevelopWorkspace currentWs; - public async void FillWidget () + public void FillWidget () { if (Ide.IdeApp.ProjectOperations.CurrentSelectedSolution == null) { foreach (var assembly in defaultAssemblies) { - Widget.AddReferenceByAssemblyName (assembly); + Widget.AddReferenceByAssemblyName (assembly); } } else { - var alreadyAdded = new HashSet (); - currentWs = IdeApp.TypeSystemService.GetWorkspace (IdeApp.ProjectOperations.CurrentSelectedSolution); - if (currentWs != null) - currentWs.WorkspaceLoaded += Handle_WorkspaceLoaded; - var allTasks = new List (); - foreach (var project in Ide.IdeApp.ProjectOperations.CurrentSelectedSolution.GetAllProjects ()) { - try { - Widget.AddProject (project, false); - } catch (Exception e) { - LoggingService.LogError ("Error while adding project " + project.Name + " to the tree.", e); - } - } - await Task.WhenAll (allTasks).ContinueWith (delegate { - Runtime.RunInMainThread (delegate { + var token = cts.Token; + + var workspace = IdeApp.TypeSystemService.GetWorkspaceAsync (IdeApp.ProjectOperations.CurrentSelectedSolution) + .ContinueWith (t => { + if (token.IsCancellationRequested) + return; + + foreach (var project in IdeApp.ProjectOperations.CurrentSelectedSolution.GetAllProjects ()) { + try { + Widget.AddProject (project, false); + } catch (Exception e) { + LoggingService.LogError ("Error while adding project " + project.Name + " to the tree.", e); + } + } widget.StartSearch (); - }); - }); + }, token, TaskContinuationOptions.DenyChildAttach, Runtime.MainTaskScheduler); } } } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserWidget.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserWidget.cs index fc47e392e0..681fdac935 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserWidget.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyBrowserWidget.cs @@ -880,19 +880,19 @@ namespace MonoDevelop.AssemblyBrowser inspectEditor.Options = assemblyBrowserEditorOptions; this.inspectEditor.MimeType = "text/x-csharp"; builder.DecompileAsync (inspectEditor, nav, new DecompileFlags { PublicOnly = PublicApiOnly, MethodBodies = false }) - .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler); + .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler).Ignore (); break; case 1: inspectEditor.Options = assemblyBrowserEditorOptions; this.inspectEditor.MimeType = "text/x-ilasm"; builder.DisassembleAsync (inspectEditor, nav) - .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler); + .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler).Ignore (); break; case 2: inspectEditor.Options = assemblyBrowserEditorOptions; this.inspectEditor.MimeType = "text/x-csharp"; builder.DecompileAsync (inspectEditor, nav, new DecompileFlags { PublicOnly = PublicApiOnly, MethodBodies = true }) - .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler); + .ContinueWith (l => SetReferencedSegments (l.Result), Runtime.MainTaskScheduler).Ignore (); break; default: inspectEditor.Options = assemblyBrowserEditorOptions; @@ -914,24 +914,30 @@ namespace MonoDevelop.AssemblyBrowser internal void Open (string url, AssemblyLoader currentAssembly = null, bool expandNode = true) { Task.WhenAll (this.definitions.Select (d => d.LoadingTask)).ContinueWith (d => { - Application.Invoke ((o, args) => { - suspendNavigation = false; - ITreeNavigator nav = SearchMember (url, expandNode); - if (definitions.Count == 0) // we've been disposed - return; - if (nav != null) - return; - try { - if (currentAssembly != null) { - OpenFromAssembly (url, currentAssembly); - } else { - OpenFromAssemblyNames (url); - } - } catch (Exception e) { - LoggingService.LogError ("Error while opening the assembly browser with id:" + url, e); + // At least one of them failed. + if (d.IsFaulted) { + LoggingService.LogError ("Failed to load assemblies", d.Exception); + + // It's possible the assembly in which the type we're looking for exists + // so try probing for it regardless. + } + + suspendNavigation = false; + ITreeNavigator nav = SearchMember (url, expandNode); + if (definitions.Count == 0) // we've been disposed + return; + if (nav != null) + return; + try { + if (currentAssembly != null) { + OpenFromAssembly (url, currentAssembly); + } else { + OpenFromAssemblyNames (url); } - }); - }); + } catch (Exception e) { + LoggingService.LogError ("Error while opening the assembly browser with id:" + url, e); + } + }, Runtime.MainTaskScheduler).Ignore (); } void OpenFromAssembly (string url, AssemblyLoader currentAssembly, bool expandNode = true) @@ -960,16 +966,14 @@ namespace MonoDevelop.AssemblyBrowser result.LoadingTask.ContinueWith (t2 => { if (definitions.Count == 0) // disposed return; - Application.Invoke ((o, args) => { - var nav = SearchMember (url, expandNode); - if (nav == null) { - if (++i == references.Length) - LoggingService.LogError ("Assembly browser: Can't find: " + url + "."); - else - loadNext (); - } - }); - }, TaskScheduler.Current); + var nav = SearchMember (url, expandNode); + if (nav == null) { + if (++i == references.Length) + LoggingService.LogError ("Assembly browser: Can't find: " + url + "."); + else + loadNext (); + } + }, Runtime.MainTaskScheduler).Ignore (); }; } @@ -997,51 +1001,44 @@ namespace MonoDevelop.AssemblyBrowser LoggingService.LogError ("Assembly browser: Can't find: " + url + "."); } return; - }; - Task.Factory.ContinueWhenAll (tasks.ToArray (), tarr => { - var exceptions = tarr.Where (t => t.IsFaulted).Select (t => t.Exception).ToArray (); - if (exceptions != null) { - var ex = new AggregateException (exceptions).Flatten (); - if (ex.InnerExceptions.Count > 0) { - foreach (var inner in ex.InnerExceptions) { - LoggingService.LogError ("Error while loading assembly in the browser.", inner); - } - throw ex; + } + + Task.WhenAll (tasks.ToArray ()) + .ContinueWith (t => { + if (t.IsFaulted) { + LoggingService.LogError ("Error while loading assemblies in the browser", t.Exception); + return; } - } - if (definitions.Count == 0) // disposed - return; - Application.Invoke ((o, args) => { + + if (definitions.Count == 0) // disposed + return; + var nav = SearchMember (url); if (nav == null) { LoggingService.LogError ("Assembly browser: Can't find: " + url + "."); } - }); - }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current); + }, Runtime.MainTaskScheduler).Ignore (); } - internal void SelectAssembly (AssemblyLoader loader) + internal void SelectAssembly (PEFile cu) { - PEFile cu = loader.Assembly; - Application.Invoke ((o, args) => { - ITreeNavigator nav = TreeView.GetRootNode (); - if (nav == null) - return; + ITreeNavigator nav = TreeView.GetRootNode (); + if (nav == null) + return; + + if (expandedMember) { + expandedMember = false; + return; + } - if (expandedMember) { - expandedMember = false; + do { + if (nav.DataItem == cu || (nav.DataItem as AssemblyLoader)?.Assembly == cu) { + nav.ExpandToNode (); + nav.Selected = true; + nav.ScrollToNode (); return; } - - do { - if (nav.DataItem == cu || (nav.DataItem as AssemblyLoader)?.Assembly == cu) { - nav.ExpandToNode (); - nav.Selected = true; - nav.ScrollToNode (); - return; - } - } while (nav.MoveNext ()); - }); + } while (nav.MoveNext ()); } void Dispose (ITreeNavigator nav) where T:class, IDisposable @@ -1095,6 +1092,8 @@ namespace MonoDevelop.AssemblyBrowser def.Dispose (); definitions = definitions.Clear (); } + + projects.Clear (); ActiveMember = null; resultListStore = null; @@ -1124,7 +1123,7 @@ namespace MonoDevelop.AssemblyBrowser ImmutableList definitions = ImmutableList.Empty; - List projects = new List (); + HashSet projects = new HashSet (); internal AssemblyLoader AddReferenceByAssemblyName (PEFile reference, bool expand = false) { @@ -1158,38 +1157,36 @@ namespace MonoDevelop.AssemblyBrowser var result = new AssemblyLoader (this, fileName); definitions = definitions.Add (result); result.LoadingTask = result.LoadingTask.ContinueWith (task => { - Application.Invoke ((o, args) => { - if (TreeView == null || definitions.Count == 0) - return; - var fullName = result.Assembly.FullName; - - // filter duplicate assemblies, can happen on opening the same assembly at different locations. - foreach (var d in definitions) { - if (!d.IsLoaded || d == result) - continue; - if (d.Assembly.FullName == fullName) { - definitions = definitions.Remove (result); - LoggingService.LogInfo ("AssemblyBrowser: Loaded duplicate assembly : " + fullName); // Write a log info in case that happens, shouldn't happen often. - return; - } + if (TreeView == null || definitions.Count == 0) + return task.Result; + var fullName = result.Assembly.FullName; + + // filter duplicate assemblies, can happen on opening the same assembly at different locations. + foreach (var d in definitions) { + if (!d.IsLoaded || d == result) + continue; + if (d.Assembly.FullName == fullName) { + definitions = definitions.Remove (result); + LoggingService.LogInfo ("AssemblyBrowser: Loaded duplicate assembly : " + fullName); // Write a log info in case that happens, shouldn't happen often. + return task.Result; } - - try { - ITreeBuilder builder; - if (definitions.Count + projects.Count == 1) { - builder = TreeView.LoadTree (result); - } else { - builder = TreeView.AddChild (result, false); - } - if (TreeView.GetSelectedNode () == null) - builder.Selected = builder.Expanded = expand; - } catch (Exception e) { - LoggingService.LogError ("Error while adding assembly to the assembly list", e); + } + + try { + ITreeBuilder builder; + if (definitions.Count + projects.Count == 1) { + builder = TreeView.LoadTree (result); + } else { + builder = TreeView.AddChild (result, expand); } - }); + if (TreeView.GetSelectedNode () == null) + builder.Selected = builder.Expanded = expand; + } catch (Exception e) { + LoggingService.LogError ("Error while adding assembly to the assembly list", e); + } return task.Result; - } - ); + }, Runtime.MainTaskScheduler); + return result; } @@ -1198,7 +1195,7 @@ namespace MonoDevelop.AssemblyBrowser if (project == null) throw new ArgumentNullException ("project"); - if (projects.Contains (project)) { + if (!projects.Add (project)) { // Select the project. if (selectReference) { ITreeNavigator navigator = TreeView.GetNodeAtObject (project); @@ -1209,14 +1206,16 @@ namespace MonoDevelop.AssemblyBrowser return; } - projects.Add (project); + ITreeBuilder builder; if (definitions.Count + projects.Count == 1) { builder = TreeView.LoadTree (project); } else { - builder = TreeView.AddChild (project); + builder = TreeView.AddChild (project, false); } - builder.Selected = builder.Expanded = selectReference; + + if (TreeView.GetSelectedNode () == null || selectReference) + builder.Selected = builder.Expanded = selectReference; } //MonoDevelop.Components.RoundedFrame popupWidgetFrame; @@ -1258,6 +1257,7 @@ namespace MonoDevelop.AssemblyBrowser foreach (var def in ensuredDefinitions) { if (!definitions.Contains (def)) { definitions = definitions.Add (def); + Application.Invoke ((o, args) => { if (ensuredDefinitions.Count + projects.Count == 1) { TreeView.LoadTree (def.LoadingTask.Result); diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyLoader.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyLoader.cs index 31d7aed461..8baaf723a1 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyLoader.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/AssemblyLoader.cs @@ -35,6 +35,7 @@ using ICSharpCode.Decompiler.Metadata; using System.Reflection.Metadata; using System.Linq; using ICSharpCode.Decompiler.TypeSystem.Implementation; +using ICSharpCode.Decompiler.CSharp.Transforms; namespace MonoDevelop.AssemblyBrowser { @@ -63,18 +64,13 @@ namespace MonoDevelop.AssemblyBrowser public PEFile Assembly => AssemblyTask.Result; public Task AssemblyTask => assemblyDefinitionTaskSource.Task; - public MetadataReader ModuleDefinition { - get { - return assemblyLoaderTask.Result.Metadata; - } - } - CSharpDecompiler csharpDecompiler; public CSharpDecompiler CSharpDecompiler { get { if (csharpDecompiler == null) { - csharpDecompiler = new CSharpDecompiler (DecompilerTypeSystem, new ICSharpCode.Decompiler.DecompilerSettings ()); + csharpDecompiler = new CSharpDecompiler (DecompilerTypeSystem, new ICSharpCode.Decompiler.DecompilerSettings (LanguageVersion.Latest)); + csharpDecompiler.AstTransforms.Add (new EscapeInvalidIdentifiers ()); } return csharpDecompiler; @@ -84,16 +80,13 @@ namespace MonoDevelop.AssemblyBrowser DecompilerTypeSystem decompilerTypeSystem; public DecompilerTypeSystem DecompilerTypeSystem { get { - LoadTypeSystem (Assembly); + if (decompilerTypeSystem == null) { + decompilerTypeSystem = new DecompilerTypeSystem (Assembly, new AssemblyResolver (Assembly, widget)); + } return decompilerTypeSystem; } } - void LoadTypeSystem (PEFile peFile) - { - decompilerTypeSystem = new DecompilerTypeSystem (peFile, new AssemblyResolver (Assembly, widget)); - } - public Error Error { get; internal set; } public bool IsLoaded { get; private set; } @@ -122,19 +115,7 @@ namespace MonoDevelop.AssemblyBrowser assemblyDefinitionTaskSource.SetResult (null); return null; } finally { IsLoaded = true; } - }); - } - - ICompilation typeSystem; - - public ICompilation GetMinimalTypeSystem () - { - if (typeSystem != null) - return typeSystem; - var assembly = Assembly; - if (assembly == null) - return null; - return typeSystem = new SimpleCompilation (assembly.WithOptions (TypeSystemOptions.Default | TypeSystemOptions.Uncached | TypeSystemOptions.KeepModifiers), MinimalCorlib.Instance); + }, src.Token); } class MyUniversalAssemblyResolver : UniversalAssemblyResolver diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/MetadataExtensions.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/MetadataExtensions.cs index 197fb93c08..df992f6f8c 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/MetadataExtensions.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/MetadataExtensions.cs @@ -40,6 +40,11 @@ namespace MonoDevelop.AssemblyBrowser entity.Accessibility == Accessibility.ProtectedOrInternal || entity.Accessibility == Accessibility.Public; + public static bool IsPublic (this Microsoft.CodeAnalysis.ISymbol entity) => + entity.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Protected || + entity.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.ProtectedOrInternal || + entity.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public; + public static string GetStockIcon (this Accessibility attributes) { switch (attributes) { diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyBrowserTypeNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyBrowserTypeNodeBuilder.cs index 9e9ed85e07..58aa2b9a6f 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyBrowserTypeNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyBrowserTypeNodeBuilder.cs @@ -34,6 +34,7 @@ using MonoDevelop.Ide.TypeSystem; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using System.Threading.Tasks; using System.Collections.Generic; +using System.Linq; namespace MonoDevelop.AssemblyBrowser { @@ -79,5 +80,16 @@ namespace MonoDevelop.AssemblyBrowser return treeBuilder.GetParentDataItem (typeof(AssemblyLoader), true) != null; } + protected static void AddFilteredChildren (ITreeBuilder builder, IReadOnlyCollection collection, bool publicApiOnly) where T:IEntity + { + if (collection.Count == 0) + return; + + var children = publicApiOnly + ? collection.Where (x => x.IsPublic ()) + : collection; + + builder.AddChildren (collection); + } } } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyReferenceNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyReferenceNodeBuilder.cs index 98d83e6e94..641aa3412d 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyReferenceNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/AssemblyReferenceNodeBuilder.cs @@ -82,7 +82,7 @@ namespace MonoDevelop.AssemblyBrowser if (e2 == null) return -1; - return e1.Name.CompareTo (e2.Name); + return string.Compare(e1.Name, e2.Name, StringComparison.Ordinal); } catch (Exception e) { LoggingService.LogError ("Exception in assembly browser sort function.", e); return -1; diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/BaseTypeFolderNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/BaseTypeFolderNodeBuilder.cs index dc17aa56b6..fc1f30d49d 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/BaseTypeFolderNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/BaseTypeFolderNodeBuilder.cs @@ -67,9 +67,7 @@ namespace MonoDevelop.AssemblyBrowser public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode) { - var r1 = thisNode.DataItem as ITypeReference; - var r2 = thisNode.DataItem as ITypeReference; - return r1.ToString ().CompareTo (r2.ToString ()); + return string.Compare (thisNode.NodeName, otherNode.NodeName, StringComparison.Ordinal); } } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/AssemblyNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/AssemblyNodeBuilder.cs index 0e2c3fd73a..d4ac415ec8 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/AssemblyNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/AssemblyNodeBuilder.cs @@ -100,26 +100,23 @@ namespace MonoDevelop.AssemblyBrowser var resources = new AssemblyResourceFolder (assemblyLoader.Assembly); if (resources.Resources.Any ()) treeBuilder.AddChild (resources); - - var namespaces = new Dictionary (); - bool publicOnly = Widget.PublicApiOnly; - - foreach (var type in assemblyLoader.GetMinimalTypeSystem ().MainModule.TopLevelTypeDefinitions) { - string namespaceName = string.IsNullOrEmpty (type.Namespace) ? "" : type.Namespace; - if (!namespaces.ContainsKey (namespaceName)) - namespaces [namespaceName] = new NamespaceData (namespaceName); - - var ns = namespaces [namespaceName]; - ns.Types.Add ((type.IsPublic (), type)); - } - treeBuilder.AddChildren (namespaces.Where (ns => ns.Key != "" && (!publicOnly || ns.Value.Types.Any (t => t.isPublic))).Select (n => n.Value)); - if (namespaces.ContainsKey ("")) { - foreach (var child in namespaces [""].Types) { - if (((INamedElement)child.typeObject).Name == "") - continue; - treeBuilder.AddChild (child); - } + var mainModule = assemblyLoader.DecompilerTypeSystem.MainModule; + var rootData = new NamespaceData (mainModule.RootNamespace); + if (rootData.Types.Length > 0) + treeBuilder.AddChild (rootData); + + var allNamespaces = new List (32); + CollectNamespaces (allNamespaces, mainModule.RootNamespace.ChildNamespaces); + treeBuilder.AddChildren (allNamespaces); + } + + void CollectNamespaces (List accumulator, IEnumerable namespaces) + { + accumulator.AddRange (namespaces.Select (x => new NamespaceData(x))); + + foreach (var ns in namespaces) { + CollectNamespaces (accumulator, ns.ChildNamespaces); } } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/MethodDefinitionNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/MethodDefinitionNodeBuilder.cs index 81b1fa822b..e9b28c36dd 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/MethodDefinitionNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/MethodDefinitionNodeBuilder.cs @@ -124,14 +124,14 @@ namespace MonoDevelop.AssemblyBrowser } - public static async Task> DecompileAsync (TextEditor data, AssemblyLoader assemblyLoader, Func decompile, DecompilerSettings settings = null, DecompileFlags flags = null) + public static Task> DecompileAsync (TextEditor data, AssemblyLoader assemblyLoader, Func decompile, DecompilerSettings settings = null, DecompileFlags flags = null) { if (data == null) throw new ArgumentNullException (nameof (data)); if (assemblyLoader == null) throw new ArgumentNullException (nameof (assemblyLoader)); - return await Task.Run (async delegate { + return Task.Run (async delegate { settings = settings ?? GetDecompilerSettings (data, publicOnly: flags.PublicOnly); var csharpDecompiler = assemblyLoader.CSharpDecompiler; try { diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/TypeDefinitionNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/TypeDefinitionNodeBuilder.cs index b875def8f7..90f83a0e73 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/TypeDefinitionNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Cecil/TypeDefinitionNodeBuilder.cs @@ -98,46 +98,28 @@ namespace MonoDevelop.AssemblyBrowser public override void BuildChildNodes (ITreeBuilder builder, object dataObject) { var type = (ITypeDefinition)dataObject; - var list = new System.Collections.ArrayList (); if (type.DirectBaseTypes.Any ()) - list.Add (new BaseTypeFolder (type)); - bool publicOnly = Widget.PublicApiOnly; - - foreach (var field in type.Fields.OrderBy (m => m.Name, StringComparer.InvariantCulture)) { - if (publicOnly && !field.IsPublic ()) - continue; - builder.AddChild (field); - } - - foreach (var property in type.Properties.OrderBy (m => m.Name, StringComparer.InvariantCulture)) { - var accessor = property.Getter ?? property.Setter; - if (publicOnly && !accessor.IsPublic ()) - continue; - builder.AddChild (property); - } + builder.AddChild (new BaseTypeFolder (type)); - foreach (var evt in type.Events.OrderBy (m => m.Name, StringComparer.InvariantCulture)) { - var accessor = evt.AddAccessor ?? evt.RemoveAccessor; - if (publicOnly && !accessor.IsPublic ()) - continue; - builder.AddChild (evt); - } + bool publicOnly = Widget.PublicApiOnly; - var accessorMethods = type.GetAccessors (); - foreach (var method in type.Methods.OrderBy (m => m.Name, StringComparer.InvariantCulture)) { - if (publicOnly && !method.IsPublic ()) - continue; - if (!accessorMethods.Contains (method)) { - builder.AddChild (method); - } - } + // PERF: We can take advantage of the fact that AddChildren is faster than AddChild, due to not processing + // sorting of child nodes. Avoid creating additional collection, as TreeBuilder does not optimize for ICollection implementors, + // thus the overhead of creating a IEnumerable is not that big. + AddFilteredChildren (builder, type.Members, publicOnly); + AddFilteredChildren (builder, type.NestedTypes, publicOnly); } public override bool HasChildNodes (ITreeBuilder builder, object dataObject) { return true; } - + + public override int GetSortIndex (ITreeNavigator node) + { + return -50; + } + #region IAssemblyBrowserNodeBuilder internal static void PrintAssembly (StringBuilder result, ITreeNavigator navigator) { diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/ModuleReferenceNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/ModuleReferenceNodeBuilder.cs index e9a6b593a2..9262f9612f 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/ModuleReferenceNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/ModuleReferenceNodeBuilder.cs @@ -70,7 +70,7 @@ namespace MonoDevelop.AssemblyBrowser if (e2 == null) return 1; - return e1.Name.CompareTo (e2.Name); + return string.Compare (e1.Name, e2.Name, StringComparison.Ordinal); } catch (Exception e) { LoggingService.LogError ("Exception in assembly browser sort function.", e); return -1; diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceBuilder.cs index 89c848dc27..0307db2738 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceBuilder.cs @@ -64,7 +64,7 @@ namespace MonoDevelop.AssemblyBrowser if (e2 == null) return -1; - return e1.Name.CompareTo (e2.Name); + return string.Compare (e1.Name, e2.Name, StringComparison.Ordinal); } catch (Exception e) { LoggingService.LogError ("Exception in assembly browser sort function.", e); return -1; @@ -87,12 +87,12 @@ namespace MonoDevelop.AssemblyBrowser public override void BuildChildNodes (ITreeBuilder ctx, object dataObject) { NamespaceData ns = (NamespaceData)dataObject; - bool publicOnly = Widget.PublicApiOnly; - foreach (var type in ns.Types) { - if (publicOnly && !type.isPublic) - continue; - ctx.AddChild (type.typeObject); - } + + IEnumerable result = ns.Types; + if (Widget.PublicApiOnly) + result = result.Where (x => NamespaceData.IsPublic (x)); + + ctx.AddChildren (result); } public override bool HasChildNodes (ITreeBuilder builder, object dataObject) diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceData.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceData.cs index 56950b7d79..47a2f0f7f7 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceData.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/NamespaceData.cs @@ -28,42 +28,61 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.Decompiler.TypeSystem; +using MonoDevelop.Ide.TypeSystem; namespace MonoDevelop.AssemblyBrowser { class NamespaceData : IDisposable { - List<(bool, object)> types = new List<(bool, object)> (); - - public string Name { - get; - private set; + public string Name { get; } + INamespace decompilerNs; + Microsoft.CodeAnalysis.INamespaceSymbol roslynNamespace; + + public static bool IsPublic (object typeObject) + { + return (typeObject is ITypeDefinition typeDefinition && typeDefinition.IsPublic ()) + || (typeObject is Microsoft.CodeAnalysis.INamedTypeSymbol symbol && symbol.IsPublic ()); } - public List<(bool isPublic, object typeObject)> Types { + object [] types; + public object[] Types { get { + if (types == null) { + types = decompilerNs?.Types.ToArray () + ?? roslynNamespace?.GetTypeMembers ().ToArray () + ?? Array.Empty (); + } return types; } } - - public NamespaceData (string name) + + public NamespaceData(INamespace ns) { - this.Name = name; + Name = ns.FullName; + decompilerNs = ns; + + // Remove from root namespace. + if (ns.ParentNamespace == null) { + types = decompilerNs.Types.Where (x => x.Name != "").ToArray (); + } + } + + public NamespaceData(Microsoft.CodeAnalysis.INamespaceSymbol namespaceSymbol) + { + Name = namespaceSymbol.GetFullName (); + roslynNamespace = namespaceSymbol; } public void Dispose () { - if (types != null) { - // types.ForEach (t => t.Dispose ()); - types.Clear (); - types = null; - } + types = null; } public override string ToString () { - return string.Format ("[Namespace: Name={0}, #Types={1}]", Name, Types.Count); + return string.Format ("[Namespace: Name={0}, #Types={1}]", Name, Types.Length); } } } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/ProjectNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/ProjectNodeBuilder.cs index e65bfd01da..15487176c0 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/ProjectNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/ProjectNodeBuilder.cs @@ -58,7 +58,7 @@ namespace MonoDevelop.AssemblyBrowser var project = (Project)dataObject; return project.Name; } - + public override void BuildNode (ITreeBuilder treeBuilder, object dataObject, NodeInfo nodeInfo) { var project = (Project)dataObject; @@ -74,27 +74,27 @@ namespace MonoDevelop.AssemblyBrowser var dom = IdeApp.TypeSystemService.GetCompilationAsync (project).Result; if (dom == null) return; - bool nestedNamespaces = builder.Options ["NestedNamespaces"]; - HashSet addedNames = new HashSet (); - foreach (var ns in dom.Assembly.GlobalNamespace.GetNamespaceMembers ()) { - FillNamespaces (builder, project, ns); + + var data = new List (32); + CollectNamespaces (data, dom.Assembly.GlobalNamespace.GetNamespaceMembers ()); + builder.AddChildren (data); + + var types = dom.Assembly.GlobalNamespace.GetTypeMembers (); + if (types.Length > 0) { + var children = publicOnly + ? types.Where (t => t.IsPublic ()) + : types; + + builder.AddChildren (children); } - builder.AddChildren (dom.Assembly.GlobalNamespace.GetTypeMembers () - .Where (type => !publicOnly || type.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public)); } - public static void FillNamespaces (ITreeBuilder builder, Project project, Microsoft.CodeAnalysis.INamespaceSymbol ns) + static void CollectNamespaces (List acc, IEnumerable namespaces) { - var members = ns.GetTypeMembers (); - //IParserContext ctx = IdeApp.Workspace.ParserDatabase.GetProjectParserContext (project); - if (members.Any ()) { - var data = new NamespaceData (ns.Name); - foreach (var member in members) - data.Types.Add ((member.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public, member)); - builder.AddChild (data); - } - foreach (var nSpace in ns.GetNamespaceMembers ()) { - FillNamespaces (builder, project, nSpace); + acc.AddRange (namespaces.Select (x => new NamespaceData (x))); + + foreach (var ns in namespaces) { + CollectNamespaces (acc, ns.GetNamespaceMembers ()); } } @@ -118,7 +118,7 @@ namespace MonoDevelop.AssemblyBrowser if (e2 == null) return 1; - return e1.Name.CompareTo (e2.Name); + return string.Compare (e1.Name, e2.Name, StringComparison.Ordinal); } catch (Exception e) { LoggingService.LogError ("Exception in assembly browser sort function.", e); return -1; diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynMemberNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynMemberNodeBuilder.cs index 57b2f79562..3707a94029 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynMemberNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynMemberNodeBuilder.cs @@ -45,39 +45,14 @@ namespace MonoDevelop.AssemblyBrowser public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode) { - if (!(otherNode.DataItem is ISymbol)) return 1; - - if (thisNode.Options ["GroupByType"]) { - int v1 = GetTypeSortValue (thisNode.DataItem); - int v2 = GetTypeSortValue (otherNode.DataItem); - if (v1 < v2) return -1; - else if (v1 > v2) return 1; - } - if (thisNode.Options ["GroupByAccess"]) { - int v1 = GetAccessSortValue (((ISymbol)thisNode.DataItem).DeclaredAccessibility); - int v2 = GetAccessSortValue (((ISymbol)otherNode.DataItem).DeclaredAccessibility); - if (v1 < v2) return -1; - else if (v1 > v2) return 1; + try { + if (thisNode == null || otherNode == null) + return -1; + return string.Compare (thisNode.NodeName, otherNode.NodeName, StringComparison.OrdinalIgnoreCase); + } catch (Exception e) { + LoggingService.LogError ("Exception in assembly browser sort function.", e); + return -1; } - return DefaultSort; - } - - int GetTypeSortValue (object member) - { - if (member is IFieldSymbol) return 0; - if (member is IEventSymbol) return 1; - if (member is IPropertySymbol) return 2; - if (member is IMethodSymbol) return 3; - return 4; - } - - int GetAccessSortValue (Accessibility mods) - { - if ((mods & Accessibility.Private) != 0) return 0; - if ((mods & Accessibility.Internal) != 0) return 1; - if ((mods & Accessibility.Protected) != 0) return 2; - if ((mods & Accessibility.Public) != 0) return 3; - return 4; } public Task> DecompileAsync (TextEditor data, ITreeNavigator navigator, DecompileFlags flags) @@ -85,17 +60,17 @@ namespace MonoDevelop.AssemblyBrowser return DisassembleAsync (data, navigator); } - public Task> DisassembleAsync (TextEditor data, ITreeNavigator navigator) + public async Task> DisassembleAsync (TextEditor data, ITreeNavigator navigator) { var symbol = navigator.DataItem as ISymbol; if (symbol == null) { data.Text = "// DataItem is no symbol " + navigator.DataItem; // should never happen LoggingService.LogError ("DataItem is no symbol " + navigator.DataItem); - return AssemblyBrowserTypeNodeBuilder.EmptyReferenceSegmentTask; + return new List (); } var location = symbol.Locations [0]; if (location.IsInSource) { - var root = location.SourceTree.GetRoot (); + var root = await location.SourceTree.GetRootAsync (); var node = root.FindNode (location.SourceSpan); if (node != null) { data.Text = node.ToFullString (); @@ -106,7 +81,7 @@ namespace MonoDevelop.AssemblyBrowser data.Text = "// Error: Symbol " + symbol.MetadataName + " is not in source."; // should never happen LoggingService.LogError ("Symbol " + symbol.MetadataName + " is not in source."); } - return AssemblyBrowserTypeNodeBuilder.EmptyReferenceSegmentTask; + return new List (); } diff --git a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynTypeNodeBuilder.cs b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynTypeNodeBuilder.cs index 81b74424aa..b798484b31 100644 --- a/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynTypeNodeBuilder.cs +++ b/main/src/addins/MonoDevelop.AssemblyBrowser/MonoDevelop.AssemblyBrowser/TreeNodes/Roslyn/RoslynTypeNodeBuilder.cs @@ -88,30 +88,24 @@ namespace MonoDevelop.AssemblyBrowser if (classData.TypeKind == TypeKind.Delegate) return; - builder.AddChildren (classData.GetTypeMembers () - .Where (innerClass => innerClass.DeclaredAccessibility == Accessibility.Public || - (innerClass.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); + Func filter = symbol => !MethodPropertyFilter (symbol); + if (Widget.PublicApiOnly) + filter = symbol => symbol.IsPublic () && !MethodPropertyFilter (symbol); - builder.AddChildren (classData.GetMembers ().OfType ().Where (m => m.MethodKind != MethodKind.PropertyGet && m.MethodKind != MethodKind.PropertySet) - .Where (method => method.DeclaredAccessibility == Accessibility.Public || - (method.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); + var typeMembers = classData.GetTypeMembers (); + if (typeMembers.Length > 0) { + builder.AddChildren (Enumerable.Where (typeMembers, filter)); + } - builder.AddChildren (classData.GetMembers ().OfType () - .Where (property => property.DeclaredAccessibility == Accessibility.Public || - (property.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); + var members = classData.GetMembers (); + if (members.Length > 0) { + builder.AddChildren (members.Where (filter)); + } - builder.AddChildren (classData.GetMembers ().OfType () - .Where (field => field.DeclaredAccessibility == Accessibility.Public || - (field.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); - - builder.AddChildren (classData.GetMembers ().OfType () - .Where (e => e.DeclaredAccessibility == Accessibility.Public || - (e.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); + bool MethodPropertyFilter (ISymbol symbol) + { + return symbol is IMethodSymbol method && (method.MethodKind == MethodKind.PropertyGet || method.MethodKind == MethodKind.PropertySet); + } } public override bool HasChildNodes (ITreeBuilder builder, object dataObject) diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValueTreeView.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValueTreeView.cs index a7f5cb353d..afceba6802 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValueTreeView.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValueTreeView.cs @@ -947,15 +947,15 @@ namespace MonoDevelop.Debugger } int numberOfChildren = store.IterNChildren (iter); - Task.Factory.StartNew (delegate (object arg) { + Task.Run (() => { try { - return ((ObjectValue)arg).GetRangeOfChildren (numberOfChildren - 1, 20); + return value.GetRangeOfChildren (numberOfChildren - 1, 20); } catch (Exception ex) { // Note: this should only happen if someone breaks ObjectValue.GetAllChildren() LoggingService.LogError ("Failed to get ObjectValue children.", ex); return new ObjectValue[0]; } - }, value, cancellationTokenSource.Token).ContinueWith (t => { + }, cancellationTokenSource.Token).ContinueWith (t => { TreeIter it; if (disposed) return; @@ -975,7 +975,7 @@ namespace MonoDevelop.Debugger if (compact) RecalculateWidth (); enumerableLoading.Remove (value); - }, cancellationTokenSource.Token, TaskContinuationOptions.NotOnCanceled, Xwt.Application.UITaskScheduler); + }, cancellationTokenSource.Token, TaskContinuationOptions.NotOnCanceled, Runtime.MainTaskScheduler).Ignore (); } void RefreshRow (TreeIter iter, ObjectValue val) diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs index 984c13692c..df43588e79 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs @@ -58,15 +58,19 @@ namespace MonoDevelop.DotNetCore void FileService_FileChanged (object sender, FileEventArgs e) { - var globalJson = e.FirstOrDefault (x => x.FileName.FileName.IndexOf ("global.json", StringComparison.OrdinalIgnoreCase) == 0 && !x.FileName.IsDirectory); - if (globalJson == null) - return; - - // make sure the global.json file that has been changed is the one we got when loading the project - if (Project.ParentSolution.ExtendedProperties [GlobalJsonPathExtendedPropertyName] is string globalJsonPath - && globalJsonPath.IndexOf (globalJson.FileName, StringComparison.OrdinalIgnoreCase) == 0) { - DetectSDK (restore: true); + foreach (var arg in e) { + if (arg.IsDirectory || !arg.FileName.HasExtension (".json")) + continue; + + // avoid allocation caused by not querying .FileName + string fileName = arg.FileName; + // make sure the global.json file that has been changed is the one we got when loading the project + if (Project.ParentSolution.ExtendedProperties [GlobalJsonPathExtendedPropertyName] is string globalJsonPath + && globalJsonPath.Equals (fileName, StringComparison.OrdinalIgnoreCase)) { + DetectSDK (restore: true); + } } + } protected override bool SupportsObject (WorkspaceObject item) diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs index 3b22615cab..301d8a6b92 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs @@ -107,8 +107,8 @@ namespace MonoDevelop.VersionControl.Git { if (scheduler == null) { scheduler = new ConcurrentExclusiveSchedulerPair (); - blockingOperationFactory = new TaskFactory (scheduler.ExclusiveScheduler); - readingOperationFactory = new TaskFactory (scheduler.ConcurrentScheduler); + blockingOperationFactory = new TaskFactory (default, TaskCreationOptions.PreferFairness, TaskContinuationOptions.PreferFairness, scheduler.ExclusiveScheduler); + readingOperationFactory = new TaskFactory (default, TaskCreationOptions.PreferFairness, TaskContinuationOptions.PreferFairness, scheduler.ConcurrentScheduler); } } @@ -431,10 +431,12 @@ namespace MonoDevelop.VersionControl.Git var submoduleWriteTime = File.GetLastWriteTimeUtc (RootPath.Combine (".gitmodules")); if (cachedSubmoduleTime != submoduleWriteTime) { cachedSubmoduleTime = submoduleWriteTime; - cachedSubmodules = RootRepository.Submodules.Select (s => { + lock (this) { + cachedSubmodules = RootRepository.Submodules.Select (s => { var fp = new FilePath (Path.Combine (RootRepository.Info.WorkingDirectory, s.Path.Replace ('/', Path.DirectorySeparatorChar))).CanonicalPath; return new Tuple (fp, new LibGit2Sharp.Repository (fp)); }).ToArray (); + } } return cachedSubmodules; } diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitSelectRevisionDialog.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitSelectRevisionDialog.cs index 3947f48909..50bf7e6136 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitSelectRevisionDialog.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitSelectRevisionDialog.cs @@ -105,7 +105,9 @@ namespace MonoDevelop.VersionControl.Git }; revisionList.Columns.Add (shaColumn); - Task.Factory.StartNew (async () => { + var token = cts.Token; + + Task.Run (async () => { const int sliceSize = 150; var history = repo.GetHistory (repo.RootPath, null); @@ -114,7 +116,7 @@ namespace MonoDevelop.VersionControl.Git for (int i = 0; i < slices; ++i) { await Runtime.RunInMainThread (() => { for (int n = 0; n < sliceSize; ++n) { - if (cts.IsCancellationRequested) + if (token.IsCancellationRequested) return; int row = revisionStore.AddRow (); @@ -128,7 +130,7 @@ namespace MonoDevelop.VersionControl.Git } }); } - }, cts.Token); + }, token).Ignore (); revisionList.SelectionChanged += delegate { CheckSensitive (); diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs index 8ac398f2a8..7ec8059025 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs @@ -281,7 +281,7 @@ namespace MonoDevelop.VersionControl RecursiveDirectoryInfoQuery rq; bool query = false; lock (queryLock) { - rq = recursiveDirectoryQueryQueue.FirstOrDefault (q => q.Directory == path); + rq = recursiveDirectoryQueryQueue.FirstOrDefault (q => q.Directory == path || path.IsChildPathOf (q.Directory)); if (rq == null) { query = true; var mre = new ManualResetEvent (false); -- cgit v1.2.3 From 788db1611148a030de9df8b2ae09eb453aa69e94 Mon Sep 17 00:00:00 2001 From: iain holmes Date: Thu, 6 Jun 2019 16:46:35 +0100 Subject: [Mac] Don't resize the window frame when placing the window Calling setFrame on the NSWindow resizes the window, but not the Gtk contents causing offset issues in 8.1 There appears to be a race condition caused by making the startup sequence more async than in previous versions. This is triggered by starting MonoDevelop from Finder by double clicking on a solution file. The call to Ide.OpenFilesAsync occurs earlier in the startup sequence now, and the call to Workbench.Present causes the error. Workbench.Show is called later in the method by OpenWorkbenchItem, and if we remove the first call to Workbench.Present, then the workbench window opens correctly, but slightly later. I am still tracking this down, but removing this setFrame call seems to be the least dangerous fix for this bug until we fully understand what is going on. Fixes VSTS #900933 --- main/src/addins/MacPlatform/MacPlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs index d60c4f79c8..90116f6d53 100644 --- a/main/src/addins/MacPlatform/MacPlatform.cs +++ b/main/src/addins/MacPlatform/MacPlatform.cs @@ -1281,7 +1281,7 @@ namespace MonoDevelop.MacIntegration y += GetTitleBarHeight (w); var dr = FromDesktopRect (new Gdk.Rectangle (x, y, width, height)); var r = w.FrameRectFor (dr); - w.SetFrame (r, true); + base.PlaceWindow (window, x, y, width, height); } -- cgit v1.2.3 From 51c223960bd20df37c49b3dc35100a58a7846343 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Thu, 6 Jun 2019 10:44:32 -0400 Subject: [Debugger] Improved source checksum logic for UNIX and DOS line endings Since it is possible that the assemblies being debugged could have been compiled on a different system (potentially with different line endings), compute hashes for the source code in 3 formats: 1. The source code file with line endings as-is 2. The source code file with DOS line endings 3. The source code file with UNIX line endings Note: sometimes source code may have mixed line endings, so it is important to calculate the source code as-is and not just canonicalized UNIX and DOS line endings. Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/642329 Fixes issue #5260 --- .../MonoDevelop.Debugger/SourceCodeLookup.cs | 56 ++++------------------ 1 file changed, 8 insertions(+), 48 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/SourceCodeLookup.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/SourceCodeLookup.cs index bd69d29c79..91cc41a8e8 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/SourceCodeLookup.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/SourceCodeLookup.cs @@ -23,15 +23,17 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. + using System; -using MonoDevelop.Core; -using System.Collections.Generic; using System.IO; -using System.Security.Cryptography; using System.Linq; +using System.Collections.Generic; + +using Mono.Debugging.Client; + using MonoDevelop.Ide; +using MonoDevelop.Core; using MonoDevelop.Projects; -using Mono.Debugging.Client; namespace MonoDevelop.Debugger { @@ -120,50 +122,9 @@ namespace MonoDevelop.Debugger return FilePath.Null; } - public static bool CheckFileHash (FilePath file, byte[] hash) + public static bool CheckFileHash (FilePath path, byte[] checksum) { - if (hash == null) - return false; - if (File.Exists (file)) { - using (var fs = File.OpenRead (file)) { - // Roslyn SHA1 checksum always starts with 20 - if (hash.Length > 0 && hash [0] == 20) - using (var sha1 = SHA1.Create ()) { - if (sha1.ComputeHash (fs).Take (15).SequenceEqual (hash.Skip (1))) { - return true; - } - } - if (hash.Length > 0 && hash [0] == 32) - using (var sha1 = SHA256.Create ()) { - if (sha1.ComputeHash (fs).Take (15).SequenceEqual (hash.Skip (1))) { - return true; - } - } - if (hash.Length == 20) { - using (var sha1 = SHA1.Create ()) { - fs.Position = 0; - if (sha1.ComputeHash (fs).SequenceEqual (hash)) { - return true; - } - } - } - if (hash.Length == 32) { - using (var sha256 = SHA256.Create ()) { - fs.Position = 0; - if (sha256.ComputeHash (fs).SequenceEqual (hash)) { - return true; - } - } - } - fs.Position = 0; - using (var md5 = MD5.Create ()) { - if (md5.ComputeHash (fs).SequenceEqual (hash)) { - return true; - } - } - } - } - return false; + return SourceLocation.CheckFileHash (path, checksum); } /// @@ -223,4 +184,3 @@ namespace MonoDevelop.Debugger } } } - -- cgit v1.2.3