Как да използвате SemanticModel, за да проверите дали променливата е тествана?

Работя върху разширение Roslyn за предупреждение срещу незащитен .Value достъп до Nullable<T> стойности.

Това осигурява следното поведение:

Предупреждение: Nullable 'x' трябва да бъде проверен за нулеви стойности преди достъп до свойството 'Value'

Това разширение вече донякъде работи, но кодът за тестване дали достъпът е „безопасен“ е нещо като хак. Сега просто преминавам през синтактичното дърво, търся if изявления.

Този подход е доста грозен и произвежда куп невалидни предупреждения.

Ето няколко примера за случаи, при които достъпът x.Value трябва да е безопасен:

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;

Има ли начин да използвате SemanticModel, за да напишете правилно този тест?

Едно от нещата, за които мисля, е да направя Абстрактна интерпретация върху синтактичното дърво. Но това изглежда като много работа и се надявам, че не е необходим пълноценен абстрактен интерпретатор.

Не съм съвсем сигурен как анализът на мъртъв код се прилага в Roslyn, но изглежда донякъде свързан с това.


person Tom Lokhorst    schedule 05.05.2014    source източник
comment
Мисля, че вашият пример с бележката има грешка: ако bar == true и x == null, това ще се срине. || Операторът трябва да е симетричен по отношение на безопасността, според мен (въпреки че лявата страна може да означава безопасност от дясната страна).   -  person Jason Malinowski    schedule 06.05.2014
comment
Това трябва да е &&, а не ||   -  person SLaks    schedule 06.05.2014
comment
И това, което искате, се нарича анализ на достъпността.   -  person SLaks    schedule 06.05.2014
comment
Внедряването на Roslyn е вътрешно и може да бъде намерено на source .roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/   -  person SLaks    schedule 06.05.2014
comment
@JasonMalinowski Точно така, това беше грешка. Оправих примера.   -  person Tom Lokhorst    schedule 06.05.2014
comment
@SLaks: внедряването е публичен API, можете просто да извикате SemanticModel.AnalyzeDataFlow. Том обаче се нуждае от нещо по-силно.   -  person Jason Malinowski    schedule 06.05.2014


Отговори (2)


Все още изобщо не съм играл с Рослин. Но като потребител на ReSharper, който също има точно тази функция, мога да направя следното изявление:

Моето наблюдение е, че ReSharper разглежда само последното скорошно използване на съответния символ (тип Nullable‹>). Това е итеративно доказателство. Ако променливата е била използвана (очевидно) успешно, тя е безопасна за продължителна употреба. След това зависи от предишната проверка за използване, за да докаже, че това отново е безопасен достъп. Така: проверете предишния достъп или за друг предишен достъп, или за спасително сравнение с null, за да видите дали е безопасно.

if( x != null)
     x.access

Пример:

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
person Robetto    schedule 03.06.2014
comment
Харесвам идеята ви (или ReSharpers ;-)), но не е ли по-скоро оптимизация, отколкото действително решение на проблема? Все пак ще трябва да докажете, че първият достъп до променливата е безопасен или нулева проверка (или изрично чрез != null или HasValue, или имплицитно чрез сравнение, ненулево присвояване и т.н.). - person andyp; 03.06.2014
comment
Вероятно завършва като рекурсивен проблем. Така да се каже: докажете, че първият достъп и следващите са безопасни. - person Robetto; 30.06.2014

Решаването на този проблем изисква анализ на потока, който Рослин все още не прави.

person Neal Gafter    schedule 05.06.2014