From eb83c85a087b19fe8e35e12b090bea8469e01d9c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 19 Feb 2026 15:52:34 -0600 Subject: [PATCH] [ci] Add lint check to prevent powf in core and base entity platforms Add a ci-custom.py check that prevents powf() from being introduced into esphome/core/ and base entity platform components (sensor, light, climate, etc.). These files are linked into every build, and powf pulls in __ieee754_powf (~2.3KB flash). Existing legitimate uses of powf with non-integer exponents (gamma correction in helpers.cpp) are excluded. New uses can opt out with // NOLINT if truly necessary. --- esphome/core/helpers.cpp | 4 ++-- esphome/core/helpers.h | 2 +- script/ci-custom.py | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 6e4f5ac1c4..18592b524f 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -714,7 +714,7 @@ float gamma_correct(float value, float gamma) { if (gamma <= 0.0f) return value; - return powf(value, gamma); + return powf(value, gamma); // NOLINT - deprecated, removal 2026.9.0 } float gamma_uncorrect(float value, float gamma) { if (value <= 0.0f) @@ -722,7 +722,7 @@ float gamma_uncorrect(float value, float gamma) { if (gamma <= 0.0f) return value; - return powf(value, 1 / gamma); + return powf(value, 1 / gamma); // NOLINT - deprecated, removal 2026.9.0 } void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 0185437cc4..3419c80df8 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -440,7 +440,7 @@ template class SmallBufferWithHeapFallb ///@{ /// Compute 10^exp using iterative multiplication/division. -/// Avoids pulling in powf/__ieee754_powf (~2.3KB flash) for small integer exponents. +/// Avoids pulling in powf/__ieee754_powf (~2.3KB flash) for small integer exponents. // NOLINT /// Exact for non-negative exponents up to 10 (powers of 10 up to 10^10 are exact in float). inline float pow10_int(int8_t exp) { float result = 1.0f; diff --git a/script/ci-custom.py b/script/ci-custom.py index 231f587068..895c13194e 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -825,6 +825,54 @@ def lint_no_scanf(fname, match): ) +# Base entity platforms - these are linked into most builds and should not +# pull in powf/__ieee754_powf (~2.3KB flash). +BASE_ENTITY_PLATFORMS = [ + "alarm_control_panel", + "binary_sensor", + "button", + "climate", + "cover", + "datetime", + "event", + "fan", + "light", + "lock", + "media_player", + "number", + "select", + "sensor", + "switch", + "text", + "text_sensor", + "update", + "valve", + "water_heater", +] + +# Directories protected from powf: core + all base entity platforms +POWF_PROTECTED_DIRS = ["esphome/core"] + [ + f"esphome/components/{p}" for p in BASE_ENTITY_PLATFORMS +] + + +@lint_re_check( + r"[^\w]powf\s*\(" + CPP_RE_EOL, + include=[ + f"{d}/*.{ext}" for d in POWF_PROTECTED_DIRS for ext in ["h", "cpp", "tcc"] + ], +) +def lint_no_powf_in_core(fname, match): + return ( + f"{highlight('powf()')} pulls in __ieee754_powf (~2.3KB flash) and is not allowed in " + f"core or base entity platform code. These files are linked into every build.\n" + f"Please use alternatives:\n" + f" - {highlight('pow10_int(exp)')} for integer powers of 10 (from helpers.h)\n" + f" - Precomputed lookup tables for gamma/non-integer exponents\n" + f"(If powf is strictly necessary, add `// NOLINT` to the line)" + ) + + @lint_content_find_check( "ESP_LOG", include=["*.h", "*.tcc"],