Comments 12
При глубине анализа в единицу это даже сработает. Но мы потеряем ошибки в других файлах, которые могли быть вызваны новыми изменениями.
И снова граф вызовов помог бы :)
Префиксное дерево
Ну или схалявить и воспользоваться тем, что память дешевая и процессоры мощные -- данные писать пропуская через xz/gz/lz/хз :)
Да, действительно. Но, не факт, что такой подход будет быстрым с учётом того, чего ждут от инкрементального анализа. Тут мы сталкиваемся с той же задачей, что и при глубоком анализе. Чтобы передать информацию об эффектах, которые передаются через несколько вызовов функций необходимо несколько раз выполнить проверку файлов с исходным кодом. Подробнее об этой проблеме описано в разделе глубокого анализа.
Не обязательно же. Можно построить граф зависимостей, провести топологическую сортировку и пройти по функциям (не файлам!) в этом порядке.
Граф вызовов и проход по ф-ям так же позволит моментальный проход на изменения. Это же как формулы в экселе!
После того, как анализатор собрал всю информацию из единицы трансляции вся память сбрасывается. Так сделано потому что внутреннее представление анализатора для всех модулей программы просто не влезет в адекватные объемы. Из-за этого, чтобы снова разобрать функцию, нужно полностью транслировать файл. При чем не получится читать только тело функции, так как в ней могут быть различные сайд эффекты и типы данных. Например, глобальные переменные, или вызов других функций. Всю эту информацию придется собирать заново. Если функция вызывает другую функцию, определение которой находится в другой единице трансляции, то и эту единицу трансляции тоже придется анализировать целиком. И так по цепочке. Все это усугубляется возможными циклическими вызовами.
Идея конечно неплохая. Но, для реализации необходимо промежуточное представление, при чем связываемое с исходным кодом. Такое, чтобы его трансляция была быстрой и давала всю необходимую информацию. Сделать такое уже по сути сравнимо с написанием полноценного компилятора. Да и будет ли это достаточно эффективно - открытый вопрос.
Да, держать в памяти всё из всех единиц трансляции -- не пыщ пыщ, по любому. Но из статьи я не понял почему нельзя генерить объектники с полным результатом анализа, в который и заглядывать если файл не поменялся -- перечитать, если поменялся.
Да, инкрементальные обновления этого представления во время редактирования это дорого и сложно, нужна совершенно другая архитектура и представление, которое позволяет "наслаивать" изменения для хотя бы простых отмен; возможна ли структура которая позволит инкрементально менять дерево в обе стороны (дописали букву a после int lo => определение lo убрали, определение loa добавили, если где-то есть доступы к lo пометили как проблемные и пр)... Ну точнее возможна-то возможна, а вот возможна ли эффективно и в разумные затраты человекочасов?
Приведу текст из статьи как раз про эту проблему
Первый вариант решить эту проблему – сохранить промежуточные результаты разбора кода в файлы, чтобы потом можно было их использовать повторно. При таком подходе нам не придётся множество раз транслировать один и тот же код, что намного быстрее и удобнее. Но тут есть одна проблема. Внутреннее представление кода программы в памяти анализатора может отличаться от исходника. Некоторые незначительные для анализа фрагменты могут удаляться или модифицироваться. Поэтому не представляется возможным связать представление с исходным файлом. Кроме того, есть сложности с сохранением данных семантического анализа (data flow, символьные вычисления и т. д.), которые хранятся только в контексте блока, где они собраны.
Мы не можем сохранить объектники с полным результатом анализа. Только результат семантического анализа. В таких семантических модулях нет контекста использования символов. По этому изменившийся файл нужно транслировать заново. А так как эти изменения могут повлиять на результат анализа и в других единицах трансляции (которые сами по себе не изменились), то и их нужно перетранслировать.
Я по прежнему не понимаю "почему" :) Я понимаю "почему сейчас в лоб" это не сделать.
Но я не понимаю почему нельзя расширить объекты прямыми ссылками на исходные точки (возможно, множественные). Это довольно дешевое изменение.
А вот data flow, symbol computation и прочее как раз нормально не сохранять ибо они локальны. Впрочем, связанные с глобальными переменными контекст нужен весь...
В общем, я так понимаю, это всё из категории "это дорого и сложно, нужна совершенно другая архитектура и представление".
Программист, как известно, это существо, которое способно доказать что что-то невозможно когда ему просто лень. А менеджер -- когда не хватает бюджета.
Внутренее представление (в виде синтаксического дерева, системы типов, аннотаций межпроцедурного анализа, и промежуточной информацией, собранной диагностическими алгоритмами) плохо подходит для сереализации. Есть несколько причин.
Первая - оно достаточно объемное для того, чтобы нельзя было сохранять его как есть (2-5 гб в среднем на каждый файд, в зависимости от исходника). Мало того, что если в проекте файлов 500 представление не поместится на диск, так и читать его в общую память будет проблематично.
Вторая - как я уже писал, такое представление может частично отличаться от исходного кода, так как в процессе анализа может перестраваться.
Дело в том, что внутреннее представление не предназначалось для таких целей.
Пожалуй, соглашусь, что можно поменять архитекруту и сделать красиво. Вот только это занимает много времени (дело не в лени). К тому же архитектура постепенно переписывается. Но, прежде чем это сделано, нужно было решение ещё вчера). Благо, оно работает, хоть и с некоторыми ограничениями.
Межмодульный анализ C и C++ проектов в деталях. Часть 2