Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SemanticModel to check if variable has been tested?

Tags:

c#

roslyn

I'm working on a Roslyn extension to warn against unprotected .Value accesses of Nullable<T> values.

This provides the following behaviour:

Warning: "Nullable 'x' must be checked for null values before accessing 'Value' property"

This extension already sort of works, but the code to test if an access is "safe" is sort of a hack. I now simply walk the syntax tree, looking for if statements.

This approach is quite ugly and produces a bunch of invalid warnings.

Here are some examples of cases where access x.Value should be safe:

int y;
int? x = foo();

y = x != null ? x.Value : 42;

if (x > 4)
  y = x.Value;

if (x != null && someExpr) // With && only one branch needs to be a test
  y = x.Value;

if (x == 3 || x == 4) // With || both branches must be a test
  y = x.Value;

if (x == null) return; // Exit method body before access .Value
y = x.Value;

Is there a way to use the SemanticModel to properly write this test?

One of things I'm thinking about is to do Abstract interpretation over the syntax tree. But that seems like a lot of work, and I'm hoping a full blown abstract interpreter is not needed.

I'm not quite sure how dead code analysis is implemented in Roslyn, but it seems somewhat related to this.

like image 531
Tom Lokhorst Avatar asked May 05 '14 20:05

Tom Lokhorst


2 Answers

I haven't played with Roslyn at all, yet. But being a user of ReSharper which has this exact feature as well, I can do the following statement:

My observation is that ReSharper only looks to the last recent usage of the respective symbol (type Nullable<>). This is an iterative proof. If the variable has been used (obviously) successfully, it is safe for continuus usage. Then it is up to the previous usage check to proove that this again is a safe access. Thus: check the previous access for either another previous access or a salvaging comparison against null to see if it is safe.

if( x != null)
     x.access

Example:

var z = x.Value; // unsafe because it is first and un-tested
var y = x.Value; // safe because it is not first and therefore dependent on first access
like image 196
Robetto Avatar answered Nov 15 '22 06:11

Robetto


Solving this problem requires flow analysis, which Roslyn doesn't yet do.

like image 39
Neal Gafter Avatar answered Nov 15 '22 07:11

Neal Gafter