/* 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 . */ using System; using System.Collections.Generic; using dnlib.DotNet; using dnSpy.Contracts.Documents.Tabs.DocViewer; using dnSpy.Contracts.Metadata; using Microsoft.VisualStudio.Text; namespace dnSpy.Contracts.Decompiler { /// /// Method debug info service /// public interface IMethodDebugService { /// /// Gets the number of s /// int Count { get; } /// /// Gets s /// /// Text position /// Options /// IList FindByTextPosition(int textPosition, FindByTextPositionOptions options = FindByTextPositionOptions.None); /// /// Gets a code /// /// Method /// Code offset /// MethodSourceStatement? FindByCodeOffset(MethodDef method, uint codeOffset); /// /// Gets a code /// /// Token /// Code offset /// MethodSourceStatement? FindByCodeOffset(ModuleTokenId token, uint codeOffset); /// /// Gets a or null if it doesn't exist /// /// Method /// MethodDebugInfo? TryGetMethodDebugInfo(MethodDef method); /// /// Gets a or null if it doesn't exist /// /// Token /// MethodDebugInfo? TryGetMethodDebugInfo(ModuleTokenId token); /// /// Gets all s that intersect a span /// /// Span /// IEnumerable GetStatementsByTextSpan(Span span); } /// /// Find options /// public enum FindByTextPositionOptions { /// /// No bit is set /// None = 0, /// /// If set, only return statements within the method that contains the text position /// SameMethod = 0x00000001, /// /// If there are nested methods or delegates in the method, return the outer most statement. /// If it's not set, the statement inside the nested method / delegate is returned. /// OuterMostStatement = 0x00000002, } /// /// Constants /// internal static class MethodDebugServiceConstants { /// /// key /// public static readonly object MethodDebugServiceKey = new object(); } /// /// Extension methods /// public static class MethodDebugServiceExtensions { /// /// Gets a instance /// /// This /// public static IMethodDebugService GetMethodDebugService(this IDocumentViewer? self) => self.TryGetMethodDebugService() ?? EmptyMethodDebugService.Instance; /// /// Gets a or null if none exists /// /// This /// public static IMethodDebugService? TryGetMethodDebugService(this IDocumentViewer? self) { if (self is null) return null; return (IMethodDebugService?)self.GetContentData(MethodDebugServiceConstants.MethodDebugServiceKey); } sealed class EmptyMethodDebugService : IMethodDebugService { public static readonly EmptyMethodDebugService Instance = new EmptyMethodDebugService(); int IMethodDebugService.Count => 0; IList IMethodDebugService.FindByTextPosition(int textPosition, FindByTextPositionOptions options) => Array.Empty(); MethodSourceStatement? IMethodDebugService.FindByCodeOffset(ModuleTokenId token, uint codeOffset) => null; MethodSourceStatement? IMethodDebugService.FindByCodeOffset(MethodDef method, uint codeOffset) => null; MethodDebugInfo? IMethodDebugService.TryGetMethodDebugInfo(ModuleTokenId token) => null; MethodDebugInfo? IMethodDebugService.TryGetMethodDebugInfo(MethodDef method) => null; IEnumerable IMethodDebugService.GetStatementsByTextSpan(Span span) => Array.Empty(); } } }