27

I'm making an extension to Visual Studio. Within the code I'm using Code Contracts to make assertions and checks. I set the warning option level to high.

What I would like to do is maintain that warning level while ignoring any checks made on EnvDTE references.

Consider the following code example:

public static string GetAbsoluteOutputFolder(EnvDTE.Project project)
{
    if (project == null) throw new ArgumentNullException("project");

    var path =
        project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
    //...
}

With my current settings, CC would require me to add the following checks before assigning the path variable:

Contract.Assume(project.ConfigurationManager != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration.Properties != null);

Therefore what I'd like to do here is to tell CC to "trust" EnvDTE and ignore these types and their properties.

I thought the "Be optimistic on external API" CC option served this very purpose; turns out it doesn't.

Is there a way to make it behave the way I want that would not require a lower warning level?

EDIT: I want a solution that would work at project level and that would still allow "regular" checks to be performed.

Crono
  • 10,211
  • 6
  • 43
  • 75
  • 1
    If it was me I would just add the Checks you want to omit. If your code blows up because of a Null Reference someplace in EnvDTE.Project having those checks should let you know exactly where the problem is instead of trying to guess where the Null is. – Mike Burdick Dec 04 '14 at 20:51
  • @MikeBurdick The thing is that some of these properties are very likely never null. But since that assembly wasn't compiled with contracts, there's no way for the engine to tell. Therefore it treats these as it would any properties without contracts, forcing the use of pointless checks for the same property over and over again. If there was a global, do-it-once way to enforce that `Configuration.Properties` (for example) never returns null I'd gladly use it but there isn't. So IMHO the lesser evil would be to tell CC to simply ignore any code that belongs to that specific assembly. – Crono Mar 05 '15 at 17:20

3 Answers3

4

Can´t provide a detailed solution but this should be solvable by using either the Baseline Feature or System.Diagnostics.CodeAnalysis.SuppressMessage on assembly level:

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Contracts", "Whatever")]

You can use the "Target" Property of the SuppressMessageAttribute to only ignore the Message on specific Types / Methods / Namespaces:

[SuppressMessage("Microsoft.Contracts", 
                 "CC1055", 
                 Scope="Member", 
                 Target="YouNamespace.EnvDTE.Project")]

Note that the Parameters i used are just a good bet, you´ll have to figure out the correct Scope, MessageId and Target yourself :) On a sidenote, i think the Attribute is Conditional("CODE_ANALYSIS").

The official suggested solution to this problem is to create some sort of wrapper, in your case probably a repository that would create or contain your EnvDTE.Project objects. Then you can add the required Contract.Ensures there.

RB.
  • 36,301
  • 12
  • 91
  • 131
Mecaveli
  • 1,507
  • 10
  • 16
  • How can I place an assembly level warning if I don't own the code for said assembly? – Crono Mar 31 '15 at 13:05
  • 1
    @Crono: You can suppress Messages on external libs by using the "Target" Property of the SuppressMessageAttribute, i´ll add that to the answer. – Mecaveli Apr 01 '15 at 15:50
1

I don't think it's possible to solve the problem but since C# 6.0 there is a workaround which at least eases the pain a bit:

Instead of

Contract.Assume(project.ConfigurationManager != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration.Properties != null);

you can now write

Contract.Assume(project.ConfigurationManager?.ActiveConfiguration?.Properties != null);
Tim Pohlmann
  • 4,140
  • 3
  • 32
  • 61
0

Have you tried something with : [assembly: Contracts.ContractVerification(false)] at the assembly level ?

You should be able to do it dynamically : https://msdn.microsoft.com/en-us/library/bb458043.aspx

Hope this helps,

Rénald
  • 1,412
  • 12
  • 29
  • 1
    If I understand this attribute correctly it will only prevent contract verification in that assembly. What OP wants is to ignore all warnings created by using the assembly. – Tim Pohlmann Jul 11 '16 at 14:02