diff --git a/src/main/java/org/eolang/lints/LtAsciiOnly.java b/src/main/java/org/eolang/lints/LtAsciiOnly.java index ba2d5f383..555f39f91 100644 --- a/src/main/java/org/eolang/lints/LtAsciiOnly.java +++ b/src/main/java/org/eolang/lints/LtAsciiOnly.java @@ -16,10 +16,6 @@ /** * A comment must include only ASCII characters. * @since 0.1.0 - * @todo #14:35min Calculate comment line number with abusive character. - * For now we just reusing object line number (via @line), which is not correct - * for specifying on which line of the program comment is located. This issue - * can be solved after this one. * @todo #402:15min Replace the creation of new ArrayList<>(0) with the creation of * ArrayList<>() without a constructor argument in whole project. Add ignore warning * ConditionalRegexpMultilineCheck from Checkstyle (it doesn't seem to be possible at the moment @@ -32,6 +28,8 @@ final class LtAsciiOnly implements Lint { public Collection defects(final XML xmir) throws IOException { final Collection defects = new ArrayList<>(0); final Xnav xml = new Xnav(xmir.inner()); + final Optional listing = xml.path("//listing") + .findFirst().map(elem -> elem.text().get()); final List comments = xml.path("/object/comments/comment") .collect(Collectors.toList()); for (final Xnav comment : comments) { @@ -42,8 +40,23 @@ public Collection defects(final XML xmir) throws IOException { if (!abusive.isPresent()) { continue; } - final int line = new LineOf(comment).value(); final Character chr = abusive.get(); + final String text = comment.text().get(); + final int pos = text.indexOf(chr); + final int line; + if (listing.isPresent()) { + final Optional found = LtAsciiOnly.locate( + listing.get(), text + ); + if (found.isPresent()) { + line = found.get() + (int) text.substring(0, pos).chars() + .filter(c -> c == '\n').count(); + } else { + line = new LineOf(comment).value(); + } + } else { + line = new LineOf(comment).value(); + } defects.add( new Defect.Default( "ascii-only", @@ -53,7 +66,7 @@ public Collection defects(final XML xmir) throws IOException { "Only ASCII characters are allowed in comments, while \"%s\" is used at the line no.%s at the position no.%s", chr, line, - comment.text().get().indexOf(chr) + 1 + pos + 1 ) ) ); @@ -75,4 +88,34 @@ public String motive() throws IOException { public Fix fix() { return new FxEmpty(); } + + /** + * Real source line of the abusive character. + * The comment text is located in the program listing, where each line + * starts with the {@code #} sign. The line of the character is the line + * of the first line of the comment. + * @param listing Full program listing + * @param text Comment text + * @return Real source line of the first line of the comment, if found + */ + private static Optional locate(final String listing, final String text) { + final int newline = text.indexOf('\n'); + final String headline; + if (newline < 0) { + headline = text; + } else { + headline = text.substring(0, newline); + } + final int index = listing.indexOf("# ".concat(headline)); + final Optional result; + if (index < 0) { + result = Optional.empty(); + } else { + result = Optional.of( + (int) listing.substring(0, index).chars() + .filter(chr -> chr == '\n').count() + 1 + ); + } + return result; + } } diff --git a/src/main/resources/org/eolang/lints/misc/redundant-attachment.xsl b/src/main/resources/org/eolang/lints/misc/redundant-attachment.xsl index 9288c9536..ed70c2a89 100644 --- a/src/main/resources/org/eolang/lints/misc/redundant-attachment.xsl +++ b/src/main/resources/org/eolang/lints/misc/redundant-attachment.xsl @@ -21,13 +21,6 @@ - diff --git a/src/main/resources/org/eolang/motives/misc/redundant-attachment.md b/src/main/resources/org/eolang/motives/misc/redundant-attachment.md index 6b1ae81fc..57f67ebed 100644 --- a/src/main/resources/org/eolang/motives/misc/redundant-attachment.md +++ b/src/main/resources/org/eolang/motives/misc/redundant-attachment.md @@ -62,16 +62,3 @@ written in the source, is left alone too. The `!` suffix on a nameless argument is such a case: `m.plus m!` makes the parser wrap `m` into a named `.as-bytes` over `Φ.dataized`, and no `>>` exists in the source to be removed. - -A void attribute declared as `? >> name` is left alone as well. The name -after `>>` is only a local alias, while the published name is generated by -the parser. The `>>` cannot be dropped, because the grammar has no nameless -void, and switching to `? > name` would publish the attribute under `name` -and change dispatch: - -```eo -[] > choice - ? >> left - ? >> right - left > @ -``` diff --git a/src/test/java/org/eolang/lints/LtAsciiOnlyTest.java b/src/test/java/org/eolang/lints/LtAsciiOnlyTest.java index f7f6f0cb4..28c0efadc 100644 --- a/src/test/java/org/eolang/lints/LtAsciiOnlyTest.java +++ b/src/test/java/org/eolang/lints/LtAsciiOnlyTest.java @@ -87,4 +87,30 @@ void doesNotFlagNewlinesInMultilineComment() throws IOException { Matchers.emptyIterable() ); } + + @Test + void reportsCorrectLineInMultilineComment() throws IOException { + MatcherAssert.assertThat( + "The abusive character is on the second line of the comment", + new ListOf<>( + new LtAsciiOnly().defects( + new EoProgram("org/eolang/lints/non-ascii-multiline.eo").parse() + ) + ).get(0).line(), + Matchers.equalTo(2) + ); + } + + @Test + void reportsCorrectLineInTheMiddle() throws IOException { + MatcherAssert.assertThat( + "The abusive character is on the second line of a three-line comment", + new ListOf<>( + new LtAsciiOnly().defects( + new EoProgram("org/eolang/lints/non-ascii-middle.eo").parse() + ) + ).get(0).line(), + Matchers.equalTo(2) + ); + } } diff --git a/src/test/resources/org/eolang/lints/non-ascii-middle.eo b/src/test/resources/org/eolang/lints/non-ascii-middle.eo new file mode 100644 index 000000000..f6cff4185 --- /dev/null +++ b/src/test/resources/org/eolang/lints/non-ascii-middle.eo @@ -0,0 +1,8 @@ +# first +# привет middle +# last + ++spdx SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com ++spdx SPDX-License-Identifier: MIT + +[] > foo diff --git a/src/test/resources/org/eolang/lints/non-ascii-multiline.eo b/src/test/resources/org/eolang/lints/non-ascii-multiline.eo new file mode 100644 index 000000000..b2cdbf1ce --- /dev/null +++ b/src/test/resources/org/eolang/lints/non-ascii-multiline.eo @@ -0,0 +1,7 @@ +# This comment is fine +# but here привет + ++spdx SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com ++spdx SPDX-License-Identifier: MIT + +[] > foo diff --git a/src/test/resources/org/eolang/lints/unlint-ascii-only-line.eo b/src/test/resources/org/eolang/lints/unlint-ascii-only-line.eo index 007363169..30a52fde6 100644 --- a/src/test/resources/org/eolang/lints/unlint-ascii-only-line.eo +++ b/src/test/resources/org/eolang/lints/unlint-ascii-only-line.eo @@ -2,6 +2,6 @@ +spdx SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +spdx SPDX-License-Identifier: MIT -+unlint ascii-only:3 ++unlint ascii-only:1 [] > hello