rubydex 0.4.0-aarch64-linux → 0.4.1-aarch64-linux
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 +4 -20
- 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/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/cli/command/lint/explain.rb +8 -6
- data/lib/rubydex/cli/command/lint.rb +10 -4
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/linter/rule_loader.rb +1 -1
- 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/rubydex/Cargo.toml +4 -0
- data/rust/rubydex/src/bin/generate_ruby_rules.rs +94 -0
- data/rust/rubydex/src/diagnostic.rs +142 -51
- data/rust/rubydex/src/query.rs +191 -1
- data/rust/rubydex-sys/src/definition_api.rs +68 -1
- data/rust/rubydex-sys/src/diagnostic_api.rs +0 -35
- data/rust/rubydex-sys/src/graph_api.rs +112 -11
- data/rust/rubydex-sys/src/name_api.rs +47 -11
- metadata +13 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a70d28b6e2a005cc04ca033934b7bc32c17d88b76baa0c02b914a1be690fe321
|
|
4
|
+
data.tar.gz: 7cf3e4cab8ee5d14236749f9fdb3a215e5bc92a276f32945fa869a179e8e58bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f906b9f461dc0bffe39965ad48959b22e4ca78096856aaa9058ce4ac89d0351095769fb68fc5ef6b5ee1f3577b594902ea8cfa258c991dc6ffb1abd7ea7e31c3
|
|
7
|
+
data.tar.gz: f29ce56721abd682206660c4a605b9236a67f61016242d85ebd2f9b2d4137c34538cb6a278d8e48dfe49171e9024b6cb938114f9d5e61d1465595386f0d76d35
|
data/README.md
CHANGED
|
@@ -114,7 +114,7 @@ Thread safety comes from an `RwLock` on the Rust side, **not** from Ruby's
|
|
|
114
114
|
|
|
115
115
|
All built-in tools are experimental. These tools can change without deprecation warnings.
|
|
116
116
|
|
|
117
|
-
###
|
|
117
|
+
### Querying
|
|
118
118
|
|
|
119
119
|
Rubydex exposes the indexed graph through a read-only subset of the
|
|
120
120
|
[Cypher](https://opencypher.org/) query language. Only read clauses (`MATCH`,
|
|
@@ -153,27 +153,11 @@ puts result.render("json")
|
|
|
153
153
|
puts Rubydex::Query.schema("table")
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
###
|
|
156
|
+
### Linter
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
See the [linter docs](docs/linter.md).
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
bundle exec rdx lint
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Rubydex uses the bundle root, or the current directory when no bundle is available.
|
|
167
|
-
|
|
168
|
-
Configure a rule in `rubydex.toml`:
|
|
169
|
-
|
|
170
|
-
```toml
|
|
171
|
-
[linter.rules.<Rule name>]
|
|
172
|
-
enabled = true
|
|
173
|
-
exclude = ["path_to_skip/**"]
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### `rdx mcp`
|
|
160
|
+
### MCP server
|
|
177
161
|
|
|
178
162
|
Rubydex can run as an MCP (Model Context Protocol) server, enabling AI assistants
|
|
179
163
|
like Claude to semantically query your Ruby codebase.
|
data/ext/rubydex/definition.c
CHANGED
|
@@ -38,6 +38,17 @@ VALUE cClassVariableDefinition;
|
|
|
38
38
|
VALUE cMethodAliasDefinition;
|
|
39
39
|
VALUE cGlobalVariableAliasDefinition;
|
|
40
40
|
|
|
41
|
+
uint64_t rdxi_definition_id_for_graph(VALUE definition, VALUE graph_obj) {
|
|
42
|
+
HandleData *data;
|
|
43
|
+
TypedData_Get_Struct(definition, HandleData, &handle_type, data);
|
|
44
|
+
|
|
45
|
+
if (data->graph_obj != graph_obj) {
|
|
46
|
+
rb_raise(rb_eArgError, "definition must belong to this graph");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return data->id;
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
// Keep this in sync with definition.rs
|
|
42
53
|
VALUE rdxi_definition_class_for_kind(DefinitionKind kind) {
|
|
43
54
|
switch (kind) {
|
|
@@ -153,6 +164,25 @@ static VALUE rdxr_definition_name(VALUE self) {
|
|
|
153
164
|
return rdxi_owned_c_string_to_ruby(name);
|
|
154
165
|
}
|
|
155
166
|
|
|
167
|
+
/*
|
|
168
|
+
* call-seq:
|
|
169
|
+
* raw_name -> String
|
|
170
|
+
*
|
|
171
|
+
* Returns the class, module, or constant name as written in source, preserving explicit parent scopes like "Foo::Bar"
|
|
172
|
+
* and rooted paths like "::Bar".
|
|
173
|
+
*/
|
|
174
|
+
static VALUE rdxr_definition_raw_name(VALUE self) {
|
|
175
|
+
HandleData *data;
|
|
176
|
+
void *graph = rdxi_graph_from_handle(self, &data);
|
|
177
|
+
|
|
178
|
+
const char *name = rdx_definition_raw_name(graph, data->id);
|
|
179
|
+
if (name == NULL) {
|
|
180
|
+
rb_raise(rb_eRuntimeError, "Definition not found");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return rdxi_owned_c_string_to_ruby(name);
|
|
184
|
+
}
|
|
185
|
+
|
|
156
186
|
/*
|
|
157
187
|
* call-seq:
|
|
158
188
|
* deprecated? -> bool
|
|
@@ -442,6 +472,7 @@ void rdxi_initialize_definition(VALUE mod) {
|
|
|
442
472
|
rb_define_method(cDefinition, "document", rdxr_definition_document, 0);
|
|
443
473
|
|
|
444
474
|
cClassDefinition = rb_define_class_under(mRubydex, "ClassDefinition", cDefinition);
|
|
475
|
+
rb_define_method(cClassDefinition, "raw_name", rdxr_definition_raw_name, 0);
|
|
445
476
|
rb_define_method(cClassDefinition, "superclass", rdxr_class_definition_superclass, 0);
|
|
446
477
|
rb_define_method(cClassDefinition, "mixins", rdxr_definition_mixins, 0);
|
|
447
478
|
|
|
@@ -449,10 +480,13 @@ void rdxi_initialize_definition(VALUE mod) {
|
|
|
449
480
|
rb_define_method(cSingletonClassDefinition, "mixins", rdxr_definition_mixins, 0);
|
|
450
481
|
|
|
451
482
|
cModuleDefinition = rb_define_class_under(mRubydex, "ModuleDefinition", cDefinition);
|
|
483
|
+
rb_define_method(cModuleDefinition, "raw_name", rdxr_definition_raw_name, 0);
|
|
452
484
|
rb_define_method(cModuleDefinition, "mixins", rdxr_definition_mixins, 0);
|
|
453
485
|
|
|
454
486
|
cConstantDefinition = rb_define_class_under(mRubydex, "ConstantDefinition", cDefinition);
|
|
487
|
+
rb_define_method(cConstantDefinition, "raw_name", rdxr_definition_raw_name, 0);
|
|
455
488
|
cConstantAliasDefinition = rb_define_class_under(mRubydex, "ConstantAliasDefinition", cDefinition);
|
|
489
|
+
rb_define_method(cConstantAliasDefinition, "raw_name", rdxr_definition_raw_name, 0);
|
|
456
490
|
cConstantVisibilityDefinition = rb_define_class_under(mRubydex, "ConstantVisibilityDefinition", cDefinition);
|
|
457
491
|
cMethodVisibilityDefinition = rb_define_class_under(mRubydex, "MethodVisibilityDefinition", cDefinition);
|
|
458
492
|
cMethodDefinition = rb_define_class_under(mRubydex, "MethodDefinition", cDefinition);
|
data/ext/rubydex/definition.h
CHANGED
|
@@ -22,6 +22,9 @@ extern VALUE cGlobalVariableAliasDefinition;
|
|
|
22
22
|
|
|
23
23
|
void rdxi_initialize_definition(VALUE mRubydex);
|
|
24
24
|
|
|
25
|
+
// Returns the definition ID after verifying that the definition belongs to `graph_obj`.
|
|
26
|
+
uint64_t rdxi_definition_id_for_graph(VALUE definition, VALUE graph_obj);
|
|
27
|
+
|
|
25
28
|
// Returns the Ruby class for a given DefinitionKind without calling back into Rust
|
|
26
29
|
VALUE rdxi_definition_class_for_kind(DefinitionKind kind);
|
|
27
30
|
|
data/ext/rubydex/diagnostic.c
CHANGED
|
@@ -6,11 +6,8 @@
|
|
|
6
6
|
* mRubydex = rb_define_module("Rubydex")
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
static VALUE mRubydex;
|
|
10
9
|
static VALUE mRules;
|
|
11
10
|
VALUE cDiagnostic;
|
|
12
|
-
static VALUE cRule;
|
|
13
|
-
static ID id_default_severity;
|
|
14
11
|
|
|
15
12
|
VALUE rdxi_build_diagnostic_severity_value(VALUE mRubydex, DiagnosticSeverity severity) {
|
|
16
13
|
VALUE mSeverity = rb_const_get(mRubydex, rb_intern("Severity"));
|
|
@@ -31,55 +28,11 @@ VALUE rdxi_build_diagnostic_severity_value(VALUE mRubydex, DiagnosticSeverity se
|
|
|
31
28
|
return Qnil;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
/*
|
|
35
|
-
* call-seq:
|
|
36
|
-
* default_severity -> Rubydex::Severity::Base
|
|
37
|
-
*
|
|
38
|
-
* Returns the Rubydex::Severity subclass the diagnostics of this rule get unless the configuration overrides it.
|
|
39
|
-
*/
|
|
40
|
-
static VALUE rdxr_generated_rule_default_severity(VALUE self) {
|
|
41
|
-
VALUE severity = rb_attr_get(self, id_default_severity);
|
|
42
|
-
|
|
43
|
-
// Class-level instance variables are not inherited, so a class inheriting from a generated rule reaches this without
|
|
44
|
-
// a severity of its own.
|
|
45
|
-
if (NIL_P(severity)) {
|
|
46
|
-
rb_raise(rb_eRuntimeError, "Rule %s has no default severity", rb_class2name(self));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return severity;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Generates a rule class for every rule the graph can report. Severities are resolved here rather than when they are
|
|
53
|
-
// read, which is why Rubydex::Severity is loaded before this extension (see `lib/rubydex.rb`).
|
|
54
|
-
static void define_generated_rules(void) {
|
|
55
|
-
CRuleArray rule_array = rdx_rules();
|
|
56
|
-
VALUE rules = rb_ary_new_capa((long)rule_array.len);
|
|
57
|
-
|
|
58
|
-
for (size_t i = 0; i < rule_array.len; i++) {
|
|
59
|
-
CRule built_in_rule = rule_array.items[i];
|
|
60
|
-
VALUE name = rb_utf8_str_new(built_in_rule.name, (long)built_in_rule.name_length);
|
|
61
|
-
VALUE rule = rb_define_class_under(mRules, StringValueCStr(name), cRule);
|
|
62
|
-
VALUE severity = rdxi_build_diagnostic_severity_value(mRubydex, built_in_rule.default_severity);
|
|
63
|
-
|
|
64
|
-
rb_ivar_set(rule, id_default_severity, severity);
|
|
65
|
-
rb_define_singleton_method(rule, "default_severity", rdxr_generated_rule_default_severity, 0);
|
|
66
|
-
rb_ary_push(rules, rule);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
rdx_rules_free(rule_array);
|
|
70
|
-
rb_define_const(mRules, "ALL", rb_obj_freeze(rules));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
31
|
VALUE rdxi_rule_class_from_name(const char *name, size_t length) {
|
|
74
32
|
return rb_const_get_at(mRules, rb_intern2(name, (long)length));
|
|
75
33
|
}
|
|
76
34
|
|
|
77
35
|
void rdxi_initialize_diagnostic(VALUE moduleRubydex) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
cDiagnostic = rb_define_class_under(mRubydex, "Diagnostic", rb_cObject);
|
|
82
|
-
cRule = rb_define_class_under(mRubydex, "Rule", rb_cObject);
|
|
83
|
-
mRules = rb_define_module_under(mRubydex, "Rules");
|
|
84
|
-
define_generated_rules();
|
|
36
|
+
cDiagnostic = rb_define_class_under(moduleRubydex, "Diagnostic", rb_cObject);
|
|
37
|
+
mRules = rb_define_module_under(moduleRubydex, "Rules");
|
|
85
38
|
}
|
data/ext/rubydex/extconf.rb
CHANGED
|
@@ -23,12 +23,12 @@ release = ENV["RELEASE"] || !developing_rubydex
|
|
|
23
23
|
root_dir = gem_dir.join("rust")
|
|
24
24
|
target_dir = root_dir.join("target")
|
|
25
25
|
target_dir = target_dir.join("x86_64-pc-windows-gnu") if Gem.win_platform?
|
|
26
|
-
target_dir = target_dir.join(
|
|
26
|
+
target_dir = target_dir.join("$(RUST_PROFILE)")
|
|
27
27
|
|
|
28
28
|
bindings_path = root_dir.join("rubydex-sys").join("rustbindings.h")
|
|
29
29
|
|
|
30
30
|
cargo_args = ["--manifest-path #{root_dir.join("Cargo.toml")}"]
|
|
31
|
-
cargo_args << "
|
|
31
|
+
cargo_args << "$(CARGO_PROFILE_FLAG)"
|
|
32
32
|
|
|
33
33
|
if Gem.win_platform?
|
|
34
34
|
cargo_args << "--target x86_64-pc-windows-gnu"
|
|
@@ -102,6 +102,8 @@ makefile = File.read("Makefile")
|
|
|
102
102
|
|
|
103
103
|
new_makefile = makefile.gsub("$(OBJS): $(HDRS) $(ruby_headers)", <<~MAKEFILE.chomp)
|
|
104
104
|
.PHONY: compile_rust
|
|
105
|
+
RUST_PROFILE = $(if $(strip $(RELEASE)),release,#{developing_rubydex ? "debug" : "release"})
|
|
106
|
+
CARGO_PROFILE_FLAG = $(if $(filter release,$(RUST_PROFILE)),--release)
|
|
105
107
|
RUST_SRCS = #{File.expand_path("Cargo.toml", root_dir)} #{File.expand_path("Cargo.lock", root_dir)} #{rust_srcs.join(" ")}
|
|
106
108
|
|
|
107
109
|
.rust_built: $(RUST_SRCS)
|
data/ext/rubydex/graph.c
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "graph.h"
|
|
2
2
|
#include "config.h"
|
|
3
3
|
#include "declaration.h"
|
|
4
|
+
#include "definition.h"
|
|
4
5
|
#include "diagnostic.h"
|
|
5
6
|
#include "document.h"
|
|
6
7
|
#include "location.h"
|
|
@@ -256,6 +257,30 @@ static VALUE rdxr_graph_fuzzy_search(int argc, VALUE *argv, VALUE self) {
|
|
|
256
257
|
return rdxr_graph_yield_search_results(self, iter);
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
/*
|
|
261
|
+
* call-seq:
|
|
262
|
+
* dead_code_candidates -> Enumerator[Rubydex::Declaration]
|
|
263
|
+
*
|
|
264
|
+
* Returns an enumerator over declarations that may be unused because the analysis could not find any references to
|
|
265
|
+
* them. This misses metaprogramming or untyped code, which is why the term candidates is used.
|
|
266
|
+
*
|
|
267
|
+
* Currently, only supports constants.
|
|
268
|
+
*/
|
|
269
|
+
static VALUE rdxr_graph_dead_code_candidates(VALUE self) {
|
|
270
|
+
if (!rb_block_given_p()) {
|
|
271
|
+
return rb_enumeratorize(self, rb_str_new2("dead_code_candidates"), 0, NULL);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
void *graph;
|
|
275
|
+
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
276
|
+
|
|
277
|
+
void *iter = rdx_graph_dead_code_candidates(graph);
|
|
278
|
+
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
|
|
279
|
+
rb_ensure(rdxi_declarations_yield, args, rdxi_declarations_ensure, args);
|
|
280
|
+
|
|
281
|
+
return self;
|
|
282
|
+
}
|
|
283
|
+
|
|
259
284
|
// Body function for rb_ensure in Graph#documents
|
|
260
285
|
static VALUE graph_documents_yield(VALUE args) {
|
|
261
286
|
VALUE self = rb_ary_entry(args, 0);
|
|
@@ -486,26 +511,48 @@ static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
|
|
|
486
511
|
|
|
487
512
|
/*
|
|
488
513
|
* call-seq:
|
|
489
|
-
* resolve_constant(name,
|
|
514
|
+
* resolve_constant(name, context) -> Rubydex::Declaration?
|
|
490
515
|
*
|
|
491
|
-
* Runs the resolver on a single constant reference
|
|
516
|
+
* Runs the resolver on a single constant reference using an array of nesting names or a namespace definition as its
|
|
517
|
+
* context.
|
|
492
518
|
*/
|
|
493
|
-
static VALUE rdxr_graph_resolve_constant(VALUE self, VALUE const_name, VALUE
|
|
519
|
+
static VALUE rdxr_graph_resolve_constant(VALUE self, VALUE const_name, VALUE context) {
|
|
494
520
|
Check_Type(const_name, T_STRING);
|
|
495
|
-
rdxi_check_array_of_strings(nesting);
|
|
496
521
|
const char *const_name_string = StringValueCStr(const_name);
|
|
497
522
|
|
|
498
|
-
// Convert the given file paths into a char** array, so that we can pass to Rust
|
|
499
|
-
size_t length = RARRAY_LEN(nesting);
|
|
500
|
-
char **converted_file_paths = rdxi_str_array_to_char(nesting, length);
|
|
501
|
-
|
|
502
523
|
void *graph;
|
|
503
524
|
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
504
525
|
|
|
505
|
-
const CDeclaration *decl
|
|
506
|
-
|
|
526
|
+
const CDeclaration *decl;
|
|
527
|
+
if (RB_TYPE_P(context, T_ARRAY)) {
|
|
528
|
+
rdxi_check_array_of_strings(context);
|
|
529
|
+
|
|
530
|
+
size_t length = RARRAY_LEN(context);
|
|
531
|
+
char **converted_names = rdxi_str_array_to_char(context, length);
|
|
532
|
+
decl = rdx_graph_resolve_constant(graph, const_name_string, (const char **)converted_names, length);
|
|
533
|
+
rdxi_free_str_array(converted_names, length);
|
|
534
|
+
} else if (rb_obj_is_kind_of(context, cClassDefinition) ||
|
|
535
|
+
rb_obj_is_kind_of(context, cSingletonClassDefinition) ||
|
|
536
|
+
rb_obj_is_kind_of(context, cModuleDefinition)) {
|
|
537
|
+
uint64_t definition_id = rdxi_definition_id_for_graph(context, self);
|
|
538
|
+
CDefinitionConstantResolutionResult result =
|
|
539
|
+
rdx_graph_resolve_constant_from_definition(graph, const_name_string, definition_id);
|
|
540
|
+
|
|
541
|
+
if (result.status == CDefinitionConstantResolution_DefinitionNotFound) {
|
|
542
|
+
rb_raise(rb_eRuntimeError, "Definition not found");
|
|
543
|
+
}
|
|
544
|
+
if (result.status == CDefinitionConstantResolution_InvalidDefinitionKind) {
|
|
545
|
+
// This is unreachable because the rb_obj_is_kind_of checks above only accept supported definition kinds.
|
|
546
|
+
rb_raise(rb_eRuntimeError, "Unexpected definition kind");
|
|
547
|
+
}
|
|
507
548
|
|
|
508
|
-
|
|
549
|
+
decl = result.declaration;
|
|
550
|
+
} else {
|
|
551
|
+
rb_raise(
|
|
552
|
+
rb_eTypeError,
|
|
553
|
+
"context must be an Array of Strings, ClassDefinition, SingletonClassDefinition, or ModuleDefinition"
|
|
554
|
+
);
|
|
555
|
+
}
|
|
509
556
|
|
|
510
557
|
if (decl == NULL) {
|
|
511
558
|
return Qnil;
|
|
@@ -938,6 +985,7 @@ void rdxi_initialize_graph(VALUE moduleRubydex) {
|
|
|
938
985
|
rb_define_method(cGraph, "[]", rdxr_graph_aref, 1);
|
|
939
986
|
rb_define_method(cGraph, "search", rdxr_graph_search, -1);
|
|
940
987
|
rb_define_method(cGraph, "fuzzy_search", rdxr_graph_fuzzy_search, -1);
|
|
988
|
+
rb_define_method(cGraph, "dead_code_candidates", rdxr_graph_dead_code_candidates, 0);
|
|
941
989
|
rb_define_method(cGraph, "encoding=", rdxr_graph_set_encoding, 1);
|
|
942
990
|
rb_define_method(cGraph, "resolve_require_path", rdxr_graph_resolve_require_path, 2);
|
|
943
991
|
rb_define_method(cGraph, "require_paths", rdxr_graph_require_paths, 1);
|
data/lib/rubydex/3.2/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.3/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.4/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/4.0/rubydex.so
CHANGED
|
Binary file
|
|
@@ -9,8 +9,10 @@ module Rubydex
|
|
|
9
9
|
class Lint
|
|
10
10
|
# `rdx lint explain <RULE>` — prints documentation for rules with a matching name.
|
|
11
11
|
class Explain < Command
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
BASE_PATHS = [
|
|
13
|
+
File.expand_path("../../../linter/custom_rule.rb", __dir__),
|
|
14
|
+
File.expand_path("../../../rule.rb", __dir__),
|
|
15
|
+
] #: Array[String]
|
|
14
16
|
|
|
15
17
|
class << self
|
|
16
18
|
#: -> String
|
|
@@ -30,17 +32,17 @@ module Rubydex
|
|
|
30
32
|
workspace_path = current_workspace_path
|
|
31
33
|
|
|
32
34
|
graph = Rubydex::Graph.configure_for_workspace(workspace_path)
|
|
33
|
-
graph.index_all([
|
|
35
|
+
graph.index_all([*BASE_PATHS, *Rubydex::Linter::RuleLoader.paths(workspace_path)])
|
|
34
36
|
graph.resolve
|
|
35
37
|
|
|
36
|
-
base_rule = graph[
|
|
37
|
-
abort("Base rule class
|
|
38
|
+
base_rule = graph["Rubydex::Rule"]
|
|
39
|
+
abort("Base rule class is not found. This is an issue in Rubydex itself") unless base_rule.is_a?(Rubydex::Class)
|
|
38
40
|
|
|
39
41
|
rule_declarations = base_rule.descendants.grep(Rubydex::Class) #: as Array[Rubydex::Class]
|
|
40
42
|
matched_rule_names = rule_declarations.filter_map do |declaration|
|
|
41
43
|
declaration_name = declaration.name
|
|
42
44
|
next unless declaration_name
|
|
43
|
-
next if declaration_name ==
|
|
45
|
+
next if declaration_name == "Rubydex::Rule" || declaration_name == "Rubydex::Linter::CustomRule"
|
|
44
46
|
next unless declaration_name.end_with?(rule_name)
|
|
45
47
|
|
|
46
48
|
declaration
|
|
@@ -35,7 +35,7 @@ module Rubydex
|
|
|
35
35
|
require "rubydex/linter"
|
|
36
36
|
|
|
37
37
|
custom_rules = load_linter_rules(workspace_path)
|
|
38
|
-
warn_unknown_rules
|
|
38
|
+
warn_unknown_rules
|
|
39
39
|
|
|
40
40
|
graph = build_graph($stderr, workspace_path:, config:)
|
|
41
41
|
runner = Rubydex::Linter::Runner.new(graph, custom_rules:, config: linter_config)
|
|
@@ -64,9 +64,15 @@ module Rubydex
|
|
|
64
64
|
@linter_config ||= config.linter #: Rubydex::LinterConfig?
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
#: (
|
|
68
|
-
def warn_unknown_rules
|
|
69
|
-
known_rule_names = (Rubydex::
|
|
67
|
+
#: () -> void
|
|
68
|
+
def warn_unknown_rules
|
|
69
|
+
known_rule_names = (Rule.subclasses + Rubydex::Linter::CustomRule.subclasses).filter_map do |rule|
|
|
70
|
+
name = rule.rule_name
|
|
71
|
+
name unless name == "CustomRule"
|
|
72
|
+
end
|
|
73
|
+
known_rule_names.uniq!
|
|
74
|
+
known_rule_names.sort!
|
|
75
|
+
|
|
70
76
|
unknown_rule_names = linter_config.rules.keys.reject { |name| known_rule_names.include?(name) }.sort
|
|
71
77
|
return if unknown_rule_names.empty?
|
|
72
78
|
|
|
Binary file
|
|
@@ -4,7 +4,7 @@ module Rubydex
|
|
|
4
4
|
module Linter
|
|
5
5
|
# Loads project and bundled-gem rules using the Rubydex linter path convention.
|
|
6
6
|
class RuleLoader
|
|
7
|
-
BUILT_IN_RULE_GLOB = File.expand_path("../../rubydex_linter/rules/**/*.rb", __dir__) #: String
|
|
7
|
+
BUILT_IN_RULE_GLOB = File.expand_path("../../{rubydex_linter,rubydex}/rules/**/*.rb", __dir__) #: String
|
|
8
8
|
RULE_GLOB = "rubydex_linter/rules/**/*.rb" #: String
|
|
9
9
|
|
|
10
10
|
class << self
|
|
@@ -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
|