rubydex 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -14
- data/THIRD_PARTY_LICENSES.html +13 -24
- data/ext/rubydex/definition.c +34 -0
- data/ext/rubydex/definition.h +3 -0
- data/ext/rubydex/diagnostic.c +2 -49
- data/ext/rubydex/extconf.rb +4 -2
- data/ext/rubydex/graph.c +59 -11
- data/lib/rubydex/cli/command/dead_code.rb +59 -0
- data/lib/rubydex/cli/command/lint/explain.rb +8 -6
- data/lib/rubydex/cli/command/lint.rb +10 -4
- data/lib/rubydex/linter/rule_loader.rb +1 -1
- data/lib/rubydex/mcp_server/tools/codebase_stats_tool.rb +1 -1
- data/lib/rubydex/mcp_server/tools/find_constant_references_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/find_dead_code_candidates_tool.rb +33 -0
- data/lib/rubydex/mcp_server/tools/get_declaration_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/get_descendants_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/search_declarations_tool.rb +6 -6
- data/lib/rubydex/mcp_server.rb +24 -12
- data/lib/rubydex/rules/dynamic_ancestor.rb +29 -0
- data/lib/rubydex/rules/dynamic_constant_reference.rb +25 -0
- data/lib/rubydex/rules/dynamic_singleton_definition.rb +30 -0
- data/lib/rubydex/rules/invalid_constant_visibility.rb +28 -0
- data/lib/rubydex/rules/invalid_method_visibility.rb +28 -0
- data/lib/rubydex/rules/parse_error.rb +25 -0
- data/lib/rubydex/rules/parse_warning.rb +28 -0
- data/lib/rubydex/rules/top_level_mixin_self.rb +27 -0
- data/lib/rubydex/rules/undefined_constant_visibility_target.rb +27 -0
- data/lib/rubydex/rules/undefined_method_visibility_target.rb +27 -0
- data/lib/rubydex/skill.rb +1 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +2 -0
- data/lib/rubydex_linter/rules/rule_structure.rb +19 -4
- data/rbi/rubydex.rbi +32 -130
- data/rust/Cargo.lock +17 -11
- data/rust/Cargo.toml +3 -0
- data/rust/rubydex/Cargo.toml +6 -2
- data/rust/rubydex/src/bin/generate_ruby_rules.rs +94 -0
- data/rust/rubydex/src/compile_assertions.rs +2 -0
- data/rust/rubydex/src/config.rs +1 -1
- data/rust/rubydex/src/diagnostic.rs +142 -51
- data/rust/rubydex/src/indexing/rbs_indexer.rs +4 -4
- data/rust/rubydex/src/indexing/ruby_indexer.rs +26 -18
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +42 -2
- data/rust/rubydex/src/indexing.rs +6 -6
- data/rust/rubydex/src/listing.rs +12 -12
- data/rust/rubydex/src/model/built_in.rs +1 -1
- data/rust/rubydex/src/model/comment.rs +4 -4
- data/rust/rubydex/src/model/declaration.rs +25 -17
- data/rust/rubydex/src/model/document.rs +11 -11
- data/rust/rubydex/src/model/graph.rs +3 -3
- data/rust/rubydex/src/offset.rs +1 -13
- data/rust/rubydex/src/operation/ruby_builder.rs +29 -19
- data/rust/rubydex/src/query.rs +193 -2
- data/rust/rubydex/src/test_utils/graph_test.rs +2 -2
- data/rust/rubydex/src/test_utils/local_graph_test.rs +13 -6
- data/rust/rubydex-sys/Cargo.toml +2 -2
- data/rust/rubydex-sys/src/definition_api.rs +69 -2
- data/rust/rubydex-sys/src/diagnostic_api.rs +0 -35
- data/rust/rubydex-sys/src/graph_api.rs +193 -45
- data/rust/rubydex-sys/src/name_api.rs +219 -48
- metadata +191 -180
|
@@ -4,10 +4,10 @@ module Rubydex
|
|
|
4
4
|
module MCPServer
|
|
5
5
|
class GetFileDeclarationsTool < BaseTool
|
|
6
6
|
tool_name "get_file_declarations"
|
|
7
|
-
description "List
|
|
7
|
+
description "List Ruby declarations defined in an indexed file."
|
|
8
8
|
input_schema(
|
|
9
9
|
properties: {
|
|
10
|
-
file_path: { type: "string", description: "
|
|
10
|
+
file_path: { type: "string", description: "Absolute path or path relative to the workspace root" },
|
|
11
11
|
},
|
|
12
12
|
required: ["file_path"],
|
|
13
13
|
)
|
|
@@ -4,14 +4,14 @@ module Rubydex
|
|
|
4
4
|
module MCPServer
|
|
5
5
|
class SearchDeclarationsTool < BaseTool
|
|
6
6
|
tool_name "search_declarations"
|
|
7
|
-
description
|
|
7
|
+
description "Find definitions of Ruby classes, modules, methods, or constants by full or partial name."
|
|
8
8
|
input_schema(
|
|
9
9
|
properties: {
|
|
10
|
-
query: { type: "string", description: "
|
|
11
|
-
kind: { type: "string", description: "
|
|
12
|
-
match_mode: { type: "string", description: '
|
|
13
|
-
limit: { type: "integer", description: "
|
|
14
|
-
offset: { type: "integer", description: "Number of results to skip
|
|
10
|
+
query: { type: "string", description: "Text to match against fully qualified names. An empty string matches all declarations." },
|
|
11
|
+
kind: { type: "string", description: "Case-insensitive declaration kind, such as Class, Module, Method, or Constant" },
|
|
12
|
+
match_mode: { type: "string", description: '"fuzzy" (default) matches characters in order, ignoring ASCII case. "exact" matches a case-sensitive substring.' },
|
|
13
|
+
limit: { type: "integer", description: "Page size (default 50, capped at 100)" },
|
|
14
|
+
offset: { type: "integer", description: "Number of results to skip (default 0)" },
|
|
15
15
|
},
|
|
16
16
|
required: ["query"],
|
|
17
17
|
)
|
data/lib/rubydex/mcp_server.rb
CHANGED
|
@@ -10,19 +10,13 @@ Dir[File.join(__dir__, "mcp_server", "tools", "*_tool.rb")].sort.each { |file| r
|
|
|
10
10
|
module Rubydex
|
|
11
11
|
module MCPServer
|
|
12
12
|
SERVER_INSTRUCTIONS = <<~TEXT
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Use these tools for Ruby source files (.rb, .rbi, .rbs) when you need structural information about declarations, locations, hierarchy, references, or codebase composition.
|
|
16
|
-
|
|
17
|
-
Use text search instead for literal strings, comments, log messages, non-Ruby files, or content search rather than structural queries.
|
|
18
|
-
|
|
19
|
-
Fully qualified name format: "Foo::Bar" for classes/modules/constants, "Foo::Bar#method_name" for instance methods.
|
|
20
|
-
|
|
21
|
-
Pagination: tools that may return a high number of results include `total` for pagination. When `total` exceeds the number of returned items, use `offset` to fetch the next page.
|
|
13
|
+
Tools query a static index of workspace code, available bundle dependencies, and available Ruby core and standard-library RBS definitions.
|
|
14
|
+
The index is built at server startup and does not track file changes; restart the server to refresh it.
|
|
22
15
|
TEXT
|
|
23
16
|
|
|
24
17
|
class Server
|
|
25
18
|
WORKER_COUNT = 4
|
|
19
|
+
SHUTDOWN_JOIN_TIMEOUT = 2
|
|
26
20
|
|
|
27
21
|
#: (root_path: String, ?transport: StdioTransport) -> void
|
|
28
22
|
def initialize(root_path:, transport: nil)
|
|
@@ -34,13 +28,14 @@ module Rubydex
|
|
|
34
28
|
@outgoing_queue = Thread::Queue.new
|
|
35
29
|
@workers = []
|
|
36
30
|
@outgoing_dispatcher = nil
|
|
31
|
+
@indexer = nil
|
|
37
32
|
end
|
|
38
33
|
|
|
39
34
|
attr_reader :root_path
|
|
40
35
|
|
|
41
36
|
#: -> Thread
|
|
42
37
|
def spawn_indexer
|
|
43
|
-
Thread.new do
|
|
38
|
+
@indexer = Thread.new do
|
|
44
39
|
@graph.index_workspace
|
|
45
40
|
@graph.resolve
|
|
46
41
|
@index_finished = true
|
|
@@ -150,9 +145,26 @@ module Rubydex
|
|
|
150
145
|
#: -> void
|
|
151
146
|
def run_shutdown
|
|
152
147
|
@incoming_queue.close unless @incoming_queue.closed?
|
|
153
|
-
@workers
|
|
148
|
+
join_or_kill_all(@workers + [@indexer])
|
|
154
149
|
@outgoing_queue.close unless @outgoing_queue.closed?
|
|
155
|
-
@outgoing_dispatcher
|
|
150
|
+
join_or_kill_all([@outgoing_dispatcher])
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#: (Array[Thread?]) -> void
|
|
154
|
+
def join_or_kill_all(threads)
|
|
155
|
+
live_threads = threads.compact.select(&:alive?)
|
|
156
|
+
return if live_threads.empty?
|
|
157
|
+
|
|
158
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + SHUTDOWN_JOIN_TIMEOUT
|
|
159
|
+
live_threads.each do |thread|
|
|
160
|
+
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
161
|
+
break if remaining <= 0
|
|
162
|
+
|
|
163
|
+
thread.join(remaining)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
live_threads.select(&:alive?).each(&:kill)
|
|
167
|
+
live_threads.select(&:alive?).each(&:join)
|
|
156
168
|
end
|
|
157
169
|
|
|
158
170
|
#: -> Thread
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Dynamic ancestor references cannot be reasoned about statically because they depend on runtime values. The
|
|
9
|
+
# program may still be valid, but the quality of the analysis degrades. In the case of ancestors, since they
|
|
10
|
+
# influence constant resolution, the degradation may be more impactful than other dynamic references.
|
|
11
|
+
#
|
|
12
|
+
# ```ruby
|
|
13
|
+
# class Foo < var
|
|
14
|
+
# ^^^ Dynamic ancestor reference. This might be correct, but it cannot be understood by the analysis.
|
|
15
|
+
# include SomeClass.method_call
|
|
16
|
+
# ^^^^^^^^^^^^^^^^^^^^^ Dynamic ancestor reference.
|
|
17
|
+
# end
|
|
18
|
+
# ```
|
|
19
|
+
class DynamicAncestor < Rule
|
|
20
|
+
class << self
|
|
21
|
+
# @override
|
|
22
|
+
#: -> singleton(Severity::Base)
|
|
23
|
+
def default_severity
|
|
24
|
+
Severity::Information
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Dynamic constant references cannot be reasoned about statically because they depend on runtime values. The
|
|
9
|
+
# program may still be valid, but the quality of the analysis degrades.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# var::Foo
|
|
13
|
+
# ^^^^^^^^ Dynamic constant reference. This might be correct, but it cannot be understood by the analysis.
|
|
14
|
+
# ```
|
|
15
|
+
class DynamicConstantReference < Rule
|
|
16
|
+
class << self
|
|
17
|
+
# @override
|
|
18
|
+
#: -> singleton(Severity::Base)
|
|
19
|
+
def default_severity
|
|
20
|
+
Severity::Information
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Dynamic singleton targets cannot be reasoned about statically because they depend on runtime values. The program
|
|
9
|
+
# may still be valid, but the quality of the analysis degrades.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# class << var
|
|
13
|
+
# ^^^ Dynamic singleton target. This might be correct, but it cannot be understood by the analysis.
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# def var.bar
|
|
17
|
+
# ^^^ Dynamic singleton target.
|
|
18
|
+
# end
|
|
19
|
+
# ```
|
|
20
|
+
class DynamicSingletonDefinition < Rule
|
|
21
|
+
class << self
|
|
22
|
+
# @override
|
|
23
|
+
#: -> singleton(Severity::Base)
|
|
24
|
+
def default_severity
|
|
25
|
+
Severity::Information
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Constant visibility operations that depend on dynamic values cannot be reasoned about statically because they
|
|
9
|
+
# depend on runtime values. The program may still be valid, but the quality of the analysis degrades.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# var.private_constant :Foo
|
|
13
|
+
# ^^^ Invalid constant visibility. This might be correct, but it cannot be understood by the analysis.
|
|
14
|
+
#
|
|
15
|
+
# private_constant(var)
|
|
16
|
+
# ^^^ Invalid constant visibility.
|
|
17
|
+
# ```
|
|
18
|
+
class InvalidConstantVisibility < Rule
|
|
19
|
+
class << self
|
|
20
|
+
# @override
|
|
21
|
+
#: -> singleton(Severity::Base)
|
|
22
|
+
def default_severity
|
|
23
|
+
Severity::Warning
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Method visibility operations that depend on dynamic values cannot be reasoned about statically because they
|
|
9
|
+
# depend on runtime values. The program may still be valid, but the quality of the analysis degrades.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# var.private :foo
|
|
13
|
+
# ^^^ Invalid method visibility. This might be correct, but it cannot be understood by the analysis.
|
|
14
|
+
#
|
|
15
|
+
# private(var)
|
|
16
|
+
# ^^^ Invalid method visibility.
|
|
17
|
+
# ```
|
|
18
|
+
class InvalidMethodVisibility < Rule
|
|
19
|
+
class << self
|
|
20
|
+
# @override
|
|
21
|
+
#: -> singleton(Severity::Base)
|
|
22
|
+
def default_severity
|
|
23
|
+
Severity::Warning
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# A parse error represents invalid Ruby syntax and a program that will fail to execute. For example, a missing
|
|
9
|
+
# `end`, an unterminated string, a missing parenthesis.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# class Foo
|
|
13
|
+
# ^^^^^ Syntax error. Missing end token
|
|
14
|
+
# ```
|
|
15
|
+
class ParseError < Rule
|
|
16
|
+
class << self
|
|
17
|
+
# @override
|
|
18
|
+
#: -> singleton(Severity::Base)
|
|
19
|
+
def default_severity
|
|
20
|
+
Severity::Error
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Parse warnings represent code that has valid syntax, but may not do what the developer expects. For example,
|
|
9
|
+
# local variables that are completely unused or usage in a void context (creating a line of code that does
|
|
10
|
+
# nothing).
|
|
11
|
+
#
|
|
12
|
+
# ```ruby
|
|
13
|
+
# CONST = 1
|
|
14
|
+
# CONST
|
|
15
|
+
# ^^^^^ Constant used in void context (the expression does nothing).
|
|
16
|
+
# puts CONST + 2
|
|
17
|
+
# ```
|
|
18
|
+
class ParseWarning < Rule
|
|
19
|
+
class << self
|
|
20
|
+
# @override
|
|
21
|
+
#: -> singleton(Severity::Base)
|
|
22
|
+
def default_severity
|
|
23
|
+
Severity::Warning
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# The top level of a Ruby program is the special <main> object. It is not possible to use `include self` or
|
|
9
|
+
# `extend self` on that object.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# include self
|
|
13
|
+
# ^^^^ Cannot include self at the top level
|
|
14
|
+
# extend self
|
|
15
|
+
# ^^^^ Cannot extend self at the top level
|
|
16
|
+
# ```
|
|
17
|
+
class TopLevelMixinSelf < Rule
|
|
18
|
+
class << self
|
|
19
|
+
# @override
|
|
20
|
+
#: -> singleton(Severity::Base)
|
|
21
|
+
def default_severity
|
|
22
|
+
Severity::Information
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Undefined constant visibility target means the analysis couldn't find the definition for the constant the code is
|
|
9
|
+
# attempting to change visibility of. It could be defined through meta-programming or it indeed does not exist.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# class Foo
|
|
13
|
+
# private_constant :Bar
|
|
14
|
+
# ^^^ Undefined constant visibility target. The constant `Bar` is not defined.
|
|
15
|
+
# end
|
|
16
|
+
# ```
|
|
17
|
+
class UndefinedConstantVisibilityTarget < Rule
|
|
18
|
+
class << self
|
|
19
|
+
# @override
|
|
20
|
+
#: -> singleton(Severity::Base)
|
|
21
|
+
def default_severity
|
|
22
|
+
Severity::Warning
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file is generated by `generate_ruby_rules.rs`. Do not edit this manually.
|
|
5
|
+
|
|
6
|
+
module Rubydex
|
|
7
|
+
module Rules
|
|
8
|
+
# Undefined method visibility target means the analysis couldn't find the definition for the method the code is
|
|
9
|
+
# attempting to change visibility of. It could be defined through meta-programming or it indeed does not exist.
|
|
10
|
+
#
|
|
11
|
+
# ```ruby
|
|
12
|
+
# class Foo
|
|
13
|
+
# private :bar
|
|
14
|
+
# ^^^ Undefined method visibility target. The method `bar` is not defined.
|
|
15
|
+
# end
|
|
16
|
+
# ```
|
|
17
|
+
class UndefinedMethodVisibilityTarget < Rule
|
|
18
|
+
class << self
|
|
19
|
+
# @override
|
|
20
|
+
#: -> singleton(Severity::Base)
|
|
21
|
+
def default_severity
|
|
22
|
+
Severity::Warning
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/rubydex/skill.rb
CHANGED
data/lib/rubydex/version.rb
CHANGED
data/lib/rubydex.rb
CHANGED
|
@@ -9,7 +9,8 @@ module Rubydex
|
|
|
9
9
|
# - Each rule subclass outside a test directory is in a rule directory.
|
|
10
10
|
# - Each checked rule subclass is in the `Rubydex::Linter::Rules` namespace.
|
|
11
11
|
#
|
|
12
|
-
# The rule directories are `rubydex_linter/rules/` and `lib/rubydex_linter/rules
|
|
12
|
+
# The rule directories are `rubydex_linter/rules/` and `lib/rubydex_linter/rules/`, including
|
|
13
|
+
# `lib/rubydex_linter/rules/` directories in nested gems.
|
|
13
14
|
# This rule does not report files in those directories that define no rule subclass.
|
|
14
15
|
class RuleStructure < CustomRule
|
|
15
16
|
include Helpers::SourceAccessHelpers
|
|
@@ -18,7 +19,7 @@ module Rubydex
|
|
|
18
19
|
RULE_NAMESPACE = "Rubydex::Linter::Rules" #: String
|
|
19
20
|
RULE_FILE_PATTERNS = [
|
|
20
21
|
"rubydex_linter/rules/**/*.rb",
|
|
21
|
-
"lib/rubydex_linter/rules/**/*.rb",
|
|
22
|
+
"**/lib/rubydex_linter/rules/**/*.rb",
|
|
22
23
|
].freeze #: Array[String]
|
|
23
24
|
TEST_FILE_PATTERNS = ["test/**/*", "**/test/**/*"].freeze #: Array[String]
|
|
24
25
|
|
|
@@ -37,6 +38,8 @@ module Rubydex
|
|
|
37
38
|
rule_definitions_by_file = {} #: Hash[String, Hash[Rubydex::Class, Definition]]
|
|
38
39
|
|
|
39
40
|
rules.each do |rule|
|
|
41
|
+
rule_docs = []
|
|
42
|
+
|
|
40
43
|
rule.definitions.each do |rule_definition|
|
|
41
44
|
uri = rule_definition.document.uri
|
|
42
45
|
path = path_for_uri(uri)
|
|
@@ -48,6 +51,8 @@ module Rubydex
|
|
|
48
51
|
elsif !test_file?(path)
|
|
49
52
|
report_wrong_rule_directory(rule.name, rule_definition)
|
|
50
53
|
end
|
|
54
|
+
|
|
55
|
+
rule_docs.concat(rule_definition.comments)
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
rule_definition = rule.definitions.find do |definition|
|
|
@@ -55,9 +60,19 @@ module Rubydex
|
|
|
55
60
|
path_in_workspace?(path) && (rule_file?(path) || !test_file?(path))
|
|
56
61
|
end
|
|
57
62
|
next unless rule_definition
|
|
58
|
-
next if rule.name.start_with?("#{RULE_NAMESPACE}::")
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
rule_name = rule.name
|
|
65
|
+
|
|
66
|
+
if rule_docs.empty?
|
|
67
|
+
add_diagnostic(
|
|
68
|
+
"`#{rule_name}` is missing documentation.",
|
|
69
|
+
diagnostic_location(rule_definition),
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
next if rule_name.start_with?("#{RULE_NAMESPACE}::")
|
|
74
|
+
|
|
75
|
+
report_wrong_rule_namespace(rule_name, rule_definition)
|
|
61
76
|
end
|
|
62
77
|
|
|
63
78
|
rule_definitions_by_file.each do |uri, rule_definitions|
|
data/rbi/rubydex.rbi
CHANGED
|
@@ -175,8 +175,17 @@ class Rubydex::AttrAccessorDefinition < Rubydex::Definition; end
|
|
|
175
175
|
class Rubydex::AttrReaderDefinition < Rubydex::Definition; end
|
|
176
176
|
class Rubydex::AttrWriterDefinition < Rubydex::Definition; end
|
|
177
177
|
class Rubydex::ClassVariableDefinition < Rubydex::Definition; end
|
|
178
|
-
|
|
179
|
-
class Rubydex::
|
|
178
|
+
|
|
179
|
+
class Rubydex::ConstantAliasDefinition < Rubydex::Definition
|
|
180
|
+
sig { returns(String) }
|
|
181
|
+
def raw_name; end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
class Rubydex::ConstantDefinition < Rubydex::Definition
|
|
185
|
+
sig { returns(String) }
|
|
186
|
+
def raw_name; end
|
|
187
|
+
end
|
|
188
|
+
|
|
180
189
|
class Rubydex::GlobalVariableAliasDefinition < Rubydex::Definition; end
|
|
181
190
|
class Rubydex::GlobalVariableDefinition < Rubydex::Definition; end
|
|
182
191
|
class Rubydex::InstanceVariableDefinition < Rubydex::Definition; end
|
|
@@ -271,6 +280,9 @@ class Rubydex::Signature::BlockParameter < Rubydex::Signature::Parameter; end
|
|
|
271
280
|
class Rubydex::ModuleDefinition < Rubydex::Definition
|
|
272
281
|
sig { returns(T::Array[Rubydex::Mixin]) }
|
|
273
282
|
def mixins; end
|
|
283
|
+
|
|
284
|
+
sig { returns(String) }
|
|
285
|
+
def raw_name; end
|
|
274
286
|
end
|
|
275
287
|
|
|
276
288
|
class Rubydex::SingletonClassDefinition < Rubydex::Definition
|
|
@@ -284,6 +296,9 @@ class Rubydex::ClassDefinition < Rubydex::Definition
|
|
|
284
296
|
|
|
285
297
|
sig { returns(T::Array[Rubydex::Mixin]) }
|
|
286
298
|
def mixins; end
|
|
299
|
+
|
|
300
|
+
sig { returns(String) }
|
|
301
|
+
def raw_name; end
|
|
287
302
|
end
|
|
288
303
|
|
|
289
304
|
class Rubydex::Mixin
|
|
@@ -337,80 +352,6 @@ class Rubydex::Rule
|
|
|
337
352
|
end
|
|
338
353
|
end
|
|
339
354
|
|
|
340
|
-
module Rubydex::Rules
|
|
341
|
-
ALL = T.let(T.unsafe(nil), T::Array[T.class_of(Rubydex::Rule)])
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
class Rubydex::Rules::ParseError < Rubydex::Rule
|
|
345
|
-
class << self
|
|
346
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
347
|
-
def default_severity; end
|
|
348
|
-
end
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
class Rubydex::Rules::ParseWarning < Rubydex::Rule
|
|
352
|
-
class << self
|
|
353
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
354
|
-
def default_severity; end
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
class Rubydex::Rules::DynamicConstantReference < Rubydex::Rule
|
|
359
|
-
class << self
|
|
360
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
361
|
-
def default_severity; end
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
class Rubydex::Rules::DynamicSingletonDefinition < Rubydex::Rule
|
|
366
|
-
class << self
|
|
367
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
368
|
-
def default_severity; end
|
|
369
|
-
end
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
class Rubydex::Rules::DynamicAncestor < Rubydex::Rule
|
|
373
|
-
class << self
|
|
374
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
375
|
-
def default_severity; end
|
|
376
|
-
end
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
class Rubydex::Rules::TopLevelMixinSelf < Rubydex::Rule
|
|
380
|
-
class << self
|
|
381
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
382
|
-
def default_severity; end
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
class Rubydex::Rules::InvalidConstantVisibility < Rubydex::Rule
|
|
387
|
-
class << self
|
|
388
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
389
|
-
def default_severity; end
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
class Rubydex::Rules::InvalidMethodVisibility < Rubydex::Rule
|
|
394
|
-
class << self
|
|
395
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
396
|
-
def default_severity; end
|
|
397
|
-
end
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
class Rubydex::Rules::UndefinedMethodVisibilityTarget < Rubydex::Rule
|
|
401
|
-
class << self
|
|
402
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
403
|
-
def default_severity; end
|
|
404
|
-
end
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
class Rubydex::Rules::UndefinedConstantVisibilityTarget < Rubydex::Rule
|
|
408
|
-
class << self
|
|
409
|
-
sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
|
|
410
|
-
def default_severity; end
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
355
|
class Rubydex::RelatedInformation
|
|
415
356
|
sig { params(message: String, location: Rubydex::Location).void }
|
|
416
357
|
def initialize(message, location); end
|
|
@@ -594,58 +535,6 @@ class Rubydex::Linter::Rules::RuleStructure < Rubydex::Linter::CustomRule
|
|
|
594
535
|
def lint; end
|
|
595
536
|
end
|
|
596
537
|
|
|
597
|
-
class Rubydex::Linter::RuleTestCase < Minitest::Test
|
|
598
|
-
DEFAULT_FILE = T.let(T.unsafe(nil), String)
|
|
599
|
-
ANNOTATION_PATTERN = T.let(T.unsafe(nil), Regexp)
|
|
600
|
-
|
|
601
|
-
sig { returns(String) }
|
|
602
|
-
def workspace_path; end
|
|
603
|
-
|
|
604
|
-
sig { params(name: String).void }
|
|
605
|
-
def initialize(name); end
|
|
606
|
-
|
|
607
|
-
sig { void }
|
|
608
|
-
def teardown; end
|
|
609
|
-
|
|
610
|
-
sig { returns(T.class_of(Rubydex::Linter::CustomRule)) }
|
|
611
|
-
def rule_class; end
|
|
612
|
-
|
|
613
|
-
sig { params(sources: T::Hash[String, String]).void }
|
|
614
|
-
def add_shared_source(sources); end
|
|
615
|
-
|
|
616
|
-
sig { returns(T::Array[String]) }
|
|
617
|
-
def ignored_diagnostic_files; end
|
|
618
|
-
|
|
619
|
-
sig { returns(Rubydex::LinterConfig) }
|
|
620
|
-
def rule_config; end
|
|
621
|
-
|
|
622
|
-
sig do
|
|
623
|
-
params(
|
|
624
|
-
args: T.any(String, T::Hash[T.any(String, Symbol), String]),
|
|
625
|
-
rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
|
|
626
|
-
).returns(T::Array[Rubydex::Diagnostic])
|
|
627
|
-
end
|
|
628
|
-
def assert_diagnostics(*args, &rule_builder); end
|
|
629
|
-
|
|
630
|
-
sig do
|
|
631
|
-
params(
|
|
632
|
-
args: T.any(String, T::Hash[T.any(String, Symbol), String]),
|
|
633
|
-
rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
|
|
634
|
-
).returns(T::Array[Rubydex::Diagnostic])
|
|
635
|
-
end
|
|
636
|
-
def assert_no_diagnostics(*args, &rule_builder); end
|
|
637
|
-
|
|
638
|
-
sig do
|
|
639
|
-
params(
|
|
640
|
-
dependency: String,
|
|
641
|
-
args: T.any(String, T::Hash[T.any(String, Symbol), String]),
|
|
642
|
-
after_excluding: T::Array[String],
|
|
643
|
-
rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
|
|
644
|
-
).void
|
|
645
|
-
end
|
|
646
|
-
def assert_handles_missing_required_dependency(dependency, *args, after_excluding: [], &rule_builder); end
|
|
647
|
-
end
|
|
648
|
-
|
|
649
538
|
class Rubydex::Linter::Runner
|
|
650
539
|
sig do
|
|
651
540
|
params(
|
|
@@ -891,8 +780,18 @@ class Rubydex::Graph
|
|
|
891
780
|
sig { returns(T.self_type) }
|
|
892
781
|
def resolve; end
|
|
893
782
|
|
|
894
|
-
sig
|
|
895
|
-
|
|
783
|
+
sig do
|
|
784
|
+
params(
|
|
785
|
+
name: String,
|
|
786
|
+
context: T.any(
|
|
787
|
+
T::Array[String],
|
|
788
|
+
Rubydex::ClassDefinition,
|
|
789
|
+
Rubydex::SingletonClassDefinition,
|
|
790
|
+
Rubydex::ModuleDefinition,
|
|
791
|
+
),
|
|
792
|
+
).returns(T.nilable(Rubydex::Declaration))
|
|
793
|
+
end
|
|
794
|
+
def resolve_constant(name, context); end
|
|
896
795
|
|
|
897
796
|
sig { params(require_path: String, load_paths: T::Array[String]).returns(T.nilable(Rubydex::Document)) }
|
|
898
797
|
def resolve_require_path(require_path, load_paths); end
|
|
@@ -903,6 +802,9 @@ class Rubydex::Graph
|
|
|
903
802
|
sig { params(queries: String).returns(T::Enumerable[Rubydex::Declaration]) }
|
|
904
803
|
def fuzzy_search(*queries); end
|
|
905
804
|
|
|
805
|
+
sig { returns(T::Enumerable[Rubydex::Declaration]) }
|
|
806
|
+
def dead_code_candidates; end
|
|
807
|
+
|
|
906
808
|
sig { params(encoding: String).void }
|
|
907
809
|
def encoding=(encoding); end
|
|
908
810
|
|