diff --git a/.agents/instructions/style/cpp.md b/.agents/instructions/style/cpp.md index 0dff4c7..3f1620e 100644 --- a/.agents/instructions/style/cpp.md +++ b/.agents/instructions/style/cpp.md @@ -10,7 +10,8 @@ truth: never edit them to make code pass. `else` on its own line. Never a one-line `if`, loop, block or function. - Pointer and reference sign bind to the name: `const char *name`. - Namespaces `aether::`, closed with `} // namespace aether::`. -- Functions and methods are `camelCase`; constants are `kPascalCase`. +- Names follow `docs/naming.md` (kind and scope prefixes), checked by + clang-tidy; the boolean `b` prefix is checked in review. - Public headers live under `include/aether//` and are included with angle brackets: `#include `. The module's own header comes first, then the others, sorted by clang-format. diff --git a/.clang-tidy b/.clang-tidy index bf51472..3a0a857 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -8,7 +8,46 @@ Checks: > cppcoreguidelines-*, bugprone-*, clang-analyzer-*, + readability-identifier-naming, -modernize-use-trailing-return-type WarningsAsErrors: false HeaderFilterRegex: "(^|/)sources/.+\\.hpp$" FormatStyle: Google +CheckOptions: + readability-identifier-naming.NamespaceCase: lower_case + readability-identifier-naming.ClassCase: CamelCase + readability-identifier-naming.StructCase: CamelCase + readability-identifier-naming.AbstractClassCase: CamelCase + readability-identifier-naming.AbstractClassPrefix: I + readability-identifier-naming.EnumCase: CamelCase + readability-identifier-naming.EnumPrefix: E + readability-identifier-naming.EnumConstantCase: CamelCase + readability-identifier-naming.TypeAliasCase: CamelCase + readability-identifier-naming.TypeAliasIgnoredRegexp: "^([iuf][0-9]+|usize)$" + readability-identifier-naming.TypedefCase: CamelCase + readability-identifier-naming.TypeTemplateParameterCase: CamelCase + readability-identifier-naming.TypeTemplateParameterPrefix: T + readability-identifier-naming.TypeTemplateParameterIgnoredRegexp: "^T$" + readability-identifier-naming.ValueTemplateParameterCase: CamelCase + readability-identifier-naming.FunctionCase: camelBack + readability-identifier-naming.MethodCase: camelBack + readability-identifier-naming.ParameterCase: camelBack + readability-identifier-naming.VariableCase: camelBack + readability-identifier-naming.LocalVariableCase: camelBack + readability-identifier-naming.PublicMemberCase: camelBack + readability-identifier-naming.PrivateMemberCase: camelBack + readability-identifier-naming.PrivateMemberPrefix: m_ + readability-identifier-naming.ProtectedMemberCase: camelBack + readability-identifier-naming.ProtectedMemberPrefix: m_ + readability-identifier-naming.ClassMemberCase: camelBack + readability-identifier-naming.ClassMemberPrefix: s_ + readability-identifier-naming.GlobalVariableCase: camelBack + readability-identifier-naming.GlobalVariablePrefix: g_ + readability-identifier-naming.ConstexprVariableCase: CamelCase + readability-identifier-naming.ConstexprVariablePrefix: k + readability-identifier-naming.GlobalConstantCase: CamelCase + readability-identifier-naming.GlobalConstantPrefix: k + readability-identifier-naming.StaticConstantCase: CamelCase + readability-identifier-naming.StaticConstantPrefix: k + readability-identifier-naming.MacroDefinitionCase: UPPER_CASE + readability-identifier-naming.MacroDefinitionPrefix: AETHER_ diff --git a/docs/naming.md b/docs/naming.md new file mode 100644 index 0000000..dac511e --- /dev/null +++ b/docs/naming.md @@ -0,0 +1,37 @@ +# Naming + +How names are written in the engine. Read it to recognise what a name is in +the API, or before writing engine code. A name tells its kind and its scope, +so a diff reads right even without an IDE (a review on GitHub, on a phone). + +| Element | Convention | Example | +| --- | --- | --- | +| Class, struct, type alias | `PascalCase` | `Texture`, `LogRecord` | +| Interface (abstract class) | `I` + `PascalCase` | `ISink` | +| Enum | `E` + `PascalCase` | `ESeverity` | +| Enum value | `PascalCase` | `ESeverity::Warning` | +| Type template parameter | `T` + `PascalCase` | `TValue`, `TArgs` | +| Function, method | `camelCase` | `loadTexture` | +| Local variable, parameter | `camelCase` | `frameCount` | +| Public member of a struct | `camelCase` | `record.message` | +| Private or protected member | `m_` + `camelCase` | `m_file` | +| Static member | `s_` + `camelCase` | `s_instance` | +| Global variable | `g_` + `camelCase` | `g_dispatcher` | +| Constant, `constexpr` | `k` + `PascalCase` | `kMaxLights` | +| Boolean | `b` + `PascalCase` | `bVisible`, `m_bDirty` | +| Macro | `AETHER_` + `UPPER_CASE` | `AETHER_ASSERT` | +| Namespace | `lower_case` | `aether::core` | + +How to read it: + +- An uppercase prefix marks a type (`E`, `I`, `T`), a lowercase one a value + (`m`, `s`, `g`, `k`, `b`). +- A scope prefix (`m` member, `s` static, `g` global) is followed by `_`, + because the name after it starts in lowercase. A type or kind prefix is + glued to a capital letter: `ESeverity`, `kMaxLights`, `bVisible`. +- Prefixes combine, scope first: `m_bDirty`. +- The fixed-size aliases of `` (`i32`, `u8`, `f32`, + `usize`) are lowercase on purpose, like built-in types. + +clang-tidy (`readability-identifier-naming` in `.clang-tidy`) checks every +rule except the boolean one, which is left to review.