diff options
73 files changed, 1248 insertions, 563 deletions
diff --git a/main/build/MacOSX/Makefile.am b/main/build/MacOSX/Makefile.am index 37d22f0e65..e662ab92d5 100644 --- a/main/build/MacOSX/Makefile.am +++ b/main/build/MacOSX/Makefile.am @@ -12,7 +12,7 @@ EXTERNAL=../../external MONOSTUB_STATIC_LINK=$(EXTERNAL)/Xamarin.Mac.registrar.full.a if !RELEASE_BUILDS -HYBRID_SUSPEND_ABORT=-DHYBRID_SUSPEND_ABORT +HYBRID_SUSPEND_ABORT_DEBUG=-DHYBRID_SUSPEND_ABORT_DEBUG endif #SDK_PATH=$(shell xcrun --sdk macosx10.8 --show-sdk-path) diff --git a/main/build/MacOSX/make-dmg-bundle.sh b/main/build/MacOSX/make-dmg-bundle.sh index 1170152801..748aceaf4d 100755 --- a/main/build/MacOSX/make-dmg-bundle.sh +++ b/main/build/MacOSX/make-dmg-bundle.sh @@ -32,22 +32,9 @@ MOUNT_POINT="$VOLUME_NAME.mounted" rm -f "$DMG_FILE" rm -f "$DMG_FILE.master" -# Compute an approximated image size in MB, and bloat by double -# codesign adds a unknown amount of extra size requirements and there are some -# files where the additional size required is even more "unknown". doubling -# is a brute force approach, but doesn't really impact final distribution size -# because the empty space is compressed to nothing. -image_size=$(du -ck "$DMG_APP" | tail -n1 | cut -f1) -image_size=$((($image_size *2) / 1000)) - -echo "Creating disk image (${image_size}MB)..." -hdiutil create "$DMG_FILE" -megabytes $image_size -volname "$VOLUME_NAME" -fs HFS+ -quiet || exit $? - -echo "Attaching to disk image..." -hdiutil attach "$DMG_FILE" -readwrite -noautoopen -mountpoint "$MOUNT_POINT" -quiet || exit $? - echo "Populating image..." +mkdir -p "$MOUNT_POINT/.background" # this used to be mv, but we need to preserve the bundle directory to do more checks on the contents # such as compatibility-check ditto "$DMG_APP" "$MOUNT_POINT/$DMG_APP" @@ -74,20 +61,19 @@ if [ -e VolumeIcon.icns ] ; then fi SetFile -a C "$MOUNT_POINT" -echo "Detaching from disk image..." -hdiutil detach "$MOUNT_POINT" -quiet || exit $? - -mv "$DMG_FILE" "$DMG_FILE.master" +# Compute an approximated image size in MB, and bloat by double +# codesign adds a unknown amount of extra size requirements and there are some +# files where the additional size required is even more "unknown". doubling +# is a brute force approach, but doesn't really impact final distribution size +# because the empty space is compressed to nothing. +image_size=$(du -ck "$DMG_APP" | tail -n1 | cut -f1) +image_size=$((($image_size *2) / 1000)) -echo "Creating distributable image..." -hdiutil convert -quiet -format UDBZ -o "$DMG_FILE" "$DMG_FILE.master" || exit $? +echo "Creating disk image (${image_size}MB)..." +hdiutil create -srcfolder "$MOUNT_POINT" -megabytes $image_size -ov "$DMG_FILE" -volname "$VOLUME_NAME" -fs HFS+ -format UDBZ || exit $? echo "Built disk image $DMG_FILE" -if [ ! "x$1" = "x-m" ]; then -rm "$DMG_FILE.master" -fi - rm -rf "$MOUNT_POINT" echo "Done." diff --git a/main/build/MacOSX/monostub.mm b/main/build/MacOSX/monostub.mm index d6bd254556..600a161d2e 100644 --- a/main/build/MacOSX/monostub.mm +++ b/main/build/MacOSX/monostub.mm @@ -277,13 +277,11 @@ main (int argc, char **argv) // prevents the code from running correctly, so unset it here. // See https://devdiv.visualstudio.com/DevDiv/_workitems/edit/896438 unsetenv ("MONO_REGISTRY_PATH"); -#if HYBRID_SUSPEND_ABORT + +#if HYBRID_SUSPEND_ABORT_DEBUG setenv ("MONO_SLEEP_ABORT_LIMIT", "5000", 0); #endif - // To be removed: https://github.com/mono/monodevelop/issues/6326 - setenv ("MONO_THREADS_SUSPEND", "preemptive", 0); - setenv ("MONO_GC_PARAMS", "major=marksweep-conc,nursery-size=8m", 0); void *libmono = dlopen ("libmonosgen-2.0.dylib", RTLD_LAZY); diff --git a/main/external/debugger-libs b/main/external/debugger-libs -Subproject 7bca91a582a8161b0765e9121abb61b2aa28541 +Subproject 0ab6b6eb9331f4dcbda476d5652584ed8feeac2 diff --git a/main/external/vs-editor-api b/main/external/vs-editor-api -Subproject 5bd38ee6dcf9c128fe2e890711b1e1d2030cf99 +Subproject 1bc2074f35ff1df5500d5b9d86de4f4417206e4 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 @@ <Compile Include="MonoDevelop.CSharp.Refactoring\CommandArgsFactories.cs" /> <Compile Include="MonoDevelop.CSharp.Debugger\DebuggerCompletionController.cs" /> <Compile Include="MonoDevelop.CSharp.ClassOutline\CSharpOutlineTextEditorExtensionProvider.cs" /> + <Compile Include="MonoDevelop.CSharp.Debugger\CSharpBreakpointSpanResolver.cs" /> </ItemGroup> <ItemGroup> <None Include="MonoDevelop.CSharp.CodeRefactorings\ConvertToEnum\ConvertToEnumCodeRefactoringProvider.cs" /> 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..15aaf60a49 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 @@ -47,6 +49,8 @@ namespace MonoDevelop.CSharp.Project private global::Gtk.VBox vbox3; private global::Gtk.Table table2; + + private MonoDevelop.Components.ImageView langVersionWarningIcon; private global::Gtk.Label label2; @@ -254,14 +258,21 @@ 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.Menu); + this.langVersionWarningIcon.Visible = false; + 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, 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"; 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..f21971dc9f --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Debugger/CSharpBreakpointSpanResolver.cs @@ -0,0 +1,58 @@ +// +// CSharpBreakpointSpanResolver.cs +// +// Author: +// Jeffrey Stedfast <jestedfa@microsoft.com> +// +// 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")] + class CSharpBreakpointSpanResolver : DocumentControllerExtension, IBreakpointSpanResolver + { + public override Task<bool> SupportsController (DocumentController controller) + { + return Task.FromResult (controller.GetContent<ITextBuffer> () != null); + } + + public async Task<Span> 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/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..99525f77db 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CompilerOptionsPanelWidget.cs @@ -29,6 +29,8 @@ using System; using System.Linq; +using System.Collections.Generic; +using System.Text.RegularExpressions; using Gtk; using MonoDevelop.Components; @@ -55,7 +57,7 @@ namespace MonoDevelop.CSharp.Project LanguageVersion.LatestMajor, LanguageVersion.Preview }; - + public CompilerOptionsPanelWidget (DotNetProject project) { this.Build(); @@ -98,26 +100,51 @@ 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 ()) { - if (unsupportedLanguageVersions.Contains (version) && compilerParameters.LangVersion != version) { - // Mono's MSBuild does not currently support C# 8. + var langVerStore = new ListStore (typeof (string), typeof(LanguageVersion), typeof (bool)); + var langVersions = CSharpLanguageVersionHelper.GetKnownLanguageVersions (); + string badVersion = null; + LanguageVersion? langVersion = null; + + try { + langVersion = compilerParameters.LangVersion; + } catch (Exception) { + badVersion = configuration.Properties.GetProperty ("LangVersion").Value; + } + + foreach (var (text, version) in langVersions) { + if (unsupportedLanguageVersions.Contains (version)) { + 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); + langVerStore.AppendValues (text, version, false); } } + langVerCombo.Model = langVerStore; - TreeIter iter; - if (langVerStore.GetIterFirst (out iter)) { - do { - var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); - if (val == compilerParameters.LangVersion) { - langVerCombo.SetActiveIter (iter); - break; - } - } while (langVerStore.IterNext (ref iter)); + if (badVersion != null) { + var badIter = langVerStore.AppendValues (GettextCatalog.GetString ("{0} (Unknown Version)", badVersion), LanguageVersion.Default, true); + langVerCombo.SetActiveIter (badIter); + langVersionWarningIcon.Visible = true; + } else { + TreeIter iter; + if (langVerStore.GetIterFirst (out iter)) { + do { + var val = (LanguageVersion)(int)langVerStore.GetValue (iter, 1); + if (val == compilerParameters.LangVersion) { + langVerCombo.SetActiveIter (iter); + break; + } + } while (langVerStore.IterNext (ref iter)); + } } SetupAccessibility (); @@ -175,11 +202,13 @@ namespace MonoDevelop.CSharp.Project public void Store (ItemConfigurationCollection<ItemConfiguration> 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) { @@ -218,7 +247,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; } } 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); } 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<string> (); - currentWs = IdeApp.TypeSystemService.GetWorkspace (IdeApp.ProjectOperations.CurrentSelectedSolution); - if (currentWs != null) - currentWs.WorkspaceLoaded += Handle_WorkspaceLoaded; - var allTasks = new List<Task> (); - 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<T> (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<AssemblyLoader> definitions = ImmutableList<AssemblyLoader>.Empty; - List<Project> projects = new List<Project> (); + HashSet<Project> projects = new HashSet<Project> (); 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<PEFile> 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<T> (ITreeBuilder builder, IReadOnlyCollection<T> 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<string, NamespaceData> (); - 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 == "<Module>") - 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<NamespaceData> (32); + CollectNamespaces (allNamespaces, mainModule.RootNamespace.ChildNamespaces); + treeBuilder.AddChildren (allNamespaces); + } + + void CollectNamespaces (List<NamespaceData> accumulator, IEnumerable<INamespace> 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<List<ReferenceSegment>> DecompileAsync (TextEditor data, AssemblyLoader assemblyLoader, Func<CSharpDecompiler, SyntaxTree> decompile, DecompilerSettings settings = null, DecompileFlags flags = null) + public static Task<List<ReferenceSegment>> DecompileAsync (TextEditor data, AssemblyLoader assemblyLoader, Func<CSharpDecompiler, SyntaxTree> 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<object> 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<object> (); + } return types; } } - - public NamespaceData (string name) + + public NamespaceData(INamespace ns) { - this.Name = name; + Name = ns.FullName; + decompilerNs = ns; + + // Remove <Module> from root namespace. + if (ns.ParentNamespace == null) { + types = decompilerNs.Types.Where (x => x.Name != "<Module>").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<string> addedNames = new HashSet<string> (); - foreach (var ns in dom.Assembly.GlobalNamespace.GetNamespaceMembers ()) { - FillNamespaces (builder, project, ns); + + var data = new List<NamespaceData> (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<NamespaceData> acc, IEnumerable<Microsoft.CodeAnalysis.INamespaceSymbol> 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<List<ReferenceSegment>> DecompileAsync (TextEditor data, ITreeNavigator navigator, DecompileFlags flags) @@ -85,17 +60,17 @@ namespace MonoDevelop.AssemblyBrowser return DisassembleAsync (data, navigator); } - public Task<List<ReferenceSegment>> DisassembleAsync (TextEditor data, ITreeNavigator navigator) + public async Task<List<ReferenceSegment>> 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<ReferenceSegment> (); } 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<ReferenceSegment> (); } 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<ISymbol, bool> filter = symbol => !MethodPropertyFilter (symbol); + if (Widget.PublicApiOnly) + filter = symbol => symbol.IsPublic () && !MethodPropertyFilter (symbol); - builder.AddChildren (classData.GetMembers ().OfType<IMethodSymbol> ().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<IPropertySymbol> () - .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<IFieldSymbol> () - .Where (field => field.DeclaredAccessibility == Accessibility.Public || - (field.DeclaredAccessibility == Accessibility.Protected && publicProtectedOnly) || - !publicOnly)); - - builder.AddChildren (classData.GetMembers ().OfType<IEventSymbol> () - .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.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<Breakpoint, ManagerBreakpoint> breakpoints = new Dictionary<Breakpoint, ManagerBreakpoint> (); - private void OnBreakpointsChanged (object sender, EventArgs eventArgs) + private async void OnBreakpointsChanged (object sender, EventArgs eventArgs) { - var snapshot = textBuffer.CurrentSnapshot; var newBreakpoints = new Dictionary<Breakpoint, ManagerBreakpoint> (); - 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 @@ <Compile Include="MonoDevelop.Debugger.VSTextView\QuickInfo\IDebugInfoProvider.cs" /> <Compile Include="MonoDevelop.Debugger.VSTextView\BreakpointManagerService.cs" /> <Compile Include="MonoDevelop.Debugger.VSTextView\BreakpointManager.cs" /> + <Compile Include="MonoDevelop.Debugger\IBreakpointSpanResolver.cs" /> + <Compile Include="MonoDevelop.Debugger\DefaultBreakpointSpanResolver.cs" /> </ItemGroup> <ItemGroup Condition="$(OS) != 'Windows_NT'"> <Compile Include="MonoDevelop.Debugger.VSTextView\ExceptionCaught\ExceptionCaughtProvider.cs" /> 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<Span> 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<IBreakpointSpanResolver> (); + + 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 <jestedfa@microsoft.com> +// +// 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<Span> 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 <jestedfa@microsoft.com> +// +// 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 +{ + /// <summary> + /// An interface for resolving the span of a breakpoint. + /// </summary> + public interface IBreakpointSpanResolver + { + /// <summary> + /// Resolve the span of a breakpoint. + /// </summary> + /// <param name="buffer">The text buffer.</param> + /// <param name="position">The cursor position.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>The span of the breakpoint.</returns> + Task<Span> GetBreakpointSpanAsync (ITextBuffer buffer, int position, CancellationToken cancellationToken); + } +} 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<ObjectValue[]> (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.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); } /// <summary> @@ -223,4 +184,3 @@ namespace MonoDevelop.Debugger } } } - 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/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs index 8c3540eacd..be0378ce09 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Commands/PackagesCommandHandler.cs @@ -56,38 +56,34 @@ namespace MonoDevelop.PackageManagement.Commands protected DotNetProject GetSelectedDotNetProject ()
{
- return IdeApp.ProjectOperations.CurrentSelectedProject as DotNetProject;
- }
-
- protected bool SelectedDotNetProjectHasPackages ()
- {
- DotNetProject project = GetSelectedDotNetProject ();
- return (project != null) && project.HasPackages ();
+ return CurrentSelectedProject as DotNetProject;
}
protected bool IsDotNetSolutionSelected ()
{
- return IdeApp.ProjectOperations.CurrentSelectedSolution != null;
+ return CurrentSelectedSolution != null;
}
- protected bool SelectedDotNetSolutionHasPackages ()
- {
- Solution solution = IdeApp.ProjectOperations.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 ()
@@ -96,7 +92,7 @@ namespace MonoDevelop.PackageManagement.Commands if (project != null) {
return project.ParentSolution;
}
- return IdeApp.ProjectOperations.CurrentSelectedSolution;
+ return CurrentSelectedSolution;
}
protected bool CanUpdatePackagesForSelectedDotNetProject () @@ -107,7 +103,7 @@ namespace MonoDevelop.PackageManagement.Commands bool CanUpdatePackagesForSelectedDotNetSolution ()
{
- Solution solution = IdeApp.ProjectOperations.CurrentSelectedSolution;
+ Solution solution = CurrentSelectedSolution;
return solution?.CanUpdatePackages () == true;
} @@ -120,5 +116,19 @@ namespace MonoDevelop.PackageManagement.Commands }
return false;
}
+
+ /// <summary> + /// Used by unit tests to avoid having to initialize the IDE workspace. + /// </summary>
+ protected virtual Solution CurrentSelectedSolution {
+ get { return IdeApp.ProjectOperations.CurrentSelectedSolution; }
+ } + + /// <summary> + /// Used by unit tests to avoid having to initialize the IDE workspace. + /// </summary> + protected virtual Project CurrentSelectedProject {
+ get { return IdeApp.ProjectOperations.CurrentSelectedProject; }
+ }
}
}
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.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 <matt.ward@microsoft.com> +// +// 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 <matt.ward@microsoft.com> +// +// 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 25d8ffd69f..db41a064a4 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 @@ <Compile Include="MonoDevelop.PackageManagement.Tests\FullyQualifiedReferencePathTests.cs" /> <Compile Include="MonoDevelop.PackageManagement.Tests\MSBuildPackageSpecCreatorTests.cs" /> <Compile Include="MonoDevelop.PackageManagement.Tests\InstallPackageWithAvailableItemNameTests.cs" /> + <Compile Include="MonoDevelop.PackageManagement.Tests\PackagesCommandHandlerTests.cs" /> + <Compile Include="MonoDevelop.PackageManagement.Tests.Helpers\TestableRestorePackagesHandler.cs" /> + <Compile Include="MonoDevelop.PackageManagement.Tests.Helpers\TestableRestorePackagesInProjectHandler.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\core\MonoDevelop.Core\MonoDevelop.Core.csproj"> 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..7cec48b14d --- /dev/null +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/PackagesCommandHandlerTests.cs @@ -0,0 +1,257 @@ +// +// PackagesCommandHandlerTests.cs +// +// Author: +// Matt Ward <matt.ward@microsoft.com> +// +// 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, "<packages />"); + + // 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 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 () + { + 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 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 () + { + 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"); + } + } +} 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<ProjectPackageReference> ().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 ());
+ }
}
}
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); 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<FilePath, LibGit2Sharp.Repository> (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); diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextSegmentMarker.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextSegmentMarker.cs index b53bc41e2f..2a688e976e 100644 --- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextSegmentMarker.cs +++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextSegmentMarker.cs @@ -1,4 +1,4 @@ -//
+//
// TextSegmentMarker.cs
//
// Author:
@@ -152,18 +152,26 @@ namespace Mono.TextEditor int /*lineNr,*/ x_pos; uint curIndex = 0;
uint byteIndex = 0;
- uint idx = (uint)Math.Min (Math.Max (0, start - startOffset), metrics.Layout.Text.Length - 1);
- metrics.Layout.TranslateToUTF8Index (idx, ref curIndex, ref byteIndex); - - x_pos = layout.IndexToPos (System.Math.Max (0, (int)byteIndex)).X; - @from = startXPos + (int)(x_pos / Pango.Scale.PangoScale);
-
- idx = (uint)Math.Min (Math.Max (0, end - startOffset), metrics.Layout.Text.Length - 1);
- metrics.Layout.TranslateToUTF8Index (idx, ref curIndex, ref byteIndex); - - x_pos = layout.IndexToPos (System.Math.Max (0, (int)byteIndex)).X; - - to = startXPos + (int)(x_pos / Pango.Scale.PangoScale);
+ + var textLength = metrics.Layout.Text.Length; + if (textLength > 0) { + uint idx = (uint)Math.Min (Math.Max (0, start - startOffset), textLength - 1); + metrics.Layout.TranslateToUTF8Index (idx, ref curIndex, ref byteIndex); + + x_pos = layout.IndexToPos (System.Math.Max (0, (int)byteIndex)).X; + @from = startXPos + (int)(x_pos / Pango.Scale.PangoScale); + + idx = (uint)Math.Min (Math.Max (0, end - startOffset), textLength - 1); + metrics.Layout.TranslateToUTF8Index (idx, ref curIndex, ref byteIndex); + + x_pos = layout.IndexToPos (System.Math.Max (0, (int)byteIndex)).X; + + to = startXPos + (int)(x_pos / Pango.Scale.PangoScale); + } else { + @from = startXPos; + to = startXPos + editor.TextViewMargin.CharWidth; + }
+
var line = editor.GetLineByOffset (endOffset);
if (markerEnd > endOffset || @from == to) {
to += editor.TextViewMargin.CharWidth;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs index 6ec1e3b665..d4f6439cf8 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs @@ -37,6 +37,7 @@ using MonoDevelop.Core.AddIns; using MonoDevelop.Core.Execution; using MonoDevelop.Core.Instrumentation; using System.Runtime.CompilerServices; +using System.Collections.Immutable; namespace MonoDevelop.Core.Assemblies { @@ -268,14 +269,19 @@ namespace MonoDevelop.Core.Assemblies return GetBackend (fx).GetFrameworkFolders (); } + // You can't really delete Facade assemblies while running the app. + static ImmutableDictionary<TargetFramework, string []> cachedFacadeAssemblies = ImmutableDictionary<TargetFramework, string []>.Empty; public IEnumerable<string> FindFacadeAssembliesForPCL (TargetFramework tx) { + if (cachedFacadeAssemblies.TryGetValue (tx, out var value)) + return value; + foreach (var folder in GetFrameworkFolders (tx)) { var facades = Path.Combine (folder, "Facades"); if (!Directory.Exists (facades)) continue; - return Directory.EnumerateFiles (facades, "*.dll"); + return ImmutableInterlocked.GetOrAdd (ref cachedFacadeAssemblies, tx, (_, dir) => Directory.GetFiles (dir, "*.dll"), facades); } //MonoDroid is special case because it's keeping Fascades in v1.0 folder @@ -283,12 +289,13 @@ namespace MonoDevelop.Core.Assemblies var frameworkFolder = GetFrameworkFolders (tx).FirstOrDefault (); if (frameworkFolder != null) { var facades = Path.Combine (Path.Combine (Path.GetDirectoryName (frameworkFolder), "v1.0"), "Facades"); - if (Directory.Exists (facades)) - return Directory.EnumerateFiles (facades, "*.dll"); + if (Directory.Exists (facades)) { + return ImmutableInterlocked.GetOrAdd (ref cachedFacadeAssemblies, tx, (_, dir) => Directory.GetFiles (dir, "*.dll"), facades); + } } } - return new string[0]; + return ImmutableInterlocked.GetOrAdd (ref cachedFacadeAssemblies, tx, Array.Empty<string> ()); } /// <summary> diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Setup/UpdateChannel.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Setup/UpdateChannel.cs index 0b0cee17f1..c09a12c469 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Setup/UpdateChannel.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Setup/UpdateChannel.cs @@ -116,7 +116,7 @@ namespace MonoDevelop.Core.Setup public override int GetHashCode () { - return Idx; + return Id.GetHashCode(); } public override string ToString () diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs index fbf568f9d1..1f92b20b4f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs @@ -207,7 +207,7 @@ namespace MonoDevelop.Projects.MSBuild public static Task<MSBuildProject> LoadAsync (string file) { - return Task<MSBuildProject>.Factory.StartNew (delegate { + return Task.Run (delegate { var p = new MSBuildProject (); p.Load (file); return p; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs index 536216a261..742edb3d99 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs @@ -381,7 +381,7 @@ namespace MonoDevelop.Projects.MSBuild var projectLoadMonitor = monitor as ProjectLoadProgressMonitor; if (projectLoadMonitor != null) projectLoadMonitor.CurrentSolution = sol; - await Task.Factory.StartNew (() => { + await Task.Run (() => { sol.ReadSolution (monitor); }); } catch (Exception ex) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs index 298d2e8f3f..cf85618ebe 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs @@ -914,11 +914,11 @@ namespace MonoDevelop.Projects internal protected virtual async Task<List<AssemblyReference>> OnGetReferencedAssemblies (ConfigurationSelector configuration) { - List<AssemblyReference> result = new List<AssemblyReference> (); + var result = new List<AssemblyReference> (); if (MSBuildProject.UseMSBuildEngine) { // Get the references list from the msbuild project using (Counters.ResolveMSBuildReferencesTimer.BeginTiming (GetProjectEventMetadata (configuration))) - result.AddRange (await RunResolveAssemblyReferencesTarget (configuration)); + result.AddRange (await RunResolveAssemblyReferencesTarget (configuration).ConfigureAwait (false)); } else { foreach (ProjectReference pref in References) { if (pref.ReferenceType != ReferenceType.Project) { @@ -979,7 +979,7 @@ namespace MonoDevelop.Projects } else { fullPath = Path.GetFullPath (refFilename.FilePath); } - if (await SystemAssemblyService.RequiresFacadeAssembliesAsync (fullPath)) { + if (await SystemAssemblyService.RequiresFacadeAssembliesAsync (fullPath).ConfigureAwait (false)) { addFacadeAssemblies = true; break; } @@ -987,7 +987,7 @@ namespace MonoDevelop.Projects } if (addFacadeAssemblies) { - var facades = await ProjectExtension.OnGetFacadeAssemblies (); + var facades = await ProjectExtension.OnGetFacadeAssemblies ().ConfigureAwait (false); if (facades != null) { foreach (var facade in facades) { if (!result.Contains (facade)) @@ -1022,15 +1022,11 @@ namespace MonoDevelop.Projects var property = new MSBuildPropertyEvaluated (null, "ResolvedFrom", resolvedFrom, resolvedFrom); sharedProperties.SetProperty (property.Name, property); - List<AssemblyReference> result = null; var runtime = TargetRuntime ?? Runtime.SystemAssemblyService.DefaultRuntime; var facades = runtime.FindFacadeAssembliesForPCL (TargetFramework); - foreach (var facade in facades) { - if (!File.Exists (facade)) - continue; - if (result == null) - result = new List<AssemblyReference> (); + var result = facades is ICollection<string> collection ? new List<AssemblyReference> (collection.Count) : new List<AssemblyReference> (); + foreach (var facade in facades) { var ar = new AssemblyReference (facade, sharedProperties); result.Add (ar); } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs index e2838d0ed6..e7514fe8f1 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs @@ -274,7 +274,7 @@ namespace MonoDevelop.Projects { var references = new List<AssemblyReference> (); - var traversedProjects = new HashSet<string> (); + var traversedProjects = new HashSet<string> (StringComparer.OrdinalIgnoreCase); traversedProjects.Add (Project.ItemId); await GetTransitiveAssemblyReferences (traversedProjects, references, configuration, true, token); @@ -302,7 +302,7 @@ namespace MonoDevelop.Projects bool includeNonProjectReferences, System.Threading.CancellationToken token) { - foreach (var reference in await base.OnGetReferences (configuration, token)) { + foreach (var reference in await base.OnGetReferences (configuration, token).ConfigureAwait (false)) { if (!reference.IsProjectReference) { if (includeNonProjectReferences) { references.Add (reference); @@ -322,15 +322,14 @@ namespace MonoDevelop.Projects if (project == null) continue; - if (traversedProjects.Contains (project.ItemId)) + if (!traversedProjects.Add (project.ItemId)) continue; references.Add (reference); - traversedProjects.Add (project.ItemId); var extension = project.AsFlavor<SdkProjectExtension> (); if (extension != null) - await extension.GetTransitiveAssemblyReferences (traversedProjects, references, configuration, false, token); + await extension.GetTransitiveAssemblyReferences (traversedProjects, references, configuration, false, token).ConfigureAwait (false); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookContainer.cs index 5de2ec2472..71019c3cfc 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookContainer.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookContainer.cs @@ -224,10 +224,19 @@ namespace MonoDevelop.Components.DockNotebook return newNotebook; } + static HPaned CreatePaned () + { + // FIXME: Bug #910879: HPanedThin is not functional with the new editor, + // fall-back to the regular Gtk paned until we find the right solution + if (Ide.Editor.DefaultSourceEditorOptions.Instance.EnableNewEditor) + return new HPaned (); + return new HPanedThin { GrabAreaSize = 6 }; + } + public DockNotebook InsertLeft (SdiWorkspaceWindow window) { return Insert (window, container => { - var box = new HPanedThin { GrabAreaSize = 6 }; + var box = CreatePaned (); var new_container = new DockNotebookContainer (tabControl); box.Pack1 (container, true, true); @@ -239,7 +248,7 @@ namespace MonoDevelop.Components.DockNotebook public DockNotebook InsertRight (SdiWorkspaceWindow window) { return Insert (window, container => { - var box = new HPanedThin () { GrabAreaSize = 6 }; + var box = CreatePaned (); var new_container = new DockNotebookContainer (tabControl); box.Pack1 (new_container, true, true); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs index b4616c511c..74bddf2a75 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs @@ -330,7 +330,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting public Task SaveAsync (string filename, bool atomic = false, bool binary = false) { - return Task.Factory.StartNew (() => Save (filename, atomic, binary)); + return Task.Run (() => Save (filename, atomic, binary)); } public void Save (string filename, bool atomic = false, bool binary = false) @@ -675,7 +675,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting public static Task<PDictionary> FromFileAsync (string fileName) { - return Task<PDictionary>.Factory.StartNew (() => { + return Task.Run (() => { bool isBinary; return FromFile (fileName, out isBinary); }); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/SearchResultWidget.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/SearchResultWidget.cs index 062551c243..c183d688ea 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/SearchResultWidget.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/SearchResultWidget.cs @@ -630,14 +630,18 @@ namespace MonoDevelop.Ide.FindInFiles var sb = new StringBuilder (); foreach (TreePath p in treeviewSearchResults.Selection.GetSelectedRows (out model)) { TreeIter iter; - if (!model.GetIter (out iter, p)) + if (!model.GetIter (out iter, p)) { continue; + } var result = store.GetValue (iter, SearchResultColumn) as SearchResult; - if (result == null) + if (result == null) { continue; - - sb.AppendFormat (result.GetCopyData (this)); - sb.AppendLine (); + } + try { + sb.AppendLine (result.GetCopyData (this)); + } catch (Exception e) { + LoggingService.LogInternalError ("Error while getting copy data from search results", e); + } } Clipboard clipboard = Clipboard.Get (Atom.Intern ("CLIPBOARD", false)); clipboard.Text = sb.ToString (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Shell/DefaultWorkbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Shell/DefaultWorkbench.cs index 94fd3b1208..8ee60288a4 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Shell/DefaultWorkbench.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Shell/DefaultWorkbench.cs @@ -655,8 +655,13 @@ namespace MonoDevelop.Ide.Gui Remove (rootWidget); foreach (PadCodon content in PadContentCollection) { - if (content.Initialized) - content.PadContent.Dispose (); + if (content.Initialized) { + try { + content.PadContent.Dispose (); + } catch (Exception ex) { + LoggingService.LogInternalError ("Failed to dispose pad " + content.PadId, ex); + } + } } rootWidget.Destroy (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReference.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReference.cs index 6dc0d60440..e38bcb05ce 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReference.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReference.cs @@ -32,7 +32,7 @@ namespace MonoDevelop.Ide.TypeSystem _provider = provider; _properties = properties; - FileWatcherService.WatchDirectories (this, new [] { FilePath.ParentDirectory }); + FileWatcherService.WatchDirectories (this, new [] { FilePath.ParentDirectory }).Ignore (); FileService.FileChanged += OnUpdatedOnDisk; } @@ -50,9 +50,9 @@ namespace MonoDevelop.Ide.TypeSystem void OnUpdatedOnDisk (object sender, FileEventArgs e) { - var args = new MetadataReferenceUpdatedEventArgs (this); foreach (var file in e) { if (file.FileName == FilePath) { + var args = new MetadataReferenceUpdatedEventArgs (this); SnapshotUpdated?.Invoke (this, args); return; } @@ -62,7 +62,7 @@ namespace MonoDevelop.Ide.TypeSystem public void Dispose () { FileService.FileChanged -= OnUpdatedOnDisk; - FileWatcherService.WatchDirectories (this, null); + FileWatcherService.WatchDirectories (this, null).Ignore (); } internal void UpdateSnapshot () => _currentSnapshot = new Snapshot (_provider, Properties, FilePath); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReferenceManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReferenceManager.cs index 60b644660c..4a9b92eaa0 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReferenceManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopMetadataReferenceManager.cs @@ -217,8 +217,11 @@ namespace MonoDevelop.Ide.TypeSystem public void ClearCache () { - _metadataCache.ClearCache(); + // Clear the reference cache before the metadata cache + // as the FileWatcher updates can technically trigger while the metadata cache + // is being cleared, avoiding unnecessary work and possible items not being invalidated. _metadataReferenceCache.ClearCache (); + _metadataCache.ClearCache(); } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs index 2e129b53b2..7d05f88336 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs @@ -220,7 +220,7 @@ namespace MonoDevelop.Ide.TypeSystem var tp = LoadProject (proj, token, null, null).ContinueWith (t => { if (!t.IsCanceled) projects.Add (t.Result); - }); + }, TaskContinuationOptions.ExecuteSynchronously); allTasks.Add (tp); } @@ -250,7 +250,7 @@ namespace MonoDevelop.Ide.TypeSystem var tp = LoadProject (proj, token, null, cacheInfo).ContinueWith (t => { if (!t.IsCanceled) projects.Add (t.Result); - }); + }, TaskContinuationOptions.ExecuteSynchronously); allTasks.Add (tp); } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs index e74f295005..aba2c748c8 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs @@ -450,7 +450,7 @@ namespace MonoDevelop.Ide.TypeSystem { try { BeginLoad (); - return await InternalLoadSolution (cancellationToken); + return await InternalLoadSolution (cancellationToken).ConfigureAwait (false); } finally { EndLoad (); } @@ -496,13 +496,13 @@ namespace MonoDevelop.Ide.TypeSystem if (!CurrentSolution.ContainsProject (projectInfo.Id)) {
// Cache did not contain project so add it to the solution.
OnProjectAdded (projectInfo);
- }
-
- lock (projectModifyLock) {
- projectInfo = AddVirtualDocuments (projectInfo); - OnProjectReloaded (projectInfo);
+ } else { + lock (projectModifyLock) { + projectInfo = AddVirtualDocuments (projectInfo); + OnProjectReloaded (projectInfo); + } } - await Runtime.RunInMainThread (IdeServices.TypeSystemService.UpdateRegisteredOpenDocuments);
+ await Runtime.RunInMainThread (IdeServices.TypeSystemService.UpdateRegisteredOpenDocuments).ConfigureAwait (false);
}
} catch (Exception ex) { LoggingService.LogInternalError (ex); @@ -565,10 +565,21 @@ namespace MonoDevelop.Ide.TypeSystem if (mdProject == null) return;
- var task = OpenDocumentWithTextViewAsync (doc, mdProject, activate); - // Can't wait for the task to finish synchronously since doing so would deadlock the UI thread. - while (!task.IsCompleted) { - DispatchService.RunPendingEvents (30); + // This method can be called by Roslyn or the editor in a context which is not the GTK UI context
+ // that MonoDevelop uses. In that case, before starting async an operation that may queue
+ // task continuations into the current context, we switch to the GTK context, so that
+ // whatever is queued will be dispatched when we run RunPendingEvents.
+
+ var oldContext = SynchronizationContext.Current;
+ try { + SynchronizationContext.SetSynchronizationContext (Runtime.MainSynchronizationContext); + var task = OpenDocumentWithTextViewAsync (doc, mdProject, activate); + // Can't wait for the task to finish synchronously since doing so would deadlock the UI thread. + while (!task.IsCompleted) { + DispatchService.RunPendingEvents (30); + }
+ } finally { + SynchronizationContext.SetSynchronizationContext (oldContext); }
} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs index db503d90ec..a9a6c33112 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs @@ -127,7 +127,7 @@ namespace MonoDevelop.Ide.TypeSystem { using (Counters.ParserService.WorkspaceItemLoaded.BeginTiming ()) { var wsList = new List<MonoDevelopWorkspace> (); - await CreateWorkspaces (item, wsList); + await CreateWorkspaces (item, wsList).ConfigureAwait (false); //If we want BeginTiming to work correctly we need to `await` await InternalLoad (wsList, progressMonitor, cancellationToken).ConfigureAwait (false); return wsList; @@ -138,12 +138,12 @@ namespace MonoDevelop.Ide.TypeSystem { if (item is MonoDevelop.Projects.Workspace ws) { foreach (var wsItem in ws.Items) - await CreateWorkspaces (wsItem, result); + await CreateWorkspaces (wsItem, result).ConfigureAwait (false); ws.ItemAdded += OnWorkspaceItemAdded; ws.ItemRemoved += OnWorkspaceItemRemoved; } else if (item is MonoDevelop.Projects.Solution solution) { var workspace = new MonoDevelopWorkspace (compositionManager.HostServices, solution, this); - await workspace.Initialize (); + await workspace.Initialize ().ConfigureAwait (false); lock (workspaceLock) workspaces = workspaces.Add (workspace); solution.SolutionItemAdded += OnSolutionItemAdded; @@ -617,7 +617,7 @@ namespace MonoDevelop.Ide.TypeSystem // update documents if (documentManager != null) { foreach (var openDocument in documentManager.Documents) - openDocument.DocumentContext.ReparseDocument (); + openDocument.DocumentContext?.ReparseDocument (); } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs index be6bb6de87..be125d5834 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs @@ -1207,11 +1207,11 @@ namespace MonoDevelop.Ide async Task LoadWorkspaceTypeSystem (WorkspaceItem item) { try { - var typeSystem = await serviceProvider.GetService<TypeSystemService> (); - await typeSystem.Load (item, null); + var typeSystem = await serviceProvider.GetService<TypeSystemService> ().ConfigureAwait (false); + await typeSystem.Load (item, null).ConfigureAwait (false); } catch (Exception ex) { LoggingService.LogError ("Could not load parser database.", ex); - }; + } } internal void NotifyItemRemoved (WorkspaceItem item) diff --git a/main/tests/test-projects/netframework-sdk/Class1.cs b/main/tests/test-projects/netframework-sdk/Class1.cs new file mode 100644 index 0000000000..b9a6178638 --- /dev/null +++ b/main/tests/test-projects/netframework-sdk/Class1.cs @@ -0,0 +1,8 @@ +using System;
+
+namespace netstandard_sdk
+{ + public class Class1 + { + }
+}
diff --git a/main/tests/test-projects/netframework-sdk/netframework-sdk.csproj b/main/tests/test-projects/netframework-sdk/netframework-sdk.csproj new file mode 100644 index 0000000000..424d2a40e5 --- /dev/null +++ b/main/tests/test-projects/netframework-sdk/netframework-sdk.csproj @@ -0,0 +1,7 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net472</TargetFramework> + </PropertyGroup> + +</Project> diff --git a/main/tests/test-projects/netframework-sdk/netframework-sdk.sln b/main/tests/test-projects/netframework-sdk/netframework-sdk.sln new file mode 100644 index 0000000000..41ef1571b0 --- /dev/null +++ b/main/tests/test-projects/netframework-sdk/netframework-sdk.sln @@ -0,0 +1,17 @@ +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "netframework-sdk", "netframework-sdk.csproj", "{5B443F8D-6C84-443F-A395-5429E8F4A47D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5B443F8D-6C84-443F-A395-5429E8F4A47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5B443F8D-6C84-443F-A395-5429E8F4A47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5B443F8D-6C84-443F-A395-5429E8F4A47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5B443F8D-6C84-443F-A395-5429E8F4A47D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/main/tests/test-projects/package-reference/library/library.csproj b/main/tests/test-projects/package-reference/library/library.csproj new file mode 100644 index 0000000000..24a78212d5 --- /dev/null +++ b/main/tests/test-projects/package-reference/library/library.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{4E1821DD-EE60-48C1-8552-05B2793263DC}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>LibraryProject</RootNamespace> + <AssemblyName>LibraryProject</AssemblyName> + <TargetFrameworkVersion>v4.7</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <PackageReference Include="Xamarin.Forms" Version="3.0.0.482510" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/main/tests/test-projects/package-reference/package-reference.sln b/main/tests/test-projects/package-reference/package-reference.sln new file mode 100644 index 0000000000..91c3b1c9e1 --- /dev/null +++ b/main/tests/test-projects/package-reference/package-reference.sln @@ -0,0 +1,17 @@ +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "library", "library\library.csproj", "{4E1821DD-EE60-48C1-8552-05B2793263DC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4E1821DD-EE60-48C1-8552-05B2793263DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E1821DD-EE60-48C1-8552-05B2793263DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E1821DD-EE60-48C1-8552-05B2793263DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E1821DD-EE60-48C1-8552-05B2793263DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/version-checks b/version-checks index a674796ebe..bcbb12d0ed 100644 --- a/version-checks +++ b/version-checks @@ -17,7 +17,7 @@ DEP[0]=md-addins DEP_NAME[0]=MDADDINS DEP_PATH[0]=${top_srcdir}/../md-addins DEP_MODULE[0]=git@github.com:xamarin/md-addins.git -DEP_NEEDED_VERSION[0]=6f2cfb80fed85d03eb75a2e74abea5ef9b59b89c +DEP_NEEDED_VERSION[0]=42c8a0564da96b5b187649617735c87be56c5644 DEP_BRANCH_AND_REMOTE[0]="release-8.2 origin/release-8.2" # heap-shot |