class RuboCop::Cop::Sorbet::BuggyObsoleteStrictMemoization
@see Sorbet/ObsoleteStrictMemoization
end
@foo ||= some_computation
@foo = T.let(@foo, T.nilable(Foo))
# ⚠️If ‘some_computation` has side effects, this might be a breaking change!
# This will now memoize the value as was likely intended, so `some_computation` is only ever called once.
def foo
sig { returns(Foo) }
# good
end
@foo ||= some_computation
@foo = T.let(nil, T.nilable(Foo))
# This `nil` is likely a mistake, causing the memoized value to be discarded and recomputed on every call.
def foo
sig { returns(Foo) }
# bad
@example
to the affected method) can be observed, and might be a breaking change.
If the computation being memoized had side effects, calling it only once (instead of once on every call
@safety
See `Sorbet/ObsoleteStrictMemoization` for more details.
the `Sorbet/ObsoleteStrictMemoization` cop.
The result of this correction will be the “obsolete memoization pattern”, which can further be corrected by
This cop will correct it to read from the ivar instead of `nil`, which will memoize it correctly.
on every call, causing the memoized value to be discarded and recomputed on every call.
for older Sorbet versions in `#typed: strict` files. The mistaken variant would overwrite the ivar with `nil`
Checks for the a mistaken variant of the “obsolete memoization pattern” that used to be required
def on_begin(node)
def on_begin(node) buggy_legacy_memoization_pattern?(node) do |ivar, nil_node| add_offense(nil_node) do |corrector| corrector.replace( range_between(nil_node.source_range.begin_pos, nil_node.source_range.end_pos), ivar, ) end end end
def relevant_file?(file)
def relevant_file?(file) super && sorbet_enabled? end