Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rewrite AST dynamically in resharper plugin?

The request:

I'd like to be able to write an analyzer that can provide a proxy value for a certain expression and trigger a re-parsing of the document.

The motivation:

Our code is littered with ABTests that can be either in a deployed or active state with a control and variant group. Determining a test's state is done through a database lookup. For the tests that are deployed with the control group, any statement of the following form will evaluate to false:

if(ExperimentService.IsInVariant(ABTest.Test1))
{
}

I'm trying to provide tooling to make this easier to deal with at develop time by greying it out in this scenario. As it is, this is fairly limited and not robust because I basically have to play parser myself.

What if the actual code is

if(!ExperimentService.IsInVariant(ABTest.Test1))

or

if(ExperimentService.IsInVariant(ABTest.Test1) || true)

or

var val = ..... && (ExperimentService.IsInVariant(ABTest.Test1);
if(val){
  // val is always going to be false if we deployed control.
}

A possible approach I could see provided is by allowing us to write analyzers that are fired once and rewrite the tree before the actual IDE parsing happens (or, well, just parse it a second time). These should only fire once and allow us to replace a certain expression with another. This would allow me to swap all of these experiment calls for true and false literals.

As a result, these sections could benefit from all the other IDE features such as code greying for unreachable code but also more intricate ones like a variable that will never have a different value

Obviously this is just an example and I'm not sure how feasible it is. Any suggestions for a proper feature or something that already exists are more than welcome.

like image 930
Erti-Chris Eelmaa Avatar asked Aug 09 '16 19:08

Erti-Chris Eelmaa


2 Answers

I don't think there's an approach that doesn't have a compromise.

ReSharper doesn't support rewriting the AST before analysis - that would just rewrite the text in the file.

You could write an analyser that greys out the code, by applying a "dead code" highlight to the contents of the if block, but as you say, you'd need to parse the code and analyse control flow in order to get it correct, and I think that would be very difficult (ReSharper does provide a control flow graph, so you could walk it, but it would be up to you to A. find the return value of IsInVariant and B. trace that value through whatever conditions, && or || statements until you find an appropriate if block).

Alternatively, you could mark the IsInVariant method with the ContractAnnotation attribute, something like:

[ContractAnnotation("=> false")]
public bool IsInVariant(string identifier)
{
  // whatever...
}

This will tell ReSharper's analysis that this method always returns false (you can also say it will return true/false/null/not null based on specific input). Because it always returns false, ReSharper will grey out the code in the if statement, or the else branch if you do if (!IsInVariant(…)).

The downside here is that ReSharper will also add a warning to the if statement to tell you that the expression always returns false. So, it's a compromise, but you could change the severity of that warning to Hint, so it's not so intrusive.

like image 59
citizenmatt Avatar answered Oct 07 '22 10:10

citizenmatt


This is not enough to really warrant the bounty, but one solution that might apply from the developer documentation is to create a custom language and extend the basic rules.

You said

I'm trying to provide tooling to make this easier to deal with at develop time by greying it out in this scenario.

Greying out the corresponding parts might just be done by altering syntax highlighting rules.

See this example for .tt files.

like image 28
serv-inc Avatar answered Oct 07 '22 08:10

serv-inc