0. Форматирование
ЗОЛОТОЕ ПРАВИЛО: Следуйте стилю существующего кода при внесении изменений.
- Используйте табуляцию для отступа:
- позиции табуляции каждые 4 символа (актуально только для длины строки).
- один уровень отступа -> ровно один байт (то есть символ табуляции) в исходном файле.
- Ширина строк:
- строки должны быть не более 99 символов в ширину, чтобы сделать представления diff читаемыми и уменьшить конфликты слияния.
- строки комментариев должны быть отформатированы в соответствии с удобством просмотра, но простота предпочтительнее красоты.
- Блоки с одним оператором не должны иметь фигурных скобок, если это не требуется для ясности.
- Никогда не размещайте тела условий на одной строке с условием.
- Пробел между ключевым словом и открывающей скобкой, но не после открывающей скобки или перед конечной скобкой.
- Нет пробелов для унарных операторов,
->
или .
.
- Нет пробела перед
:
но один после него, за исключением тернарного оператора: по одному с обеих сторон.
- Добавьте пробелы вокруг всех других операторов.
- Фигурные скобки, когда они используются, всегда имеют свои собственные строки и находятся на том же уровне отступа, что и «родительская» область.
- Если строки разбиты, список элементов, заключённых в круглые скобки (любого вида) и разделённых разделителем (любого вида), форматируется таким образом, чтобы на каждой строке был ровно один элемент, за которым следовал разделитель, открывающая скобка находилась на первой строке, затем следовала строка разрыва, а закрывающая скобка была на отдельной строке без отступа). См. пример ниже.
Да:
if (a == b[i])
printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'.
foo->bar(
someLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName
);
cout <<
"some very long string that contains completely irrelevant " <<
"text that talks about this and that and contains the words " <<
"\"lorem\" and \"ipsum\"" <<
endl;
Нет:
if( a==b[ i ] ) { printf ("Hello\n"); }
foo->bar(someLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName,
anotherLongVariableName);
cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl;
Чтобы установить настройки отступов и ширины табуляции единообразно, репозиторий содержит файл EditorConfig .editorconfig
, который описывает некоторые используемые стили и распознаётся многими IDE и редакторами.
1. Пространства имён
- В заголовочных файлах нет объявлений
using namespace
.
-
using namespace solidity;
и другие пространства имён проекта допустимы в файлах cpp и обычно поощряются.
- Избегайте использования
using namespace
на уровне файла для сторонних библиотек, таких как boost, ranges и т. д.
- Все символы должны быть объявлены в пространстве имён, кроме конечных приложений.
- Для помощников, область действия которых ограничена файлом cpp, используйте анонимные пространства имён.
- Символы препроцессора должны начинаться с имени пространства имён заглавными буквами и подчёркиванием.
Только в заголовке:
#include <cassert>
namespace myNamespace
{
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
}
2. Препроцессор
- Файл комментария всегда находится вверху и включает:
- Авторские права
- Лицензию (например, см. COPYING)
- Никогда не используйте
#ifdef
/#define
/#endif
для защиты файлов. Предпочитайте #pragma
once в качестве первой строки под комментарием файла.
- Предпочитайте статические переменные constexpr макросам значений.
- Предпочитайте встроенные функции constexpr функциям-макросам.
- Разделите сложный макрос на несколько строк с помощью
\
.
3. Использование заглавных букв
ЗОЛОТОЕ ПРАВИЛО: Препроцессор: ALL_CAPS
; C++: camelCase
.
- Используйте camelCase для разделения слов в именах, за исключением случаев, когда очевидно расширение функциональности STL/boost, в этом случае следуйте этим соглашениям об именах.
- Первая буква следующих сущностей — заглавная:
- Имена типов
- Параметры шаблона
- Члены перечисления
- статические константные переменные, которые формируют внешний API.
- Всё остальное. Символы препроцессора (макросы, аргументы макросов) в полном регистре с разделением слов подчёркиванием.
Все остальные сущности начинаются со строчной буквы.
4. Префиксы переменных
- Ведущий знак подчёркивания «_» для параметров функций:
- Исключение: «o_parameterName», когда он используется исключительно для вывода. См. 6(f).
- Исключение: «io_parameterName», когда он используется как для ввода, так и для вывода. См. 6(f).
- Ведущий «g_» для глобальных (неконстантных) переменных.
- Ведущий «s_» для статических (неконстантных, неглобальных) переменных.
5. Утверждения
Используйте solAssert
и solUnimplementedAssert
, чтобы проверять предположения, которые охватывают разные части кодовой базы, например, перед разыменованием указателя.
6. Объявления
- {Тип} + {квалификаторы} + {имя}.
- Только по одному на строку.
- Связывайте */& с типом, а не с переменной (на концах с парсером, но более читаемо и безопасно, если в сочетании с (b)).
- Предпочитайте объявления рядом с использованием; не объявляйте обычно в начале области видимости, как в C.
- Передавайте нетривиальные параметры как константные ссылки, если только данные не должны быть скопированы в функцию, тогда либо передавайте по константной ссылке, либо по значению и используйте std::move.
- Если функция возвращает несколько значений, используйте std::tuple (std::pair приемлемо) или лучше введите тип структуры. Не используйте */& аргументы.
- Используйте параметры типа указателя, только если nullptr является допустимым аргументом, в противном случае используйте ссылки. Часто std::optional подходит больше, чем необработанный указатель.
- Никогда не используйте макрос, где можно написать адекватный код на C++.
- Используйте auto только в том случае, если тип очень длинный и не имеет значения.
- Не передавайте bool: вместо этого предпочитайте перечисления.
- Предпочитайте enum class прямому перечислению.
- Всегда инициализируйте POD-переменные, даже если их значение будет перезаписано позже.
Да:
enum class Accuracy
{
Approximate,
Exact
};
struct MeanSigma
{
float mean = 0.0f;
float standardDeviation = 1.0f;
};
double const d = 0;
int i = 0;
int j = 0;
char* s = nullptr;
MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a);
Derived* x = dynamic_cast<Derived*>(base);
for (auto i = x->begin(); i != x->end(); ++i) {}
Нет:
const double d = 0;
int i, j;
char *s;
float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate);
Derived* x(dynamic_cast<Derived*>(base));
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
7. Структуры и классы
- Структуры следует использовать, когда все члены являются публичными и нет виртуальных функций:
- В этом случае члены должны называться естественно и не начинаться с m_.
- Классы следует использовать во всех остальных случаях.
8. Члены
- По одному члену на строку.
- Частные, нестатические, неконстантные поля начинаются с m_.
- Избегайте публичных полей, за исключением структур.
- Как можно чаще используйте override, final и const.
- Нет реализаций с объявлением класса, кроме:
- шаблонного или принудительно встроенного метода (хотя предпочтительнее реализация в нижней части файла заголовка).
- однострочной реализации (в этом случае включите её в ту же строку, что и объявление).
- Для свойства foo:
- Член: m_foo
- Получатель: foo() [также: для логических значений isFoo()]
- Установщик: setFoo()
9. Именование
- Избегайте труднопроизносимых имён.
- Имена следует сокращать только в случае крайней распространённости, но в целом следует избегать сокращения.
- Избегайте префиксов инициалов (например, не используйте IMyInterface, CMyImplementation).
- Найдите короткие, запоминающиеся и (по крайней мере полу-) описательные имена для часто используемых классов или фрагментов имён:
- Словарь и тезаурус — ваши друзья;
- Пишите правильно;
- Тщательно продумайте цель класса;
- Представьте его как изолированный компонент, чтобы попытаться деконтекстуализировать его при рассмотрении его имени;
- Не ограничивайтесь именованием его (исключительно) с точки зрения его реализации.
10. Определения типов
-
Предпочитайте using вместо typedef. Например, using ints = std::vector; вместо typedef std::vector ints; Использование shared_ptr вместо сокращения до ptr
-
В случае исключений из этого правила (из-за чрезмерного использования и ясного смысла), отметьте изменение заметно и используйте его последовательно:
- например,
using Guard = std::lock_guard<std::mutex>;
///< Guard используется во всей кодовой базе, так как он ясен по смыслу и широко используется.
-
Как правило, выражения должны быть примерно такими же важными/семантически значимыми, как пространство, которое они занимают.
-
Избегайте введения псевдонимов для типов, если только они не являются очень сложными. Учитывайте количество элементов, которые мозг может отслеживать одновременно.
11. Комментирование
- Комментарии должны быть совместимы с doxygen, используя @нотацию вместо \нотации.
- Документируйте интерфейс, а не реализацию:
- документация должна быть в состоянии остаться полностью неизменной, даже если метод будет перереализован;
- комментируйте с точки зрения свойств метода и предполагаемого изменения состояния класса (или того, какие аспекты состояния он сообщает);
- будьте осторожны при анализе документации, которая распространяется только на предполагаемое назначение и использование;
- отклоняйте документацию, которая является просто переводом реализации на английский язык.
- Избегайте комментариев в коде. Вместо этого попробуйте выделить блоки функциональности в функции. Это часто уже устраняет необходимость в комментарии в коде.
12. Включить заголовки
- Включаемые файлы должны идти в порядке увеличения общности (
libsolidity
-> libevmasm
-> libsolutil
-> boost
-> STL
).
- Соответствующий файл
.h
должен быть первым включением в соответствующий файл .cpp
.
- Между блоками включаемых файлов следует вставлять пустые строки.
Пример:
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/LValue.h>
#include <libevmasm/GasMeter.h>
#include <libsolutil/Common.h>
#include <libsolutil/SHA3.h>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <utility>
#include <numeric>
См. эту проблему для объяснения: это облегчает поиск отсутствующих включений в заголовочных файлах.
13. Рекомендуемая литература
Опубликовать ( 0 )