Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lint/UnusedComparison and Lint/UnusedLiteral #507

Merged
merged 12 commits into from
Dec 7, 2024

Conversation

nobodywasishere
Copy link
Contributor

@nobodywasishere nobodywasishere commented Nov 22, 2024

Closes #235
Closes #508

This is still a little WIP, I need to go through the code again and write more / better specs. Maybe the visitor can be moved to the main visitors, as it may be useful for writing other Lint/Useless* rules. It's basically useful for checking if the return value from a node will be captured or not, which is how I determined whether the comparison operations were useful.

image

@Sija Sija added the rule label Nov 22, 2024
@Sija
Copy link
Member

Sija commented Nov 22, 2024

Nice one ❤️ I'd rename the rule to UnusedComparison though, useless IMO brings some negative connotations.

@Sija
Copy link
Member

Sija commented Nov 22, 2024

I'll do the code review once you mark the PR as ready for review, just FYI.

@nobodywasishere nobodywasishere changed the title Add Lint/UselessComparison Add Lint/UnusedComparison and Lint/UnusedLiteral Nov 23, 2024
@nobodywasishere
Copy link
Contributor Author

I'll do the code review once you mark the PR as ready for review, just FYI.

Yeah that's why I marked it as draft, so you wouldn't waste time reviewing it only for me to completely change it.

@nobodywasishere nobodywasishere marked this pull request as ready for review November 23, 2024 08:47
@nobodywasishere
Copy link
Contributor Author

Running these rules over the ameba, Kagi, and crystal compiler codebases, didn't turn up any violations. Don't know if that's due to a bug in the rules or violations being rare, though I'm leaning towards the latter.

@nobodywasishere
Copy link
Contributor Author

The only literal that isn't supported is RegexLiteral, and that's due to them not having a location.

@nobodywasishere nobodywasishere force-pushed the nobody/useless-comparison branch from d7ff0fe to 385ce89 Compare November 27, 2024 16:23
@straight-shoota
Copy link
Contributor

Adding location to RegexLiteral in crystal-lang/crystal#15235

src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
src/ameba/rule/lint/unused_comparison.cr Outdated Show resolved Hide resolved
src/ameba/rule/lint/unused_comparison.cr Outdated Show resolved Hide resolved
src/ameba/rule/lint/unused_literal.cr Outdated Show resolved Hide resolved
@Sija Sija added this to the 1.7.0 milestone Nov 30, 2024
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
spec/ameba/rule/lint/unused_literal_spec.cr Outdated Show resolved Hide resolved
src/ameba/ast/visitors/implicit_return_visitor.cr Outdated Show resolved Hide resolved
Co-authored-by: Sijawusz Pur Rahnama <[email protected]>
@nobodywasishere
Copy link
Contributor Author

If desired, I can add support for regex literals gated behind whether Ameba is built with Crystal 1.15.0 or later. This way, support can be added and merged now without requiring ameba to update its minimum version from 1.10

diff --git a/spec/ameba/rule/lint/unused_literal_spec.cr b/spec/ameba/rule/lint/unused_literal_spec.cr
index 5c22ea7b..7494a0ba 100644
--- a/spec/ameba/rule/lint/unused_literal_spec.cr
+++ b/spec/ameba/rule/lint/unused_literal_spec.cr
@@ -252,5 +252,16 @@ module Ameba::Rule::Lint
           end
       CRYSTAL
     end
+
+    # Locations for Regex literals were added in Crystal v1.15.0
+    {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %}
+      it "fails if a regex literal is unused" do
+        expect_issue subject, <<-CRYSTAL
+            a = /hello world/
+            /goodnight moon/
+          # ^^^^^^^^^^^^^^^^ error: Literal value is not used
+          CRYSTAL
+      end
+    {% end %}
   end
 end
diff --git a/src/ameba/rule/lint/unused_literal.cr b/src/ameba/rule/lint/unused_literal.cr
index 50b3fdd6..cdf30201 100644
--- a/src/ameba/rule/lint/unused_literal.cr
+++ b/src/ameba/rule/lint/unused_literal.cr
@@ -57,6 +57,14 @@ module Ameba::Rule::Lint
       AST::ImplicitReturnVisitor.new(self, source)
     end
 
+    # Locations for Regex literals were added in Crystal v1.15.0
+    {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %}
+      def test(source, node : Crystal::RegexLiteral, last_is_used : Bool) : Bool
+        issue_for node, MSG unless last_is_used
+        true
+      end
+    {% end %}
+
     def test(
       source,
       node : Crystal::BoolLiteral | Crystal::CharLiteral | Crystal::HashLiteral |

@Sija
Copy link
Member

Sija commented Dec 3, 2024

@nobodywasishere That would be great 🚀

@Sija Sija requested a review from veelenga December 4, 2024 05:34
RegexLiteral values should be counted as used
Add spec ensuring unused regex literals aren't counted for Crystal < 1.15
@Sija Sija requested a review from veelenga December 6, 2024 23:43
Copy link
Member

@veelenga veelenga left a comment

Choose a reason for hiding this comment

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

LGTM. Great job 👏🏻

@Sija Sija merged commit 5b3c2cf into crystal-ameba:master Dec 7, 2024
4 checks passed
@nobodywasishere nobodywasishere deleted the nobody/useless-comparison branch December 7, 2024 17:46
@carlhoerberg
Copy link
Contributor

Seems to think that IO.copy(in, out, len) == len || raise IO::EOFError.new is an unused comparison, and that { error: "abc" }.to_json(context.response) is an unused literal.

@nobodywasishere
Copy link
Contributor Author

Good catch! I'll do a follow-up PR trying to limit these edge-cases. Since it's impossible to know whether a method has side-effects, I may not catch || and && if one of them is a call, and not catch literals if they're the object of a call. I'll also do some tests to see if there are other edge-cases like this that need to be handled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Lint/UnusedLiteral Condition in void context
5 participants