From d45ef5990b9eba9770745a509ede1da4f392f710 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 7 Jun 2017 16:11:06 +0200 Subject: [PATCH 1/2] Add TypeNode#has_method? --- src/compiler/crystal/macros.cr | 6 ++++++ src/compiler/crystal/macros/methods.cr | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr index 52668f91c810..90f69ef59b7d 100644 --- a/src/compiler/crystal/macros.cr +++ b/src/compiler/crystal/macros.cr @@ -1543,6 +1543,12 @@ module Crystal::Macros def methods : ArrayLiteral(Def) end + # Returns `true` if this type has a method. For example `default_options` + # (the name you pass to this method is "default_options" or :default_options + # in this cases). + def has_method?(name : StringLiteral | SymbolLiteral) : BoolLiteral + end + # Returns true if this type has an attribute. For example `@[Flags]` # or `@[Packed]` (the name you pass to this method is "Flags" or "Packed" # in these cases). diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr index ce5543df332c..259b92d2e3ad 100644 --- a/src/compiler/crystal/macros/methods.cr +++ b/src/compiler/crystal/macros/methods.cr @@ -1346,6 +1346,11 @@ module Crystal end when "methods" interpret_argless_method(method, args) { TypeNode.methods(type) } + when "has_method?" + interpret_one_arg_method(method, args) do |arg| + value = arg.to_string("argument to 'TypeNode#has_method?'") + TypeNode.has_method?(type, value) + end when "has_attribute?" interpret_one_arg_method(method, args) do |arg| value = arg.to_string("argument to 'TypeNode#has_attribute?'") @@ -1533,6 +1538,10 @@ module Crystal ArrayLiteral.new(defs) end + def self.has_method?(type, name) + BoolLiteral.new(!!type.has_def?(name)) + end + def self.overrides?(type, target, method) overrides = type.lookup_defs(method).any? do |a_def| a_def.owner != target && a_def.macro_owner != target && !target.implements?(a_def.owner) From fe3ae02183f769a1dbfc846f3d684d861116f226 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 7 Jun 2017 16:37:41 +0200 Subject: [PATCH 2/2] Add specs for TypeNode#has_method? --- spec/compiler/codegen/macro_spec.cr | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/compiler/codegen/macro_spec.cr b/spec/compiler/codegen/macro_spec.cr index ad02ea2785f8..b5bbbc1bd8f1 100644 --- a/spec/compiler/codegen/macro_spec.cr +++ b/spec/compiler/codegen/macro_spec.cr @@ -1601,6 +1601,30 @@ describe "Code gen: macro" do )).to_b.should be_false end + it "determines if method exists (true)" do + run(%( + class Foo + def foo + 42 + end + end + + {{ Foo.has_method?(:foo) }} + )).to_b.should be_true + end + + it "determines if method exists (false)" do + run(%( + class Foo + def foo + 42 + end + end + + {{ Foo.has_method?(:bar) }} + )).to_b.should be_false + end + it "forwards file location" do run(%( macro foo