Dnspy/dnSpy/dnSpy.Contracts.Logic/Decompiler/MethodDebugInfoBuilder.cs

122 lines
4.5 KiB
C#
Raw Normal View History

2021-09-20 18:20:01 +02:00
/*
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 dnlib.DotNet;
namespace dnSpy.Contracts.Decompiler {
/// <summary>
/// Builds <see cref="MethodDebugInfo"/> instances
/// </summary>
public sealed class MethodDebugInfoBuilder {
readonly MethodDef method;
readonly MethodDef? kickoffMethod;
readonly StateMachineKind stateMachineKind;
readonly List<SourceStatement> statements;
/// <summary>
/// Compiler name (<see cref="PredefinedCompilerNames"/>) or null
/// </summary>
public string? CompilerName { get; set; }
/// <summary>
/// Gets the scope builder
/// </summary>
public MethodDebugScopeBuilder Scope { get; }
/// <summary>
/// Gets/sets the parameters
/// </summary>
public SourceParameter[]? Parameters { get; set; }
/// <summary>
/// Async method debug info or null
/// </summary>
public AsyncMethodDebugInfo? AsyncInfo { get; set; }
/// <summary>
/// Start of method (eg. position of the first character of the modifier or return type)
/// </summary>
public int? StartPosition { get; set; }
/// <summary>
/// End of method (eg. after the last brace)
/// </summary>
public int? EndPosition { get; set; }
readonly int decompilerSettingsVersion;
/// <summary>
/// Constructor
/// </summary>
/// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
/// <param name="stateMachineKind">State machine kind</param>
/// <param name="method">Method</param>
/// <param name="kickoffMethod">Kickoff method or null</param>
public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef? kickoffMethod) {
this.decompilerSettingsVersion = decompilerSettingsVersion;
this.stateMachineKind = stateMachineKind;
this.method = method ?? throw new ArgumentNullException(nameof(method));
this.kickoffMethod = kickoffMethod;
statements = new List<SourceStatement>();
Scope = new MethodDebugScopeBuilder();
Scope.Span = ILSpan.FromBounds(0, (uint)method.Body.GetCodeSize());
if (method == kickoffMethod)
throw new ArgumentException();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
/// <param name="stateMachineKind">State machine kind</param>
/// <param name="method">Method</param>
/// <param name="kickoffMethod">Kickoff method or null</param>
/// <param name="locals">Locals</param>
/// <param name="parameters">Parameters or null</param>
/// <param name="asyncInfo">Async method info or null</param>
public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef? kickoffMethod, SourceLocal[] locals, SourceParameter[]? parameters, AsyncMethodDebugInfo? asyncInfo)
: this(decompilerSettingsVersion, stateMachineKind, method, kickoffMethod) {
Scope.Locals.AddRange(locals);
Parameters = parameters;
AsyncInfo = asyncInfo;
}
/// <summary>
/// Adds a <see cref="SourceStatement"/>
/// </summary>
/// <param name="statement">Statement</param>
public void Add(SourceStatement statement) => statements.Add(statement);
/// <summary>
/// Creates a <see cref="MethodDebugInfo"/>
/// </summary>
/// <returns></returns>
public MethodDebugInfo Create() {
TextSpan? methodSpan;
if (StartPosition is not null && EndPosition is not null && StartPosition.Value <= EndPosition.Value)
methodSpan = TextSpan.FromBounds(StartPosition.Value, EndPosition.Value);
else
methodSpan = null;
return new MethodDebugInfo(CompilerName, decompilerSettingsVersion, stateMachineKind, method, kickoffMethod, Parameters, statements.ToArray(), Scope.ToScope(), methodSpan, AsyncInfo);
}
}
}