diff --git a/.clang-tidy b/.clang-tidy index 5878028f48..4e128a1945 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,24 +5,30 @@ Checks: >- -altera-*, -android-*, -boost-*, + -bugprone-derived-method-shadowing-base-method, -bugprone-easily-swappable-parameters, -bugprone-implicit-widening-of-multiplication-result, + -bugprone-invalid-enum-default-initialization, -bugprone-multi-level-implicit-pointer-conversion, -bugprone-narrowing-conversions, + -bugprone-tagged-union-member-count, -bugprone-signed-char-misuse, -bugprone-switch-missing-default-case, -cert-dcl50-cpp, -cert-err33-c, -cert-err58-cpp, + -cert-int09-c, -cert-oop57-cpp, -cert-str34-c, -clang-analyzer-optin.core.EnumCastOutOfRange, -clang-analyzer-optin.cplusplus.UninitializedObject, -clang-analyzer-osx.*, + -clang-analyzer-security.ArrayBound, -clang-diagnostic-delete-abstract-non-virtual-dtor, -clang-diagnostic-delete-non-abstract-non-virtual-dtor, -clang-diagnostic-deprecated-declarations, -clang-diagnostic-ignored-optimization-argument, + -clang-diagnostic-missing-designated-field-initializers, -clang-diagnostic-missing-field-initializers, -clang-diagnostic-shadow-field, -clang-diagnostic-unused-const-variable, @@ -42,6 +48,7 @@ Checks: >- -cppcoreguidelines-owning-memory, -cppcoreguidelines-prefer-member-initializer, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-type-const-cast, @@ -54,12 +61,13 @@ Checks: >- -cppcoreguidelines-rvalue-reference-param-not-moved, -cppcoreguidelines-special-member-functions, -cppcoreguidelines-use-default-member-init, + -cppcoreguidelines-use-enum-class, -cppcoreguidelines-virtual-class-destructor, + -fuchsia-default-arguments-calls, + -fuchsia-default-arguments-declarations, -fuchsia-multiple-inheritance, -fuchsia-overloaded-operator, -fuchsia-statically-constructed-objects, - -fuchsia-default-arguments-declarations, - -fuchsia-default-arguments-calls, -google-build-using-namespace, -google-explicit-constructor, -google-readability-braces-around-statements, @@ -71,16 +79,23 @@ Checks: >- -llvm-else-after-return, -llvm-header-guard, -llvm-include-order, + -llvm-prefer-static-over-anonymous-namespace, -llvm-qualified-auto, + -llvm-use-ranges, -llvmlibc-*, -misc-const-correctness, -misc-include-cleaner, + -misc-multiple-inheritance, -misc-no-recursion, -misc-non-private-member-variables-in-classes, + -misc-override-with-different-visibility, -misc-unused-parameters, -misc-use-anonymous-namespace, + -misc-use-internal-linkage, -modernize-avoid-bind, + -modernize-avoid-variadic-functions, -modernize-avoid-c-arrays, + -modernize-avoid-c-style-cast, -modernize-concat-nested-namespaces, -modernize-macro-to-enum, -modernize-return-braced-init-list, @@ -88,32 +103,42 @@ Checks: >- -modernize-use-auto, -modernize-use-constraints, -modernize-use-default-member-init, + -modernize-use-designated-initializers, -modernize-use-equals-default, + -modernize-use-integer-sign-comparison, -modernize-use-nodiscard, -modernize-use-nullptr, - -modernize-use-nodiscard, - -modernize-use-nullptr, + -modernize-use-ranges, -modernize-use-trailing-return-type, -mpi-*, -objc-*, -performance-enum-size, + -portability-avoid-pragma-once, + -portability-template-virtual-member-function, + -readability-ambiguous-smartptr-reset-call, -readability-avoid-nested-conditional-operator, -readability-container-contains, -readability-container-data-pointer, -readability-convert-member-functions-to-static, -readability-else-after-return, + -readability-enum-initial-value, -readability-function-cognitive-complexity, -readability-implicit-bool-conversion, -readability-isolate-declaration, -readability-magic-numbers, -readability-make-member-function-const, + -readability-math-missing-parentheses, -readability-named-parameter, -readability-redundant-casting, -readability-redundant-inline-specifier, -readability-redundant-member-init, + -readability-redundant-parentheses, -readability-redundant-string-init, + -readability-redundant-typename, -readability-uppercase-literal-suffix, -readability-use-anyofallof, + -readability-use-std-min-max, + -readability-use-concise-preprocessor-directives, WarningsAsErrors: '*' FormatStyle: google CheckOptions: diff --git a/.clang-tidy.hash b/.clang-tidy.hash index 41e1b7bd2f..582e0c1eaa 100644 --- a/.clang-tidy.hash +++ b/.clang-tidy.hash @@ -1 +1 @@ -1b1ce6324c50c4595703c7df0a8a479b4fe84b71ff1a8793cce1a16f17a33324 +0c7f309d70eca8e3efd510092ddb23c530f3934c49371717efa124b788d761f8 diff --git a/esphome/components/adalight/adalight_light_effect.cpp b/esphome/components/adalight/adalight_light_effect.cpp index 4cf639a01f..06d7e0e897 100644 --- a/esphome/components/adalight/adalight_light_effect.cpp +++ b/esphome/components/adalight/adalight_light_effect.cpp @@ -129,7 +129,7 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL uint8_t *led_data = &frame_[6]; for (int led = 0; led < accepted_led_count; led++, led_data += 3) { - auto white = std::min(std::min(led_data[0], led_data[1]), led_data[2]); + auto white = std::min({led_data[0], led_data[1], led_data[2]}); it[led].set(Color(led_data[0], led_data[1], led_data[2], white)); } diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 3ff65029e1..f058f6af22 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -424,6 +424,7 @@ class ProtoEncode { if (len == 0 && !force) return; encode_field_raw(pos PROTO_ENCODE_DEBUG_ARG, field_id, 2); // type 2: Length-delimited string + // NOLINTNEXTLINE(readability-inconsistent-ifelse-braces) -- false positive on [[likely]] attribute if (len < VARINT_MAX_1_BYTE) [[likely]] { PROTO_ENCODE_CHECK_BOUNDS(pos, 1 + len); *pos++ = static_cast(len); diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index e132497140..b41ca4a540 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -374,7 +374,8 @@ void Climate::save_state_(const ClimateTraits &traits) { #define TEMP_IGNORE_MEMACCESS #endif ClimateDeviceRestoreState state{}; - // initialize as zero to prevent random data on stack triggering erase + // initialize as zero (including padding) to prevent random data on stack triggering erase + // NOLINTNEXTLINE(bugprone-raw-memory-call-on-non-trivial-type) -- intentional bytewise zero for RTC save memset(&state, 0, sizeof(ClimateDeviceRestoreState)); #ifdef TEMP_IGNORE_MEMACCESS #pragma GCC diagnostic pop diff --git a/esphome/components/debug/debug_zephyr.cpp b/esphome/components/debug/debug_zephyr.cpp index 49790b5b9a..81c8612784 100644 --- a/esphome/components/debug/debug_zephyr.cpp +++ b/esphome/components/debug/debug_zephyr.cpp @@ -17,11 +17,13 @@ constexpr std::uintptr_t MBR_PARAM_PAGE_ADDR = 0xFFC; constexpr std::uintptr_t MBR_BOOTLOADER_ADDR = 0xFF8; static inline uint32_t read_mem_u32(uintptr_t addr) { - return *reinterpret_cast(addr); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr,clang-analyzer-core.FixedAddressDereference) + return *reinterpret_cast(addr); } static inline uint8_t read_mem_u8(uintptr_t addr) { - return *reinterpret_cast(addr); // NOLINT(performance-no-int-to-ptr) + // NOLINTNEXTLINE(performance-no-int-to-ptr,clang-analyzer-core.FixedAddressDereference) + return *reinterpret_cast(addr); } // defines from https://github.com/adafruit/Adafruit_nRF52_Bootloader which prints those information @@ -98,6 +100,7 @@ void DebugComponent::log_partition_info_() { #define NRF_PERIPH_ENABLED(periph, reg) \ YESNO(((reg)->ENABLE & periph##_ENABLE_ENABLE_Msk) == (periph##_ENABLE_ENABLE_Enabled << periph##_ENABLE_ENABLE_Pos)) +// NOLINTBEGIN(clang-analyzer-core.FixedAddressDereference) -- nRF peripheral registers are MMIO at fixed addresses static void log_peripherals_info() { // most peripherals are enabled only when in use so ESP_LOGV is enough ESP_LOGV(TAG, "Peripherals status:"); @@ -131,6 +134,7 @@ static void log_peripherals_info() { YESNO((NRF_CRYPTOCELL->ENABLE & CRYPTOCELL_ENABLE_ENABLE_Msk) == (CRYPTOCELL_ENABLE_ENABLE_Enabled << CRYPTOCELL_ENABLE_ENABLE_Pos))); } +// NOLINTEND(clang-analyzer-core.FixedAddressDereference) #undef NRF_PERIPH_ENABLED #endif @@ -159,8 +163,9 @@ size_t DebugComponent::get_device_info_(std::span char *buf = buffer.data(); // Main supply status - const char *supply_status = - (nrf_power_mainregstatus_get(NRF_POWER) == NRF_POWER_MAINREGSTATUS_NORMAL) ? "Normal voltage." : "High voltage."; + // NOLINTNEXTLINE(clang-analyzer-core.FixedAddressDereference) -- NRF_POWER is MMIO at a fixed address + auto regstatus = nrf_power_mainregstatus_get(NRF_POWER); + const char *supply_status = (regstatus == NRF_POWER_MAINREGSTATUS_NORMAL) ? "Normal voltage." : "High voltage."; ESP_LOGD(TAG, "Main supply status: %s", supply_status); pos = buf_append_str(buf, size, pos, "|Main supply status: "); pos = buf_append_str(buf, size, pos, supply_status); diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index f6010a7cc9..f6300874ac 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -56,8 +56,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet // limit amount of lights per universe and received // packet.count is the number of DMX bytes including start code; divide by channels to get the number of lights int lights_in_packet = (packet.count > 0) ? (packet.count - 1) / channels_ : 0; - int output_end = - std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + lights_in_packet)); + int output_end = std::min({it->size(), output_offset + get_lights_per_universe(), output_offset + lights_in_packet}); auto *input_data = packet.values + 1; auto effect_name = get_name(); diff --git a/esphome/components/esp8266/gpio.cpp b/esphome/components/esp8266/gpio.cpp index 659233443e..a85f054dfe 100644 --- a/esphome/components/esp8266/gpio.cpp +++ b/esphome/components/esp8266/gpio.cpp @@ -140,6 +140,7 @@ void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { auto *arg = reinterpret_cast(arg_); + // NOLINTNEXTLINE(clang-analyzer-core.FixedAddressDereference) -- GPIO_REG_WRITE is MMIO at a fixed address GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin); } diff --git a/esphome/components/esp8266/preferences.cpp b/esphome/components/esp8266/preferences.cpp index f444f03555..696f83bce1 100644 --- a/esphome/components/esp8266/preferences.cpp +++ b/esphome/components/esp8266/preferences.cpp @@ -51,7 +51,7 @@ static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) { if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) { return false; } - *dest = ESP_RTC_USER_MEM[index]; // NOLINT(performance-no-int-to-ptr) + *dest = ESP_RTC_USER_MEM[index]; // NOLINT(performance-no-int-to-ptr,clang-analyzer-core.FixedAddressDereference) return true; } @@ -64,7 +64,7 @@ static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) { } auto *ptr = &ESP_RTC_USER_MEM[index]; // NOLINT(performance-no-int-to-ptr) - *ptr = value; + *ptr = value; // NOLINT(clang-analyzer-core.FixedAddressDereference) return true; } diff --git a/esphome/components/http_request/http_request_arduino.cpp b/esphome/components/http_request/http_request_arduino.cpp index 05f9db1c06..217ad0064d 100644 --- a/esphome/components/http_request/http_request_arduino.cpp +++ b/esphome/components/http_request/http_request_arduino.cpp @@ -243,7 +243,7 @@ int HttpContainerArduino::read(uint8_t *buf, size_t max_len) { // Non-chunked path int available_data = stream_ptr->available(); size_t remaining = (this->content_length > 0) ? (this->content_length - this->bytes_read_) : max_len; - int bufsize = std::min(max_len, std::min(remaining, (size_t) available_data)); + int bufsize = std::min({max_len, remaining, (size_t) available_data}); if (bufsize == 0) { this->duration_ms += (millis() - start); diff --git a/esphome/components/nrf52/uicr.cpp b/esphome/components/nrf52/uicr.cpp index 4c0beeb503..03b07f8fe3 100644 --- a/esphome/components/nrf52/uicr.cpp +++ b/esphome/components/nrf52/uicr.cpp @@ -11,6 +11,7 @@ void nvmc_wait(); nrfx_err_t nrfx_nvmc_uicr_erase(); } +// NOLINTBEGIN(clang-analyzer-core.FixedAddressDereference) -- NRF_UICR / NRF_TIMER2 are MMIO at fixed addresses namespace esphome::nrf52 { enum class StatusFlags : uint8_t { @@ -113,6 +114,7 @@ static int board_esphome_init() { return 0; } } // namespace esphome::nrf52 +// NOLINTEND(clang-analyzer-core.FixedAddressDereference) static int board_esphome_init() { return esphome::nrf52::board_esphome_init(); } diff --git a/esphome/components/ota/ota_backend_esp8266.cpp b/esphome/components/ota/ota_backend_esp8266.cpp index 93e6249fb3..7c9d392532 100644 --- a/esphome/components/ota/ota_backend_esp8266.cpp +++ b/esphome/components/ota/ota_backend_esp8266.cpp @@ -60,6 +60,7 @@ OTAResponseTypes ESP8266OTABackend::begin(size_t image_size) { // Check boot mode - if boot mode is UART download mode, // we will not be able to reset into normal mode once update is done + // NOLINTNEXTLINE(clang-analyzer-core.FixedAddressDereference) -- GPI is MMIO at a fixed address int boot_mode = (GPI >> BOOT_MODE_SHIFT) & BOOT_MODE_MASK; if (boot_mode == BOOT_MODE_UART_DOWNLOAD) { return OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING; diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index e977c05c48..336123a472 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -669,7 +669,7 @@ uint32_t Sprinkler::valve_run_duration_adjusted(const size_t valve_number) { // run_duration must not be less than any of these if ((run_duration < this->start_delay_) || (run_duration < this->stop_delay_) || (run_duration < this->switching_delay_.value_or(0) * 2)) { - return std::max(this->switching_delay_.value_or(0) * 2, std::max(this->start_delay_, this->stop_delay_)); + return std::max({this->switching_delay_.value_or(0) * 2, this->start_delay_, this->stop_delay_}); } return run_duration; } diff --git a/esphome/core/color.h b/esphome/core/color.h index 32d63b1856..442470623d 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -169,7 +169,7 @@ struct Color { uint8_t r = rand >> 16; uint8_t g = rand >> 8; uint8_t b = rand >> 0; - const uint16_t max_rgb = std::max(r, std::max(g, b)); + const uint16_t max_rgb = std::max({r, g, b}); return Color(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)), uint8_t((uint16_t(b) * 255U / max_rgb)), w); } diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index e71da95e6b..1eb3345491 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -663,8 +663,8 @@ float gamma_uncorrect(float value, float gamma) { } void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value) { - float max_color_value = std::max(std::max(red, green), blue); - float min_color_value = std::min(std::min(red, green), blue); + float max_color_value = std::max({red, green, blue}); + float min_color_value = std::min({red, green, blue}); float delta = max_color_value - min_color_value; if (delta == 0) { diff --git a/esphome/core/preference_backend.h b/esphome/core/preference_backend.h index 3766934da4..431de205af 100644 --- a/esphome/core/preference_backend.h +++ b/esphome/core/preference_backend.h @@ -69,6 +69,10 @@ template class PreferencesMixin { ESPPreferenceObject make_preference(uint32_t type) { return static_cast(this)->make_preference(sizeof(T), type); } + + private: + PreferencesMixin() = default; + friend Derived; }; // Macro for platform preferences.h headers to declare the standard aliases. diff --git a/requirements_dev.txt b/requirements_dev.txt index 0884e5b5e4..31463e07c3 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ # Useful stuff when working in a development environment clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating -clang-tidy==18.1.8 # When updating clang-tidy, also update Dockerfile +clang-tidy==22.1.0.1 yamllint==1.38.0 # also change in .pre-commit-config.yaml when updating diff --git a/script/clang-tidy b/script/clang-tidy index f2834b44ac..1c413ffa23 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -295,7 +295,7 @@ def main(): failed_files = [] try: - executable = get_binary("clang-tidy", 18) + executable = get_binary("clang-tidy", 22) task_queue = queue.Queue(args.jobs) lock = threading.Lock() for _ in range(args.jobs): @@ -341,13 +341,13 @@ def main(): try: try: subprocess.call( - ["clang-apply-replacements-18", tmpdir], close_fds=False + ["clang-apply-replacements-22", tmpdir], close_fds=False ) except FileNotFoundError: subprocess.call(["clang-apply-replacements", tmpdir], close_fds=False) except FileNotFoundError: print( - "Error please install clang-apply-replacements-18 or clang-apply-replacements.\n", + "Error please install clang-apply-replacements-22 or clang-apply-replacements.\n", file=sys.stderr, ) except: