5

I would like to implement the following suggestion from CodeContracts:

CodeContracts: MyModule: Method MyModule.MyClass.MyMethod: 
To mask *all* warnings issued like the precondition add the attribute: 

[SuppressMessage("Microsoft.Contracts", "RequiresAtCall-propertyAccessor != null")] 

to the method 

System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression,System.Reflection.MethodInfo)

It feels like I should be able to use SupressMessage with the Target attribute to make this happen. However, because this is a Framework method, I'm not sure.

//doesn't work
[module: SuppressMessage("Microsoft.Contracts", "RequiresAtCall-propertyAccessor != null", Scope = "Member", Target = "System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression,System.Reflection.MethodInfo)", Justification = "This isn't covered by Linq Contracts yet.")]

How can I globally suppress this warning, so I don't have to baseline or suppress all of the callsite warnings?

EDIT: The specific usage that requires this measure is:

void mymethod()
{
    var myObserver = new PropertyObserver<MyViewModel>();
    //this line throws the error, within the n => n.Value expression
    myObserver.RegisterHandler(n => n.Value, OnValueChanged);
}

public class PropertyObserver<TPropertySource> where TPropertySource : INotifyPropertyChanged
{
    public PropertyObserver<TPropertySource> RegisterHandler(
        Expression<Func<TPropertySource, object>> expression,
        Action<TPropertySource> handler)
    {
        //what this does is irrelevant; the violation  occurs in the method call
    }
}

//n => n.Value decompiles to the following
public static MemberExpression Property (Expression expression, MethodInfo   propertyAccessor)
{
    //and this line is the message I want to suppress, but it's in the .NET framework.
    ContractUtils.RequiresNotNull(propertyAccessor, "propertyAccessor");
    ValidateMethodInfo(propertyAccessor);
    return Property (expression, GetProperty(propertyAccessor));
}
Dave Neeley
  • 3,526
  • 1
  • 24
  • 42
  • Is there a reason that you're not using `Contract.Assume`? Just too many occurrences? – porges Jan 12 '12 at 22:11
  • We've tried to stay away from Contract.Assume generally, but yes, there are quite a few occurrences, and we continue to add more. – Dave Neeley Jan 12 '12 at 22:14
  • I'm guessing that the problem then is that the various ways to acquire Expressions/MethodInfos don't `Ensure` that the result is non-null. Have you considered using some wrapper methods such as those given in: http://social.msdn.microsoft.com/Forums/en-NZ/codecontracts/thread/d8e2c2ad-de37-42ef-a854-02052d821975 ? That way you only need to `Assume` in one place, so your `Assume` usage is minimized. – porges Jan 12 '12 at 22:22
  • That's a great idea, but the problem is the contract violation occurs in the call to the method, not _within_ the method (because the method expects to be passed an expression). I'll add an example. – Dave Neeley Jan 12 '12 at 22:47
  • In your real code, are you building up the `n=>n.Value` by expression trees? Your error mentions `Expression.Property` but that doesn't appear in the sample. – porges Jan 12 '12 at 23:11
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6673/discussion-between-porges-and-ranomore) – porges Jan 12 '12 at 23:23

3 Answers3

3

After some more investigation with ranomore, there seems to be a bug in Code Contracts.

The class being accessed via n => n.Value has a generic T Value property. If the class is changed to a non-generic class (with object Value) the warning disappears. (A generic class with object Value also gives the warning).

Of course, this doesn't answer the original question, but I don't think it's possible to do that.

porges
  • 30,133
  • 4
  • 83
  • 114
0

It actually works. You can add a SupressMessageAttribute to the method that contains the expression. Just don't use RequiresAtCall. Instead, use Requires:

[SuppressMessage("Microsoft.Contracts", "Requires",
                 Justification = "Bug in static checker")]
public void Override(AutoMapping<Bookings> mapping)
{
    Contract.Assume(mapping != null);

    mapping.Id(x => x.Id);
}

The obvious downside is that you will have to plaster your code with these...

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Isn't that pretty dangerous though? That's _all_ requires you're suppressing there. I was hoping to suppress just the one message. – Dave Neeley Feb 22 '13 at 22:41
  • @ranomore: Yes, you also can suppress just this one message. Instead of `Requires` you have to use `Requires-11-10` where the numbers specify the exact location of the warning. You get those numbers from Code Contracts when you add the following to the additional commands for the static checker on the Code Contracts project properties page: `-outputwarnmask`. For every warning it will output (in the Output window, not in the error list) a message that gives you the complete SupressMessage attribute you can use to suppress that specific warning. – Daniel Hilgarth Feb 22 '13 at 22:49
  • I didn't use this for my NHibernate mapping classes, because I was too lazy :) – Daniel Hilgarth Feb 22 '13 at 22:49
0
  1. Add GlobalSuppressions.cs to root of project.

  2. Add your [module...

  3. Replace the word module with assembly.

Does that work?

AMissico
  • 21,470
  • 7
  • 78
  • 106