Эрик имеет право: чтобы сделать это хорошо, вам нужно то, что равносильно внешнему интерфейсу компилятора. Что он не особо подчеркнул, так это потребность в сильных возможностях анализа потока (или готовность принять очень консервативные ответы, возможно, смягченные аннотациями пользователей). Возможно, он имел в виду, что во фразе «семантический анализ», хотя его примеру «определения goto» просто нужна таблица символов, а не анализ потока.
Простой синтаксический анализатор C # может использоваться только для получения очень консервативных ответов (например, если метод A в классе C содержит идентификатор X, предположим, что он читает член класса X; если A содержит нет вызовов, то вы знаете, что он не может прочитать элемент X).
Первый шаг после этого - наличие таблицы символов компилятора и информации о типе (если метод A напрямую ссылается на член класса X, то предположим, что он читает член X; если A содержит ** no * вызовов и упоминает идентификатор X только в контексте доступа к объектам, которые не принадлежат к этому типу класса, тогда вы знаете, что он не может прочитать член X). Вы также должны беспокоиться о квалифицированных ссылках; Q.X может читать элемент X, если Q совместим с C.
Важным моментом являются вызовы, которые могут скрывать произвольные действия. Анализ, основанный только на таблицах синтаксического анализа и символов, может определить, что при наличии вызовов аргументы относятся только к константам или объектам, которые не принадлежат к классу, который A может представлять (возможно, унаследованным).
Если вы найдете аргумент с C-совместимым типом класса, теперь вы должны определить, может ли этот аргумент быть связан с this , что требует анализа и анализа потока данных:
method A( ) { Object q=this;
...
...q=that;...
...
foo(q);
}
foo может скрывать доступ к X. Таким образом, вам нужно две вещи: анализ потока, чтобы определить, может ли начальное присвоение q достигнуть вызова foo (это может быть нет; q = может доминировать во всех вызовах foo), и call анализ графа, чтобы определить, какие методы foo может фактически вызывать, так что вы можете проанализировать их для доступа к члену X.
Вы можете решить, как далеко вы хотите зайти, просто сделав консервативное предположение «А читает Х» в любое время, когда у вас недостаточно информации, чтобы доказать обратное. Это даст вам «безопасный» ответ (если не «правильный» или то, что я предпочел бы назвать «точным»).
Из фреймворков, которые могут быть полезны, вы можете рассмотреть Mono, который, несомненно, анализирует и создает таблицы символов. Я не знаю, какую поддержку он предоставляет для анализа потока или извлечения графа вызовов; Я не ожидал бы, что внешний интерфейсный компилятор Mono-IL сделает это, поскольку люди обычно скрывают этот механизм в JIT-части систем на основе JIT. Недостатком является то, что Mono может отставать от кривой современного C #; в прошлый раз я слышал, что он обрабатывает только C # 2.0, но моя информация может быть устаревшей.
Альтернативой является наш инструментарий реинжиниринга программного обеспечения DMS и его C # Front End .
(Не продукт с открытым исходным кодом).
DMS обеспечивает общий синтаксический анализ исходного кода, построение / проверку / анализ дерева, поддержку таблиц общих символов и встроенный механизм для реализации анализа потока управления, анализа потока данных, анализа точек на точку (необходим для «Что означает объект O точка» к? "), и вызвать построение графа. Все это оборудование было протестировано с использованием внешних интерфейсов Java и C в DMS, а поддержка таблиц символов использовалась для реализации полного разрешения имен и типов в C ++, поэтому оно довольно эффективно. (Вы не хотите недооценивать работу, необходимую для создания всего этого механизма; мы работаем над DMS с 1995 года).
Интерфейс C # обеспечивает полный синтаксический анализ C # 4.0 и полное построение дерева. В настоящее время он не создает таблицы символов для C # (мы работаем над этим), и это недостаток по сравнению с Mono. Однако с такой таблицей символов у вас будет доступ ко всему механизму анализа потоков (который был протестирован с интерфейсами DMS для Java и C), и это может быть большим шагом по сравнению с Mono, если он этого не обеспечивает.
Если вы хотите сделать это хорошо, перед вами значительный объем работы. Если вы хотите придерживаться «простого», вам придется просто разобрать дерево и быть в порядке с очень консервативным.
Вы не много говорили о том, что метод написал члену. Если вы собираетесь минимизировать трафик, как вы описываете, вы хотите различать случаи «чтения», «записи» и «обновления» и оптимизировать сообщения в обоих направлениях. Анализ, очевидно, очень похож для разных случаев.
Наконец, вы можете рассмотреть возможность обработки MSIL напрямую, чтобы получить необходимую информацию; у Вас все еще будут проблемы анализа потока и консервативного анализа. Вы можете найти следующую техническую статью интересной; она описывает полностью распределенную объектную систему Java, которая должна выполнять тот же базовый анализ, что и вы,
и делает это, IIRC, анализируя файлы классов и выполняя массовое переписывание байт-кода.
Java Orchestra System