Browse Source

Refactor/Clean up local functions representation in type system.

pull/1586/head
Siegfried Pammer 6 years ago
parent
commit
37e14f43e3
  1. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  2. 68
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 3
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 14
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs
  5. 37
      ICSharpCode.Decompiler/CSharp/Resolver/LocalFunctionReferenceResolveResult.cs
  6. 306
      ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs
  7. 2
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  8. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  9. 69
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  10. 5
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  11. 177
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  12. 5
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  13. 4
      ICSharpCode.Decompiler/TypeSystem/IMethod.cs
  14. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs
  15. 139
      ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs
  16. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  17. 8
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs
  18. 2
      ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs

10
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -167,27 +167,21 @@ namespace LocalFunctions @@ -167,27 +167,21 @@ namespace LocalFunctions
public static Func<int> LambdaInLocalFunction()
{
int x = (int)Math.Pow(2.0, 10.0);
Enumerable.Range(1, 100).Select((Func<int, int>)Transform);
return Create();
Func<int> Create()
{
return () => x;
}
int Transform(int y)
{
return 2 * y;
}
}
public static Func<int> MethodRef()
{
int x = (int)Math.Pow(2.0, 10.0);
Enumerable.Range(1, 100).Select((Func<int, int>)F);
Enumerable.Range(1, 100).Select(LocalFunction);
return null;
int F(int y)
int LocalFunction(int y)
{
return x * y;
}

68
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -38,7 +38,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -38,7 +38,6 @@ namespace ICSharpCode.Decompiler.CSharp
{
public OpCode CallOpCode;
public bool NeedsBoxingConversion;
public bool IsLocalFunction;
}
struct ArgumentList
@ -53,18 +52,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -53,18 +52,13 @@ namespace ICSharpCode.Decompiler.CSharp
public bool AddNamesToPrimitiveValues;
public bool IsExpandedForm;
public int LocalFunctionParameterCount;
public int Length => Arguments.Length;
private int GetActualArgumentCount()
{
if (LocalFunctionParameterCount < 0 && FirstOptionalArgumentIndex < 0)
return Arguments.Length;
if (LocalFunctionParameterCount < 0)
return FirstOptionalArgumentIndex;
if (FirstOptionalArgumentIndex < 0)
return LocalFunctionParameterCount;
return Math.Min(FirstOptionalArgumentIndex, LocalFunctionParameterCount);
return Arguments.Length;
return FirstOptionalArgumentIndex;
}
public IEnumerable<ResolveResult> GetArgumentResolveResults(int skipCount = 0)
@ -180,20 +174,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -180,20 +174,19 @@ namespace ICSharpCode.Decompiler.CSharp
{
// Used for Call, CallVirt and NewObj
var expectedTargetDetails = new ExpectedTargetDetails {
CallOpCode = callOpCode,
IsLocalFunction = expressionBuilder.IsLocalFunction(method)
CallOpCode = callOpCode
};
ILFunction localFunction = null;
if (expectedTargetDetails.IsLocalFunction && (localFunction = expressionBuilder.ResolveLocalFunction(method)) == null) {
expectedTargetDetails.IsLocalFunction = false;
if (method.IsLocalFunction) {
localFunction = expressionBuilder.ResolveLocalFunction(method);
}
TranslatedExpression target;
if (callOpCode == OpCode.NewObj) {
target = default(TranslatedExpression); // no target
} else if (expectedTargetDetails.IsLocalFunction) {
} else if (method.IsLocalFunction) {
target = new IdentifierExpression(localFunction.Name)
.WithoutILInstruction()
.WithRR(new LocalFunctionReferenceResolveResult(localFunction));
.WithRR(ToMethodGroup(method, localFunction));
} else {
target = expressionBuilder.TranslateTarget(
callArguments.FirstOrDefault(),
@ -221,17 +214,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -221,17 +214,7 @@ namespace ICSharpCode.Decompiler.CSharp
var argumentList = BuildArgumentList(expectedTargetDetails, target.ResolveResult, method,
firstParamIndex, callArguments, argumentToParameterMap);
if (expectedTargetDetails.IsLocalFunction) {
int parameterCount = 0;
foreach (var param in method.Parameters) {
if (param.IsRef && param.Type is ByReferenceType byRef) {
var type = byRef.ElementType.GetDefinition();
if (type != null && type.IsCompilerGenerated())
break;
}
parameterCount++;
}
argumentList.LocalFunctionParameterCount = parameterCount;
if (method.IsLocalFunction) {
return new InvocationExpression(target, argumentList.GetArgumentExpressions())
.WithRR(new CSharpInvocationResolveResult(target.ResolveResult, method,
argumentList.GetArgumentResolveResults().ToList(), isExpandedForm: argumentList.IsExpandedForm, isLocalFunctionInvocation: true));
@ -412,7 +395,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -412,7 +395,7 @@ namespace ICSharpCode.Decompiler.CSharp
argumentList.ArgumentNames = null;
argumentList.AddNamesToPrimitiveValues = false;
var transform = GetRequiredTransformationsForCall(expectedTargetDetails, method, ref unused,
ref argumentList, CallTransformation.None, out IParameterizedMember foundMethod);
ref argumentList, CallTransformation.None, out _);
Debug.Assert(transform == CallTransformation.None || transform == CallTransformation.NoOptionalArgumentAllowed);
// Calls with only one argument do not need an array initializer expression to wrap them.
@ -591,12 +574,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -591,12 +574,10 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private ArgumentList BuildArgumentList(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method,
int firstParamIndex, IReadOnlyList<ILInstruction> callArguments, IReadOnlyList<int> argumentToParameterMap)
{
ArgumentList list = new ArgumentList();
list.LocalFunctionParameterCount = -1;
// Translate arguments to the expected parameter types
var arguments = new List<TranslatedExpression>(method.Parameters.Count);
@ -775,7 +756,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -775,7 +756,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (expressionBuilder.HidesVariableWithName(method.Name)) {
requireTarget = true;
} else {
if (expectedTargetDetails.IsLocalFunction)
if (method.IsLocalFunction)
requireTarget = false;
else if (method.IsStatic)
requireTarget = !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) || method.Name == ".cctor";
@ -1139,8 +1120,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1139,8 +1120,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
var op = AssignmentOperatorType.Assign;
var parentEvent = method.AccessorOwner as IEvent;
if (parentEvent != null) {
if (method.AccessorOwner is IEvent parentEvent) {
if (method.Equals(parentEvent.AddAccessor)) {
op = AssignmentOperatorType.Add;
}
@ -1243,15 +1223,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1243,15 +1223,14 @@ namespace ICSharpCode.Decompiler.CSharp
IType targetType;
bool requireTarget;
var expectedTargetDetails = new ExpectedTargetDetails {
CallOpCode = inst.OpCode,
IsLocalFunction = expressionBuilder.IsLocalFunction(method)
CallOpCode = inst.OpCode
};
ResolveResult result = null;
string methodName;
if (expectedTargetDetails.IsLocalFunction) {
if (method.IsLocalFunction) {
requireTarget = false;
var localFunction = expressionBuilder.ResolveLocalFunction(method);
result = new LocalFunctionReferenceResolveResult(localFunction);
result = ToMethodGroup(method, localFunction);
target = default;
methodName = localFunction.Name;
} else {
@ -1321,15 +1300,32 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1321,15 +1300,32 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(result);
targetExpression = ide;
}
if (target.ResolveResult != null) {
result = new MemberResolveResult(target.ResolveResult, method);
}
var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), targetExpression)
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(
inst.Method.DeclaringType,
target.ResolveResult != null ? new MemberResolveResult(target.ResolveResult, method) : result,
result,
Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false)));
return oce;
}
static MethodGroupResolveResult ToMethodGroup(IMethod method, ILFunction localFunction)
{
return new MethodGroupResolveResult(
null,
localFunction.Name,
new[] {
new MethodListWithDeclaringType(
method.DeclaringType,
new IParameterizedMember[] { method }
)
}, EmptyList<IType>.Instance
);
}
internal TranslatedExpression CallWithNamedArgs(Block block)
{
Debug.Assert(block.Kind == BlockKind.CallWithNamedArgs);

3
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -214,7 +214,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -214,7 +214,8 @@ namespace ICSharpCode.Decompiler.CSharp
internal ILFunction ResolveLocalFunction(IMethod method)
{
Debug.Assert(IsLocalFunction(method));
Debug.Assert(method.IsLocalFunction);
method = method.ReducedFrom;
foreach (var parent in currentFunction.Ancestors.OfType<ILFunction>()) {
var definition = parent.LocalFunctions.FirstOrDefault(f => f.Method == method);
if (definition != null) {

14
ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs

@ -53,20 +53,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -53,20 +53,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public readonly bool IsLocalFunctionInvocation;
readonly IReadOnlyList<int> argumentToParameterMap;
/// <summary>
/// If IsExtensionMethodInvocation is true this property holds the reduced method.
/// </summary>
IMethod reducedMethod;
public IMethod ReducedMethod {
get {
if (!IsExtensionMethodInvocation)
return null;
if (reducedMethod == null && Member is IMethod)
reducedMethod = new ReducedExtensionMethod ((IMethod)Member);
return reducedMethod;
}
}
public CSharpInvocationResolveResult(
ResolveResult targetResult, IParameterizedMember member,

37
ICSharpCode.Decompiler/CSharp/Resolver/LocalFunctionReferenceResolveResult.cs

@ -1,37 +0,0 @@ @@ -1,37 +0,0 @@
// Copyright (c) 2019 Siegfried Pammer
//
// 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.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
class LocalFunctionReferenceResolveResult : ResolveResult
{
public readonly ILFunction Function;
public LocalFunctionReferenceResolveResult(ILFunction function)
: base(SpecialType.NoType)
{
this.Function = function;
}
}
}

306
ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs

@ -1,306 +0,0 @@ @@ -1,306 +0,0 @@
//
// ReducedExtensionMethod.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
//
// 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.Collections.Generic;
using System.Linq;
using System.Reflection;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// An invocated extension method hides the extension parameter in its parameter list.
/// It's used to hide the internals of extension method invocation in certain situation to simulate the
/// syntactic way of writing extension methods on semantic level.
/// </summary>
public class ReducedExtensionMethod : IMethod
{
readonly IMethod baseMethod;
public ReducedExtensionMethod(IMethod baseMethod)
{
this.baseMethod = baseMethod;
}
public bool Equals(IMember obj, TypeVisitor typeNormalization)
{
var other = obj as ReducedExtensionMethod;
if (other == null)
return false;
return baseMethod.Equals(other.baseMethod, typeNormalization);
}
public override bool Equals(object obj)
{
var other = obj as ReducedExtensionMethod;
if (other == null)
return false;
return baseMethod.Equals(other.baseMethod);
}
public override int GetHashCode()
{
unchecked {
return baseMethod.GetHashCode() + 1;
}
}
public override string ToString()
{
return string.Format("[ReducedExtensionMethod: ReducedFrom={0}]", ReducedFrom);
}
#region IMember implementation
public IMember MemberDefinition {
get {
return baseMethod.MemberDefinition;
}
}
public IType ReturnType {
get {
return baseMethod.ReturnType;
}
}
public IEnumerable<IMember> ExplicitlyImplementedInterfaceMembers {
get {
return baseMethod.ExplicitlyImplementedInterfaceMembers;
}
}
public bool IsExplicitInterfaceImplementation {
get {
return baseMethod.IsExplicitInterfaceImplementation;
}
}
public bool IsVirtual {
get {
return baseMethod.IsVirtual;
}
}
public bool IsOverride {
get {
return baseMethod.IsOverride;
}
}
public bool IsOverridable {
get {
return baseMethod.IsOverridable;
}
}
public TypeParameterSubstitution Substitution {
get {
return baseMethod.Substitution;
}
}
public IMethod Specialize(TypeParameterSubstitution substitution)
{
return new ReducedExtensionMethod((IMethod)baseMethod.Specialize(substitution));
}
IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
return Specialize(substitution);
}
#endregion
#region IMethod implementation
public IReadOnlyList<ITypeParameter> TypeParameters {
get {
return baseMethod.TypeParameters;
}
}
public bool IsExtensionMethod {
get {
return true;
}
}
public bool IsConstructor {
get {
return baseMethod.IsConstructor;
}
}
public bool IsDestructor {
get {
return baseMethod.IsDestructor;
}
}
public bool IsOperator {
get {
return baseMethod.IsOperator;
}
}
public bool HasBody {
get {
return baseMethod.HasBody;
}
}
public bool IsAccessor => baseMethod.IsAccessor;
public IMember AccessorOwner => baseMethod.AccessorOwner;
public MethodSemanticsAttributes AccessorKind => baseMethod.AccessorKind;
public IMethod ReducedFrom {
get {
return baseMethod;
}
}
public IReadOnlyList<IType> TypeArguments {
get {
return baseMethod.TypeArguments;
}
}
#endregion
#region IParameterizedMember implementation
List<IParameter> parameters;
public IReadOnlyList<IParameter> Parameters {
get {
if (parameters == null)
parameters = new List<IParameter> (baseMethod.Parameters.Skip (1));
return parameters;
}
}
#endregion
#region IEntity implementation
public System.Reflection.Metadata.EntityHandle MetadataToken => baseMethod.MetadataToken;
public SymbolKind SymbolKind {
get {
return baseMethod.SymbolKind;
}
}
public ITypeDefinition DeclaringTypeDefinition {
get {
return baseMethod.DeclaringTypeDefinition;
}
}
public IType DeclaringType {
get {
return baseMethod.DeclaringType;
}
}
public IModule ParentModule {
get {
return baseMethod.ParentModule;
}
}
IEnumerable<IAttribute> IEntity.GetAttributes() => baseMethod.GetAttributes();
IEnumerable<IAttribute> IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes();
bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly;
public bool IsStatic {
get {
return false;
}
}
public bool IsAbstract {
get {
return baseMethod.IsAbstract;
}
}
public bool IsSealed {
get {
return baseMethod.IsSealed;
}
}
#endregion
#region IHasAccessibility implementation
public Accessibility Accessibility {
get {
return baseMethod.Accessibility;
}
}
#endregion
#region INamedElement implementation
public string FullName {
get {
return baseMethod.FullName;
}
}
public string Name {
get {
return baseMethod.Name;
}
}
public string ReflectionName {
get {
return baseMethod.ReflectionName;
}
}
public string Namespace {
get {
return baseMethod.Namespace;
}
}
#endregion
#region ICompilationProvider implementation
public ICompilation Compilation {
get {
return baseMethod.Compilation;
}
}
#endregion
}
}

2
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -968,7 +968,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -968,7 +968,7 @@ namespace ICSharpCode.Decompiler.CSharp
stmt.Parameters.AddRange(exprBuilder.MakeParameters(function.Parameters, function));
stmt.ReturnType = tsab.ConvertType(function.Method.ReturnType);
stmt.Body = nestedBuilder.ConvertAsBlock(function.Body);
stmt.AddAnnotation(new LocalFunctionReferenceResolveResult(function));
stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod));
return stmt;
}
}

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -60,7 +60,6 @@ @@ -60,7 +60,6 @@
<Compile Include="CSharp\CallBuilder.cs" />
<Compile Include="CSharp\CSharpLanguageVersion.cs" />
<Compile Include="CSharp\RequiredNamespaceCollector.cs" />
<Compile Include="CSharp\Resolver\LocalFunctionReferenceResolveResult.cs" />
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\Syntax\AstNode.cs" />
<Compile Include="CSharp\Syntax\AstNodeCollection.cs" />
@ -224,7 +223,7 @@ @@ -224,7 +223,7 @@
<Compile Include="CSharp\Resolver\NameLookupMode.cs" />
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
<Compile Include="CSharp\Resolver\ReducedExtensionMethod.cs" />
<Compile Include="TypeSystem\Implementation\LocalFunctionMethod.cs" />
<Compile Include="CSharp\Resolver\RenameCallbackArguments.cs" />
<Compile Include="CSharp\Resolver\TypeInference.cs" />
<Compile Include="CSharp\Transforms\CombineQueryExpressions.cs" />

69
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -29,8 +29,30 @@ namespace ICSharpCode.Decompiler.IL @@ -29,8 +29,30 @@ namespace ICSharpCode.Decompiler.IL
{
partial class ILFunction
{
/// <summary>
/// Gets the method definition from metadata.
/// May be null for functions that were not constructed from metadata,
/// e.g., expression trees.
/// </summary>
public readonly IMethod Method;
/// <summary>
/// Gets the generic context of this function.
/// </summary>
public readonly GenericContext GenericContext;
/// <summary>
/// Gets the name of this function, usually this returns the name from metadata.
/// <para>
/// For local functions:
/// This is the name that is used to declare and use the function.
/// It may not conflict with the names of local variables of ancestor functions
/// and may be overwritten by the AssignVariableNames step.
///
/// For top-level functions, delegates and expressions trees modifying this usually
/// has no effect, as the name should not be used in the final AST construction.
/// </para>
/// </summary>
public string Name;
/// <summary>
@ -38,6 +60,10 @@ namespace ICSharpCode.Decompiler.IL @@ -38,6 +60,10 @@ namespace ICSharpCode.Decompiler.IL
/// Note: after async/await transform, this is the code size of the MoveNext function.
/// </summary>
public int CodeSize;
/// <summary>
/// List of ILVariables used in this function.
/// </summary>
public readonly ILVariableCollection Variables;
/// <summary>
@ -60,6 +86,9 @@ namespace ICSharpCode.Decompiler.IL @@ -60,6 +86,9 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public bool IsIterator;
/// <summary>
/// Gets whether the YieldReturnDecompiler determined that the Mono C# compiler was used to compile this function.
/// </summary>
public bool StateMachineCompiledWithMono;
/// <summary>
@ -79,6 +108,11 @@ namespace ICSharpCode.Decompiler.IL @@ -79,6 +108,11 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public IMethod MoveNextMethod;
/// <summary>
/// If this function is a local function, this field stores the reduced version of the function.
/// </summary>
internal TypeSystem.Implementation.LocalFunctionMethod ReducedMethod;
internal DebugInfo.AsyncDebugInfo AsyncDebugInfo;
int ctorCallStart = int.MinValue;
@ -105,24 +139,43 @@ namespace ICSharpCode.Decompiler.IL @@ -105,24 +139,43 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// If this is an expression tree or delegate, returns the expression tree type Expression{T} or T.
/// T is the delegate type that matches the signature of this method.
/// Otherwise this must be null.
/// </summary>
public IType DelegateType;
ILFunctionKind kind;
/// <summary>
/// Gets which kind of function this is.
/// </summary>
public ILFunctionKind Kind {
get => kind;
set {
internal set {
if (kind == ILFunctionKind.TopLevelFunction || kind == ILFunctionKind.LocalFunction)
throw new InvalidOperationException("ILFunction.Kind of a top-level or local function may not be changed.");
kind = value;
}
}
/// <summary>
/// Return type of this function.
/// Might be null, if this function was not created from metadata.
/// </summary>
public readonly IType ReturnType;
/// <summary>
/// List of parameters of this function.
/// Might be null, if this function was not created from metadata.
/// </summary>
public readonly IReadOnlyList<IParameter> Parameters;
/// <summary>
/// Constructs a new ILFunction from the given metadata and with the given ILAst body.
/// </summary>
/// <remarks>
/// Use <see cref="ILReader"/> to create ILAst.
/// <paramref name="method"/> may be null.
/// </remarks>
public ILFunction(IMethod method, int codeSize, GenericContext genericContext, ILInstruction body, ILFunctionKind kind = ILFunctionKind.TopLevelFunction) : base(OpCode.ILFunction)
{
this.Method = method;
@ -137,7 +190,10 @@ namespace ICSharpCode.Decompiler.IL @@ -137,7 +190,10 @@ namespace ICSharpCode.Decompiler.IL
this.kind = kind;
}
public ILFunction(IType returnType, IReadOnlyList<IParameter> parameters, GenericContext genericContext, ILInstruction body) : base(OpCode.ILFunction)
/// <summary>
/// This constructor is only to be used by the TransformExpressionTrees step.
/// </summary>
internal ILFunction(IType returnType, IReadOnlyList<IParameter> parameters, GenericContext genericContext, ILInstruction body) : base(OpCode.ILFunction)
{
this.GenericContext = genericContext;
this.Body = body;
@ -366,14 +422,23 @@ namespace ICSharpCode.Decompiler.IL @@ -366,14 +422,23 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// ILFunction is a delegate or lambda expression.
/// </summary>
/// <remarks>
/// This kind is introduced by the DelegateConstruction and TransformExpressionTrees steps in the decompiler pipeline.
/// </remarks>
Delegate,
/// <summary>
/// ILFunction is an expression tree lambda.
/// </summary>
/// <remarks>
/// This kind is introduced by the TransformExpressionTrees step in the decompiler pipeline.
/// </remarks>
ExpressionTree,
/// <summary>
/// ILFunction is a C# 7.0 local function.
/// </summary>
/// <remarks>
/// This kind is introduced by the LocalFunctionDecompiler step in the decompiler pipeline.
/// </remarks>
LocalFunction
}
}

5
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -24,7 +24,10 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -24,7 +24,10 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
public class DelegateConstruction : IILTransform
/// <summary>
///
/// </summary>
class DelegateConstruction : IILTransform
{
ILTransformContext context;
ITypeResolveContext decompilationContext;

177
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -28,38 +28,45 @@ using System.Text.RegularExpressions; @@ -28,38 +28,45 @@ using System.Text.RegularExpressions;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Decompiler step for C# 7.0 local functions
/// </summary>
class LocalFunctionDecompiler : IILTransform
{
ILTransformContext context;
ITypeResolveContext decompilationContext;
/// <summary>
/// The transform works like this:
///
/// <para>
/// local functions can either be used in method calls, i.e., call and callvirt instructions,
/// or can be used as part of the "delegate construction" pattern, i.e., <c>newobj Delegate(&lt;target-expression&gt;, ldftn &lt;method&gt;)</c>. Note that this pattern would also be possible with <c>ldvirtftn</c>, but I haven't yet disovered a case where a compiler generates such code.
/// </para>
/// As local functions can be declared practically anywhere, we have to take a look at all use-sites and infer the declaration location from that.
/// </summary>
public void Run(ILFunction function, ILTransformContext context)
{
if (!context.Settings.LocalFunctions)
return;
this.context = context;
this.decompilationContext = new SimpleTypeResolveContext(function.Method);
var localFunctions = new Dictionary<IMethod, List<CallInstruction>>();
var cancellationToken = context.CancellationToken;
// Find use-sites
foreach (var inst in function.Descendants) {
cancellationToken.ThrowIfCancellationRequested();
if (inst is CallInstruction call && IsLocalFunctionMethod(call.Method)) {
if (function.Ancestors.OfType<ILFunction>().SelectMany(f => f.LocalFunctions).Any(f => f.Method == call.Method))
continue;
if (inst is CallInstruction call && IsLocalFunctionMethod(call.Method) && !call.Method.IsLocalFunction) {
if (!localFunctions.TryGetValue(call.Method, out var info)) {
info = new List<CallInstruction>() { call };
localFunctions.Add(call.Method, info);
} else {
info.Add(call);
}
} else if (inst is LdFtn ldftn && ldftn.Parent is NewObj newObj && IsLocalFunctionMethod(ldftn.Method) && DelegateConstruction.IsDelegateConstruction(newObj)) {
if (function.Ancestors.OfType<ILFunction>().SelectMany(f => f.LocalFunctions).Any(f => f.Method == ldftn.Method))
continue;
} else if (inst is LdFtn ldftn && !ldftn.Method.IsLocalFunction && ldftn.Parent is NewObj newObj && IsLocalFunctionMethod(ldftn.Method) && DelegateConstruction.IsDelegateConstruction(newObj)) {
context.StepStartGroup($"LocalFunctionDecompiler {ldftn.StartILOffset}", ldftn);
if (!localFunctions.TryGetValue(ldftn.Method, out var info)) {
info = new List<CallInstruction>() { newObj };
@ -111,7 +118,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -111,7 +118,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal static bool IsClosureParameter(IParameter parameter)
{
return parameter.IsRef
&& ((ByReferenceType)parameter.Type).ElementType.GetDefinition()?.IsCompilerGenerated() == true;
&& ((ByReferenceType)parameter.Type).ElementType
.GetDefinition()?.IsCompilerGenerated() == true;
}
static IType UnwrapByRef(IType type)
{
if (type is ByReferenceType byRef) {
type = byRef.ElementType;
}
return type;
}
internal static ILInstruction GetStatement(ILInstruction inst)
@ -132,44 +148,49 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -132,44 +148,49 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var genericContext = DelegateConstruction.GenericContextFromTypeArguments(targetMethod.Substitution);
if (genericContext == null)
return null;
var ilReader = context.CreateILReader();
var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.LocalFunction, context.CancellationToken);
// Embed the local function into the parent function's ILAst, so that "Show steps" can show
// how the local function body is being transformed.
parentFunction.LocalFunctions.Add(function);
function.DeclarationScope = (BlockContainer)parentFunction.Body;
function.CheckInvariant(ILPhase.Normal);
var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
if (IsNonLocalTarget(targetMethod, useSites, out var target)) {
Debug.Assert(target != null);
nestedContext.Step("LocalFunctionDecompiler (ReplaceDelegateTargetVisitor)", function);
var thisVar = function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter);
function.AcceptVisitor(new DelegateConstruction.ReplaceDelegateTargetVisitor(target, thisVar));
var function = parentFunction.Ancestors.OfType<ILFunction>().SelectMany(f => f.LocalFunctions).FirstOrDefault(f => f.Method == targetMethod);
if (function == null) {
var ilReader = context.CreateILReader();
var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.LocalFunction, context.CancellationToken);
// Embed the local function into the parent function's ILAst, so that "Show steps" can show
// how the local function body is being transformed.
parentFunction.LocalFunctions.Add(function);
function.DeclarationScope = (BlockContainer)parentFunction.Body;
function.CheckInvariant(ILPhase.Normal);
var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext);
if (IsNonLocalTarget(targetMethod, useSites, out var target)) {
Debug.Assert(target != null);
nestedContext.Step("LocalFunctionDecompiler (ReplaceDelegateTargetVisitor)", function);
var thisVar = function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter);
function.AcceptVisitor(new DelegateConstruction.ReplaceDelegateTargetVisitor(target, thisVar));
}
function.DeclarationScope = null;
function.ReducedMethod = ReduceToLocalFunction(targetMethod);
foreach (var innerUseSite in function.Descendants.OfType<CallInstruction>()) {
if (innerUseSite.Method != function.Method)
continue;
if (innerUseSite.OpCode == OpCode.NewObj) {
TransformToLocalFunctionReference(function, innerUseSite);
} else {
TransformToLocalFunctionInvocation(function.ReducedMethod, innerUseSite);
}
}
}
function.DeclarationScope = null;
foreach (var useSite in useSites) {
for (int i = useSite.Arguments.Count - 1; i >= 0; i--) {
if (!useSite.Arguments[i].MatchLdLocRef(out var closureVar))
break;
if (!TransformDisplayClassUsage.IsPotentialClosure(context, closureVar.Type.GetDefinition()))
break;
var instructions = closureVar.StoreInstructions.OfType<ILInstruction>()
.Concat(closureVar.AddressInstructions).OrderBy(inst => inst.StartILOffset);
var additionalScope = BlockContainer.FindClosestContainer(instructions.First());
if (closureVar.CaptureScope == null)
closureVar.CaptureScope = additionalScope;
else
closureVar.CaptureScope = FindCommonAncestorInstruction<BlockContainer>(closureVar.CaptureScope, additionalScope);
if (function.DeclarationScope == null)
function.DeclarationScope = closureVar.CaptureScope;
else
function.DeclarationScope = FindCommonAncestorInstruction<BlockContainer>(function.DeclarationScope, closureVar.CaptureScope);
if (useSite.OpCode == OpCode.NewObj) {
TransformToLocalFunctionReference(function, useSite);
} else {
DetermineCaptureAndDeclarationScope(function, useSite);
TransformToLocalFunctionInvocation(function.ReducedMethod, useSite);
}
}
if (function.DeclarationScope != null && function.DeclarationScope.Parent is ILFunction betterParentFunction) {
if (function.DeclarationScope != null
&& parentFunction.LocalFunctions.Contains(function)
&& function.DeclarationScope.Parent is ILFunction betterParentFunction) {
parentFunction.LocalFunctions.Remove(function);
betterParentFunction.LocalFunctions.Add(function);
}
@ -177,6 +198,76 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -177,6 +198,76 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return function;
}
LocalFunctionMethod ReduceToLocalFunction(IMethod method)
{
int parametersToRemove = 0;
for (int i = method.Parameters.Count - 1; i >= 0; i--) {
if (!IsClosureParameter(method.Parameters[i]))
break;
parametersToRemove++;
}
return new LocalFunctionMethod(method, parametersToRemove);
}
static void TransformToLocalFunctionReference(ILFunction function, CallInstruction useSite)
{
useSite.Arguments[0].ReplaceWith(new LdNull().WithILRange(useSite.Arguments[0]));
var fnptr = (IInstructionWithMethodOperand)useSite.Arguments[1];
var replacement = new LdFtn(function.ReducedMethod).WithILRange((ILInstruction)fnptr);
useSite.Arguments[1].ReplaceWith(replacement);
}
void TransformToLocalFunctionInvocation(LocalFunctionMethod reducedMethod, CallInstruction useSite)
{
bool wasInstanceCall = !useSite.Method.IsStatic;
var replacement = new Call(reducedMethod);
int firstArgumentIndex = wasInstanceCall ? 1 : 0;
int argumentCount = useSite.Arguments.Count;
int reducedArgumentCount = argumentCount - (reducedMethod.NumberOfCompilerGeneratedParameters + firstArgumentIndex);
replacement.Arguments.AddRange(useSite.Arguments.Skip(firstArgumentIndex).Take(reducedArgumentCount));
// copy flags:
replacement.ConstrainedTo = useSite.ConstrainedTo;
replacement.ILStackWasEmpty = useSite.ILStackWasEmpty;
replacement.IsTail = useSite.IsTail;
// copy IL ranges
replacement = replacement.WithILRange(useSite);
if (wasInstanceCall) {
replacement = replacement.WithILRange(useSite.Arguments[0]);
}
for (int i = 0; i < reducedMethod.NumberOfCompilerGeneratedParameters; i++) {
replacement = replacement.WithILRange(useSite.Arguments[argumentCount - i - 1]);
}
useSite.ReplaceWith(replacement);
}
void DetermineCaptureAndDeclarationScope(ILFunction function, CallInstruction useSite)
{
for (int i = useSite.Arguments.Count - 1; i >= 0; i--) {
var arg = useSite.Arguments[i];
ILVariable closureVar;
if (!(arg.MatchLdLoc(out closureVar) || arg.MatchLdLoca(out closureVar)))
break;
if (closureVar.Kind == VariableKind.NamedArgument)
break;
if (!TransformDisplayClassUsage.IsPotentialClosure(context, UnwrapByRef(closureVar.Type).GetDefinition()))
break;
if (closureVar.AddressCount == 0 && closureVar.StoreInstructions.Count == 0)
continue;
// determine the capture scope of closureVar and the declaration scope of the function
var instructions = closureVar.StoreInstructions.OfType<ILInstruction>()
.Concat(closureVar.AddressInstructions).OrderBy(inst => inst.StartILOffset);
var additionalScope = BlockContainer.FindClosestContainer(instructions.First());
if (closureVar.CaptureScope == null)
closureVar.CaptureScope = additionalScope;
else
closureVar.CaptureScope = FindCommonAncestorInstruction<BlockContainer>(closureVar.CaptureScope, additionalScope);
if (function.DeclarationScope == null)
function.DeclarationScope = closureVar.CaptureScope;
else
function.DeclarationScope = FindCommonAncestorInstruction<BlockContainer>(function.DeclarationScope, closureVar.CaptureScope);
}
}
bool IsNonLocalTarget(IMethod targetMethod, List<CallInstruction> useSites, out ILInstruction target)
{
target = null;
@ -275,7 +366,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -275,7 +366,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
struct FindTypeDecoder : ISignatureTypeProvider<bool, Unit>
{
TypeDefinitionHandle handle;
readonly TypeDefinitionHandle handle;
public FindTypeDecoder(TypeDefinitionHandle handle)
{

5
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.CSharp.OutputVisitor; @@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler
@ -177,9 +178,9 @@ namespace ICSharpCode.Decompiler @@ -177,9 +178,9 @@ namespace ICSharpCode.Decompiler
}
if (node is LocalFunctionDeclarationStatement) {
var localFunction = node.GetResolveResult() as LocalFunctionReferenceResolveResult;
var localFunction = node.GetResolveResult() as MemberResolveResult;
if (localFunction != null)
return localFunction.Function.Method;
return localFunction.Member;
}
return null;

4
ICSharpCode.Decompiler/TypeSystem/IMethod.cs

@ -53,6 +53,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -53,6 +53,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
IReadOnlyList<IType> TypeArguments { get; }
bool IsExtensionMethod { get; }
bool IsLocalFunction { get; }
bool IsConstructor { get; }
bool IsDestructor { get; }
bool IsOperator { get; }
@ -81,8 +82,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -81,8 +82,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
MethodSemanticsAttributes AccessorKind { get; }
/// <summary>
/// If this method is reduced from an extension method return the original method, <c>null</c> otherwise.
/// If this method is reduced from an extension method or a local function returns the original method, <c>null</c> otherwise.
/// A reduced method doesn't contain the extension method parameter. That means that it has one parameter less than its definition.
/// A local function doesn't contain compiler-generated method parameters at the end.
/// </summary>
IMethod ReducedFrom { get; }

1
ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs

@ -139,6 +139,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -139,6 +139,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IReadOnlyList<IType> IMethod.TypeArguments => TypeParameters;
bool IMethod.IsExtensionMethod => false;
bool IMethod.IsLocalFunction => false;
bool IMethod.IsConstructor => symbolKind == SymbolKind.Constructor;
bool IMethod.IsDestructor => symbolKind == SymbolKind.Destructor;
bool IMethod.IsOperator => symbolKind == SymbolKind.Operator;

139
ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs

@ -0,0 +1,139 @@ @@ -0,0 +1,139 @@
// Copyright (c) 2019 Siegfried Pammer
//
// 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.Collections.Generic;
using System.Reflection;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
/// <summary>
/// A local function has zero or more compiler-generated parameters added at the end.
/// </summary>
class LocalFunctionMethod : IMethod
{
readonly IMethod baseMethod;
public LocalFunctionMethod(IMethod baseMethod, int numberOfCompilerGeneratedParameters)
{
this.baseMethod = baseMethod;
this.NumberOfCompilerGeneratedParameters = numberOfCompilerGeneratedParameters;
}
public bool Equals(IMember obj, TypeVisitor typeNormalization)
{
if (!(obj is LocalFunctionMethod other))
return false;
return baseMethod.Equals(other.baseMethod, typeNormalization);
}
public override bool Equals(object obj)
{
var other = obj as LocalFunctionMethod;
if (other == null)
return false;
return baseMethod.Equals(other.baseMethod);
}
public override int GetHashCode()
{
unchecked {
return baseMethod.GetHashCode() + 1;
}
}
public override string ToString()
{
return string.Format("[LocalFunctionMethod: ReducedFrom={0}, NumberOfGeneratedParameters={1}]", ReducedFrom, NumberOfCompilerGeneratedParameters);
}
internal int NumberOfCompilerGeneratedParameters { get; }
public IMember MemberDefinition {
get {
if (baseMethod.MemberDefinition == baseMethod)
return this;
return new LocalFunctionMethod((IMethod)baseMethod.MemberDefinition, NumberOfCompilerGeneratedParameters);
}
}
public IType ReturnType => baseMethod.ReturnType;
IEnumerable<IMember> IMember.ExplicitlyImplementedInterfaceMembers => baseMethod.ExplicitlyImplementedInterfaceMembers;
bool IMember.IsExplicitInterfaceImplementation => baseMethod.IsExplicitInterfaceImplementation;
public bool IsVirtual => baseMethod.IsVirtual;
public bool IsOverride => baseMethod.IsOverride;
public bool IsOverridable => baseMethod.IsOverridable;
public TypeParameterSubstitution Substitution => baseMethod.Substitution;
public IMethod Specialize(TypeParameterSubstitution substitution)
{
return SpecializedMethod.Create(this, substitution);
}
IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
return Specialize(substitution);
}
public IReadOnlyList<ITypeParameter> TypeParameters => baseMethod.TypeParameters;
public bool IsExtensionMethod => baseMethod.IsExtensionMethod;
public bool IsLocalFunction => true;
public bool IsConstructor => baseMethod.IsConstructor;
public bool IsDestructor => baseMethod.IsDestructor;
public bool IsOperator => baseMethod.IsOperator;
public bool HasBody => baseMethod.HasBody;
public bool IsAccessor => baseMethod.IsAccessor;
public IMember AccessorOwner => baseMethod.AccessorOwner;
public MethodSemanticsAttributes AccessorKind => baseMethod.AccessorKind;
public IMethod ReducedFrom => baseMethod;
public IReadOnlyList<IType> TypeArguments => baseMethod.TypeArguments;
List<IParameter> parameters;
public IReadOnlyList<IParameter> Parameters {
get {
if (parameters == null)
parameters = new List<IParameter>(baseMethod.Parameters.SkipLast(NumberOfCompilerGeneratedParameters));
return parameters;
}
}
public System.Reflection.Metadata.EntityHandle MetadataToken => baseMethod.MetadataToken;
public SymbolKind SymbolKind => baseMethod.SymbolKind;
public ITypeDefinition DeclaringTypeDefinition => baseMethod.DeclaringTypeDefinition;
public IType DeclaringType => baseMethod.DeclaringType;
public IModule ParentModule => baseMethod.ParentModule;
IEnumerable<IAttribute> IEntity.GetAttributes() => baseMethod.GetAttributes();
IEnumerable<IAttribute> IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes();
bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly;
public bool IsStatic => true;
public bool IsAbstract => baseMethod.IsAbstract;
public bool IsSealed => baseMethod.IsSealed;
public Accessibility Accessibility => baseMethod.Accessibility;
public string FullName => baseMethod.FullName;
public string Name => baseMethod.Name;
public string ReflectionName => baseMethod.ReflectionName;
public string Namespace => baseMethod.Namespace;
public ICompilation Compilation => baseMethod.Compilation;
}
}

1
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly EntityHandle accessorOwner;
public MethodSemanticsAttributes AccessorKind { get; }
public bool IsExtensionMethod { get; }
bool IMethod.IsLocalFunction => false;
// lazy-loaded fields:
ITypeDefinition declaringType;

8
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs

@ -102,11 +102,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -102,11 +102,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return specializedTypeParameters ?? methodDefinition.TypeParameters;
}
}
public bool IsExtensionMethod {
get { return methodDefinition.IsExtensionMethod; }
}
public bool IsLocalFunction {
get { return methodDefinition.IsLocalFunction; }
}
public bool IsConstructor {
get { return methodDefinition.IsConstructor; }
}

2
ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs

@ -129,6 +129,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -129,6 +129,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
get { return baseMethod.IsExtensionMethod; }
}
bool IMethod.IsLocalFunction => false;
public bool IsConstructor {
get { return baseMethod.IsConstructor; }
}

Loading…
Cancel
Save