diff --git a/spec/ameba/rule/lint/unused_pseudo_method_call_spec.cr b/spec/ameba/rule/lint/unused_pseudo_method_call_spec.cr new file mode 100644 index 000000000..1ae61b87c --- /dev/null +++ b/spec/ameba/rule/lint/unused_pseudo_method_call_spec.cr @@ -0,0 +1,181 @@ +require "../../../spec_helper" + +module Ameba::Rule::Lint + describe UnusedPseudoMethodCall do + subject = UnusedPseudoMethodCall.new + + it "passes if typeof is unused" do + expect_no_issues subject, <<-CRYSTAL + typeof(1) + CRYSTAL + end + + it "passes if as is unused" do + expect_no_issues subject, <<-CRYSTAL + as(Int32) + CRYSTAL + end + + it "fails if pointerof is unused" do + expect_issue subject, <<-CRYSTAL + pointerof(Int32) + # ^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if sizeof is unused" do + expect_issue subject, <<-CRYSTAL + sizeof(Int32) + # ^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if instance_sizeof is unused" do + expect_issue subject, <<-CRYSTAL + instance_sizeof(Int32) + # ^^^^^^^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if alignof is unused" do + expect_issue subject, <<-CRYSTAL + alignof(Int32) + # ^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if instance_alignof is unused" do + expect_issue subject, <<-CRYSTAL + instance_alignof(Int32) + # ^^^^^^^^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if offsetof is unused" do + expect_issue subject, <<-CRYSTAL + offsetof(Int32, 1) + # ^^^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if is_a? is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + foo.is_a?(Int32) + # ^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if as? is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + foo.as?(Int32) + # ^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if responds_to? is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + foo.responds_to?(:bar) + # ^^^^^^^^^^^^^^^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if nil? is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + foo.nil? + # ^^^^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if prefix not is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + !foo + # ^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "fails if suffix not is unused" do + expect_issue subject, <<-CRYSTAL + foo = 1 + foo.! + # ^^^ error: Pseudo-method call is not used + CRYSTAL + end + + it "passes if pointerof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = pointerof(Int32) + CRYSTAL + end + + it "passes if sizeof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = sizeof(Int32) + CRYSTAL + end + + it "passes if instance_sizeof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = instance_sizeof(Int32) + CRYSTAL + end + + it "passes if alignof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = alignof(Int32) + CRYSTAL + end + + it "passes if instance_alignof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = instance_alignof(Int32) + CRYSTAL + end + + it "passes if offsetof is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = offsetof(Int32, 1) + CRYSTAL + end + + it "passes if is_a? is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = is_a?(Int32) + CRYSTAL + end + + it "passes if as? is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = as?(Int32) + CRYSTAL + end + + it "passes if responds_to? is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = responds_to?(:foo) + CRYSTAL + end + + it "passes if nil? is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = nil? + CRYSTAL + end + + it "passes if prefix not is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = !true + CRYSTAL + end + + it "passes if suffix not is used as an assign value" do + expect_no_issues subject, <<-CRYSTAL + var = true.! + CRYSTAL + end + end +end diff --git a/src/ameba/rule/lint/unused_pseudo_method_call.cr b/src/ameba/rule/lint/unused_pseudo_method_call.cr new file mode 100644 index 000000000..56aa6e4f3 --- /dev/null +++ b/src/ameba/rule/lint/unused_pseudo_method_call.cr @@ -0,0 +1,44 @@ +module Ameba::Rule::Lint + # A rule that disallows unused pseudo method calls (is_a?, sizeof, etc). + # + # For example, these are considered invalid: + # + # ``` + # pointerof(foo) + # sizeof(Bar) + # + # def method + # !!valid? if guard? + # nil + # end + # ``` + # + # YAML configuration example: + # + # ``` + # Lint/UnusedPseudoMethodCall: + # Enabled: true + # ``` + class UnusedPseudoMethodCall < Base + properties do + since_version "1.7.0" + description "Disallows unused pseudo-method calls" + end + + MSG = "Pseudo-method call 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, + in_macro : Bool, + ) + issue_for node, MSG + end + end +end