Ищем ошибки в Mono. Develop / Блог компании PVS- Studio / Хабрахабр. В жизни анализатора PVS- Studio состоялось важное событие — в последней версии была добавлена возможность проверки кода, написанного на C#. Являясь одним из разработчиков данного анализатора, я просто не мог пройти мимо, не проверив какой- нибудь проект. Понятно, что мало кому будет интересно читать про проверку маленьких и неизвестных проектов, поэтому нужно было выбрать что- то известное, и выбор пал на Mono. Develop. Немного о проекте. Mono. Develop— свободная среда разработки, предназначенная для создания приложений C#, Java, Boo, Nemerle, Visual Basic . NET, Vala, CIL, Cи C++. Также планируется поддержка Oxygeneсо стороны Embarcadero Technologies. Изначально это был порт Sharp. Develop на Mono/GTK+, но с того времени проект далеко ушёл от своего начального состояния. Mono. Develop является частью проекта Mono. Встроен в дистрибутив Unity. D как средство написания скриптов, но устаревшей версии (4. Среди возможностей данной среды разработки выделяют подсветку синтаксиса, сворачивание кода, автодополнение кода, браузер классов, поддержку плагинов, встроенный отладчик, визуальный конструктор форм, модульное тестирование. Исходный код проекта доступен в соответствующем репозитории на Git. Hub, а инструкции по сборке описаны на официальном сайте проекта. Чем проверяли? Эта первый релиз C#- анализатора, и на данный момент в нём реализовано более 4. Понятно, что это версия ещё развита далеко не так сильно, как C++- анализатор, но используя данный инструмент уже можно найти достаточно интересные ошибки (некоторые из которых и будет приведены в этой статье). ![]() C#- анализатор не является отдельным продуктом, он входит в состав того же PVS- Studio, который теперь просто умеет анализировать код, написанный на ещё одном языке программирования. Скачать последнюю версию анализатора можно по этой ссылке. Несколько слов о результате анализа. В результате анализа было проверено 8. Анализатор выдал 1. Кто- то может сказать, что это не так уж и много для такого количества файлов. Но здесь стоит принять во внимание тот факт, что на данный момент реализовано меньшее количество диагностик, нежели в С++ анализаторе. Во- вторых, анализатор малоэффективен при разовых проверках. Хоть это неоднократно повторялось, но стоит упомянуть ещё раз — для получения полноценной пользы от использования инструментов статического анализа, они должны применяться регулярно, а не разово. Это сэкономит время на поиск и устранение ошибок, и как следствие — сделает разработку проекта дешевле и легче. Результаты анализа. В статье будут рассмотрены некоторые наиболее интересные из найденных ошибок, так как обзор всех найденных ошибок увеличил бы объём этой статьи до неприличных размеров. Статья разбита на подразделы, содержащие в себе описание тех или иных типов ошибок с примерами кода из проекта. Так что вы можете сразу перейти к просмотру наиболее интересных для вас ошибок. Generic-версии не работают с интерфейсами, а typeof работает. Определите константы для горячих клавиш отладки, и храните их в . Решено: Давно перестали работать горячие клавиши. Долго не обращал внимания, теперь решил разобраться, возможно ли, что я сам . Это обзор горячих клавиш Unity, установленных по умолчанию. Вы также можете скачать таблицу в формате PDF для Windows и MacOSX. Одинаковые выражения слева и справа от оператора. В данном подразделе приводятся описания ошибок вида 'A . Зачастую такие ошибки получаются в результате опечаток или неудачного 'copy- paste' и невнимательности программиста. Часто такие ошибки бывает сложно найти в больших объёмах кода, особенно если названия переменных достаточно длинные и различаются только одним символом. Как правило, подразумевается использование другой переменной, но порой подобные проверки являются просто избыточным кодом. Подробнее обо всём этом чуть ниже. Source. Code. Location. Get. Source. Code. Location (string fixture. Type. Namespace. string fixture. Type. Name. string method. Name). . Mono. Develop. NUnit NUnit. Project. Test. Suite. cs 8. Ошибку видно невооружённым глазом — в условии дважды проверяется одна и та же строковая переменная на равенство 'null' или на эквивалентность 'String. Empty'. Ниже по коду (здесь приведено не всё тело, чтобы не усложнять восприятие, так что поверьте на слово) схожая проверка осуществляется для переменной 'fixture. Type. Namespace', так что можно предположить, что вторая проверка данного условия в качестве аргумента метода должна была принимать переменную 'method. Name' или вовсе отсутствовать. Другой пример подобной ошибки: bool Try. Add. Document (string file. Name. out Open. Razor. Document current. Document). . Mono. Develop. Asp. Net Razor. CSharp. Parser. cs 1. Опять 2 одинаковые проверки в пределах одного выражения. Теоретически после приведения переменной 'sender' с использованием оператора 'as' в переменную 'doc' может быть записано значение 'null'. В результате, при выполнении проверки 'doc. Editor != null' будет сгенерировано исключение типа 'Null. Reference. Exception'. Исправленный вариант кода мог бы выглядеть так: if (doc != null & & doc. Editor != null). Ещё один фрагмент кода с ошибкой: static Member. Core Get. Later. Defined. Member (Member. Spec a, Member. Spec b). ? ICSharp. Code. NRefactory. CSharp membercache. Подобная ошибка может и не броситься в глаза, но анализатор — не человек, и такие вещи не пропускает. Из кода видно, что свойство 'File' объекта 'mc? Mono. Develop. Ide Gtk. Tree. Model. Result. Переменная 'result. Iter' имеет nullable- тип, следовательно, проверки вида 'result. Iter != null' и 'result. Iter. Has. Value' являются идентичными и можно было ограничиться одной из них. Точно такой же код встретился ещё 1 раз. Соответствующее предупреждение анализатора: V3. There are identical sub- expressions 'result. Iter != null' to the left and to the right of the '& & ' operator. Mono. Develop. Ide Gtk. Tree. Model. Result. Рассмотрим следующий фрагмент кода: Accessibility Declared. Accessibility . CSharp. Binding Abstract. Implement. Interface. Service. Code. Action. Очередная опечатка. Причём не одна, а сразу две. Опять между собой выполняется сравнение свойств одного и того же объекта ('member. Так как свойства примитивные и никакой дополнительной логики в них нет, то и смысл подобные проверки тоже теряют. Да и из кода видно, что должны были сравниваться свойства объектов 'member. Корректный вариант кода: if (member. Declared. Accessibility != member. Declared. Accessibility. Зачастую ошибочными являются ситуации, когда какому- то члену класса в методе необходимо присвоить значение одного из переданных аргументов, причём эти имена зачастую отличаются только регистром первого символа. При этом легко допустить ошибку. Встречаются и простые случаи присваивания переменной самой себе и если это — свойства, компилятор не будет выдавать никаких предупреждений. Такие действия понятны, если на геттер/сеттер свойства повешена сложная логика, но если её нет — присваивание выглядит как минимум странно. Но не будем голословны, лучше взглянем на примеры таких ошибок. Vi. Macro (char macro. Character) . Mono. Text. Editor Vi. Macro. О чём и говорилось выше — из- за того, что имена свойства и аргумента конструктора различаются только регистром первого символа, значение свойства записывается само в себя вместо того, чтобы в него записывалось значение, переданное в качестве аргумента. Посмотрев на определение свойства можно убедиться, что никакой дополнительной логики оно не содержит. Vi. Mark (char mark. Character) . Mono. Text. Editor Vi. Mark. Ошибка точь- в- точь аналогична предыдущей. Опять перепутан первый символ в названии переменный, из- за чего конструктор работает не так, как ожидалось. Whitespace. Node(string white. Space. Text. Text. Location start. Location). ICSharp. Code. NRefactory. CSharp Whitespace. Node. cs 6. 5Ошибка вновь аналогична предыдущим, но в этот раз код более интересен тем, что в одном из двух присваиваний программист не опечатался. В ходе быстрого набора текста подобную ошибку легко пропустить, тем более, если используются средства автоматической подстановки кода. Впрочем, этого можно было бы избежать, регулярно проверяя новый код с помощью статического анализатора. Например, в PVS- Studio имеется возможность автоматической проверки нового кода после компиляции (см. Mono. Develop. Hex. Editor Hex. Editor. Это второй тип ошибки, описанный мной в начале подраздела. Советы и рекомендации по работе с Unity. D / Хабрахабр. Я опубликовал первую статью «5. Unity» 4 года назад. Несмотря на то, что б. Например, теперь я могу доверять счётчику FPS. Возможность использования Property Drawers снизила необходимость написания пользовательских редакторов (Custom Editors). Способ работы с префабами стал меньше требовать заданных встроенных префабов (nested prefabs) и их альтернатив. Скриптуемые объекты стали более дружелюбными. Улучшилась интеграция с Visual Studio, отладка стала намного проще и уменьшилась потребность в «обезьяньем» дебаггинге. Стали лучше сторонние инструменты и библиотеки. В Asset Store появилось очень много ассетов, упрощающих такие аспекты, как визуальная отладка и логирование. Большая часть кода нашего собственного (бесплатного) плагина Extensions описана в моей первой статье (и многое из него описано здесь). Усовершенствован контроль версий. Например, теперь не нужно создавать множественные или резервные копии для префабов. Я стал более опытным. За последние 4 года я поработал над многими проектами в Unity, в том числе над кучей прототипов игр, завершёнными играми, такими как Father. IO, и над нашим основным ассетом Unity Grids. Эти советы подходят не ко всем проектам Unity: Они основаны на моём опыте работы над проектами в составе небольших команд (от 3 до 2. У структурированности, возможности повторного использования, ясности кода и других аспектов есть своя цена: от размера команды, объёма проекта и целей проекта зависит то, стоит ли платить эту цену. Например, для геймджема вы всё это использовать не будете. Использование многих советов — вопрос вкуса (возможно, есть отличающиеся, но всё равно хорошие техники для любого из перечисленных здесь советов). С самого начала определитесь с масштабом и создавайте всё одного масштаба. Если вы этого не сделаете, возможно, позже вам придётся переделывать ассеты (например, анимация не всегда правильно масштабируется). Для 3. D- игр наверно лучше всего принять 1 единицу Unity равной 1 метру. Для 2. D- игр, не использующих освещение и физику, обычно подходит 1 единица Unity, равная 1 пикселю (в «рабочем» разрешении). Для UI (и 2. D- игр) выберите рабочее разрешение (мы используем HD или 2x. HD) и создавайте все ассеты под масштаб в этом разрешении. Сделайте каждую сцену запускаемой. Это позволит вам не переключаться между сценами для запуска игры и ускорит таким образом процесс тестирования. Это может быть сложным, если вы используете передаваемые между загрузками сцен (persistent) объекты, которые требуются во всех сценах. Один из способов добиться этого — сделать передаваемые объекты синглтонами, которые будут загружать себя сами, если они отсутствуют в сцене. Синглтоны подробнее рассматриваются в другом совете. Применяйте контроль исходного кода и научитесь использовать его эффективно. Сериализируйте ассеты как текст. На самом деле это не сделает сцены и префабы более совместимыми, но при этом будет проще отслеживать изменения. Освойте стратегию обмена сценами и префабами. Обычно над сценой или префабом не должны работать несколько человек. В маленькой команде перед началом работы над сценой или префабом может быть достаточно попросить всех не работать над ними. Может быть полезным использование физических токенов, обозначающих того, кто в текущий момент работает над сценой (вы можете работать над сценой, только если у вас на столе лежит соответствующий токен). Используйте теги в качестве закладок. Выберите стратегию ветвления и придерживайтесь её. Поскольку соединение сцен и префабов невозможно сделать плавным, организация ветвления может стать довольно сложной. Какой бы способ ветвления вы ни выбрали, он должен работать с вашей стратегией обмена сценами и префабами. Используйте подмодули с осторожностью. Подмодули могут стать отличным способом поддержки повторно используемого кода, однако существует несколько опасностей: Метафайлы для разных проектов в общем случае неодинаковы. Обычно это не является проблемой для кода, не использующего Mono. Behaviour или скриптуемые объекты, однако для Mono. Behaviour и скриптуемых объектов использование подмодулей может привести к утере кода. Если вы работаете над несколькими проектами (один или несколько из которых используют подмодули), то иногда вы можете столкнуться с «лавиной обновлений», когда необходимо выполнить несколько итераций pull- merge- commit- push для разных проектов, чтобы стабилизировать код во всех проектах (а если во время этого процесса кто- то ещё вносит изменения, лавина может стать непрерывной). Одним из способов минимизации этого эффекта является внесение изменений в подмодули из проектов, которые к ним относятся. При этом проекты, использующие подмодули, должны будут всегда выполнять pull, и им никогда не придётся делать push. Всегда отделяйте тестовые сцены от кода. Выполняйте коммиты временных ассетов и скриптов в репозиторий и удаляйте их из проекта, когда закончите работу с ними. Выполняйте обновление инструментов (в особенности Unity) одновременно. Unity уже гораздо лучше сохраняет связи при открытии проекта из отличных от текущей версий, однако связи всё равно иногда теряются, если члены команды работают в разных версиях. Импортируйте ассеты сторонних разработчиков в чистый проект и импортируйте новый пакет для своего использования уже оттуда. При непосредственном импорте в проект ассеты иногда могут приводить к проблемам: Возможно возникновение коллизий (файлов или имён), особенно для ассетов, содержащих файлы в корне папки Plugins, или для тех, которые используют в своих примерах ассеты из Standard Assets. Они могут быть неупорядоченными и раскидать свои файлы по всему вашему проекту. Это становится особенной проблемой, если вы решаете не использовать его и хотите удалить его. Создайте новый проект и импортируйте ассет. Запустите примеры и убедитесь, что они работают. Упорядочьте ассет в более подходящую структуру папок. Но я проверяю, что все файлы находятся в одной папке и что в важных местах нет файлов, которые могут перезаписать уже имеющиеся файлы моего проекта.)4. Запустите примеры и убедитесь, что они всё ещё работают. Теперь удалите составляющие, которые вам не нужны (такие как примеры). Убедитесь, что ассет по- прежнему компилируется и префабы всё ещё имеют все свои связи. Если осталось ещё что- то незапущенное, протестируйте его. Теперь выберите все ассеты и экспортируйте пакет. Импортируйте его в свой проект. Автоматизируйте процесс сборки. Это полезно даже в небольших проектах, но в особенности это полезно, когда: необходимо выполнить сборку множества различных версий игры,нужно делать сборки другим членам команды с различным уровнем технического опыта иливам нужно внести небольшие изменения в проект, прежде чем можно будет выполнять его сборку. Документируйте свои настройки. Заставлять разработчиков рыться в коде в поисках настроек значит тратить их время. Документированные настройки повышают эффективность (если поддерживается актуальность документов). Документируйте следующее: Использование тегов. Использование слоёв (для коллизий, culling и raycasting — указывайте, что в каком слое должно быть). Глубина GUI для слоёв (что над чем должно располагаться). Настройки сцены. Структура сложных префабов. Выбранные идиомы. Настройка сборки. Общие советы по коду. Размещайте весь свой код в пространстве имён. Это позволяет избежать конфликта кода ваших собственных библиотек и стороннего кода. Но не полагайтесь на пространства имён, когда стремитесь избежать конфликтов кода с важными классами. Даже если вы используете другие пространства имён, не берите в качестве имён классов «Object», «Action» или «Event». Используйте утверждения (assertions). Утверждения полезны для тестирования инвариантов в коде и помогают избавиться от логических багов. Утверждения доступны через класс Unity. Assertions. Assert. Они проверяют условие и записывают в консоль сообщение, если оно неверно. Если вы не знаете, для чего могут быть полезны утверждения см. Не используйте строки ни для чего, кроме отображения текста. В частности, не используйте строки для идентификации объектов или префабов.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
November 2017
Categories |