--- description: Refactoriza una clase C++ aplicando buenas prácticas de estilo --- # Refactor Class Command Refactoriza una clase C++ siguiendo estas reglas de estilo y buenas prácticas: ## Reglas de Refactorización ### 1. Inicialización de Variables Miembro - **Inicializar en la declaración** todas las variables "simples" que no tengan dependencias complejas: - Tipos primitivos: `int`, `float`, `bool`, etc. - Enumeraciones: valores de enum class - Valores por defecto conocidos: `0`, `0.0F`, `false`, `nullptr`, etc. - **NO inicializar en declaración** si: - Dependen de otros miembros - Requieren llamadas a funciones complejas - Son punteros a recursos que necesitan construcción específica ### 2. Structs con Valores por Defecto - **Todos los miembros de structs** deben tener valores por defecto: - Tipos primitivos: `int x{0}`, `float y{0.0F}`, `bool flag{false}` - Strings: `std::string name{}` - Punteros: `Type* ptr{nullptr}` - **Ventajas**: Inicialización segura, evita valores indefinidos ### 3. Arrays C-style → std::array - Convertir **todos** los arrays C-style a `std::array`: - `Type array[N]` → `std::array array{}` - Inicializar con `{}` para zero-initialization - Agregar `#include ` si no existe - **Ventajas**: type-safety, size(), métodos STL, sin decay a pointer ### 3. Reorganización de la Clase #### Orden de Secciones 1. **public** (primero) 2. **private** (después) #### Dentro de cada sección (private principalmente) 1. **Estructuras y enumeraciones** (tipos anidados) 2. **Constantes** (static constexpr) 3. **Métodos** (funciones miembro) 4. **Variables miembro** (al final) ### 4. Agrupación y Comentarios de Métodos - **En sección public**: Agrupar métodos relacionados funcionalmente - **Comentarios en línea** (a la derecha) para describir cada método/grupo - **Formato**: `void method(); // Descripción concisa` - **Espaciado**: Línea en blanco entre grupos funcionales **Ejemplo:** ```cpp public: static void init(...); // Inicialización singleton static void destroy(); // Destrucción singleton static auto get() -> T*; // Acceso al singleton void render(); // Renderizado void update(float dt); // Actualización lógica auto isActive() -> bool; // Consulta estado ``` ### 5. Comentarios de Variables - **Posición**: A la derecha de la variable/grupo - **Formato**: `// Descripción concisa` - Agrupar variables relacionadas con un comentario común ### 6. Constructores en Structs - **Eliminar constructores por defecto redundantes** en structs: - Si todos los miembros tienen inicialización en declaración - Y no hay múltiples constructores - Eliminar `explicit Type() = default;` - El compilador generará automáticamente un constructor por defecto **Ejemplo:** ```cpp struct Data { int x{0}; std::string name{}; // NO NECESITA: explicit Data() = default; }; ``` ### 7. Includes Necesarios - Agregar includes faltantes según lo que se use - Mantener orden alfabético si es posible ### 8. Header Guards - **Usar `#pragma once`** en todas las cabeceras (`.hpp`) - **NO usar** `#ifndef`/`#define`/`#endif` tradicionales - `#pragma once` debe ser la primera línea del archivo (antes de includes) - **Ventajas**: Más simple, menos propenso a errores, ampliamente soportado ## Ejemplo de Aplicación ### Antes: ```cpp class Example { private: struct Data { std::string name; int value; }; int counter_; bool flag_; float values_[10]; public: Example(); void update(); }; // Constructor Example::Example() : counter_(0), flag_(false) { for (int i = 0; i < 10; ++i) { values_[i] = 0.0F; } } ``` ### Después: ```cpp #pragma once #include class Example { public: Example() = default; // Ya no necesita inicializar void update(); private: // Tipos anidados struct Data { std::string name{}; // Nombre con valor por defecto int value{0}; // Valor inicializado }; // Variables miembro int counter_{0}; // Contador de frames bool flag_{false}; // Estado activo std::array values_{}; // Buffer de valores }; ``` ## Tareas a Realizar Cuando uses este comando en una clase específica: 1. **Leer** el archivo `.hpp` y `.cpp` correspondiente 2. **Verificar** que la cabecera use `#pragma once` (reemplazar `#ifndef`/`#define`/`#endif` si existen) 3. **Identificar** structs y agregar valores por defecto a todos sus miembros 4. **Identificar** variables que pueden inicializarse en declaración 5. **Identificar** arrays C-style que convertir a std::array 6. **Reorganizar** la estructura de la clase (public/private, agrupación) 7. **Actualizar** el archivo `.cpp` eliminando inicializaciones redundantes 8. **Compilar** para verificar sintaxis correcta 9. **Ejecutar clang-tidy** (análisis, sin --fix) y revisar resultados 10. **Ejecutar cppcheck** (nivel -w) y revisar resultados 11. **Aplicar fixes apropiados** basados en análisis de linters 12. **Recompilar** si se aplicaron fixes 13. **Reportar resumen** al usuario: cambios + hallazgos de linters ## Workflow de Linters (Pasos 9-12) ### Paso 9: Ejecutar clang-tidy ```bash tools/linter/run_clang-tidy.sh archivo.cpp archivo.hpp ``` **Analizar resultados:** - Identificar issues críticos (bugprone, cert) - Separar recomendaciones válidas de falsos positivos - Ignorar: magic-numbers en game constants, defaults.hpp errors - Si hay issues críticos, informar al usuario y pausar - Si solo hay recomendaciones, continuar ### Paso 10: Ejecutar cppcheck ```bash tools/linter/run_cppcheck.sh -w --path archivo.cpp ``` **Leer archivo de resultados:** - `tools/linter/cppcheck-result-warning-style-performance.txt` - Identificar errores críticos (error, nullPointer, uninitvar) - Separar warnings de style issues - Filtrar falsos positivos (passedByValue para tipos pequeños, unusedFunction en API pública) - Si hay errores críticos, informar al usuario y pausar ### Paso 11: Aplicar Fixes **Si hay issues aplicables:** 1. **Fixes automáticos de clang-tidy** (solo si son seguros): - modernize-use-auto - readability-redundant-access-specifiers - Performance optimizations claras ```bash tools/linter/run_clang-tidy.sh --fix archivo.cpp archivo.hpp ``` 2. **Fixes manuales necesarios:** - Inicializar variables no inicializadas - Corregir null pointer issues - Resolver memory leaks 3. **Documentar cambios** para el reporte final ### Paso 12: Recompilar Si se aplicaron fixes en paso 11: ```bash cmake --build build ``` **Verificar:** - ✅ Compilación exitosa → Continuar a reporte - ❌ Errores → Informar al usuario, sugerir revisión manual ## Formato de Reporte Final (Paso 13) ``` === Refactor Completado: ClassName === 📝 Cambios estructurales: ✅ #pragma once aplicado ✅ 3 structs actualizados con valores por defecto ✅ 12 variables movidas a inicialización en declaración ✅ 2 arrays C-style → std::array ✅ Clase reorganizada (public primero, variables al final) ✅ Constructor simplificado (elimina 12 inicializaciones redundantes) 🔍 Análisis de linters: clang-tidy: ✅ Sin issues críticos 🟡 3 recomendaciones aplicadas automáticamente: - Modernize: use auto (2 lugares) - Readability: redundant specifier (1 lugar) ⚪ 2 opcionales ignorados: - magic-numbers en game constants cppcheck: ✅ Sin errores 🟡 2 style issues encontrados: - Unused variable 'temp' en línea 45 → Eliminada - Redundant assignment en línea 102 → Corregida 📊 Resultado: ✅ Compilación exitosa ✅ Todos los linters pasan sin issues críticos ✅ Código refactorizado y verificado 💡 Próximos pasos: - Revisar cambios manualmente - Ejecutar tests si existen - Commitear con mensaje descriptivo ``` ## Notas Importantes - **No cambiar lógica**: Solo refactorización estructural - **Mantener compatibilidad**: std::array usa misma sintaxis [] para acceso - **Formato consistente**: Respetar estilo del proyecto (comentarios, espaciado) - **Validar compilación**: Siempre verificar que compile después de cambios - **Linters integrados**: Análisis automático post-refactor para garantizar calidad - **Fixes inteligentes**: Solo aplicar --fix de clang-tidy si los cambios son seguros - **Contexto importa**: Game code tiene patrones legítimos (magic numbers, etc.) - **Falsos positivos**: Identificar y documentar, no corregir ciegamente