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.
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.
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);
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,
Related
I have a lot of classes that share a lot of properites and have a lot of common interfaces.
It happens very regularly that i want to construct an object with data from another object and they share an interface. To make that more easy i have this neat little method:
public static List<PropertyInfo> InterfaceProperties(Type type)
{
return new[] {type}
.Concat(type.GetInterfaces())
.SelectMany(i => i.GetProperties(BindingFlags.Instance | BindingFlags.Public)).ToList();
}
public static void SetFromSimilar<TInterface>(TInterface destination,TInterface source)
{
var properties = InterfaceProperties(typeof(TInterface));
foreach (var property in properties)
{
var val = property.GetValue(source, null);
property.SetValue(destination, val, null);
}
}
It works fantastic because now i can do this:
public class MyClass: IMyInterface
{
public MyClass(IMyInterface otherClass)
{
SetFromSimilar(this,otherClass)
}
....MyProperties.....
}
Now rider complains about non-nullable properties being uninitialized which makes sense. I know they are initialized but for the IDE thats hard to see and i get compilerwarnings. This throws me off because i see it marked as a potentialy error and i have to think everytime if there is something wrong.
Is there a substitute for my method where this will not happen?
Ok i got no answers so far. Is it not possible? Is this not a normal usecase? Is it somehow possible with net5?
The compiler warning:
C:\My\File\Path\MyClass.cs(10,16): warning CS8618: Non-Nullable-Eigenschaft "MyProperty" muss beim Beenden des Konstruktors einen Wert ungleich NULL enthalten.
Erwägen Sie eine Deklaration von "Eigenschaft" als Nullable. [C:\My\File\Path\MyProject.csproj]
It tells me to maybe make the property nullable which i absolutely don`t want.
The compiler and analyzers cannot usually (or easily) interpret reflection code, so it is quite reasonably unconvinced as to their assignment and nullability. If you know something is correct that the compiler can't verify: just add a suppression for the warning over that particular code block, via #pragma, a [SuppressMessage(...)] on the affected code, or a suppression file (which is just [assembly:SuppressMessage(...)] in a different file, with a Target to tell the compiler what it applies to). Rider may have some other ways of suppressing messages, via the context menu.
Note: if you go this route, you may also want to add assertions - especially in a DEBUG build - that what you belive to be true: is actually true.
If you're using C# 9, you could add a smattering of dammit (!) markers, or turn off nullability checking for that code.
Well yea, this does not look like a perfectly elegant solution to your problem, in my opinion. Here's some solutions I can think of, in order of elegance:
1. Quick & Brute force
Just tell rider to not complain about it with a #pragma statement, I believe in your case it should be this:
#pragma warning disable CS8618
[code that throws the warning]
#pragma warning restore CS8618
2. Write code to generate code
Write yourself a small application that extracts those common interfaces to autogenerate set-value code for each
3. Don't mix data with control code
If you need to set data on classes with different controllers, i.e. classes, put it into its own data class. Tadaaa, you just gained the ability of class inheritance for setting common values.
Here is a piece of code:
IUser user = managerUser.GetUserById(UserId);
if ( user==null )
throw new Exception(...);
Quote quote = new Quote(user.FullName, user.Email);
Everything is fine here. But if I replace "if" line with the following one:
ComponentException<MyUserManagerException>.FailIfTrue(user == null, "Can't find user with Id=" + UserId);
where function implementation is following:
public abstract class ComponentException<T> : ComponentException
where T : ComponentException, new()
{
public static void FailIfTrue(bool expression, string message)
{
if (expression)
{
T t = new T();
t.SetErrorMessage(message);
throw t;
}
}
//...
}
Then ReSharper generates me a warning: Possible 'System.NullReferenceException' pointing on 1st usage of 'user' object.
Q1. Why it generates such exception? As far as I see if user==null then exception will be generated and execution will never reach the usage point.
Q2. How to remove that warning? Please note:
1. I don't want to suppress this warning with comments (I will have a lot of similar pieces and don't want to transform my source code in 'commented garbage);
2. I don't want to changes ReSharper settings to change this problem from warning to 'suggestion' of 'hint'.
Thanks.
Any thoughts are welcome!
P.S. I am using resharper 5.1, MVSV 2008, C#
Resharper only looks at the current method for its analysis, and does not recursively analyse other methods you call.
You can however direct Resharper a bit and give it meta-information about certain methods. It knows for example about "Assert.IsNotNull(a)", and will take that information into account for the analysis. It is possible to make an external annotations file for Resharper and give it extra information about a certain library to make its analysis better. Maybe this might offer a way to solve your problem.
More information can be found here.
An example showing how it's used for the library Microsoft.Contracts can be found here.
A new answer in old post...
Here a little sample of my code regarding how to use CodeContract via ContractAnnotation with Resharper:
[ContractAnnotation("value:null=>true")]
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
It is very simple...if u find the breadcrumb in the wood. You can check other cases too.
Have a nice day
Q1: Because Resharper doesn't do path analysing. It just sees a possible null reference and flags that.
Q2: You can't without doing either of what you provided already.
You do know (or expect) that this code will throw an exception if there is a null reference:
ComponentException<MyUserManagerException>.FailIfTrue([...]);
However, since there is no contract specifying this, ReSharper has to assume that this is just a normal method call which may return without throwing any exception in any case.
Make this method implement the ReSharper contract, or as a simple workaround (which only affects debug mode, therefore no performance penalty for release mode), just after the FailIfTrue call:
Debug.Assert(user != null);
That will get rid of the warning, and as an added bonus do a runtime check in debug mode to ensure that the condition assumed by you after calling FailIfTrue is indeed met.
This is caused by the Resharper engine. These "possible NullReferenceException" happen because someone (probably at Resharper) has declared/configured somewhere an annotation on the method.
Here is how it works: ReSharper NullReferenceException Analysis and Its Contracts
Unfortunately, sometimes, these useful annotation are just wrong.
When you detect an error, you should report it to JetBrains and they will update the annotations on the next release. They're used to this.
Meanwhile, you can try to fix it by yourself. Read the article for more :)
Please check if you have any user==null if check above the given code. If there is, then ReSharper thinks that the variable "can be null" so recommends you to use a check/assert before referencing it. In some cases, that's the only way ReSharper can guess whether a variable can or cannot be null.
I have the following piece of c# code:
myClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
CodeContract knows that myClaimsIdentity is never null. But it complains that the FindFirst(string) method might return null:
Warning CodeContracts: Possibly calling a method on a null reference. Do you expect that System.Security.Claims.ClaimsIdentity.FindFirst(System.String) returns non-null?
I do expect this, but how can I tell it to the CodeChecker? Of course I can't change the the FindFirst(string) since it comes from an external library.
The simple approach is:
var nameIdentifier = myClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier);
Contract.Assume(nameIdentifier != null);
nameIdentifier.Value;
Code contracts will not try to prove the Assume condition, but will use it when proving other requirements.
It's probably possible to create a contract reference assembly for the external code which has the appropriate Ensures post-conditions. The code contracts team does this for the BCL types. But I don't know how to do that.
Usually, when I want to check if, let's say a constructor argument is initialized, I do it like this:
public MyCtor(MyObj obj) {
if(obj == null)
throw new ArgumentNullException("obj");
}
However recently I stumpled upon this nice feature from the System.Diagnostics namespace:
Contract.Requires<ArgumentNullException>(condition);
Does this have the same effect? Are there any drawbacks when using Contracts to validate arguments?
Yes unless:
You must turn on run-time checking to use the Requires method.
(from MSDN). Instruction how to turn it on must be somewhere here.
An alternative is CuttingEdge.Conditions:
Condition.Requires(obj).IsNotNull();
Condition.Requires(myIntValue).IsGreaterThan(0);
Condition.Requries(myString).IsNotNullOrWhitespace();
More on codeplex.
This do the same job but syntax simpler and more human readable (in my opinion) - so there has no drawbacks (but remeber: it's opinion based). Is use it since I've discovered :)
I'm trying to get rid of all DateTime.Now method calls and replace them with my own GetNow() method, which may sometimes return a fixed date for testing purposes.
How can I enforce that no one adds a DateTime.Now call in the future? Can I use NDepend or StyleCop to check this on my continuous integration server?
With NDepend it is very easy to write this rule:
// <Name>Forbid DateTime.Now, use xxx.GetNow() instead</Name>
WARN IF Count > 0 IN
SELECT METHODS WHERE
IsDirectlyUsing "OPTIONAL:System.DateTime.get_Now()"
Notice:
The prefix WARN IF Count > 0 IN that transforms the CQL query into a rule
The way the property is referenced through the string System.DateTime.get_Now()
The prefix OPTIONAL that means "Don't emit a compilation error if the property get_Now is not found". This makes sense since if your code doesn't use anymore get_Now(), it is not anymore referenced from NDepend analysis.
Also, to generate the original query...
SELECT METHODS WHERE
IsDirectlyUsing "OPTIONAL:System.DateTime.get_Now()"
...just right-click DateTime.get_Now() and choose Select methods ... that are directly using me
Firstly, DateTime.Now is a property.
That means you don't need to put parenthesis after call.
Secondly, if by testing purposes you mean a framework like NUnit, you might want to check out Microsoft Moles which allows you to substitute any static method call with your own custom implementation while testing. Heck, it's cool:
[Test]
[ExpectedException (typeof (Y2KBugException))]
public void TestY2KBug ()
{
MDateTime.NowGet = () => new DateTime (2001, 1, 1);
Bomb.DetonateIfY2K ();
}
public static class Bomb {
public static void DetonateIfY2K ()
{
if (DateTime.Now == new DateTime (2001, 1, 1))
throw new Y2KBugException (); // take cover!
}
}
There's no real way to enforce something like this.
The closest you're going to come is making a custom FxCop rule or custom Visual Studio Code Analysis rule to error/warn on calls to DateTime.Now.
You could use Moles in your tests to provide your own DateTime.Now when required, without the need to modify any existing code that calls it.
Another option might be to modify the assembly after compilation to call something else. (Perhaps, use Mono.Cecil to rewrite the IL, and add a command to the post-build in VS to run it.)
You could perhaps grab the Mono source and build yourself a custom mscorlib with the function removed.
One approach might be to add a pre-commit hook to your source control repository of choice to look for DateTime.Now and abort the check-in if you find the offending string. It's not foolproof and it might be annoying to your colleagues but it should help keep it out of the codebase.
I don't think that this is possible. What you are actually trying to do is override DateTime's struct functionality.
The only way I can think of is just to go with a custom class that will wrap common functionality of DateTime and offer different functionality on demand...