From b06299a2aa24818eb4b908ae965314506f659ea3 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 29 Jan 2025 10:49:25 -0500 Subject: [PATCH 1/4] Add `Lint/UnusedPseudoMethod` --- .../rule/lint/unused_pseudo_method_spec.cr | 60 +++++++++++++++++ src/ameba/rule/lint/unused_pseudo_method.cr | 64 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 spec/ameba/rule/lint/unused_pseudo_method_spec.cr create mode 100644 src/ameba/rule/lint/unused_pseudo_method.cr diff --git a/spec/ameba/rule/lint/unused_pseudo_method_spec.cr b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr new file mode 100644 index 000000000..739c44a9b --- /dev/null +++ b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr @@ -0,0 +1,60 @@ +require "../../../spec_helper" + +module Ameba::Rule::Lint + subject = UnusedPseudoMethod.new + + describe UnusedPseudoMethod do + it "passes if return value of typeof or as isn't used" do + expect_no_issues subject, <<-CRYSTAL + typeof(1) + as(Int32) + CRYSTAL + end + + it "fails if pseudo methods are unused top-level" do + expect_issue subject, <<-CRYSTAL + pointerof(Int32) + # ^^^^^^^^^^^^^^ error: Pesudo-method is not used + sizeof(Int32) + # ^^^^^^^^^^^ error: Pesudo-method is not used + instance_sizeof(Int32) + # ^^^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + alignof(Int32) + # ^^^^^^^^^^^^ error: Pesudo-method is not used + instance_alignof(Int32) + # ^^^^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + offsetof(Int32, 1) + # ^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + is_a?(Int32) + # ^^^^^^^^^^ error: Pesudo-method is not used + as?(Int32) + # ^^^^^^^^ error: Pesudo-method is not used + responds_to?(:hello) + # ^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + nil? + # ^^ error: Pesudo-method is not used + true.! + # ^^^^ error: Pesudo-method is not used + !true + # ^^^ error: Pesudo-method is not used + CRYSTAL + end + + it "passes if pseudo methods are used as assign values" do + expect_no_issues subject, <<-CRYSTAL + var = pointerof(Int32) + var = sizeof(Int32) + var = instance_sizeof(Int32) + var = alignof(Int32) + var = instance_alignof(Int32) + var = offsetof(Int32, 1) + var = is_a?(Int32) + var = as?(Int32) + var = responds_to?(:hello) + var = nil? + var = true.! + var = !true + CRYSTAL + end + end +end diff --git a/src/ameba/rule/lint/unused_pseudo_method.cr b/src/ameba/rule/lint/unused_pseudo_method.cr new file mode 100644 index 000000000..88c45b3e4 --- /dev/null +++ b/src/ameba/rule/lint/unused_pseudo_method.cr @@ -0,0 +1,64 @@ +module Ameba::Rule::Lint + # A rule that disallows unused pseudo methods (is_a?, sizeof, etc). + # + # For example, these are considered invalid: + # + # ``` + # pointerof(1234_f32) + # + # method_call.as(Int32) + # + # def method + # if guard? + # !!valid? + # end + # + # true + # end + # ``` + # + # And these are considered valid: + # + # ``` + # a : pointerof(1234_f32) + # + # var = method_call.as(Int32) + # + # def method + # if guard? + # return !!valid? + # end + # + # true + # end + # ``` + # + # YAML configuration example: + # + # ``` + # Lint/UnusedPseudoMethod: + # Enabled: true + # ``` + class UnusedPseudoMethod < Base + properties do + since_version "1.7.0" + description "Disallows unused pseudo-methods" + end + + MSG = "Pesudo-method is not used" + + def test(source : Source) + AST::ImplicitReturnVisitor.new(self, source) + end + + def test( + source, + node : Crystal::PointerOf | Crystal::SizeOf | Crystal::InstanceSizeOf | + Crystal::AlignOf | Crystal::InstanceAlignOf | Crystal::OffsetOf | + Crystal::IsA | Crystal::NilableCast | Crystal::RespondsTo | Crystal::Not, + node_is_used : Bool, + ) + issue_for node, MSG unless node_is_used + end + end +end From cfa3b5ef33a3d6a5f7fb0638bc25dbe11d097d21 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 29 Jan 2025 10:49:32 -0500 Subject: [PATCH 2/4] Add `Lint/UnusedSelf` --- spec/ameba/rule/lint/unused_self_spec.cr | 47 +++++++++++++++++++++ src/ameba/rule/lint/unused_self.cr | 52 ++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 spec/ameba/rule/lint/unused_self_spec.cr create mode 100644 src/ameba/rule/lint/unused_self.cr diff --git a/spec/ameba/rule/lint/unused_self_spec.cr b/spec/ameba/rule/lint/unused_self_spec.cr new file mode 100644 index 000000000..623976e2d --- /dev/null +++ b/spec/ameba/rule/lint/unused_self_spec.cr @@ -0,0 +1,47 @@ +require "../../../spec_helper" + +module Ameba::Rule::Lint + subject = UnusedSelf.new + + describe UnusedSelf do + it "passes if self is used" do + expect_no_issues subject, <<-CRYSTAL + class MyClass + class_property name : String = "George" + + def self.hello + puts "hello, #{self.name}!" + end + + def name : String + name.self + + self.class.name + end + end + CRYSTAL + end + + it "fails if self is unused" do + expect_issue subject, <<-CRYSTAL + class MyClass + self + # ^^^^ error: `self` is not used + + class_property name : String = begin + self + # ^^^^ error: `self` is not used + + "George" + end + + def self.hello + self + # ^^^^ error: `self` is not used + puts "hello, #{self.name}!" + end + end + CRYSTAL + end + end +end diff --git a/src/ameba/rule/lint/unused_self.cr b/src/ameba/rule/lint/unused_self.cr new file mode 100644 index 000000000..33da17a76 --- /dev/null +++ b/src/ameba/rule/lint/unused_self.cr @@ -0,0 +1,52 @@ +module Ameba::Rule::Lint + # A rule that disallows unused `self`. + # + # For example, this is considered invalid: + # + # ``` + # class MyClass + # self + # end + # ``` + # + # And these are considered valid: + # + # ``` + # class MyClass + # def self.hello + # puts "Hello, world!" + # end + # + # self.hello + # end + # ``` + # + # YAML configuration example: + # + # ``` + # Lint/UnusedSelf: + # Enabled: true + # ``` + class UnusedSelf < Base + properties do + since_version "1.7.0" + description "Disallows unused self" + end + + MSG = "`self` is not used" + + def test(source : Source) + AST::ImplicitReturnVisitor.new(self, source) + end + + def test(source, node : Crystal::Self, node_is_used : Bool) + issue_for node, MSG unless node_is_used + end + + def test(source, node : Crystal::Var, node_is_used : Bool) + return if node_is_used || node.name != "self" + + issue_for node, MSG + end + end +end From 9c3e0a193b539056a0f91aa399fee9c7d944e130 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 29 Jan 2025 16:41:29 -0500 Subject: [PATCH 3/4] Move subjects --- spec/ameba/rule/lint/unused_pseudo_method_spec.cr | 4 ++-- spec/ameba/rule/lint/unused_self_spec.cr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/ameba/rule/lint/unused_pseudo_method_spec.cr b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr index 739c44a9b..97fe62696 100644 --- a/spec/ameba/rule/lint/unused_pseudo_method_spec.cr +++ b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedPseudoMethod.new - describe UnusedPseudoMethod do + subject = UnusedPseudoMethod.new + it "passes if return value of typeof or as isn't used" do expect_no_issues subject, <<-CRYSTAL typeof(1) diff --git a/spec/ameba/rule/lint/unused_self_spec.cr b/spec/ameba/rule/lint/unused_self_spec.cr index 623976e2d..a4c341892 100644 --- a/spec/ameba/rule/lint/unused_self_spec.cr +++ b/spec/ameba/rule/lint/unused_self_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedSelf.new - describe UnusedSelf do + subject = UnusedSelf.new + it "passes if self is used" do expect_no_issues subject, <<-CRYSTAL class MyClass From e737603d5f44e947f310178c8d39744cac3c737e Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 29 Jan 2025 16:48:59 -0500 Subject: [PATCH 4/4] Spelling --- .../rule/lint/unused_pseudo_method_spec.cr | 24 +++++++++---------- src/ameba/rule/lint/unused_pseudo_method.cr | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/spec/ameba/rule/lint/unused_pseudo_method_spec.cr b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr index 97fe62696..552ec8a7d 100644 --- a/spec/ameba/rule/lint/unused_pseudo_method_spec.cr +++ b/spec/ameba/rule/lint/unused_pseudo_method_spec.cr @@ -14,29 +14,29 @@ module Ameba::Rule::Lint it "fails if pseudo methods are unused top-level" do expect_issue subject, <<-CRYSTAL pointerof(Int32) - # ^^^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^^^ error: Pseudo-method is not used sizeof(Int32) - # ^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^ error: Pseudo-method is not used instance_sizeof(Int32) - # ^^^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^^^^^^^^^ error: Pseudo-method is not used alignof(Int32) - # ^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^ error: Pseudo-method is not used instance_alignof(Int32) - # ^^^^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^^^^^^^^^^ error: Pseudo-method is not used offsetof(Int32, 1) - # ^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^^^^^ error: Pseudo-method is not used is_a?(Int32) - # ^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^ error: Pseudo-method is not used as?(Int32) - # ^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^ error: Pseudo-method is not used responds_to?(:hello) - # ^^^^^^^^^^^^^^^^^^ error: Pesudo-method is not used + # ^^^^^^^^^^^^^^^^^^ error: Pseudo-method is not used nil? - # ^^ error: Pesudo-method is not used + # ^^ error: Pseudo-method is not used true.! - # ^^^^ error: Pesudo-method is not used + # ^^^^ error: Pseudo-method is not used !true - # ^^^ error: Pesudo-method is not used + # ^^^ error: Pseudo-method is not used CRYSTAL end diff --git a/src/ameba/rule/lint/unused_pseudo_method.cr b/src/ameba/rule/lint/unused_pseudo_method.cr index 88c45b3e4..88fd92f43 100644 --- a/src/ameba/rule/lint/unused_pseudo_method.cr +++ b/src/ameba/rule/lint/unused_pseudo_method.cr @@ -45,7 +45,7 @@ module Ameba::Rule::Lint description "Disallows unused pseudo-methods" end - MSG = "Pesudo-method is not used" + MSG = "Pseudo-method is not used" def test(source : Source) AST::ImplicitReturnVisitor.new(self, source)