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

Support @[Deprecated] on annotation #12557

58 changes: 58 additions & 0 deletions spec/compiler/semantic/warnings_spec.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
require "../spec_helper"

describe "Semantic: warnings" do
describe "deprecated aliases" do
it "detects deprecated aliases" do
assert_warning <<-CR,
struct SomeType; end

@[Deprecated]
alias OtherType = SomeType

OtherType.new
CR
"warning in line 4\nWarning: Deprecated alias OtherType."
end

it "detects deprecated namespaced aliases" do
assert_warning <<-CR,
struct SomeType; end

module MyNamespace
@[Deprecated]
alias OtherType = SomeType
end

MyNamespace::OtherType.new
CR
"warning in line 5\nWarning: Deprecated alias MyNamespace::OtherType."
end
end

describe "deprecated annotations" do
it "detects deprecated annotations" do
assert_warning <<-CR,
@[Deprecated]
annotation Foo; end

@[Foo]
def bar; end

bar
CR
"warning in line 2\nWarning: Deprecated annotation Foo."
end

it "detects deprecated namespaced annotations" do
assert_warning <<-CR,
module MyNamespace
@[Deprecated]
annotation Foo; end
end

@[MyNamespace::Foo]
def bar; end

bar
CR
"warning in line 3\nWarning: Deprecated annotation MyNamespace::Foo."
end
end

describe "deprecated methods" do
it "detects top-level deprecated methods" do
assert_warning <<-CR,
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/crystal/semantic/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,17 @@ module Crystal
end

class Alias
include Annotatable

property! resolved_type : AliasType
end

class AnnotationDef
include Annotatable

property! resolved_type : AnnotationType
end

class External < Def
property real_name : String
property! fun_def : FunDef
Expand Down
12 changes: 12 additions & 0 deletions src/compiler/crystal/semantic/cleanup_transformer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ module Crystal
{@last_is_truthy, @last_is_falsey}
end

def transform(node : Alias)
caspiano marked this conversation as resolved.
Show resolved Hide resolved
@program.check_call_to_deprecated_alias node

node
end

def transform(node : AnnotationDef)
@program.check_call_to_deprecated_annotation node

node
end

def transform(node : Def)
node.hook_expansions.try &.map! &.transform self
node
Expand Down
13 changes: 12 additions & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
def visit(node : AnnotationDef)
check_outside_exp node, "declare annotation"

annotations = read_annotations
process_annotations(annotations) do |annotation_type, ann|
node.add_annotation(annotation_type, ann)
end

scope, name, type = lookup_type_def(node)

if type
Expand All @@ -286,7 +291,9 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
scope.types[name] = type
end

attach_doc type, node, annotations: nil
node.resolved_type = type

attach_doc type, node, annotations

false
end
Expand All @@ -296,6 +303,10 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor

annotations = read_annotations

process_annotations(annotations) do |annotation_type, ann|
node.add_annotation(annotation_type, ann)
end

scope, name, existing_type = lookup_type_def(node)

if existing_type
Expand Down
26 changes: 26 additions & 0 deletions src/compiler/crystal/semantic/warnings.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ module Crystal
@deprecated_constants_detected = Set(String).new
@deprecated_methods_detected = Set(String).new
@deprecated_macros_detected = Set(String).new
@deprecated_aliases_detected = Set(String).new
@deprecated_annotations_detected = Set(String).new

def check_deprecated_constant(const : Const, node : Path)
return unless @warnings.level.all?
Expand All @@ -30,6 +32,18 @@ module Crystal
end
end

def check_call_to_deprecated_alias(node : Alias) : Nil
return unless @warnings.level.all?

check_deprecation(node, node.name, @deprecated_aliases_detected)
end

def check_call_to_deprecated_annotation(node : AnnotationDef) : Nil
return unless @warnings.level.all?

check_deprecation(node, node.name, @deprecated_aliases_detected)
end

private def check_deprecation(object, use_site, detects)
if (ann = object.annotation(self.deprecated_annotation)) &&
(deprecated_annotation = DeprecatedAnnotation.from(ann))
Expand Down Expand Up @@ -59,6 +73,18 @@ module Crystal
end
end

class Alias
def short_reference
"alias #{resolved_type}"
end
end

class AnnotationDef
def short_reference
"annotation #{resolved_type}"
end
end

class Macro
def short_reference
case owner
Expand Down