rigortype 0.0.9 → 0.1.0
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 +40 -2
- data/lib/rigor/analysis/check_rules.rb +228 -40
- data/lib/rigor/analysis/diagnostic.rb +15 -1
- data/lib/rigor/analysis/runner.rb +183 -4
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +1 -1
- data/lib/rigor/cache/rbs_constant_table.rb +2 -2
- data/lib/rigor/cache/rbs_descriptor.rb +2 -0
- data/lib/rigor/cache/rbs_instance_definitions.rb +79 -0
- data/lib/rigor/cache/store.rb +2 -0
- data/lib/rigor/cli.rb +9 -3
- data/lib/rigor/configuration/severity_profile.rb +109 -0
- data/lib/rigor/configuration.rb +110 -6
- data/lib/rigor/environment/rbs_loader.rb +89 -13
- data/lib/rigor/flow_contribution/conflict.rb +81 -0
- data/lib/rigor/flow_contribution/element.rb +53 -0
- data/lib/rigor/flow_contribution/fact.rb +88 -0
- data/lib/rigor/flow_contribution/merge_result.rb +67 -0
- data/lib/rigor/flow_contribution/merger.rb +275 -0
- data/lib/rigor/flow_contribution.rb +51 -0
- data/lib/rigor/inference/block_parameter_binder.rb +15 -0
- data/lib/rigor/inference/expression_typer.rb +84 -5
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +95 -9
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +21 -1
- data/lib/rigor/inference/multi_target_binder.rb +2 -0
- data/lib/rigor/inference/narrowing.rb +105 -130
- data/lib/rigor/inference/scope_indexer.rb +75 -1
- data/lib/rigor/inference/statement_evaluator.rb +380 -40
- data/lib/rigor/plugin/access_denied_error.rb +24 -0
- data/lib/rigor/plugin/base.rb +241 -0
- data/lib/rigor/plugin/io_boundary.rb +102 -0
- data/lib/rigor/plugin/load_error.rb +23 -0
- data/lib/rigor/plugin/loader.rb +191 -0
- data/lib/rigor/plugin/manifest.rb +134 -0
- data/lib/rigor/plugin/registry.rb +50 -0
- data/lib/rigor/plugin/services.rb +65 -0
- data/lib/rigor/plugin/trust_policy.rb +99 -0
- data/lib/rigor/plugin.rb +61 -0
- data/lib/rigor/rbs_extended.rb +57 -9
- data/lib/rigor/reflection.rb +2 -2
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +7 -0
- data/sig/rigor/environment.rbs +7 -1
- data/sig/rigor/inference.rbs +1 -0
- data/sig/rigor/rbs_extended.rbs +2 -0
- data/sig/rigor/scope.rbs +1 -0
- data/sig/rigor/type.rbs +7 -0
- metadata +18 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Plugin
|
|
5
|
+
# Read-side query API over the plugins loaded for a single
|
|
6
|
+
# `Analysis::Runner.run`. Constructed by
|
|
7
|
+
# {Rigor::Plugin::Loader.load} and exposed downstream so the
|
|
8
|
+
# contribution merger (slice 3) and diagnostic provenance
|
|
9
|
+
# (slice 5) can iterate over loaded plugin instances in
|
|
10
|
+
# deterministic order.
|
|
11
|
+
#
|
|
12
|
+
# The registry is read-only after construction; ordering is
|
|
13
|
+
# the order in which {Rigor::Plugin::Loader} resolved
|
|
14
|
+
# configuration entries, which is project-config order with
|
|
15
|
+
# plugin-id alphabetical as the tie-breaker.
|
|
16
|
+
class Registry
|
|
17
|
+
attr_reader :plugins, :load_errors
|
|
18
|
+
|
|
19
|
+
# @param plugins [Array<Rigor::Plugin::Base>] instantiated
|
|
20
|
+
# plugin instances in deterministic order.
|
|
21
|
+
# @param load_errors [Array<Rigor::Plugin::LoadError>] failures
|
|
22
|
+
# surfaced during loading. Each error is also turned into a
|
|
23
|
+
# diagnostic by the runner.
|
|
24
|
+
def initialize(plugins: [], load_errors: [])
|
|
25
|
+
@plugins = plugins.dup.freeze
|
|
26
|
+
@load_errors = load_errors.dup.freeze
|
|
27
|
+
freeze
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find(id)
|
|
31
|
+
id_s = id.to_s
|
|
32
|
+
plugins.find { |plugin| plugin.manifest.id == id_s }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ids
|
|
36
|
+
plugins.map { |plugin| plugin.manifest.id }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def empty?
|
|
40
|
+
plugins.empty?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def any_load_errors?
|
|
44
|
+
!load_errors.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
EMPTY = new.freeze
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Plugin
|
|
5
|
+
# Dependency-injection container handed to every plugin's
|
|
6
|
+
# {Rigor::Plugin::Base#init} method. Plugins read from the
|
|
7
|
+
# container; they MUST NOT mutate it. The container is
|
|
8
|
+
# constructed once per `Analysis::Runner.run` and destroyed
|
|
9
|
+
# at the end of the run.
|
|
10
|
+
#
|
|
11
|
+
# ADR-2 § "Registration, Configuration, and Caching" reserves
|
|
12
|
+
# this surface for "constructor injection for analyzer
|
|
13
|
+
# services such as reflection providers, type factories,
|
|
14
|
+
# loggers, and configuration readers". Slice 1 wires four
|
|
15
|
+
# of those:
|
|
16
|
+
#
|
|
17
|
+
# - `reflection`: the {Rigor::Reflection} read-side facade.
|
|
18
|
+
# - `type`: the {Rigor::Type::Combinator} factory module.
|
|
19
|
+
# - `configuration`: the project's {Rigor::Configuration}.
|
|
20
|
+
# - `cache_store`: the {Rigor::Cache::Store} the run is using
|
|
21
|
+
# (or `nil` when caching is disabled). Slice 6 wires
|
|
22
|
+
# plugin-side cache producers through this entry.
|
|
23
|
+
#
|
|
24
|
+
# Loggers are not yet a public surface in the core analyzer;
|
|
25
|
+
# they will be added when the diagnostics formatter grows a
|
|
26
|
+
# progress channel.
|
|
27
|
+
#
|
|
28
|
+
# Slice 2 (Plugin trust / I/O policy) extends the container
|
|
29
|
+
# with `trust_policy` and a per-plugin `io_boundary_for(plugin_id)`
|
|
30
|
+
# factory. Plugins should reach for the boundary rather than
|
|
31
|
+
# raw `File.read` so reads stay within the trusted scope and
|
|
32
|
+
# feed cache invalidation; ADR-2 § "Plugin Trust and I/O
|
|
33
|
+
# Policy" documents the trust model the boundary enforces.
|
|
34
|
+
class Services
|
|
35
|
+
attr_reader :reflection, :type, :configuration, :cache_store, :trust_policy
|
|
36
|
+
|
|
37
|
+
def initialize(reflection:, type:, configuration:, cache_store: nil, trust_policy: nil)
|
|
38
|
+
@reflection = reflection
|
|
39
|
+
@type = type
|
|
40
|
+
@configuration = configuration
|
|
41
|
+
@cache_store = cache_store
|
|
42
|
+
@trust_policy = trust_policy || default_trust_policy
|
|
43
|
+
freeze
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns a fresh {IoBoundary} bound to `plugin_id` and the
|
|
47
|
+
# current `trust_policy`. The boundary accumulates per-plugin
|
|
48
|
+
# cache descriptor entries; the loader / contribution merger
|
|
49
|
+
# constructs one boundary per plugin per run.
|
|
50
|
+
def io_boundary_for(plugin_id)
|
|
51
|
+
IoBoundary.new(policy: @trust_policy, plugin_id: plugin_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def default_trust_policy
|
|
57
|
+
TrustPolicy.new(
|
|
58
|
+
trusted_gems: [],
|
|
59
|
+
allowed_read_roots: [Dir.pwd],
|
|
60
|
+
network_policy: :disabled
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Plugin
|
|
5
|
+
# Declarative trust / I/O policy for the active plugin set.
|
|
6
|
+
# Pinned by [ADR-2 § "Plugin Trust and I/O Policy"](../../../docs/adr/2-extension-api.md):
|
|
7
|
+
# plugins are *trusted Ruby gems selected by the user, their
|
|
8
|
+
# Gemfile, or project configuration*; this class is the
|
|
9
|
+
# programmatic surface that documents that trust and lets the
|
|
10
|
+
# analyzer enforce read scope + network disablement at the
|
|
11
|
+
# documented edges.
|
|
12
|
+
#
|
|
13
|
+
# The policy is **not a sandbox.** A plugin that uses raw
|
|
14
|
+
# `File.read` or `Net::HTTP` bypasses the policy — ADR-2
|
|
15
|
+
# explicitly chooses documentation over forced isolation. The
|
|
16
|
+
# contract is: when plugins go through {Rigor::Plugin::IoBoundary}
|
|
17
|
+
# (the analyzer-side helper service slice 2 introduces), the
|
|
18
|
+
# boundary checks against this policy and feeds compliant reads
|
|
19
|
+
# into the cache descriptor for invalidation. Slices 3-6 wire
|
|
20
|
+
# plugin contributions through the boundary so the policy is
|
|
21
|
+
# the actual mechanism, not just paperwork.
|
|
22
|
+
#
|
|
23
|
+
# ## Fields
|
|
24
|
+
#
|
|
25
|
+
# - `trusted_gems`: gem names the user has authorised. Derived
|
|
26
|
+
# from the `plugins:` section of `.rigor.yml` plus any gems
|
|
27
|
+
# they reach transitively. Used today for documentation and
|
|
28
|
+
# future trust diagnostics.
|
|
29
|
+
# - `allowed_read_roots`: absolute paths plugin code may read
|
|
30
|
+
# from through the {IoBoundary}. The default set covers the
|
|
31
|
+
# project root, the project's `signature_paths`, the active
|
|
32
|
+
# `Gemfile.lock`, and each trusted gem's
|
|
33
|
+
# `Gem::Specification#full_gem_path`. The user extends this
|
|
34
|
+
# with `.rigor.yml`'s `plugins_io.allowed_paths:`.
|
|
35
|
+
# - `network_policy`: `:disabled` in slice 2; the only value
|
|
36
|
+
# accepted today. Plugin {IoBoundary#open_url} always raises
|
|
37
|
+
# while the policy is `:disabled`.
|
|
38
|
+
class TrustPolicy
|
|
39
|
+
VALID_NETWORK_POLICIES = %i[disabled].freeze
|
|
40
|
+
|
|
41
|
+
attr_reader :trusted_gems, :allowed_read_roots, :network_policy
|
|
42
|
+
|
|
43
|
+
def initialize(trusted_gems: [], allowed_read_roots: [], network_policy: :disabled)
|
|
44
|
+
validate_network_policy!(network_policy)
|
|
45
|
+
|
|
46
|
+
@trusted_gems = trusted_gems.map { |g| g.to_s.dup.freeze }.uniq.sort.freeze
|
|
47
|
+
@allowed_read_roots = allowed_read_roots
|
|
48
|
+
.map { |path| File.expand_path(path).freeze }
|
|
49
|
+
.uniq
|
|
50
|
+
.sort
|
|
51
|
+
.freeze
|
|
52
|
+
@network_policy = network_policy
|
|
53
|
+
freeze
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @param path [String]
|
|
57
|
+
# @return [Boolean] true when the absolute path falls inside
|
|
58
|
+
# any allowed read root. Symlinks are resolved through
|
|
59
|
+
# `File.expand_path` only (no `realpath`); plugins with
|
|
60
|
+
# adversarial intent are out of scope per ADR-2.
|
|
61
|
+
def allow_read?(path)
|
|
62
|
+
absolute = File.expand_path(path.to_s)
|
|
63
|
+
@allowed_read_roots.any? { |root| inside?(absolute, root) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def network_allowed?
|
|
67
|
+
@network_policy != :disabled
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def gem_trusted?(name)
|
|
71
|
+
@trusted_gems.include?(name.to_s)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_h
|
|
75
|
+
{
|
|
76
|
+
"trusted_gems" => trusted_gems,
|
|
77
|
+
"allowed_read_roots" => allowed_read_roots,
|
|
78
|
+
"network_policy" => network_policy.to_s
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def validate_network_policy!(policy)
|
|
85
|
+
return if VALID_NETWORK_POLICIES.include?(policy)
|
|
86
|
+
|
|
87
|
+
raise ArgumentError,
|
|
88
|
+
"TrustPolicy network_policy must be one of #{VALID_NETWORK_POLICIES.inspect}, got #{policy.inspect}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def inside?(absolute, root)
|
|
92
|
+
return true if absolute == root
|
|
93
|
+
|
|
94
|
+
prefix = "#{root}#{File::SEPARATOR}"
|
|
95
|
+
absolute.start_with?(prefix)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/rigor/plugin.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "plugin/manifest"
|
|
4
|
+
require_relative "plugin/access_denied_error"
|
|
5
|
+
require_relative "plugin/trust_policy"
|
|
6
|
+
require_relative "plugin/io_boundary"
|
|
7
|
+
require_relative "plugin/services"
|
|
8
|
+
require_relative "plugin/base"
|
|
9
|
+
require_relative "plugin/registry"
|
|
10
|
+
require_relative "plugin/load_error"
|
|
11
|
+
|
|
12
|
+
module Rigor
|
|
13
|
+
module Plugin
|
|
14
|
+
@registered = {}
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def register(plugin_class)
|
|
19
|
+
unless plugin_class.is_a?(Class) && plugin_class < Base
|
|
20
|
+
raise ArgumentError,
|
|
21
|
+
"Rigor::Plugin.register expects a subclass of Rigor::Plugin::Base, got #{plugin_class.inspect}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
manifest = plugin_class.manifest # rigor:disable undefined-method
|
|
25
|
+
@mutex.synchronize do
|
|
26
|
+
existing = @registered[manifest.id]
|
|
27
|
+
if existing && existing != plugin_class
|
|
28
|
+
raise LoadError.new(
|
|
29
|
+
"plugin id #{manifest.id.inspect} already registered to #{existing}, " \
|
|
30
|
+
"cannot re-register to #{plugin_class}",
|
|
31
|
+
plugin_ref: manifest.id
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@registered[manifest.id] = plugin_class
|
|
36
|
+
end
|
|
37
|
+
plugin_class
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def registered_for(id)
|
|
41
|
+
@mutex.synchronize { @registered[id.to_s] }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def registered
|
|
45
|
+
@mutex.synchronize { @registered.dup.freeze }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def unregister!(id = nil)
|
|
49
|
+
@mutex.synchronize do
|
|
50
|
+
if id.nil?
|
|
51
|
+
@registered.clear
|
|
52
|
+
else
|
|
53
|
+
@registered.delete(id.to_s)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
require_relative "plugin/loader"
|
data/lib/rigor/rbs_extended.rb
CHANGED
|
@@ -64,6 +64,23 @@ module Rigor
|
|
|
64
64
|
def falsey_only? = edge == :falsey_only
|
|
65
65
|
def negative? = negative == true
|
|
66
66
|
def refinement? = !refinement_type.nil?
|
|
67
|
+
|
|
68
|
+
# ADR-7 § "Slice 4-A" canonical translation. Lifts the
|
|
69
|
+
# parser-side carrier into a `Rigor::FlowContribution::Fact`
|
|
70
|
+
# that the merger and plugin contribution stream consume
|
|
71
|
+
# uniformly. `class_name` lifts to `Nominal[<class>]`;
|
|
72
|
+
# `refinement_type` is already a `Rigor::Type` and passes
|
|
73
|
+
# through. The `edge` field doesn't survive the conversion —
|
|
74
|
+
# the slot it lands in (truthy_facts / falsey_facts / ...)
|
|
75
|
+
# encodes that.
|
|
76
|
+
def to_fact
|
|
77
|
+
FlowContribution::Fact.new(
|
|
78
|
+
target_kind: target_kind,
|
|
79
|
+
target_name: target_name,
|
|
80
|
+
type: refinement_type || Rigor::Type::Combinator.nominal_of(class_name),
|
|
81
|
+
negative: negative == true
|
|
82
|
+
)
|
|
83
|
+
end
|
|
67
84
|
end
|
|
68
85
|
|
|
69
86
|
# Returned for `assert` / `assert-if-true` /
|
|
@@ -87,6 +104,21 @@ module Rigor
|
|
|
87
104
|
def if_falsey_return? = condition == :if_falsey_return
|
|
88
105
|
def negative? = negative == true
|
|
89
106
|
def refinement? = !refinement_type.nil?
|
|
107
|
+
|
|
108
|
+
# ADR-7 § "Slice 4-A" canonical translation. Same shape as
|
|
109
|
+
# `PredicateEffect#to_fact`; the `condition` field
|
|
110
|
+
# (`:always` / `:if_truthy_return` / `:if_falsey_return`)
|
|
111
|
+
# routes which slot the resulting fact lands in at the
|
|
112
|
+
# `read_flow_contribution` boundary, but does not surface
|
|
113
|
+
# on the Fact itself.
|
|
114
|
+
def to_fact
|
|
115
|
+
FlowContribution::Fact.new(
|
|
116
|
+
target_kind: target_kind,
|
|
117
|
+
target_name: target_name,
|
|
118
|
+
type: refinement_type || Rigor::Type::Combinator.nominal_of(class_name),
|
|
119
|
+
negative: negative == true
|
|
120
|
+
)
|
|
121
|
+
end
|
|
90
122
|
end
|
|
91
123
|
|
|
92
124
|
module_function
|
|
@@ -425,12 +457,16 @@ module Rigor
|
|
|
425
457
|
).freeze
|
|
426
458
|
|
|
427
459
|
# Rolls up every recognised RBS::Extended directive on
|
|
428
|
-
# `method_def` into a single {Rigor::FlowContribution}
|
|
460
|
+
# `method_def` into a single {Rigor::FlowContribution} with
|
|
461
|
+
# the canonical {Rigor::FlowContribution::Fact} payload (see
|
|
462
|
+
# ADR-7 § "Slice 4-A"):
|
|
429
463
|
#
|
|
430
|
-
# - `predicate-if-true`
|
|
431
|
-
# - `predicate-if-false`
|
|
432
|
-
# - `assert
|
|
433
|
-
# - `
|
|
464
|
+
# - `predicate-if-true` → `truthy_facts`
|
|
465
|
+
# - `predicate-if-false` → `falsey_facts`
|
|
466
|
+
# - `assert` → `post_return_facts`
|
|
467
|
+
# - `assert-if-true` → `truthy_facts`
|
|
468
|
+
# - `assert-if-false` → `falsey_facts`
|
|
469
|
+
# - `return:` override → `return_type` (`Rigor::Type`)
|
|
434
470
|
#
|
|
435
471
|
# Param overrides are intentionally NOT included — they refine
|
|
436
472
|
# the call's signature contract rather than its flow facts and
|
|
@@ -452,12 +488,24 @@ module Rigor
|
|
|
452
488
|
build_flow_contribution(predicate_effects, assert_effects, return_override)
|
|
453
489
|
end
|
|
454
490
|
|
|
455
|
-
def build_flow_contribution(predicate_effects, assert_effects, return_override)
|
|
491
|
+
def build_flow_contribution(predicate_effects, assert_effects, return_override) # rubocop:disable Metrics/CyclomaticComplexity
|
|
492
|
+
truthy = predicate_effects.select(&:truthy_only?).map(&:to_fact)
|
|
493
|
+
falsey = predicate_effects.select(&:falsey_only?).map(&:to_fact)
|
|
494
|
+
post_return = []
|
|
495
|
+
|
|
496
|
+
assert_effects.each do |effect|
|
|
497
|
+
case effect.condition
|
|
498
|
+
when :if_truthy_return then truthy << effect.to_fact
|
|
499
|
+
when :if_falsey_return then falsey << effect.to_fact
|
|
500
|
+
else post_return << effect.to_fact
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
456
504
|
FlowContribution.new(
|
|
457
505
|
return_type: return_override,
|
|
458
|
-
truthy_facts: nilable_slot(
|
|
459
|
-
falsey_facts: nilable_slot(
|
|
460
|
-
post_return_facts: nilable_slot(
|
|
506
|
+
truthy_facts: nilable_slot(truthy),
|
|
507
|
+
falsey_facts: nilable_slot(falsey),
|
|
508
|
+
post_return_facts: nilable_slot(post_return),
|
|
461
509
|
provenance: RBS_EXTENDED_PROVENANCE
|
|
462
510
|
)
|
|
463
511
|
end
|
data/lib/rigor/reflection.rb
CHANGED
|
@@ -147,7 +147,7 @@ module Rigor
|
|
|
147
147
|
return nil if loader.nil?
|
|
148
148
|
|
|
149
149
|
loader.instance_definition(class_name.to_s)
|
|
150
|
-
rescue
|
|
150
|
+
rescue ::RBS::BaseError
|
|
151
151
|
nil
|
|
152
152
|
end
|
|
153
153
|
|
|
@@ -157,7 +157,7 @@ module Rigor
|
|
|
157
157
|
return nil if loader.nil?
|
|
158
158
|
|
|
159
159
|
loader.singleton_definition(class_name.to_s)
|
|
160
|
-
rescue
|
|
160
|
+
rescue ::RBS::BaseError
|
|
161
161
|
nil
|
|
162
162
|
end
|
|
163
163
|
|
data/lib/rigor/version.rb
CHANGED
data/lib/rigor.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "rigor/version"
|
|
4
4
|
require_relative "rigor/configuration"
|
|
5
|
+
require_relative "rigor/configuration/severity_profile"
|
|
5
6
|
require_relative "rigor/trinary"
|
|
6
7
|
require_relative "rigor/type"
|
|
7
8
|
require_relative "rigor/ast"
|
|
@@ -27,7 +28,13 @@ require_relative "rigor/cache/rbs_known_class_names"
|
|
|
27
28
|
require_relative "rigor/cache/rbs_class_ancestor_table"
|
|
28
29
|
require_relative "rigor/cache/rbs_class_type_param_names"
|
|
29
30
|
require_relative "rigor/cache/rbs_environment"
|
|
31
|
+
require_relative "rigor/cache/rbs_instance_definitions"
|
|
30
32
|
require_relative "rigor/flow_contribution"
|
|
33
|
+
require_relative "rigor/flow_contribution/fact"
|
|
34
|
+
require_relative "rigor/flow_contribution/conflict"
|
|
35
|
+
require_relative "rigor/flow_contribution/merge_result"
|
|
36
|
+
require_relative "rigor/flow_contribution/merger"
|
|
37
|
+
require_relative "rigor/plugin"
|
|
31
38
|
require_relative "rigor/source"
|
|
32
39
|
require_relative "rigor/inference/scope_indexer"
|
|
33
40
|
require_relative "rigor/inference/coverage_scanner"
|
data/sig/rigor/environment.rbs
CHANGED
|
@@ -32,19 +32,25 @@ module Rigor
|
|
|
32
32
|
class RbsLoader
|
|
33
33
|
attr_reader libraries: Array[String]
|
|
34
34
|
attr_reader signature_paths: Array[String | _ToPath]
|
|
35
|
+
attr_reader cache_store: untyped?
|
|
35
36
|
|
|
36
37
|
def self.default: () -> RbsLoader
|
|
37
38
|
def self.reset_default!: () -> void
|
|
39
|
+
def self.build_env_for: (libraries: Array[String], signature_paths: Array[String | _ToPath]) -> untyped
|
|
38
40
|
|
|
39
|
-
def initialize: (?libraries: Array[String], ?signature_paths: Array[String | _ToPath]) -> void
|
|
41
|
+
def initialize: (?libraries: Array[String], ?signature_paths: Array[String | _ToPath], ?cache_store: untyped?) -> void
|
|
40
42
|
def class_known?: (String | Symbol name) -> bool
|
|
41
43
|
def instance_definition: (String | Symbol class_name) -> untyped?
|
|
42
44
|
def instance_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
|
|
45
|
+
def uncached_instance_definition: (String | Symbol class_name) -> untyped?
|
|
43
46
|
def singleton_definition: (String | Symbol class_name) -> untyped?
|
|
44
47
|
def singleton_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
|
|
48
|
+
def uncached_singleton_definition: (String | Symbol class_name) -> untyped?
|
|
45
49
|
def class_type_param_names: (String | Symbol class_name) -> Array[Symbol]
|
|
46
50
|
def class_ordering: (String | Symbol lhs, String | Symbol rhs) -> ordering
|
|
47
51
|
def constant_type: (String name) -> Type::t?
|
|
52
|
+
def constant_names: () -> Array[String]
|
|
53
|
+
def each_known_class_name: () { (String name) -> void } -> untyped
|
|
48
54
|
end
|
|
49
55
|
|
|
50
56
|
class RbsHierarchy
|
data/sig/rigor/inference.rbs
CHANGED
|
@@ -86,6 +86,7 @@ module Rigor
|
|
|
86
86
|
def self?.narrow_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t
|
|
87
87
|
def self?.narrow_not_class: (Type::t type, String class_name, ?exact: bool, ?environment: Environment) -> Type::t
|
|
88
88
|
def self?.narrow_not_refinement: (Type::t current_type, Type::t refinement_type) -> Type::t
|
|
89
|
+
def self?.narrow_for_fact: (Type::t current, untyped fact, untyped environment) -> Type::t
|
|
89
90
|
def self?.predicate_scopes: (untyped node, Scope scope) -> [Scope, Scope]
|
|
90
91
|
def self?.case_when_scopes: (untyped subject, Array[untyped] conditions, Scope scope) -> [Scope, Scope]
|
|
91
92
|
def self?.analyse: (untyped node, Scope scope) -> untyped
|
data/sig/rigor/rbs_extended.rbs
CHANGED
|
@@ -43,6 +43,8 @@ module Rigor
|
|
|
43
43
|
def self?.read_return_type_override: (untyped method_def) -> Type::t?
|
|
44
44
|
def self?.parse_return_type_override: (String string) -> Type::t?
|
|
45
45
|
|
|
46
|
+
def self?.read_flow_contribution: (untyped method_def) -> untyped?
|
|
47
|
+
|
|
46
48
|
class ParamOverride
|
|
47
49
|
attr_reader param_name: Symbol
|
|
48
50
|
attr_reader type: Type::t
|
data/sig/rigor/scope.rbs
CHANGED
data/sig/rigor/type.rbs
CHANGED
|
@@ -244,9 +244,16 @@ module Rigor
|
|
|
244
244
|
def self?.decimal_int_string: () -> Refined
|
|
245
245
|
def self?.octal_int_string: () -> Refined
|
|
246
246
|
def self?.hex_int_string: () -> Refined
|
|
247
|
+
def self?.literal_string: () -> Refined
|
|
248
|
+
def self?.non_lowercase_string: () -> Refined
|
|
249
|
+
def self?.non_uppercase_string: () -> Refined
|
|
250
|
+
def self?.non_numeric_string: () -> Refined
|
|
251
|
+
def self?.literal_string_carrier?: (Type::t refined) -> bool
|
|
252
|
+
def self?.literal_string_compatible?: (Type::t type) -> bool
|
|
247
253
|
def self?.intersection: (*Type::t members) -> Type::t
|
|
248
254
|
def self?.non_empty_lowercase_string: () -> Type::t
|
|
249
255
|
def self?.non_empty_uppercase_string: () -> Type::t
|
|
256
|
+
def self?.non_empty_literal_string: () -> Type::t
|
|
250
257
|
def self?.integer_range: ((Integer | Symbol) min, (Integer | Symbol) max) -> IntegerRange
|
|
251
258
|
def self?.positive_int: () -> IntegerRange
|
|
252
259
|
def self?.non_negative_int: () -> IntegerRange
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rigortype
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rigor contributors
|
|
@@ -198,6 +198,7 @@ files:
|
|
|
198
198
|
- lib/rigor/cache/rbs_descriptor.rb
|
|
199
199
|
- lib/rigor/cache/rbs_environment.rb
|
|
200
200
|
- lib/rigor/cache/rbs_environment_marshal_patch.rb
|
|
201
|
+
- lib/rigor/cache/rbs_instance_definitions.rb
|
|
201
202
|
- lib/rigor/cache/rbs_known_class_names.rb
|
|
202
203
|
- lib/rigor/cache/store.rb
|
|
203
204
|
- lib/rigor/cli.rb
|
|
@@ -207,11 +208,17 @@ files:
|
|
|
207
208
|
- lib/rigor/cli/type_scan_renderer.rb
|
|
208
209
|
- lib/rigor/cli/type_scan_report.rb
|
|
209
210
|
- lib/rigor/configuration.rb
|
|
211
|
+
- lib/rigor/configuration/severity_profile.rb
|
|
210
212
|
- lib/rigor/environment.rb
|
|
211
213
|
- lib/rigor/environment/class_registry.rb
|
|
212
214
|
- lib/rigor/environment/rbs_hierarchy.rb
|
|
213
215
|
- lib/rigor/environment/rbs_loader.rb
|
|
214
216
|
- lib/rigor/flow_contribution.rb
|
|
217
|
+
- lib/rigor/flow_contribution/conflict.rb
|
|
218
|
+
- lib/rigor/flow_contribution/element.rb
|
|
219
|
+
- lib/rigor/flow_contribution/fact.rb
|
|
220
|
+
- lib/rigor/flow_contribution/merge_result.rb
|
|
221
|
+
- lib/rigor/flow_contribution/merger.rb
|
|
215
222
|
- lib/rigor/inference/acceptance.rb
|
|
216
223
|
- lib/rigor/inference/block_parameter_binder.rb
|
|
217
224
|
- lib/rigor/inference/builtins/array_catalog.rb
|
|
@@ -255,6 +262,16 @@ files:
|
|
|
255
262
|
- lib/rigor/inference/rbs_type_translator.rb
|
|
256
263
|
- lib/rigor/inference/scope_indexer.rb
|
|
257
264
|
- lib/rigor/inference/statement_evaluator.rb
|
|
265
|
+
- lib/rigor/plugin.rb
|
|
266
|
+
- lib/rigor/plugin/access_denied_error.rb
|
|
267
|
+
- lib/rigor/plugin/base.rb
|
|
268
|
+
- lib/rigor/plugin/io_boundary.rb
|
|
269
|
+
- lib/rigor/plugin/load_error.rb
|
|
270
|
+
- lib/rigor/plugin/loader.rb
|
|
271
|
+
- lib/rigor/plugin/manifest.rb
|
|
272
|
+
- lib/rigor/plugin/registry.rb
|
|
273
|
+
- lib/rigor/plugin/services.rb
|
|
274
|
+
- lib/rigor/plugin/trust_policy.rb
|
|
258
275
|
- lib/rigor/rbs_extended.rb
|
|
259
276
|
- lib/rigor/reflection.rb
|
|
260
277
|
- lib/rigor/scope.rb
|