objectionary / objectionary/lints

`sprintf-constant-args` selects the removed `Φ.txt.sprintf`, so the rule never fires on current EO

Open
#1,366 1 comment 0 reactions 1 assignee View on GitHub

@yegor256 is already working on this.

Since Sep 8, 2026.

bug
Dominant language
Java
Stars
14
Forks
39
Avg merge
22h 54m
Merged PRs (30d)
90

Description

sprintf-constant-args selects an object current EO does not have, so the rule can never fire on real code.

src/main/resources/org/eolang/lints/misc/sprintf-constant-args.xsl:20:

<xsl:for-each select="//o[@base='Φ.txt.sprintf'][count(o)=2][o[2][@base='Φ.tuple']]">

There is no txt package in objectionary/eo any more, and no sprintf object anywhere in the runtime. Formatting is eo-runtime/src/main/eo/string/printf.eo, reached as a method on the format string, so a parsed XMIR carries a dispatch:

$ grep -rl "txt.sprintf" eo-runtime/target/eo/1-parse/
(nothing)

$ grep -o 'base="[^"]*printf[^"]*"' eo-runtime/target/eo/1-parse/bytes/as-i16.xmir
base=".printf"

Every one of the eight packs feeds the rule txt.sprintf, so the suite stays green while nothing in a real program is ever examined.

The check itself is worth keeping: a format template that is a literal, with arguments that are all literal strings, has a result known at parse time and should be written as one string.

Root cause

The shape of the call changed with the object. "fmt".printf (* args) puts the template on the receiver, which a real XMIR emits as the child without an as attribute, and leaves exactly one argument:

<o base=".printf">
  <o base="Φ.string">…the format…</o>
  <o as="α0" base="Φ.tuple">…the arguments…</o>
</o>

(checked against eo-runtime/target/eo/1-parse/bytes/as-i16.xmir)

so count(o)=2 still holds, but o[1] is the template rather than o[2] being the tuple, and @base is .printf.

Suggested fix

<xsl:for-each select="//o[@base='.printf'][o[@as][1][@base='Φ.tuple']]">
  <xsl:variable name="text" select="o[not(@as)][1][@base='Φ.string']/o[1][@base='Φ.bytes']/o/text()"/>
  ...
  <xsl:apply-templates select="o[@as][1]" mode="constant-args"/>

with the message naming .printf, and the packs rewritten to the current call form so they exercise something the parser can actually produce.

Counting the formatters needs the same treatment as in #1355: the byte pairs 2573, 2564, 2566, 2578, 2562 miss every specifier that carries a flag, a width or a precision, so "%08.2f" counts as zero formatters and the rule stays silent on a call it should examine.

Two sibling rules have the same dead selector and are reported separately, since each needs its own adaptation: #1355 is about arity and tuple shape, #1357 about the template's content, and this one about arguments that are all literals.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.