Skip to content

Conversation

@h1alexbel
Copy link
Member

@h1alexbel h1alexbel commented Oct 9, 2025

In this PR I've optimized redundant-object lint from O(n^2) to O(n + G) execution time, where n - the number of objects, and G - one-time grouping pass.

Evaluation

To evaluate results, I used the following script

mvn clean test -Dtest=SourceTest#lintsBenchmarkSourcesFromJava -Pbenchmark
cat target/timings.csv | sort -t, -k2 -n -r | grep "redundant-object"

Before:

"redundant-object (XXL)","403"
"redundant-object (XL)","56"
"redundant-object (S)","114"
"redundant-object (M)","36"
"redundant-object (L)","42"

After:

"redundant-object (XXL)","56"
"redundant-object (XL)","22"
"redundant-object (S)","104"
"redundant-object (M)","20"
"redundant-object (L)","22"

see #744

Summary by CodeRabbit

  • Bug Fixes

    • Refined “redundant-object” lint detection for more precise reporting, which may change the number of flagged cases.
    • Standardized lint output: severity reported as “warning” and context included only when the line number is unknown.
  • Tests

    • Benchmark configuration updated to include “redundant-object” in scans, expanding the measured defect set.

@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

Walkthrough

Refactors redundant-object lint XSL to compute eligible objects, group references, and emit a single warning-style defect element per object based on refs count and context rules. Updates benchmark to stop excluding “redundant-object” from scansXmir, leaving only “duplicate-names-in-diff-context” excluded.

Changes

Cohort / File(s) Summary
Lint rule: redundant-object selection and defect emission
src/main/resources/org/eolang/lints/misc/redundant-object.xsl
Introduces variables eligible and ref-groups; counts refs by base-name pattern; iterates over eligible objects excluding top id; flags defects when refs ≤ 1 and not dataized; switches to single <defect> element with line and severity="warning", adds context only when eo:lineno(@line) = '0'.
Benchmarks: defect exclusions
src/test/java/benchmarks/SourceBench.java
In scansXmir, removes exclusion of "redundant-object", keeping only "duplicate-names-in-diff-context"; .defects() call unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant XMIR as XMIR doc
    participant XSL as redundant-object.xsl
    participant Lints as Lints Output

    XMIR->>XSL: Apply lint template
    rect rgba(200,230,255,0.3)
      note over XSL: New selection flow
      XSL->>XSL: Compute eligible objects
      XSL->>XSL: Group refs by base-name pattern (ref-groups)
      loop For each eligible (excluding top-generated-id)
        XSL->>XSL: refs = count from ref-groups
        alt refs ≤ 1 and not dataized
          XSL-->>Lints: Emit <defect line=... severity="warning"[ context? ]/>
        else No defect
          XSL-->>Lints: Skip
        end
      end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

core

Suggested reviewers

  • yegor256
  • maxonfjvipon

Poem

I nose through XMIR fields with cheer,
Counting refs both far and near—
One hop, two hops, none to spare?
I warn with whiskers in the air.
Benchmarks trim my burrow’s scope—
Carrot-clean, I lint with hope. 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly and accurately summarizes the primary change in this pull request by indicating that the redundant-object lint has been optimized, and it references the related issue number for context without unnecessary detail or verbosity.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/resources/org/eolang/lints/misc/redundant-object.xsl (1)

22-22: Simplify condition (redundant @name check)

$eligible already guarantees @name; drop it from the guard.

-        <xsl:if test="$refs &lt;= 1 and not(@name and o[1]/@base = 'Φ.org.eolang.dataized')">
+        <xsl:if test="$refs &lt;= 1 and not(o[1]/@base = 'Φ.org.eolang.dataized')">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c98434 and 85f3baf.

📒 Files selected for processing (2)
  • src/main/resources/org/eolang/lints/misc/redundant-object.xsl (1 hunks)
  • src/test/java/benchmarks/SourceBench.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: reserved
  • GitHub Check: qulice
  • GitHub Check: mvn (windows-2022, 21)
  • GitHub Check: mvn (macos-15, 11)
  • GitHub Check: ort
  • GitHub Check: mvn (windows-2022, 11)
  • GitHub Check: mvn (macos-15, 21)
  • GitHub Check: mvn (ubuntu-24.04, 21)
  • GitHub Check: mvn (ubuntu-24.04, 11)
  • GitHub Check: deep
🔇 Additional comments (2)
src/test/java/benchmarks/SourceBench.java (1)

51-52: LGTM: enabling redundant-object in scans

Removing it from exclusions aligns with the lint changes and reported perf gains.

src/main/resources/org/eolang/lints/misc/redundant-object.xsl (1)

23-30: Confirmed attribute-based severity support All XSL templates emit <defect> with a severity attribute and Java consumers parse @severity; nested <severity/> elements are not used.

Comment on lines +13 to +17
<xsl:variable name="ref-groups" as="element(group)*">
<xsl:for-each-group select="//o[matches(@base, '^ξ(?:\.ρ)*\.')]" group-by="replace(@base, '^ξ(?:\.ρ)*\.([^.\s]+).*', '$1')">
<group name="{current-grouping-key()}" count="{count(current-group())}"/>
</xsl:for-each-group>
</xsl:variable>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Refs are counted by name globally; collisions across scopes → incorrect results

Grouping by only the name merges references from different lexical scopes (e.g., multiple siblings each having o @name="tmp"). This can suppress true defects or create false negatives/positives. Group by nearest scope + name, and use that for $refs.

Apply this diff:

-    <xsl:variable name="ref-groups" as="element(group)*">
-      <xsl:for-each-group select="//o[matches(@base, '^ξ(?:\.ρ)*\.')]" group-by="replace(@base, '^ξ(?:\.ρ)*\.([^.\s]+).*', '$1')">
-        <group name="{current-grouping-key()}" count="{count(current-group())}"/>
-      </xsl:for-each-group>
-    </xsl:variable>
+    <xsl:variable name="ref-groups" as="element(group)*">
+      <!-- Group by lexical scope (nearest ancestor o) + local name to avoid cross-scope collisions -->
+      <xsl:for-each-group
+        select="//o[matches(@base, '^ξ(?:\.ρ)*\.')]"
+        group-by="concat(generate-id(ancestor::o[1]), '::', replace(@base, '^ξ(?:\.ρ)*\.([^.\s]+).*', '$1'))">
+        <group
+          scope="{generate-id(current-group()[1]/ancestor::o[1])}"
+          name="{replace(current-group()[1]/@base, '^ξ(?:\.ρ)*\.([^.\s]+).*', '$1')}"
+          count="{count(current-group())}"/>
+      </xsl:for-each-group>
+    </xsl:variable>
@@
-        <xsl:variable name="refs" select="number(($ref-groups[@name = current()/@name]/@count, 0)[1])"/>
+        <xsl:variable name="refs"
+          select="number(($ref-groups[@name = current()/@name and @scope = generate-id(ancestor::o[1])]/@count, 0)[1])"/>

Also applies to: 21-21

🤖 Prompt for AI Agents
In src/main/resources/org/eolang/lints/misc/redundant-object.xsl around lines 13
to 17 (also apply same change at line 21), the current grouping key uses only
the object name which causes collisions across different lexical scopes; change
the group-by to include the nearest scope identifier plus the name (e.g.,
compute or capture the nearest enclosing scope node or its unique id and combine
it with replace(@base, '^ξ(?:\.ρ)*\.([^.\s]+).*', '$1') into the grouping key)
and then use that combined scope+name key for $refs so references are counted
per-scope rather than globally.

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.

1 participant