Browse Source

Refactor LocalFunctionDeclarationStatement + LocalFunctionMethod

pull/2077/head
Siegfried Pammer 5 years ago
parent
commit
18ace00266
  1. 41
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 12
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 6
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 14
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  5. 29
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  6. 67
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs
  7. 8
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  8. 20
      ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs
  9. 2
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  10. 31
      ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs

41
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1345,30 +1345,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1345,30 +1345,35 @@ namespace ICSharpCode.Decompiler.CSharp
}
entityDecl.AddAnnotation(function);
if (function.IsIterator) {
if (localSettings.DecompileMemberBodies && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) {
body.Add(new YieldBreakStatement());
}
if (function.IsAsync) {
RemoveAttribute(entityDecl, KnownAttribute.AsyncIteratorStateMachine);
} else {
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
}
if (function.StateMachineCompiledWithMono) {
RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden);
}
CleanUpMethodDeclaration(entityDecl, body, function, localSettings.DecompileMemberBodies);
} catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException)) {
throw new DecompilerException(module, method, innerException);
}
}
internal static void CleanUpMethodDeclaration(EntityDeclaration entityDecl, BlockStatement body, ILFunction function, bool decompileBody = true)
{
if (function.IsIterator) {
if (decompileBody && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) {
body.Add(new YieldBreakStatement());
}
if (function.IsAsync) {
entityDecl.Modifiers |= Modifiers.Async;
RemoveAttribute(entityDecl, KnownAttribute.AsyncStateMachine);
RemoveAttribute(entityDecl, KnownAttribute.DebuggerStepThrough);
RemoveAttribute(entityDecl, KnownAttribute.AsyncIteratorStateMachine);
} else {
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
}
} catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException)) {
throw new DecompilerException(module, method, innerException);
if (function.StateMachineCompiledWithMono) {
RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden);
}
}
if (function.IsAsync) {
entityDecl.Modifiers |= Modifiers.Async;
RemoveAttribute(entityDecl, KnownAttribute.AsyncStateMachine);
RemoveAttribute(entityDecl, KnownAttribute.DebuggerStepThrough);
}
}
bool RemoveAttribute(EntityDeclaration entityDecl, KnownAttribute attributeType)
internal static bool RemoveAttribute(EntityDeclaration entityDecl, KnownAttribute attributeType)
{
bool found = false;
foreach (var section in entityDecl.Attributes) {

12
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -197,8 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -197,8 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp
} else if (localFunction != null) {
var ide = new IdentifierExpression(localFunction.Name);
if (method.TypeArguments.Count > 0) {
int skipCount = localFunction.ReducedMethod.NumberOfCompilerGeneratedTypeParameters;
ide.TypeArguments.AddRange(method.TypeArguments.Skip(skipCount).Select(expressionBuilder.ConvertType));
ide.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
}
ide.AddAnnotation(localFunction);
target = ide.WithoutILInstruction()
@ -1327,7 +1326,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1327,7 +1326,6 @@ namespace ICSharpCode.Decompiler.CSharp
target = default;
targetType = default;
methodName = localFunction.Name;
// TODO : think about how to handle generic local functions
} else if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) {
step = 5;
targetType = method.Parameters[0].Type;
@ -1406,11 +1404,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1406,11 +1404,7 @@ namespace ICSharpCode.Decompiler.CSharp
} else {
var ide = new IdentifierExpression(methodName);
if ((step & 2) != 0) {
int skipCount = 0;
if (localFunction != null && method.TypeArguments.Count > 0) {
skipCount = localFunction.ReducedMethod.NumberOfCompilerGeneratedTypeParameters;
}
ide.TypeArguments.AddRange(method.TypeArguments.Skip(skipCount).Select(expressionBuilder.ConvertType));
ide.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
}
targetExpression = ide.WithRR(result);
}
@ -1469,7 +1463,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1469,7 +1463,7 @@ namespace ICSharpCode.Decompiler.CSharp
method.DeclaringType,
new IParameterizedMember[] { method }
)
}, method.TypeArguments.Skip(localFunction.ReducedMethod.NumberOfCompilerGeneratedTypeParameters).ToArray()
}, method.TypeArguments
);
}

6
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -92,6 +92,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -92,6 +92,7 @@ namespace ICSharpCode.Decompiler.CSharp
this.astBuilder = new TypeSystemAstBuilder(resolver);
this.astBuilder.AlwaysUseShortTypeNames = true;
this.astBuilder.AddResolveResultAnnotations = true;
this.astBuilder.ShowAttributes = true;
this.astBuilder.UseNullableSpecifierForValueTypes = settings.LiftNullables;
this.typeInference = new TypeInference(compilation) { Algorithm = TypeInferenceAlgorithm.Improved };
}
@ -1983,7 +1984,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1983,7 +1984,7 @@ namespace ICSharpCode.Decompiler.CSharp
return SpecialType.UnknownType;
}
internal IEnumerable<ParameterDeclaration> MakeParameters(IReadOnlyList<IParameter> parameters, ILFunction function)
IEnumerable<ParameterDeclaration> MakeParameters(IReadOnlyList<IParameter> parameters, ILFunction function)
{
var variables = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
int i = 0;
@ -1992,9 +1993,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1992,9 +1993,6 @@ namespace ICSharpCode.Decompiler.CSharp
if (string.IsNullOrEmpty(pd.Name) && !pd.Type.IsArgList()) {
// needs to be consistent with logic in ILReader.CreateILVarable(ParameterDefinition)
pd.Name = "P_" + i;
// if this is a local function, we have to skip the parameters for closure references
if (settings.LocalFunctions && function.Kind == ILFunctionKind.LocalFunction && IL.Transforms.LocalFunctionDecompiler.IsClosureParameter(parameter, decompilationContext))
break;
}
if (settings.AnonymousTypes && parameter.Type.ContainsAnonymousType())
pd.Type = null;

14
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1876,19 +1876,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1876,19 +1876,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitLocalFunctionDeclarationStatement(LocalFunctionDeclarationStatement localFunctionDeclarationStatement)
{
StartNode(localFunctionDeclarationStatement);
WriteModifiers(localFunctionDeclarationStatement.ModifierTokens);
localFunctionDeclarationStatement.ReturnType.AcceptVisitor(this);
Space();
WriteIdentifier(localFunctionDeclarationStatement.NameToken);
WriteTypeParameters(localFunctionDeclarationStatement.TypeParameters);
Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(localFunctionDeclarationStatement.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
foreach (Constraint constraint in localFunctionDeclarationStatement.Constraints) {
constraint.AcceptVisitor(this);
}
WriteMethodBody(localFunctionDeclarationStatement.Body, policy.MethodBraceStyle);
localFunctionDeclarationStatement.Declaration.AcceptVisitor(this);
EndNode(localFunctionDeclarationStatement);
}

29
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -1002,34 +1002,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1002,34 +1002,19 @@ namespace ICSharpCode.Decompiler.CSharp
LocalFunctionDeclarationStatement TranslateFunction(ILFunction function)
{
var stmt = new LocalFunctionDeclarationStatement();
var nestedBuilder = new StatementBuilder(typeSystem, exprBuilder.decompilationContext, function, settings, cancellationToken);
stmt.Name = function.Name;
stmt.Parameters.AddRange(exprBuilder.MakeParameters(function.Parameters, function));
stmt.ReturnType = exprBuilder.ConvertType(function.Method.ReturnType);
stmt.Body = nestedBuilder.ConvertAsBlock(function.Body);
var astBuilder = exprBuilder.astBuilder;
var method = (MethodDeclaration)astBuilder.ConvertEntity(function.ReducedMethod);
method.Body = nestedBuilder.ConvertAsBlock(function.Body);
Comment prev = null;
foreach (string warning in function.Warnings) {
stmt.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
method.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
}
if (function.Method.TypeParameters.Count > 0) {
var astBuilder = exprBuilder.astBuilder;
if (astBuilder.ShowTypeParameters) {
int skipCount = function.ReducedMethod.NumberOfCompilerGeneratedTypeParameters;
stmt.TypeParameters.AddRange(function.Method.TypeParameters.Skip(skipCount).Select(t => astBuilder.ConvertTypeParameter(t)));
if (astBuilder.ShowTypeParameterConstraints) {
stmt.Constraints.AddRange(function.Method.TypeParameters.Skip(skipCount).Select(t => astBuilder.ConvertTypeParameterConstraint(t)).Where(c => c != null));
}
}
}
if (function.IsAsync) {
stmt.Modifiers |= Modifiers.Async;
}
if (settings.StaticLocalFunctions && function.ReducedMethod.IsStaticLocalFunction) {
stmt.Modifiers |= Modifiers.Static;
}
CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function);
CSharpDecompiler.RemoveAttribute(method, KnownAttribute.CompilerGenerated);
var stmt = new LocalFunctionDeclarationStatement(method);
stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod));
stmt.WithILInstruction(function);
return stmt;

67
ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs

@ -16,69 +16,22 @@ @@ -16,69 +16,22 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public class LocalFunctionDeclarationStatement : Statement
{
public AstNodeCollection<TypeParameterDeclaration> TypeParameters {
get { return GetChildrenByRole(Roles.TypeParameter); }
}
public CSharpTokenNode LParToken {
get { return GetChildByRole(Roles.LPar); }
}
public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole(Roles.Parameter); }
}
public static readonly Role<MethodDeclaration> MethodDeclarationRole = new Role<MethodDeclaration>("Method");
public CSharpTokenNode RParToken {
get { return GetChildByRole(Roles.RPar); }
public MethodDeclaration Declaration {
get { return GetChildByRole(MethodDeclarationRole); }
set { SetChildByRole(MethodDeclarationRole, value); }
}
public AstNodeCollection<Constraint> Constraints {
get { return GetChildrenByRole(Roles.Constraint); }
}
public BlockStatement Body {
get { return GetChildByRole(Roles.Body); }
set { SetChildByRole(Roles.Body, value); }
}
public Modifiers Modifiers {
get { return EntityDeclaration.GetModifiers(this); }
set { EntityDeclaration.SetModifiers(this, value); }
}
public bool HasModifier(Modifiers mod)
public LocalFunctionDeclarationStatement(MethodDeclaration methodDeclaration)
{
return (Modifiers & mod) == mod;
}
public IEnumerable<CSharpModifierToken> ModifierTokens {
get { return GetChildrenByRole(EntityDeclaration.ModifierRole); }
}
public virtual string Name {
get {
return GetChildByRole(Roles.Identifier).Name;
}
set {
SetChildByRole(Roles.Identifier, Identifier.Create(value, TextLocation.Empty));
}
}
public virtual Identifier NameToken {
get { return GetChildByRole(Roles.Identifier); }
set { SetChildByRole(Roles.Identifier, value); }
}
public virtual AstType ReturnType {
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
AddChild(methodDeclaration, MethodDeclarationRole);
}
public override void AcceptVisitor(IAstVisitor visitor)
@ -98,13 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -98,13 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
protected internal override bool DoMatch(AstNode other, Match match)
{
LocalFunctionDeclarationStatement o = other as LocalFunctionDeclarationStatement;
return o != null && MatchString(this.Name, o.Name)
&& (this.Modifiers == Modifiers.Any || this.Modifiers == o.Modifiers)
&& this.ReturnType.DoMatch(o.ReturnType, match)
&& this.TypeParameters.DoMatch(o.TypeParameters, match)
&& this.Parameters.DoMatch(o.Parameters, match) && this.Constraints.DoMatch(o.Constraints, match)
&& this.Body.DoMatch(o.Body, match);
return other is LocalFunctionDeclarationStatement o && Declaration.DoMatch(o.Declaration, match);
}
}
}

8
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -1799,6 +1799,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1799,6 +1799,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return !member.IsStatic;
case SymbolKind.Destructor:
return false;
case SymbolKind.Method:
return !((IMethod)member).IsLocalFunction;
default:
return true;
}
@ -1811,7 +1813,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1811,7 +1813,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
m |= ModifierFromAccessibility (member.Accessibility);
}
if (this.ShowModifiers) {
if (member.IsStatic) {
if (member is LocalFunctionMethod localFunction) {
if (localFunction.IsStaticLocalFunction) {
m |= Modifiers.Static;
}
} else if (member.IsStatic) {
m |= Modifiers.Static;
} else {
var declaringType = member.DeclaringType;

20
ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs

@ -55,56 +55,56 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -55,56 +55,56 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override TResult VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
Debug.Assert(currentMethod == null);
var oldMethod = currentMethod;
try {
currentMethod = methodDeclaration.GetSymbol() as IMethod;
return base.VisitMethodDeclaration(methodDeclaration);
} finally {
currentMethod = null;
currentMethod = oldMethod;
}
}
public override TResult VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
Debug.Assert(currentMethod == null);
var oldMethod = currentMethod;
try {
currentMethod = constructorDeclaration.GetSymbol() as IMethod;
return base.VisitConstructorDeclaration(constructorDeclaration);
} finally {
currentMethod = null;
currentMethod = oldMethod;
}
}
public override TResult VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
{
Debug.Assert(currentMethod == null);
var oldMethod = currentMethod;
try {
currentMethod = destructorDeclaration.GetSymbol() as IMethod;
return base.VisitDestructorDeclaration(destructorDeclaration);
} finally {
currentMethod = null;
currentMethod = oldMethod;
}
}
public override TResult VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
{
Debug.Assert(currentMethod == null);
var oldMethod = currentMethod;
try {
currentMethod = operatorDeclaration.GetSymbol() as IMethod;
return base.VisitOperatorDeclaration(operatorDeclaration);
} finally {
currentMethod = null;
currentMethod = oldMethod;
}
}
public override TResult VisitAccessor(Accessor accessor)
{
Debug.Assert(currentMethod == null);
var oldMethod = currentMethod;
try {
currentMethod = accessor.GetSymbol() as IMethod;
return base.VisitAccessor(accessor);
} finally {
currentMethod = null;
currentMethod = oldMethod;
}
}
}

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

@ -484,7 +484,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -484,7 +484,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break;
parametersToRemove++;
}
return new LocalFunctionMethod(method, parametersToRemove, typeParametersToRemove);
return new LocalFunctionMethod(method, method.Name, parametersToRemove, typeParametersToRemove);
}
static void TransformToLocalFunctionReference(ILFunction function, CallInstruction useSite)

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

@ -31,11 +31,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -31,11 +31,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
readonly IMethod baseMethod;
public LocalFunctionMethod(IMethod baseMethod, int numberOfCompilerGeneratedParameters, int numberOfCompilerGeneratedTypeParameters)
public LocalFunctionMethod(IMethod baseMethod, string name, int numberOfCompilerGeneratedParameters, int numberOfCompilerGeneratedTypeParameters)
{
if (baseMethod == null)
throw new ArgumentNullException(nameof(baseMethod));
this.baseMethod = baseMethod;
this.Name = name;
this.NumberOfCompilerGeneratedParameters = numberOfCompilerGeneratedParameters;
this.NumberOfCompilerGeneratedTypeParameters = numberOfCompilerGeneratedTypeParameters;
}
@ -65,7 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -65,7 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override string ToString()
{
return string.Format("[LocalFunctionMethod: ReducedFrom={0}, NumberOfGeneratedParameters={1}, NumberOfCompilerGeneratedTypeParameters={2}]", ReducedFrom, NumberOfCompilerGeneratedParameters, NumberOfCompilerGeneratedTypeParameters);
return string.Format("[LocalFunctionMethod: ReducedFrom={0}, Name={1}, NumberOfGeneratedParameters={2}, NumberOfCompilerGeneratedTypeParameters={3}]", ReducedFrom, Name, NumberOfCompilerGeneratedParameters, NumberOfCompilerGeneratedTypeParameters);
}
internal int NumberOfCompilerGeneratedParameters { get; }
@ -88,7 +89,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -88,7 +89,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
return new LocalFunctionMethod(
baseMethod.Specialize(substitution),
NumberOfCompilerGeneratedParameters, NumberOfCompilerGeneratedTypeParameters);
Name, NumberOfCompilerGeneratedParameters, NumberOfCompilerGeneratedTypeParameters);
}
IMember IMember.Specialize(TypeParameterSubstitution substitution)
@ -96,7 +97,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -96,7 +97,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return Specialize(substitution);
}
public IReadOnlyList<ITypeParameter> TypeParameters => baseMethod.TypeParameters;
public bool IsExtensionMethod => baseMethod.IsExtensionMethod;
public bool IsLocalFunction => true;
public bool IsConstructor => baseMethod.IsConstructor;
@ -107,7 +107,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -107,7 +107,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public IMember AccessorOwner => baseMethod.AccessorOwner;
public MethodSemanticsAttributes AccessorKind => baseMethod.AccessorKind;
public IMethod ReducedFrom => baseMethod;
public IReadOnlyList<IType> TypeArguments => baseMethod.TypeArguments;
List<ITypeParameter> typeParameters;
public IReadOnlyList<ITypeParameter> TypeParameters {
get {
if (typeParameters == null)
typeParameters = new List<ITypeParameter>(baseMethod.TypeParameters.Skip(NumberOfCompilerGeneratedTypeParameters));
return typeParameters;
}
}
List<IType> typeArguments;
public IReadOnlyList<IType> TypeArguments {
get {
if (typeArguments == null)
typeArguments = new List<IType>(baseMethod.TypeArguments.Skip(NumberOfCompilerGeneratedTypeParameters));
return typeArguments;
}
}
List<IParameter> parameters;
public IReadOnlyList<IParameter> Parameters {
@ -137,8 +154,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -137,8 +154,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public Accessibility Accessibility => baseMethod.Accessibility;
public string FullName => baseMethod.FullName;
public string Name => baseMethod.Name;
public string FullName => Name;
public string Name { get; set; }
public string ReflectionName => baseMethod.ReflectionName;
public string Namespace => baseMethod.Namespace;

Loading…
Cancel
Save