Конечно, это тривиально возможно.Что-то вроде:
static void M(bool x)
{
if (x)
return;
else
M(x);
return;
}
Если вы скомпилируете это в режиме отладки, вы получите
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: brfalse.s IL_0008
IL_0006: br.s IL_0011
IL_0008: ldarg.0
IL_0009: call void A::M(bool)
IL_000e: nop
IL_000f: br.s IL_0011
IL_0011: ret
Оператор if
переходит с 0001
на 0009
, и следствиеif
- это переход к 0011
;оба оператора return
представляют собой один и тот же код, поэтому существует «дыра», содержащая nop
и безусловная ветвь между основным телом if
и последствием.
В более общем случае вам следуетникогда не предполагайте ничего о компоновке IL, созданной компилятором C #.Компилятор не дает никаких гарантий, кроме того, что созданный IL будет законным и, если это безопасно, проверяемым.
Вы говорите, что пишете некоторые инструменты анализа кода;как автор значительных частей анализатора C # и тот, кто работал над сторонними инструментами анализа в Coverity, совет: для большинства вопросов, на которые вы обычно хотите получить ответы о программах на C #, дерево разбора, созданное Roslyn, являетсясущность, которую вы хотите проанализировать, а не IL.Дерево разбора является конкретным синтаксическим деревом;это один-к-одному с каждым символом в исходном коде.Может быть очень сложно отобразить оптимизированный IL обратно в исходный исходный код, и может быть очень легко произвести ложные срабатывания в анализе IL.
Другими словами: источник-IL сохраняет семантику, но также теряет информацию;Обычно вы хотите проанализировать артефакт, в котором содержится наибольшее количество информации.
Если по какой-либо причине вам необходимо работать с анализатором на уровне IL, вашей первой задачей, вероятно, должно быть определение границ базового объекта.блоки, особенно если вы анализируете свойства достижимости.
«Базовый блок» - это непрерывный фрагмент IL, в котором конечная точка блока не «переходит» к следующей инструкции - потому что это, например, ветвление, возврат или выброс -и нет никаких ответвлений в блоке, кроме первой инструкции.
Затем вы можете сформировать график основных блоков для каждого метода, указав, какие из них могут передавать управление другим блокам.Это «поднимает уровень» вашего анализа;вместо того, чтобы анализировать эффекты последовательности инструкций IL, теперь вы анализируете эффекты графика базовых блоков.
Если вы скажете больше о том, какие виды анализа вы делаете, я могу посоветовать дальше.