From 67b0b68ea8e3c0c242e1b2a3d82675806c22ce96 Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:30:31 +0530 Subject: [PATCH 1/9] Added lint file to detect redundant ^ Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../java/org/eolang/lints/LtRedundantHat.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/java/org/eolang/lints/LtRedundantHat.java diff --git a/src/main/java/org/eolang/lints/LtRedundantHat.java b/src/main/java/org/eolang/lints/LtRedundantHat.java new file mode 100644 index 000000000..d9438f394 --- /dev/null +++ b/src/main/java/org/eolang/lints/LtRedundantHat.java @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.github.lombrozo.xnav.Xnav; +import com.jcabi.xml.XML; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import org.eolang.parser.OnDefault; + +/** + * Lint that warns if a redundant {@code ^} is used. + * + * @since 0.0.60 + */ +final class LtRedundantHat implements Lint { + + @Override + public Collection defects(final XML xmir) throws IOException { + final Collection defects = new ArrayList<>(0); + final Xnav xml = new Xnav(xmir.inner()); + final List objects = xml.path("//o[@base='^']").collect(Collectors.toList()); + for (final Xnav object : objects) { + final String name = object.attribute("name").text().get(); + final List parents = object.path(String.format("ancestor::o[.//o[@name='%s']]", name)) + .collect(Collectors.toList()); + if (parents.isEmpty()) { + defects.add( + new Defect.Default( + this.name(), + Severity.WARNING, + new OnDefault(xmir).get(), + Integer.parseInt(object.attribute("line").text().orElse("0")), + String.format( + "Redundant '^' notation: '%s' can be accessed without it", + name + ) + ) + ); + } + } + return defects; + } + + @Override + public String motive() throws IOException { + return "The '^' notation is used when there are no naming conflicts, please omitted for brevity."; + } + + @Override + public String name() { + return "redundant-hat"; + } +} + From 3bb57956a13b490fef16dddb0ee460c6390b1dc4 Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:32:59 +0530 Subject: [PATCH 2/9] Test file for lint detecting ^ Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../org/eolang/lints/LtRedundantHatTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/test/java/org/eolang/lints/LtRedundantHatTest.java diff --git a/src/test/java/org/eolang/lints/LtRedundantHatTest.java b/src/test/java/org/eolang/lints/LtRedundantHatTest.java new file mode 100644 index 000000000..39aa723af --- /dev/null +++ b/src/test/java/org/eolang/lints/LtRedundantHatTest.java @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.jcabi.xml.XML; +import com.jcabi.xml.XMLDocument; +import java.io.IOException; +import java.util.Collection; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +/** + * Test case for {@link LtRedundantHat}. + * + * @since 0.0.60 + */ +final class LtRedundantHatTest { + + @Test + void reportsNoDefectsForNecessaryHat() throws IOException { + final XML xml = new XMLDocument( + "" + ); + final LtRedundantHat lint = new LtRedundantHat(); + final Collection defects = lint.defects(xml); + MatcherAssert.assertThat( + "Should not report a defect when '^' is necessary to resolve ambiguity", + defects, + Matchers.empty() + ); + } + + @Test + void motiveContainsGuidance() throws IOException { + final LtRedundantHat lint = new LtRedundantHat(); + MatcherAssert.assertThat( + "Motive must explain when to omit redundant '^'", + lint.motive(), + Matchers.containsString("notation is used when there are no naming conflicts") + ); + } + + @Test + void nameIsStableId() { + final LtRedundantHat lint = new LtRedundantHat(); + MatcherAssert.assertThat( + "Rule id must be 'redundant-hat'", + lint.name(), + Matchers.equalTo("redundant-hat") + ); + } +} From f85cda07e7c549c577213e10c4733ce3a7e9b6fc Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:41:17 +0530 Subject: [PATCH 3/9] Update LtRedundantHatTest.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- src/test/java/org/eolang/lints/LtRedundantHatTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/eolang/lints/LtRedundantHatTest.java b/src/test/java/org/eolang/lints/LtRedundantHatTest.java index 39aa723af..5145a6079 100644 --- a/src/test/java/org/eolang/lints/LtRedundantHatTest.java +++ b/src/test/java/org/eolang/lints/LtRedundantHatTest.java @@ -34,7 +34,7 @@ void reportsNoDefectsForNecessaryHat() throws IOException { } @Test - void motiveContainsGuidance() throws IOException { + void containsGuidanceInMotive() throws IOException { final LtRedundantHat lint = new LtRedundantHat(); MatcherAssert.assertThat( "Motive must explain when to omit redundant '^'", @@ -44,7 +44,7 @@ void motiveContainsGuidance() throws IOException { } @Test - void nameIsStableId() { + void namesStableId() { final LtRedundantHat lint = new LtRedundantHat(); MatcherAssert.assertThat( "Rule id must be 'redundant-hat'", From a392722245c9891f0e53798667c64e5578a981bf Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:12:07 +0530 Subject: [PATCH 4/9] Update LtRedundantHatTest.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../org/eolang/lints/LtRedundantHatTest.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/eolang/lints/LtRedundantHatTest.java b/src/test/java/org/eolang/lints/LtRedundantHatTest.java index 5145a6079..ad736c435 100644 --- a/src/test/java/org/eolang/lints/LtRedundantHatTest.java +++ b/src/test/java/org/eolang/lints/LtRedundantHatTest.java @@ -13,23 +13,23 @@ import org.junit.jupiter.api.Test; /** - * Test case for {@link LtRedundantHat}. + * Test for {@link LtRedundantHat}. * - * @since 0.0.60 + * @since 0.0.1 */ final class LtRedundantHatTest { @Test void reportsNoDefectsForNecessaryHat() throws IOException { final XML xml = new XMLDocument( - "" + "" ); final LtRedundantHat lint = new LtRedundantHat(); final Collection defects = lint.defects(xml); MatcherAssert.assertThat( - "Should not report a defect when '^' is necessary to resolve ambiguity", - defects, - Matchers.empty() + "Should not report a defect when '^' is necessary to resolve ambiguity", + defects, + Matchers.empty() ); } @@ -37,9 +37,9 @@ void reportsNoDefectsForNecessaryHat() throws IOException { void containsGuidanceInMotive() throws IOException { final LtRedundantHat lint = new LtRedundantHat(); MatcherAssert.assertThat( - "Motive must explain when to omit redundant '^'", - lint.motive(), - Matchers.containsString("notation is used when there are no naming conflicts") + "Motive must explain when to omit redundant '^'", + lint.motive(), + Matchers.containsString("notation is redundant and can be omitted for brevity") ); } @@ -47,9 +47,10 @@ void containsGuidanceInMotive() throws IOException { void namesStableId() { final LtRedundantHat lint = new LtRedundantHat(); MatcherAssert.assertThat( - "Rule id must be 'redundant-hat'", - lint.name(), - Matchers.equalTo("redundant-hat") + "Rule id must be 'redundant-hat'", + lint.name(), + Matchers.equalTo("redundant-hat") ); } + } From b1880edf236f53234db4fe48452c7261f7f53692 Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:14:03 +0530 Subject: [PATCH 5/9] Update LtRedundantHat.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../java/org/eolang/lints/LtRedundantHat.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/eolang/lints/LtRedundantHat.java b/src/main/java/org/eolang/lints/LtRedundantHat.java index d9438f394..a1c2a35ac 100644 --- a/src/main/java/org/eolang/lints/LtRedundantHat.java +++ b/src/main/java/org/eolang/lints/LtRedundantHat.java @@ -15,19 +15,22 @@ /** * Lint that warns if a redundant {@code ^} is used. - * - * @since 0.0.60 + * @since 0.0.59 */ final class LtRedundantHat implements Lint { - @Override public Collection defects(final XML xmir) throws IOException { final Collection defects = new ArrayList<>(0); final Xnav xml = new Xnav(xmir.inner()); - final List objects = xml.path("//o[@base='^']").collect(Collectors.toList()); + final List objects = xml + .path("//o[@base='^']") + .collect(Collectors.toList()); for (final Xnav object : objects) { final String name = object.attribute("name").text().get(); - final List parents = object.path(String.format("ancestor::o[.//o[@name='%s']]", name)) + final List parents = object + .path( + String.format("ancestor::o[.//o[@name='%s']]", name) + ) .collect(Collectors.toList()); if (parents.isEmpty()) { defects.add( @@ -49,7 +52,7 @@ public Collection defects(final XML xmir) throws IOException { @Override public String motive() throws IOException { - return "The '^' notation is used when there are no naming conflicts, please omitted for brevity."; + return "The '^' notation is redundant and can be omitted for brevity."; } @Override @@ -57,4 +60,3 @@ public String name() { return "redundant-hat"; } } - From 26ada99eec2f808177b34c2f5f2b5d2db0759f9c Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 19:27:31 +0530 Subject: [PATCH 6/9] Update LtRedundantHat.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../java/org/eolang/lints/LtRedundantHat.java | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/eolang/lints/LtRedundantHat.java b/src/main/java/org/eolang/lints/LtRedundantHat.java index a1c2a35ac..63f610fb9 100644 --- a/src/main/java/org/eolang/lints/LtRedundantHat.java +++ b/src/main/java/org/eolang/lints/LtRedundantHat.java @@ -22,29 +22,49 @@ final class LtRedundantHat implements Lint { public Collection defects(final XML xmir) throws IOException { final Collection defects = new ArrayList<>(0); final Xnav xml = new Xnav(xmir.inner()); - final List objects = xml + final List objs = xml .path("//o[@base='^']") .collect(Collectors.toList()); - for (final Xnav object : objects) { - final String name = object.attribute("name").text().get(); - final List parents = object - .path( - String.format("ancestor::o[.//o[@name='%s']]", name) - ) + for (final Xnav obj : objs) { + final String name = obj.attribute("name").text().orElse(""); + final List matches = xml + .path(String.format("//o[@name='%s']", name)) .collect(Collectors.toList()); - if (parents.isEmpty()) { + final List ancestors = obj + .path(String.format("ancestor::o[@name='%s']", name)) + .collect(Collectors.toList()); + if (matches.size() == 1) { defects.add( new Defect.Default( this.name(), Severity.WARNING, new OnDefault(xmir).get(), - Integer.parseInt(object.attribute("line").text().orElse("0")), + Integer.parseInt(obj.attribute("line").text().orElse("0")), String.format( "Redundant '^' notation: '%s' can be accessed without it", name ) ) ); + } else if (!ancestors.isEmpty() && matches.size() > 1) { + final Xnav target = ancestors.get(0); + for (final Xnav match : matches) { + if (match.equals(target)) { + defects.add( + new Defect.Default( + this.name(), + Severity.WARNING, + new OnDefault(xmir).get(), + Integer.parseInt(obj.attribute("line").text().orElse("0")), + String.format( + "Redundant '^' notation: '%s' resolves to the same object without it", + name + ) + ) + ); + break; + } + } } } return defects; From 0f2b0eb2dcf6efbaced90880d8ae7269a4a0aa3b Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Mon, 15 Sep 2025 19:28:11 +0530 Subject: [PATCH 7/9] Update LtRedundantHatTest.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../org/eolang/lints/LtRedundantHatTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/org/eolang/lints/LtRedundantHatTest.java b/src/test/java/org/eolang/lints/LtRedundantHatTest.java index ad736c435..a5c57466f 100644 --- a/src/test/java/org/eolang/lints/LtRedundantHatTest.java +++ b/src/test/java/org/eolang/lints/LtRedundantHatTest.java @@ -53,4 +53,31 @@ void namesStableId() { ); } + @Test + void doesNotReportDefectWhenCaretIsNecessary() throws IOException { + final String xml = ""; + final XML doc = new XMLDocument(xml); + final LtRedundantHat lint = new LtRedundantHat(); + final Collection defects = lint.defects(doc); + MatcherAssert.assertThat( + "Should not report a defect when '^' is necessary due to ambiguity", + defects, + Matchers.empty() + ); + } + + @Test + void reportsDefectWhenCaretIsRedundantWithMultipleMatches() throws IOException { + final String xml = + ""; + final XML doc = new XMLDocument(xml); + final LtRedundantHat lint = new LtRedundantHat(); + final Collection defects = lint.defects(doc); + MatcherAssert.assertThat( + "Should report a defect when '^' is redundant among multiple matches", + defects, + Matchers.hasSize(1) + ); + } + } From dc746e26c0bea28fc8bc6be2541b439c0bcd4b2c Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:34:23 +0530 Subject: [PATCH 8/9] Update and rename LtRedundantHat.java to LtRedundantRho.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- ...tRedundantHat.java => LtRedundantRho.java} | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) rename src/main/java/org/eolang/lints/{LtRedundantHat.java => LtRedundantRho.java} (79%) diff --git a/src/main/java/org/eolang/lints/LtRedundantHat.java b/src/main/java/org/eolang/lints/LtRedundantRho.java similarity index 79% rename from src/main/java/org/eolang/lints/LtRedundantHat.java rename to src/main/java/org/eolang/lints/LtRedundantRho.java index 63f610fb9..966b39045 100644 --- a/src/main/java/org/eolang/lints/LtRedundantHat.java +++ b/src/main/java/org/eolang/lints/LtRedundantRho.java @@ -11,19 +11,22 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import org.cactoos.io.ResourceOf; +import org.cactoos.text.TextOf; +import org.cactoos.text.UncheckedText; import org.eolang.parser.OnDefault; /** * Lint that warns if a redundant {@code ^} is used. * @since 0.0.59 */ -final class LtRedundantHat implements Lint { +final class LtRedundantRho implements Lint { @Override public Collection defects(final XML xmir) throws IOException { final Collection defects = new ArrayList<>(0); final Xnav xml = new Xnav(xmir.inner()); final List objs = xml - .path("//o[@base='^']") + .path("//o[starts-with(@base,'ξ.ρ')]") .collect(Collectors.toList()); for (final Xnav obj : objs) { final String name = obj.attribute("name").text().orElse(""); @@ -41,7 +44,7 @@ public Collection defects(final XML xmir) throws IOException { new OnDefault(xmir).get(), Integer.parseInt(obj.attribute("line").text().orElse("0")), String.format( - "Redundant '^' notation: '%s' can be accessed without it", + "Redundant 'ξ.ρ' notation: '%s' can be accessed without it", name ) ) @@ -57,7 +60,7 @@ public Collection defects(final XML xmir) throws IOException { new OnDefault(xmir).get(), Integer.parseInt(obj.attribute("line").text().orElse("0")), String.format( - "Redundant '^' notation: '%s' resolves to the same object without it", + "Redundant 'ξ.ρ' notation: '%s' resolves to the same object without it", name ) ) @@ -72,7 +75,15 @@ public Collection defects(final XML xmir) throws IOException { @Override public String motive() throws IOException { - return "The '^' notation is redundant and can be omitted for brevity."; + return new UncheckedText( + new TextOf( + new ResourceOf( + String.format( + "org/eolang/motives/errors/%s.md", this.name() + ) + ) + ) + ).asString(); } @Override From 3775eb8ad8e8b1f47d30ef0459dedee974468be7 Mon Sep 17 00:00:00 2001 From: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:35:15 +0530 Subject: [PATCH 9/9] Update and rename LtRedundantHatTest.java to LtRedundantRhoTest.java Signed-off-by: SNEHA KB <63995915+Snehakb1219-christ@users.noreply.github.com> --- .../org/eolang/lints/LtRedundantHatTest.java | 83 ------------------- .../org/eolang/lints/LtRedundantRhoTest.java | 65 +++++++++++++++ 2 files changed, 65 insertions(+), 83 deletions(-) delete mode 100644 src/test/java/org/eolang/lints/LtRedundantHatTest.java create mode 100644 src/test/java/org/eolang/lints/LtRedundantRhoTest.java diff --git a/src/test/java/org/eolang/lints/LtRedundantHatTest.java b/src/test/java/org/eolang/lints/LtRedundantHatTest.java deleted file mode 100644 index a5c57466f..000000000 --- a/src/test/java/org/eolang/lints/LtRedundantHatTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com - * SPDX-License-Identifier: MIT - */ -package org.eolang.lints; - -import com.jcabi.xml.XML; -import com.jcabi.xml.XMLDocument; -import java.io.IOException; -import java.util.Collection; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; - -/** - * Test for {@link LtRedundantHat}. - * - * @since 0.0.1 - */ -final class LtRedundantHatTest { - - @Test - void reportsNoDefectsForNecessaryHat() throws IOException { - final XML xml = new XMLDocument( - "" - ); - final LtRedundantHat lint = new LtRedundantHat(); - final Collection defects = lint.defects(xml); - MatcherAssert.assertThat( - "Should not report a defect when '^' is necessary to resolve ambiguity", - defects, - Matchers.empty() - ); - } - - @Test - void containsGuidanceInMotive() throws IOException { - final LtRedundantHat lint = new LtRedundantHat(); - MatcherAssert.assertThat( - "Motive must explain when to omit redundant '^'", - lint.motive(), - Matchers.containsString("notation is redundant and can be omitted for brevity") - ); - } - - @Test - void namesStableId() { - final LtRedundantHat lint = new LtRedundantHat(); - MatcherAssert.assertThat( - "Rule id must be 'redundant-hat'", - lint.name(), - Matchers.equalTo("redundant-hat") - ); - } - - @Test - void doesNotReportDefectWhenCaretIsNecessary() throws IOException { - final String xml = ""; - final XML doc = new XMLDocument(xml); - final LtRedundantHat lint = new LtRedundantHat(); - final Collection defects = lint.defects(doc); - MatcherAssert.assertThat( - "Should not report a defect when '^' is necessary due to ambiguity", - defects, - Matchers.empty() - ); - } - - @Test - void reportsDefectWhenCaretIsRedundantWithMultipleMatches() throws IOException { - final String xml = - ""; - final XML doc = new XMLDocument(xml); - final LtRedundantHat lint = new LtRedundantHat(); - final Collection defects = lint.defects(doc); - MatcherAssert.assertThat( - "Should report a defect when '^' is redundant among multiple matches", - defects, - Matchers.hasSize(1) - ); - } - -} diff --git a/src/test/java/org/eolang/lints/LtRedundantRhoTest.java b/src/test/java/org/eolang/lints/LtRedundantRhoTest.java new file mode 100644 index 000000000..c2e614fe0 --- /dev/null +++ b/src/test/java/org/eolang/lints/LtRedundantRhoTest.java @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com + * SPDX-License-Identifier: MIT + */ +package org.eolang.lints; + +import com.jcabi.xml.XMLDocument; +import java.io.IOException; +import org.eolang.parser.EoSyntax; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +/** + * Test for {@link LtRedundantRho}. + * + * @since 0.0.1 + */ +final class LtRedundantRhoTest { + + @Test + void reportsNoDefectsForNecessaryHat() throws Exception { + MatcherAssert.assertThat( + "Should not report a defect when '^' is necessary to resolve ambiguity", + new LtRedundantRho().defects( + new EoSyntax("[] > foo\n+test > @\n^foo > bar").parsed() + ), + Matchers.allOf( + Matchers.iterableWithSize(Matchers.equalTo(0)) + ) + ); + } + + @Test + void namesStableId() { + MatcherAssert.assertThat( + "Rule id must be 'redundant-hat'", + new LtRedundantRho().name(), + Matchers.equalTo("redundant-hat") + ); + } + + @Test + void doesNotReportDefectWhenCaretIsNecessary() throws IOException { + MatcherAssert.assertThat( + "Should not report a defect when '^' is necessary due to ambiguity", + new LtRedundantRho().defects( + new EoSyntax("[] > foo\n+test > @\n^foo > bar").parsed() + ), + Matchers.empty() + ); + } + + @Test + void reportsDefectWhenCaretIsRedundantWithMultipleMatches() throws IOException { + MatcherAssert.assertThat( + "Should report a defect when '^' is redundant among multiple matches", + new LtRedundantRho().defects( + new XMLDocument("") + ), + Matchers.hasSize(1) + ); + } + +}