2021-09-20 18:20:01 +02:00

100 lines
3.8 KiB
C#

/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using dnSpy.Contracts.Debugger.Breakpoints.Code;
using dnSpy.Contracts.Debugger.DotNet.Code;
using dnSpy.Contracts.Documents;
using dnSpy.Contracts.Documents.Tabs;
using dnSpy.Contracts.Metadata;
using dnSpy.Debugger.DotNet.UI;
namespace dnSpy.Debugger.DotNet.Breakpoints.Code.TextEditor {
[Export(typeof(IDbgCodeBreakpointsServiceListener))]
sealed class DeleteBreakpointsInRemovedModules : IDbgCodeBreakpointsServiceListener {
readonly UIDispatcher uiDispatcher;
readonly Lazy<IDocumentTabService> documentTabService;
readonly Lazy<IModuleIdProvider> moduleIdProvider;
DbgCodeBreakpointsService? dbgCodeBreakpointsService;
[ImportingConstructor]
DeleteBreakpointsInRemovedModules(UIDispatcher uiDispatcher, Lazy<IDocumentTabService> documentTabService, Lazy<IModuleIdProvider> moduleIdProvider) {
this.uiDispatcher = uiDispatcher;
this.documentTabService = documentTabService;
this.moduleIdProvider = moduleIdProvider;
}
void IDbgCodeBreakpointsServiceListener.Initialize(DbgCodeBreakpointsService dbgCodeBreakpointsService) {
this.dbgCodeBreakpointsService = dbgCodeBreakpointsService;
uiDispatcher.UI(() => Initialize_UI());
}
void Initialize_UI() {
uiDispatcher.VerifyAccess();
documentTabService.Value.DocumentCollectionChanged += DocumentTabService_FileCollectionChanged;
}
void DocumentTabService_FileCollectionChanged(object? sender, NotifyDocumentCollectionChangedEventArgs e) {
Debug2.Assert(dbgCodeBreakpointsService is not null);
if (dbgCodeBreakpointsService is null)
return;
switch (e.Type) {
case NotifyDocumentCollectionType.Clear:
case NotifyDocumentCollectionType.Remove:
var existing = new HashSet<ModuleId>(documentTabService.Value.DocumentTreeView.GetAllModuleNodes().Select(a => moduleIdProvider.Value.Create(a.Document.ModuleDef)));
var removed = new HashSet<ModuleId>(e.Documents.Select(a => moduleIdProvider.Value.Create(a.ModuleDef)));
existing.Remove(new ModuleId());
removed.Remove(new ModuleId());
List<DbgCodeBreakpoint>? breakpointsToRemove = null;
foreach (var bp in dbgCodeBreakpointsService.Breakpoints) {
if (bp.IsHidden)
continue;
if (!(bp.Location is DbgDotNetCodeLocation location))
continue;
// Don't auto-remove BPs in dynamic modules since they have no disk file. The
// user must delete these him/herself.
if (location.Module.IsDynamic)
continue;
// If the file is still in the TV, don't delete anything. This can happen if
// we've loaded an in-memory module and the node just got removed.
if (existing.Contains(location.Module))
continue;
if (removed.Contains(location.Module)) {
if (breakpointsToRemove is null)
breakpointsToRemove = new List<DbgCodeBreakpoint>();
breakpointsToRemove.Add(bp);
}
}
if (breakpointsToRemove is not null)
dbgCodeBreakpointsService.Remove(breakpointsToRemove.ToArray());
break;
case NotifyDocumentCollectionType.Add:
break;
}
}
}
}