New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About MemberReferenceExpression in 4.0 #1407

Closed
sjx95 opened this Issue Jan 29, 2019 · 10 comments

Comments

Projects
None yet
2 participants
@sjx95
Copy link

sjx95 commented Jan 29, 2019

namespace Test
{
    class TSB
    {
        public void h()
        {
        }
        public void Tester()
        {
            h();
        }
    }
}

When I try to decompile a DLL as above, the behavior changed while building AST.

In Test.TSB.Tester(), it's an InvocationExpression "h()", with a MemberReferenceExpression property Target "h", while I'm using 3.1.
But in 4.0 the Target "h" is now an IdentifyExpression, I have no idea how to identify if h is a member of TSB or local function or delegate, and if it's a static member.

Could I get some hint here?

@siegfriedpammer

This comment has been minimized.

Copy link
Member

siegfriedpammer commented Jan 29, 2019

You should not rely on syntax nodes to identify a symbol. You can use the GetSymbol or GetResolveResult extension methods. For example var mrr = astNode.GetResolveResult() as MemberResolveResult; if (mrr != null) return mrr.Member.IsStatic;.

Also, if it's an invocation, there is the InvocationResolveResult.

@sjx95

This comment has been minimized.

Copy link
Author

sjx95 commented Jan 29, 2019

Thanks! This is very helpful!

Besides, should I expect (invocationExpression.GetResolveResult() as CSharpInvocationResolveResult).IsDelegateInvocation return true while decompiling the f() as below? In my test case, this return false.

class T
    {
        public void M()
        {
            var f = new Func<string>(() => "STRING");
            f();
        }
    }

siegfriedpammer added a commit that referenced this issue Jan 29, 2019

@siegfriedpammer

This comment has been minimized.

Copy link
Member

siegfriedpammer commented Jan 29, 2019

Yes, that was missing. I fixed that.

@sjx95

This comment has been minimized.

Copy link
Author

sjx95 commented Jan 30, 2019

BTW in invocationExpression {h ()} where h is a normal member method, the invocationExpression.Target.GetResolveResult() return an ErrorResolveResult, is it expected?

This can return ILVariableResolveResult if h is a local delegate variable, or MemberResolveResult if h is a delegate member.

@siegfriedpammer

This comment has been minimized.

Copy link
Member

siegfriedpammer commented Jan 30, 2019

ErrorResolveResult is only returned, if there's no annotation available.

I tested the code you posted above and it returns an ILVariableResolveResult as expected.

invocationExpression.Target.GetResolveResult()
{[ILVariableResolveResult System.Func`1[[System.String]]]}
    ConstantValue: null
    IsCompileTimeConstant: false
    IsError: false
    Type: {System.Func`1[[System.String]]}
    Variable: "f" : {System.Func`1[[System.String]]}
    @type: {System.Func`1[[System.String]]}

Can you please post the code that causes this behavior? Thanks!

@sjx95

This comment has been minimized.

Copy link
Author

sjx95 commented Jan 31, 2019

Yeah delegate is OK, but member method failed. Here is the code, which using nuget package:

using System;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;

namespace ILSpyCase
{
    class Program
    {
        class Visitor : DepthFirstAstVisitor
        {
            public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
            {
                if (methodDeclaration.Name != "targetMethod") 
                    return;
                base.VisitMethodDeclaration(methodDeclaration);
            }

            public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
            {
                base.VisitIdentifierExpression(identifierExpression);
                Console.WriteLine(identifierExpression);
                Console.WriteLine(identifierExpression.GetResolveResult());
                Console.WriteLine(identifierExpression.GetSymbol());
                Console.WriteLine("========");
            }
        }

        static void Main(string[] args)
        {
            var dec = new CSharpDecompiler(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, new DecompilerSettings());
            var ast = dec.DecompileType(new FullTypeName("ILSpyCase.Case"));
            ast.AcceptVisitor(new Visitor());
        }
    }

    class Case
    {
        private Func<int> func = () => 233;
        int method() { return 233;}

        void targetMethod()
        {
            func();
            method();
        }
    }
}

And here is the result:

func
[MemberResolveResult 04000001 ILSpyCase.Case.func]
04000001 ILSpyCase.Case.func
========
method
[ErrorResolveResult ?]

========
请按任意键继续. . .
@siegfriedpammer

This comment has been minimized.

Copy link
Member

siegfriedpammer commented Jan 31, 2019

Yes, that is expected.

The information is stored on the InvocationExpression. That is because the name of the method alone is not enough to identify the method. We only could attach a MethodGroupResolveResult to the identifier, but currently we do not do this.

@sjx95

This comment has been minimized.

Copy link
Author

sjx95 commented Jan 31, 2019

So maybe I should try to get resolve result of IdentifierExpression, if failed, check its Parent?
I'll have a try, thank you!

@sjx95 sjx95 closed this Feb 1, 2019

@sjx95 sjx95 reopened this Feb 1, 2019

@sjx95

This comment has been minimized.

Copy link
Author

sjx95 commented Feb 1, 2019

Excuse me, CSharpInvocationResolveResult.IsExtensionMethodInvocation doesn't work as I expect, could you please have a check? It used to return True in 3.1, but now False.

I think this may be a similar problem as IsDelegateInvocation.

Here is my test case:

using System;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;

namespace ILSpyCase
{
    class Program
    {
        class Visitor : DepthFirstAstVisitor
        {
            public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
            {
                if (methodDeclaration.Name != "targetMethod") 
                    return;
                base.VisitMethodDeclaration(methodDeclaration);
            }

            public override void VisitInvocationExpression(InvocationExpression invocationExpression)
            {
                var irr = invocationExpression.GetResolveResult() as CSharpInvocationResolveResult;
                Console.WriteLine(invocationExpression);
                Console.WriteLine($"IsExtensionMethodInvocation: {irr.IsExtensionMethodInvocation}");

                base.VisitInvocationExpression(invocationExpression);
            }
        }

        static void Main(string[] args)
        {
            var dec = new CSharpDecompiler(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, new DecompilerSettings());
            var ast = dec.DecompileType(new FullTypeName("ILSpyCase.Case"));
            ast.AcceptVisitor(new Visitor());
        }
    }

    static class StaticMethods
    {
        public static void ExtMethod(this Case c) { }
    }

    class Case
    {
        void targetMethod()
        {
            this.ExtMethod();
        }
    }
}
this.ExtMethod ()
IsExtensionMethodInvocation: False

siegfriedpammer added a commit that referenced this issue Feb 1, 2019

@siegfriedpammer

This comment has been minimized.

Copy link
Member

siegfriedpammer commented Feb 9, 2019

Do you need any other help? Can this be closed?

@sjx95 sjx95 closed this Feb 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment