Browse Source

Merge pull request #2077 from icsharpcode/attributes-on-local-functions

Attributes on local functions
pull/2081/head
Daniel Grunwald 6 years ago committed by GitHub
parent
commit
b4aec9a80e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 2
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 18
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  4. 41
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 12
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  6. 6
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  7. 3
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  8. 14
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  9. 17
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
  10. 29
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  11. 67
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs
  12. 8
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  13. 20
      ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs
  14. 24
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  15. 2
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  16. 63
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  17. 31
      ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs
  18. 3
      ILSpy/Languages/CSharpLanguage.cs

3
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -257,6 +257,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -257,6 +257,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
preprocessorSymbols.Add("LEGACY_CSC");
preprocessorSymbols.Add("LEGACY_VBC");
}
if (flags.HasFlag(CompilerOptions.Preview)) {
preprocessorSymbols.Add("CS90");
}
return preprocessorSymbols;
}

2
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -199,7 +199,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -199,7 +199,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void LocalFunctions([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
[Test]

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

@ -23,6 +23,12 @@ namespace LocalFunctions @@ -23,6 +23,12 @@ namespace LocalFunctions
{
internal class LocalFunctions
{
[AttributeUsage(AttributeTargets.All)]
internal class MyAttribute : Attribute
{
}
public class Generic<T1> where T1 : struct, ICloneable, IConvertible
{
public int MixedLocalFunction<T2>() where T2 : ICloneable, IConvertible
@ -31,15 +37,21 @@ namespace LocalFunctions @@ -31,15 +37,21 @@ namespace LocalFunctions
object z = this;
for (int j = 0; j < 10; j++) {
int i = 0;
i += NonStaticMethod6<object>();
int NonStaticMethod6<T3>()
i += NonStaticMethod6<object>(0);
#if CS90
[My]
[return: My]
int NonStaticMethod6<[My] T3>([My] int unused)
#else
int NonStaticMethod6<T3>(int unused)
#endif
{
t2 = default(T2);
int l = 0;
return NonStaticMethod6_1<T1>() + NonStaticMethod6_1<T2>() + z.GetHashCode();
int NonStaticMethod6_1<T4>()
{
return i + l + NonStaticMethod6<T4>() + StaticMethod1<decimal>();
return i + l + NonStaticMethod6<T4>(0) + StaticMethod1<decimal>();
}
}
}

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;

3
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

@ -24,6 +24,7 @@ using System.Linq; @@ -24,6 +24,7 @@ using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
@ -222,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -222,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(member);
if ((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType && member.DeclaringType != null) {
if ((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType && member.DeclaringType != null && !(member is LocalFunctionMethod)) {
ConvertType(member.DeclaringType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}

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);
}

17
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -93,17 +93,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -93,17 +93,18 @@ namespace ICSharpCode.Decompiler.CSharp
CollectNamespacesForTypeReference(field.ReturnType);
break;
case IMethod method:
HandleAttributes(method.GetAttributes());
HandleAttributes(method.GetReturnTypeAttributes());
CollectNamespacesForTypeReference(method.ReturnType);
foreach (var param in method.Parameters) {
HandleAttributes(param.GetAttributes());
CollectNamespacesForTypeReference(param.Type);
}
HandleTypeParameters(method.TypeParameters);
var reader = module.PEFile.Reader;
var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList();
foreach (var part in parts) {
var partMethod = module.ResolveMethod(part, genericContext);
HandleAttributes(partMethod.GetAttributes());
HandleAttributes(partMethod.GetReturnTypeAttributes());
CollectNamespacesForTypeReference(partMethod.ReturnType);
foreach (var param in partMethod.Parameters) {
HandleAttributes(param.GetAttributes());
CollectNamespacesForTypeReference(param.Type);
}
HandleTypeParameters(partMethod.TypeParameters);
HandleOverrides(part.GetMethodImplementations(module.metadata), module);
var methodDef = module.metadata.GetMethodDefinition(part);
if (method.HasBody) {

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;
}
}
}

24
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -20,6 +20,8 @@ using System; @@ -20,6 +20,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using Humanizer;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.TypeSystem;
@ -51,6 +53,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -51,6 +53,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILTransformContext context;
string[] currentFieldNames;
Dictionary<string, int> reservedVariableNames;
Dictionary<MethodDefinitionHandle, string> localFunctionMapping;
HashSet<ILVariable> loopCounters;
const char maxLoopVariableName = 'n';
@ -59,6 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -59,6 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
this.context = context;
currentFieldNames = function.Method.DeclaringTypeDefinition.Fields.Select(f => f.Name).ToArray();
reservedVariableNames = new Dictionary<string, int>();
localFunctionMapping = new Dictionary<MethodDefinitionHandle, string>();
loopCounters = CollectLoopCounters(function);
foreach (var f in function.Descendants.OfType<ILFunction>()) {
if (f.Method != null) {
@ -180,6 +184,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -180,6 +184,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName))
newName = null;
localFunction.Name = newName;
localFunction.ReducedMethod.Name = newName;
}
// Now generate names:
var mapping = new Dictionary<ILVariable, string>(ILVariableEqualityComparer.Instance);
@ -199,6 +204,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -199,6 +204,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
newName = GetAlternativeName("f");
}
localFunction.Name = newName;
localFunction.ReducedMethod.Name = newName;
localFunctionMapping[(MethodDefinitionHandle)localFunction.ReducedMethod.MetadataToken] = newName;
}
foreach (var inst in function.Descendants) {
LocalFunctionMethod localFunction;
switch (inst) {
case Call call:
localFunction = call.Method as LocalFunctionMethod;
break;
case LdFtn ldftn:
localFunction = ldftn.Method as LocalFunctionMethod;
break;
default:
localFunction = null;
break;
}
if (localFunction == null || !localFunctionMapping.TryGetValue((MethodDefinitionHandle)localFunction.MetadataToken, out var name))
continue;
localFunction.Name = name;
}
}

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)

63
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Resolver;
@ -26,6 +27,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax; @@ -26,6 +27,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler
{
@ -39,7 +41,7 @@ namespace ICSharpCode.Decompiler @@ -39,7 +41,7 @@ namespace ICSharpCode.Decompiler
bool inDocumentationComment = false;
bool firstUsingDeclaration;
bool lastUsingDeclaration;
public TextTokenWriter(ITextOutput output, DecompilerSettings settings, IDecompilerTypeSystem typeSystem)
{
if (output == null)
@ -52,13 +54,13 @@ namespace ICSharpCode.Decompiler @@ -52,13 +54,13 @@ namespace ICSharpCode.Decompiler
this.settings = settings;
this.typeSystem = typeSystem;
}
public override void WriteIdentifier(Identifier identifier)
{
if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) {
output.Write('@');
}
var definition = GetCurrentDefinition();
string name = TextWriterTokenWriter.EscapeIdentifier(identifier.Name);
switch (definition) {
@ -69,7 +71,7 @@ namespace ICSharpCode.Decompiler @@ -69,7 +71,7 @@ namespace ICSharpCode.Decompiler
output.WriteReference(m, name, true);
return;
}
var member = GetCurrentMemberReference();
switch (member) {
case IType t:
@ -110,6 +112,7 @@ namespace ICSharpCode.Decompiler @@ -110,6 +112,7 @@ namespace ICSharpCode.Decompiler
if (symbol != null && node.Role == Roles.Type && node.Parent is ObjectCreateExpression) {
symbol = node.Parent.GetSymbol();
}
if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && symbol is IMember member) {
var declaringType = member.DeclaringType;
if (declaringType != null && declaringType.Kind == TypeKind.Delegate)
@ -123,10 +126,8 @@ namespace ICSharpCode.Decompiler @@ -123,10 +126,8 @@ namespace ICSharpCode.Decompiler
if (symbol == null)
return null;
//if (settings.AutomaticEvents && member is FieldDefinition) {
// var field = (FieldDefinition)member;
// return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? member;
//}
if (symbol is LocalFunctionMethod)
return null;
return symbol;
}
@ -142,14 +143,18 @@ namespace ICSharpCode.Decompiler @@ -142,14 +143,18 @@ namespace ICSharpCode.Decompiler
if (letClauseVariable != null)
return letClauseVariable;
var gotoStatement = node as GotoStatement;
if (gotoStatement != null)
{
if (node is GotoStatement gotoStatement) {
var method = nodeStack.Select(nd => nd.GetSymbol() as IMethod).FirstOrDefault(mr => mr != null);
if (method != null)
return method + gotoStatement.Label;
}
if (node.Role == Roles.TargetExpression && node.Parent is InvocationExpression) {
var symbol = node.Parent.GetSymbol();
if (symbol is LocalFunctionMethod)
return symbol;
}
return null;
}
@ -177,29 +182,29 @@ namespace ICSharpCode.Decompiler @@ -177,29 +182,29 @@ namespace ICSharpCode.Decompiler
return method + label.Label;
}
if (node is LocalFunctionDeclarationStatement) {
var localFunction = node.GetResolveResult() as MemberResolveResult;
if (node is MethodDeclaration && node.Parent is LocalFunctionDeclarationStatement) {
var localFunction = node.Parent.GetResolveResult() as MemberResolveResult;
if (localFunction != null)
return localFunction.Member;
}
return null;
}
ISymbol GetCurrentDefinition()
{
if (nodeStack == null || nodeStack.Count == 0)
return null;
var node = nodeStack.Peek();
if (node is Identifier)
node = node.Parent;
if (IsDefinition(ref node))
return node.GetSymbol();
return null;
}
public override void WriteKeyword(Role role, string keyword)
{
//To make reference for 'this' and 'base' keywords in the ClassName():this() expression
@ -211,7 +216,7 @@ namespace ICSharpCode.Decompiler @@ -211,7 +216,7 @@ namespace ICSharpCode.Decompiler
}
output.Write(keyword);
}
public override void WriteToken(Role role, string token)
{
switch (token) {
@ -253,22 +258,22 @@ namespace ICSharpCode.Decompiler @@ -253,22 +258,22 @@ namespace ICSharpCode.Decompiler
break;
}
}
public override void Space()
{
output.Write(' ');
}
public override void Indent()
{
output.Indent();
}
public override void Unindent()
{
output.Unindent();
}
public override void NewLine()
{
if (!firstUsingDeclaration && lastUsingDeclaration) {
@ -277,7 +282,7 @@ namespace ICSharpCode.Decompiler @@ -277,7 +282,7 @@ namespace ICSharpCode.Decompiler
}
output.WriteLine();
}
public override void WriteComment(CommentType commentType, string content)
{
switch (commentType) {
@ -309,7 +314,7 @@ namespace ICSharpCode.Decompiler @@ -309,7 +314,7 @@ namespace ICSharpCode.Decompiler
break;
}
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
// pre-processor directive must start on its own line
@ -321,7 +326,7 @@ namespace ICSharpCode.Decompiler @@ -321,7 +326,7 @@ namespace ICSharpCode.Decompiler
}
output.WriteLine();
}
public override void WritePrimitiveValue(object value, LiteralFormat format = LiteralFormat.None)
{
new TextWriterTokenWriter(new TextOutputWriter(output)).WritePrimitiveValue(value, format);
@ -376,7 +381,7 @@ namespace ICSharpCode.Decompiler @@ -376,7 +381,7 @@ namespace ICSharpCode.Decompiler
break;
}
}
public override void StartNode(AstNode node)
{
if (nodeStack.Count == 0) {
@ -390,7 +395,7 @@ namespace ICSharpCode.Decompiler @@ -390,7 +395,7 @@ namespace ICSharpCode.Decompiler
}
nodeStack.Push(node);
}
private bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
@ -401,10 +406,10 @@ namespace ICSharpCode.Decompiler @@ -401,10 +406,10 @@ namespace ICSharpCode.Decompiler
if (nodeStack.Pop() != node)
throw new InvalidOperationException();
}
public static bool IsDefinition(ref AstNode node)
{
if (node is EntityDeclaration)
if (node is EntityDeclaration && !(node.Parent is LocalFunctionDeclarationStatement))
return true;
if (node is VariableInitializer && node.Parent is FieldDeclaration) {
node = node.Parent;

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;

3
ILSpy/Languages/CSharpLanguage.cs

@ -648,6 +648,9 @@ namespace ICSharpCode.ILSpy @@ -648,6 +648,9 @@ namespace ICSharpCode.ILSpy
if (!settings.LiftNullables) {
flags &= ~ConversionFlags.UseNullableSpecifierForValueTypes;
}
if (entity is IMethod m && m.IsLocalFunction) {
writer.WriteIdentifier(Identifier.Create("(local)"));
}
new CSharpAmbience() {
ConversionFlags = flags,
}.ConvertSymbol(entity, writer, settings.CSharpFormattingOptions);

Loading…
Cancel
Save