0

Let's say we have some class someone ends up consuming:

public class SampleClass
{
    [Obsolete("This property was slain in Moria", false)]
    public double SampleProperty { get; set; }

    [Obsolete("This method was slain in Moria", false)]
    public static void SampleMethod()
    {
    }
}

And then let's say someone consumes it:

public static double SampleConsumer()
{
    SampleClass.SampleMethod();
    var classy = new SampleClass();
    return classy.SampleProperty;
}

I am trying to determine all references to obsolete methods and properties within SampleConsumer.

I have figured out how to get the methods, thanks to Kris's response to this question. In summary, that looks like:

public static void GetMethodReferences(MethodDefinition method)
{
    foreach (var instruction in method.Body.Instructions)
    {
        if (instruction.OpCode == OpCodes.Call)
        {
            MethodReference methodCall = instruction.Operand as MethodReference;  
            // ...

wherein methodCall.CustomAttributes would contain the obsolete attribute we wish to detect.

I am trying to accomplish something similar for property references.


What I have tried so far:

Note that in CIL, the classy.SampleProperty is represented by a callvirt instruction:

System.Double FoobarNamespace.SampleClass::get_SampleProperty()

I tried including the OpCodes.Callvirt in GetMethodReferences, but the only attribute that the virtual get method seems to have is a CompilerGeneratedAttribute (no obsolete attribute).

Next I decided to peek inside of the virtual get method. Iterating on the virtual method's instructions, notice there is a ldfld (load field) instruction:

System.Double FoobarNamespace.SampleClass::<SampleProperty>k__BackingField    

I try to check it for the obsolete attributes:

// for each instruction in the virtual get_SampeProperty()  
    if (instruction.OpCode == OpCodes.Ldfld)
    {
        var fieldDefinition = instruction.Operand as MethodDefinition;
        // check fieldDefinition.Attributes   
        // check fieldDefinition.CustomAttributes   
        // but neither of them have the Obsolete attribute  
        // ...

I think what I actually need to do is get either a PropertyDefinition or PropertyReference for SampleProperty, but I can't seem to figure out how to do that in the context of the consumer method.

Ideas?

Community
  • 1
  • 1
scholtes
  • 113
  • 3
  • Why are you not just looking at the compiler warnings. The compiler has already handled all of this for you. – Servy May 03 '16 at 17:16
  • Do you need it to be on code? I mean, if you use VS2015 it will already give you that info, if you go to the function you will have a line telling you the number of references and if you click on it it will bring you a lens with all the calls, on other VS versions you can just go to the function name and "Find all references" – Gusman May 03 '16 at 17:17
  • @Servy we have external developers consuming our API. Some of them have been ignoring the VS compiler warnings for a while, so we want to give them a tool to run against a large [already compiled] codebase to detect if they are using any obsolete methods. In the future, they will be able to upload applications onto our platform, and we want the upload process to reject/warn them if they try to upload an application that consumes obsolete endpoints (i.e., yes it needs to be in code -- outside of the context of VS). – scholtes May 03 '16 at 17:22
  • @scholtes If they're already ignoring the compiler warnings, what makes you think that they'd be interested in your warnings? And if they were, you could trivially create a VS plugin to simply filter warnings to just show warnings for use of obsolete methods from your library. If you want people to not be *able* to use the obsolete methods, then configure the attribute to error, not warn, when they're used. – Servy May 03 '16 at 17:25
  • We do eventually plan on breaking their code, but in the mean time we are trying to make their transition as easy as possible. Even if they are ignoring compliler warnings we have to keep them satisfied. This policy is not in my control. – scholtes May 03 '16 at 17:27

1 Answers1

0

In IL, there is no notion of property for a method, there is only notion of methods for a property. I think Cecil reflects this, so you can't get from MethodDefinition to PropertyDefinition, but you can do it the other way around.

The code could look something like (untested):

MethodDefinition method;

PropertyDefinition property = method.DeclaringType.Properties
    .SingleOrDefault(p => p.GetMethod == method || p.SetMethod == method);

Keep in mind that it's theoretically possible that a single method would belong to multiple properties, but I don't think any sane compiler would do that.

svick
  • 236,525
  • 50
  • 385
  • 514