Module: MilkTea::Linter::LinterReservedNames

Included in:
MilkTea::Linter
Defined in:
lib/milk_tea/tooling/linter/reserved_names.rb

Instance Method Summary collapse

Instance Method Details

#declare_reserved_import_alias_module_binding(name, kind_label:, line:, column:, unavailable_names:) ⇒ Object



17
18
19
20
21
22
23
24
25
26
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 17

def declare_reserved_import_alias_module_binding(name, kind_label:, line:, column:, unavailable_names:)
  declare_reserved_module_binding(
    name,
    kind_label:,
    line:,
    column:,
    unavailable_names:,
    reserved_names: RESERVED_IMPORT_ALIAS_NAMES,
  )
end

#declare_reserved_module_binding(name, kind_label:, line:, column:, unavailable_names:, reserved_names:) ⇒ Object



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
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 28

def declare_reserved_module_binding(name, kind_label:, line:, column:, unavailable_names:, reserved_names:)
  replacement_name = nil
  replacement_base_name = nil
  if reserved_names.include?(name)
    replacement_base_name = suggested_reserved_primitive_name(name, kind_label:)
    replacement_name = next_available_reserved_primitive_name(
      replacement_base_name,
      unavailable_names,
    )
  end

  binding = Binding.new(
    name:,
    line:,
    column:,
    used: false,
    binding_kind: :module,
    allow_prefer_let: false,
    mutated: false,
    replacement_name:,
    replacement_base_name:,
  )
  register_reserved_primitive_name_fix(binding, kind_label:, replacement_name:) if replacement_name
  @module_bindings[name] = binding
end

#declare_reserved_primitive_module_binding(name, kind_label:, line:, column:, unavailable_names:) ⇒ Object



54
55
56
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 54

def declare_reserved_primitive_module_binding(name, kind_label:, line:, column:, unavailable_names:)
  declare_reserved_value_type_module_binding(name, kind_label:, line:, column:, unavailable_names:)
end

#declare_reserved_value_type_module_binding(name, kind_label:, line:, column:, unavailable_names:) ⇒ Object



6
7
8
9
10
11
12
13
14
15
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 6

def declare_reserved_value_type_module_binding(name, kind_label:, line:, column:, unavailable_names:)
  declare_reserved_module_binding(
    name,
    kind_label:,
    line:,
    column:,
    unavailable_names:,
    reserved_names: RESERVED_VALUE_TYPE_NAMES,
  )
end

#next_available_reserved_primitive_name(base_name, unavailable_names) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 142

def next_available_reserved_primitive_name(base_name, unavailable_names)
  unavailable = unavailable_names.to_set
  return base_name unless unavailable.include?(base_name)

  suffix = 2
  loop do
    candidate = "#{base_name}_#{suffix}"
    return candidate unless unavailable.include?(candidate)

    suffix += 1
  end
end

#record_reserved_primitive_identifier_use(binding, identifier) ⇒ Object



185
186
187
188
189
190
191
192
193
194
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 185

def record_reserved_primitive_identifier_use(binding, identifier)
  return unless binding.fix_index
  return unless identifier&.line && identifier&.column

  @reserved_primitive_name_fixes[binding.fix_index].sites << ReservedPrimitiveNameSite.new(
    line: identifier.line,
    column: identifier.column,
    length: binding.name.length,
  )
end

#register_reserved_primitive_name_fix(binding, kind_label:, replacement_name:) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 118

def register_reserved_primitive_name_fix(binding, kind_label:, replacement_name:)
  warn_reserved_primitive_name(binding.name, line: binding.line, column: binding.column, kind_label:)
  return unless binding.line && binding.column

  binding.fix_index = @reserved_primitive_name_fixes.length
  @reserved_primitive_name_fixes << ReservedPrimitiveNameFix.new(
    kind: kind_label,
    original_name: binding.name,
    replacement_name: replacement_name,
    sites: [ReservedPrimitiveNameSite.new(line: binding.line, column: binding.column, length: binding.name.length)],
  )
end

#resolve_reserved_primitive_name_conflicts!(declared_name) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 168

def resolve_reserved_primitive_name_conflicts!(declared_name)
  visible_bindings.each do |binding|
    next unless binding.replacement_name == declared_name

    replacement_name = next_available_reserved_primitive_name(
      binding.replacement_base_name || binding.replacement_name,
      visible_binding_names(excluding_name: binding.name),
    )
    next if replacement_name == binding.replacement_name

    binding.replacement_name = replacement_name
    next unless binding.fix_index

    fix = @reserved_primitive_name_fixes[binding.fix_index]
    @reserved_primitive_name_fixes[binding.fix_index] = fix.with(replacement_name:)
  end
end

#suggested_reserved_primitive_name(name, kind_label:) ⇒ Object



131
132
133
134
135
136
137
138
139
140
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 131

def suggested_reserved_primitive_name(name, kind_label:)
  case kind_label
  when "function"
    "#{name}_fn"
  when "import alias"
    "#{name}_module"
  else
    "#{name}_value"
  end
end

#visible_binding_names(excluding_name: nil) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 155

def visible_binding_names(excluding_name: nil)
  names = visible_bindings.each_with_object(Set.new) do |binding, result|
    result << binding.name
    result << binding.replacement_name if binding.replacement_name
  end
  names.delete(excluding_name) if excluding_name
  names
end

#visible_bindingsObject



164
165
166
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 164

def visible_bindings
  @module_bindings.values + @scopes.flat_map(&:values)
end

#warn_large_event_capacity(event_decl, owner_name:) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 72

def warn_large_event_capacity(event_decl, owner_name:)
  label = owner_name ? "#{owner_name}.#{event_decl.name}" : event_decl.name

  @warnings << Warning.new(
    path: @path,
    line: event_decl.line,
    column: event_decl.column,
    length: event_decl.name.length,
    code: "event-capacity",
    message: "event '#{label}' capacity #{event_decl.capacity} makes emit() copy up to #{event_decl.capacity} listeners onto the stack; prefer a smaller fixed capacity or a managed queue abstraction",
    severity: :warning,
    symbol_name: event_decl.name,
  )
end

#warn_redundant_ignored_match_binding(name, line:, column:) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 87

def warn_redundant_ignored_match_binding(name, line:, column:)
  return unless name == "_"

  span = nil
  if line && column
    source_line = @source_lines[line - 1].to_s
    span = self.class.redundant_ignored_match_binding_span(source_line, column:)
  end

  @warnings << Warning.new(
    path: @path,
    line:,
    column: span ? span[:start_char] + 1 : column,
    length: span ? span[:end_char] - span[:start_char] : 1,
    code: "redundant-ignored-match-binding",
    message: "ignored match binding is redundant; remove 'as _'",
    severity: :hint,
  )
end

#warn_reserved_primitive_name(name, line:, column:, kind_label:, reserved_names: RESERVED_VALUE_TYPE_NAMES) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 57

def warn_reserved_primitive_name(name, line:, column:, kind_label:, reserved_names: RESERVED_VALUE_TYPE_NAMES)
  return unless reserved_names.include?(name)

  @warnings << Warning.new(
    path: @path,
    line:,
    column:,
    length: name.length,
    code: "reserved-primitive-name",
    message: "#{kind_label} '#{name}' uses reserved built-in type name '#{name}'; rename it before this becomes a hard error",
    severity: :warning,
    symbol_name: name,
  )
end

#warn_reserved_primitive_type_params(type_params, kind_label:) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/milk_tea/tooling/linter/reserved_names.rb', line 107

def warn_reserved_primitive_type_params(type_params, kind_label:)
  Array(type_params).each do |type_param|
    warn_reserved_primitive_name(
      type_param.name,
      line: type_param.line,
      column: type_param.column,
      kind_label:,
      reserved_names: RESERVED_VALUE_TYPE_NAMES,
    )
  end
end