Skip to content

perf_lint: add PERF025 — redundant string() in string interpolation - #2912

Merged
borisbat merged 1 commit into
masterfrom
claude/pedantic-heyrovsky-ccbc69
May 28, 2026
Merged

perf_lint: add PERF025 — redundant string() in string interpolation#2912
borisbat merged 1 commit into
masterfrom
claude/pedantic-heyrovsky-ccbc69

Conversation

@borisbat

Copy link
Copy Markdown
Collaborator

Summary

New daslib/perf_lint.das rule PERF025: flags a string(value) cast used as a direct string-interpolation element. The interpolation already stringifies every element via the string builder's DebugDataWalker, so the cast just allocates a throwaway string the builder then copies.

// Bad
return "{string(iv)}"      // PERF025
// Good
return "{iv}"

Behavior

Fires for stringify-equivalent value types — where "{x}" and string(x) produce identical text (verified empirically):

value type action
signed int/int8/int16/int64, float, double, string, das_string warn → drop the cast
uint/uint8/uint16/uint64 warn → drop, plus a {x:d} hint: unsigned interpolates as hex by default ("{42u}"0x2a) while string() gives decimal

Deliberately skipped (dropping the cast would change the value, not just the format — no format tag fixes it):

  • string(array<uint8>) (bytes→text), string(uri), string(text_range)
  • string() nested as an argument to another call, e.g. "{length(string(x))}" — only direct interpolation elements are flagged
  • explicit hex request string(x, true)

Detection lives in the per-element preVisitExprStringBuilderElement hook; the kind is modeled as an enum (Perf025Kind { skip; equivalent; unsigned_hex }). A format spec ("{x:fmt}") lowers to _::fmt(":fmt", x), but fmt has no string-valued overload, so string(x) can never sit under a fmt wrapper — no unwrap needed.

Also drops one redundant string(das_string) the new rule found in perf_lint's own PERF024 message string.

Files

  • daslib/perf_lint.das — the rule (enum + 3 helpers + 1 visitor override) and the self-hit fix
  • utils/lint/tests/perf025_redundant_string_in_interp.das — fixture (expect 31208:8)
  • doc/source/reference/language/lint.rst — PERF025 reference section
  • skills/perf_lint.md — rules-table row

Test plan

  • utils/lint/main.das on changed .das files → 0 warnings (PERF025 is lint-clean against its own code)
  • Fixture emits exactly 8 error[31208] (5 plain-drop + 3 :d-hint); good cases produce 0; matches expect 31208:8
  • das_string headline case ("{string(fn.name)}") confirmed firing; direct "{fn.name}" does not
  • All 25 existing perf* lint fixtures still match their declared expect counts (no regression)
  • detect-dupe on the new helpers → no duplicates
  • Formatter-clean (das-fmt --verify passed on the full tree via pre-push hook)
  • Clean Sphinx build for the lint.rst change (no warnings attributable to it)

AOT/JIT steps are N/A: this is a compile-time lint pass that touches no codegen and is required by no AOT/runtime test.

Follow-up (separate sweep, not this PR): the rule surfaces a handful of pre-existing hits elsewhere in the tree (utils/mcp/subtools/aot.das, tutorials/macros/function_macro_mod.das, modules/dasClangBind/cbind/cbind_boost.das).

🤖 Generated with Claude Code

Flags a `string(value)` cast used as a direct string-interpolation element:
the interpolation already stringifies every element via the builder's
DebugDataWalker, so the cast just allocates a throwaway string the builder
then copies.

Fires for stringify-equivalent value types (signed ints, float, double,
string, das_string). Unsigned ints also warn but with a `{x:d}` format-tag
hint, since they interpolate as hex by default while string() gives decimal.
Skips value-shape conversions (array<uint8>/uri/text_range) and string()
nested as an argument to another call (e.g. length(string(x))).

Adds the lint fixture, rst reference section, and skill table row. Also drops
a redundant string(das_string) the rule found in perf_lint's own PERF024
message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 05:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new performance lint rule PERF025 to daslib/perf_lint.das that flags string(value) casts used as direct string-interpolation elements (e.g. "{string(iv)}"), since the string builder's DebugDataWalker already stringifies elements, making the cast a wasted allocation. The rule classifies the wrapped value to decide whether to warn plainly (signed ints, float, double, string, das_string) or warn with a :d format-tag hint (unsigned ints, which interpolate as hex by default), and intentionally skips value-shape-changing conversions (array<uint8>, uri, text_range), nested string(...) arguments, and explicit string(x, true) hex requests.

Changes:

  • Add Perf025Kind enum, three helpers, and a preVisitExprStringBuilderElement override implementing the rule.
  • Add fixture utils/lint/tests/perf025_redundant_string_in_interp.das with expect 31208:8 covering all equivalent and unsigned-hex cases plus negative cases.
  • Drop a redundant string(das_string) cast inside PERF024's own warning message (a self-hit from the new rule), and update lint.rst and skills/perf_lint.md documentation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
daslib/perf_lint.das Implements PERF025 (enum, helpers, visitor hook) and removes a self-hit in PERF024's message.
utils/lint/tests/perf025_redundant_string_in_interp.das New fixture exercising 8 bad cases (5 equivalent + 3 unsigned_hex) and 4 good cases.
doc/source/reference/language/lint.rst Reference section describing PERF025 behavior, the :d hint, and skipped cases.
skills/perf_lint.md Adds a PERF025 row summarizing detection shape and edge cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread daslib/perf_lint.das
@borisbat
borisbat merged commit c339113 into master May 28, 2026
32 checks passed
@borisbat
borisbat deleted the claude/pedantic-heyrovsky-ccbc69 branch May 30, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants