статический анализ — удаление ненужных строк из файла c ++

Много раз, когда я отлаживаю или повторно использую некоторый код, файл начинает получать строки, которые ничего не делают, хотя они могли что-то сделать в какой-то момент.

Такие вещи, как векторы и заполнение, а затем остаются неиспользованными, классы / структуры, которые определены, но никогда не используются, и функции, которые объявлены, но никогда не используются.

Я понимаю, что во многих случаях некоторые из этих вещей не являются лишними, так как они могут быть видны из других файлов, но в моем случае других файлов нет, просто посторонний код в моем файле.

Пока я понимаю, что с технической точки зрения, ссылаясь push_back что-то делает, и, следовательно, вектор сам по себе не используется, в моем случае его результат не используется.

Итак: есть ли способ сделать это, используя компилятор (clang, gcc, VS и т. Д.) Или внешний инструмент?

Пример:

#include<vector>
using namespace std;
void test() {
vector<int> a;
a.push_back(1);
}
int main() {
test();
return 0;
}

Должно стать: int main(){return 0};

7

Решение

Для этого можно использовать наш инструментарий реинжиниринга программного обеспечения DMS с интерфейсом C ++ 11; это в настоящее время не делает это с полки. DMS предназначен для обеспечения пользовательского конструирования инструмента для произвольных исходных языков и содержит полные анализаторы, средства разрешения имен и различные анализаторы потоков для поддержки анализа, а также возможность применять преобразования кода в исходный код на основе результатов анализа.

В общем, вам нужен статический анализ, который определяет, используются ли каждое вычисление (результат, их может быть несколько, учитывая только «x ++») или нет. По сути, для каждого неиспользуемого вычисления вы хотите удалить неиспользуемые вычисления и повторить анализ. Из соображений эффективности вы хотите провести анализ, который определяет все (точки) использования результатов только один раз; по сути, это анализ потока данных. Когда набор использования результата вычисления становится пустым, этот результат вычисления может быть удален (обратите внимание, что удаление результата значения «x ++» может оставить после «x ++», потому что приращение все еще необходимо!) И наборы использования вычислений, от которых он зависит Можно настроить удаление ссылок из удаленного, что может привести к большему удалению.

Чтобы выполнить этот анализ для любого языка, вы должны иметь возможность отслеживать результаты. Для C (и C ++) это может быть довольно уродливо; существуют «очевидные» варианты использования, где результат вычисления используется в выражении, и где он присваивается локальной / глобальной переменной (которая используется где-то еще), и существуют косвенные присваивания через указатели, обновления поля объекта, через произвольное приведение и т. д. Чтобы узнать эти эффекты, ваш инструмент анализа мертвого кода должен уметь читать все программная система, и вычислять потоки данных через нее.

Чтобы быть в безопасности, вы хотите, чтобы этот анализ был консервативным, например, если инструмент не имеет доказательств того, что результат не используется, то он должен предполагать, что результат используется; вам часто приходится делать это с помощью указателей (или индексов массивов, которые являются просто замаскированными указателями), потому что в общем случае вы не можете точно определить, где указатель «указывает». Очевидно, можно создать «безопасный» инструмент, предполагая, что используются все результаты: -} Вы также получите иногда очень консервативные, но необходимые предположения для библиотечных процедур, для которых у вас нет источника. В этом случае полезно иметь набор предварительно вычисленных сводок побочных эффектов библиотеки (например, у «strcmp» нет ни одного, «sprintf» перезаписывает определенный операнд, «push_back» изменяет его объект …). Поскольку библиотеки могут быть довольно большими, этот список может быть довольно большим.

DMS в целом может анализировать и всю базу исходного кода, создавать таблицы символов (чтобы знать, какие идентификаторы являются локальными / глобальными и их точный тип), выполнять контроль и анализ локальных потоков данных, создавать локальную сводку «побочных эффектов» для каждой функции, создавать вызов График и глобальные побочные эффекты, а также сделать глобальный точечный анализ, предоставляя эту информацию «вычисление используется» с соответствующим консерватизмом.

DMS использовался для выполнения этих вычислений в системах с кодом на C, состоящих из 26 миллионов строк кода (и да, это действительно большие вычисления; для запуска требуется виртуальная машина объемом 100 ГБ). Мы не реализовали часть устранения мертвого кода (у проекта была другая цель), но это просто, если у вас есть эти данные. DMS выполнил устранение мертвого кода в больших кодах Java с помощью более консервативного анализа (например, «упоминания об использовании без использования идентификатора», что означает, что назначения идентификатора являются мертвыми), что вызывает удивительное количество удаления кода во многих реальных кодах.

В настоящее время синтаксический анализатор DMS C ++ создает таблицы символов и может выполнять анализ потока управления для C ++ 98 с C ++ 11 под рукой. Нам все еще нужен локальный анализ потока данных, что требует определенных усилий, но глобальный анализ уже существует в DMS и доступен для использования для этого эффекта. («Нет использования идентификатора» легко получить из данных таблицы символов, если вы не возражаете против более консервативного анализа).

На практике вы не хотите, чтобы инструмент просто молча вырывал вещи; некоторые могут быть вычислениями, которые вы хотите сохранить в любом случае. Инструмент Java дает два результата: список неработающих вычислений, которые вы можете проверить, чтобы решить, верите ли вы в это, и версию исходного кода с удаленным мертвым кодом. Если вы верите в отчет об мертвом коде, вы сохраняете версию с удаленным кодом; если вы видите «мертвые» вычисления, которые, по вашему мнению, не должны быть мертвыми, вы модифицируете код, чтобы сделать его не мертвым, и снова запускаете инструмент. С большой базой кода, проверка самого отчета о мертвом коде может быть попыткой; как «вы» знаете, если какой-то явно мертвый код не оценен «кем-то еще» в вашей команде? (Контроль версий может быть использован для восстановления, если вы дурак!)

Действительно сложная проблема, которую мы не решаем (и не знаю какого-либо инструмента), это «мертвый код» при наличии условной компиляции. (У Java нет этой проблемы; у C она есть в пиках, в системах C ++ гораздо меньше). Это может быть действительно противно. Представьте себе условие, в котором рука имеет определенные побочные эффекты, а другая рука имеет различные побочные эффекты, или другой случай, когда один интерпретируется компилятором G ++ CCC, а другой — MS, и компиляторы расходятся во мнениях относительно того, что делают конструкции. (да, компиляторы C ++ не соглашаются в темных углах). В лучшем случае мы можем быть очень консервативными здесь.

CLANG обладает некоторой способностью выполнять анализ потока; и некоторая способность делать исходные преобразования, так что это может быть вынуждено сделать это. Я не знаю, может ли это сделать какой-либо глобальный анализ потока / точек. Кажется, что он имеет тенденцию к одиночным модулям компиляции, поскольку его основное использование — это компиляция одного модуля компиляции.

3

Другие решения

Чтобы перехватить неиспользуемые переменные, вы можете включить флаг -Wunused на компиляторе gcc. Это предупредит вас о неиспользуемых параметрах, переменных и вычисленных значениях во время компиляции. Я обнаружил, что использование флагов -Wall -Wextra и -Werror гарантирует, что компилятор улавливает некоторые проблемы, описанные вами.
Более подробную информацию можно найти здесь: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Что касается поиска неиспользуемых классов, одним из вариантов является использование IDE, скажем, как Eclipse, и использование функции «Найти ссылки» для поиска мест, где этот класс / объект может быть использован.

1

Краткий ответ «нет». Статическим анализом клиентского кода невозможно определить, что вектор push_back Метод не имеет каких-либо важных побочных эффектов. Инструмент анализа знает все, что он записывает в базу данных где-то и ведет торговлю акциями.

1

Я бы рекомендовал использовать программное обеспечение для управления версиями — SVN, Git, Mercurial, Perforce, … — чтобы после отладки вы могли использовать указанный инструмент управления версиями для поиска и удаления остатков отладки. Это делает ваш код более простым.

Кроме того, этот вид тестового кода обычно имеет небольшое тестовое покрытие, поэтому, если у вас есть модульное тестирование, они должны отображаться как не покрытый код.

Тогда есть инструменты, которые явно ищут такие вещи — Lint, Coverity и так далее. Большинство из них являются коммерческими. Также попробуйте использовать -O3 в GCC, компилятор может распознавать больше фактически неиспользуемых переменных таким образом, так как он будет более агрессивно встроен и исключит код.

0
По вопросам рекламы [email protected]