/
raise_exception.rb
75 lines (63 loc) · 2.14 KB
/
raise_exception.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# frozen_string_literal: true
module RuboCop
module Cop
module Lint
# This cop checks for `raise` or `fail` statements which are
# raising `Exception` class.
#
# You can specify a module name that will be an implicit namespace
# using `AllowedImplicitNamespaces` option. The cop cause a false positive
# for namespaced `Exception` when a namespace is omitted. This option can
# prevent the false positive by specifying a namespace to be omitted for
# `Exception`. Alternatively, make `Exception` a fully qualified class
# name with an explicit namespace.
#
# @example
# # bad
# raise Exception, 'Error message here'
#
# # good
# raise StandardError, 'Error message here'
#
# @example AllowedImplicitNamespaces: ['Gem']
# # good
# module Gem
# def self.foo
# raise Exception # This exception means `Gem::Exception`.
# end
# end
class RaiseException < Cop
MSG = 'Use `StandardError` over `Exception`.'
def_node_matcher :exception?, <<~PATTERN
(send nil? {:raise :fail} (const ${cbase nil?} :Exception) ... )
PATTERN
def_node_matcher :exception_new_with_message?, <<~PATTERN
(send nil? {:raise :fail}
(send (const ${cbase nil?} :Exception) :new ... ))
PATTERN
def on_send(node)
exception?(node, &check(node)) ||
exception_new_with_message?(node, &check(node))
end
private
def check(node)
lambda do |cbase|
return if cbase.nil? && implicit_namespace?(node)
add_offense(node)
end
end
def implicit_namespace?(node)
return false unless (parent = node.parent)
if parent.module_type?
namespace = parent.identifier.source
return allow_implicit_namespaces.include?(namespace)
end
implicit_namespace?(parent)
end
def allow_implicit_namespaces
cop_config['AllowedImplicitNamespaces'] || []
end
end
end
end
end