-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
close_sinks rule false positive #57882
Comments
From @lukepighetti on December 9, 2018 21:32 It looks like your close function is outside of your Bloc class. Can you confirm? |
@jaumard : could you share a more complete example so we can reproduce on our end? Thanks! |
Sure I'll do a small example asap, but the simple way to reproduce can be to simply put the Stream under a List and then iterate on the list to close them, the linter will still say it's not closed. |
I suspect the problem is that lint rules are limited to performing local analysis and that the coding style you're describing would require non-local analysis. Using this rule as an example, it can check to see whether a stream opened in a given method is closed before that method exists, but it cannot verify that if an instance of I would propose that the solution is to not produce a lint when a stream is assigned to a field, added to a collection, or otherwise escapes the bounds of what the rule can look at to verify safety. |
Great proposal. 👍 |
I recently faced a similar but different issue with close_sinks: Consider the following function that returns a Sink getSink(); Then used as such: final sink = getSink(); This will trigger a |
I've created a sample app which you can use to reproduce the issue at https://github.com/felangel/bloc-close-sinks-bug. Hope that helps 👍 |
Thanks a million @felangel! |
@pq is there any update on this? |
Hey @felangel. Sorry no, I haven't had time to dig in. Looking at felangel/bloc#572 (comment), I'm missing some context too. Are |
@pq BlocProvider automatically closes them when it is disposed (implementation). Please let me know if you have any other questions or if there’s anything else I can do to help, thanks! |
Great. It sounds like we want to ignore blocks created by The initial hurdle is a bit mechanical since I need mock out a bunch of your classes (and now that I'm looking, that's more cumbersome than it should be...) I'll update this issue w/ progress. |
As a more general rule, maybe this warning should simply not trigger for sinks that are returned by a function:
|
Interesting idea @rrousselGit! I'm definitely for generalizing but need to think this through. /fyi @bwilkerson (maybe we can chat about this later?) |
Ok, a few follow-ups. Thanks all for the thoughtful input so far! @felangel: how do you ensure As for @rrousselGit's suggestion, after a conversation w/ @bwilkerson I'm cooling on it after hearing about experiences with exceptions made to a similar rule implemented in CodePro. My thinking now is to just update the predicate to be something like:
It seems like that would at least hand the If there are other framework classes that are similarly managed we could consider adding a more general purpose marker interface or annotation. @felangel, @rrousselGit: wdyt? |
@pq thanks for the quick follow-up! Your proposal would address the false positive but it would also remove the warning in places where a Ideally, we'd be able to determine where the bloc was instantiated and disable the warning if it was done in the context of BlocProvider's builder. BlocProvider(
builder: (_) => MyBloc(), // sink is automatically closed
child: MyChild(),
), It would be nice to still have the warning in cases where the bloc is instantiated manually. BlocProvider.value(
value: MyBloc(), // sink is not automatically closed
); void main() {
final bloc = MyBloc(); // sink is not automatically closed
} Thoughts? |
I don't like the exception specific for For example, And doing this: BlocProvider.value(
value: MyBloc(),
); should trigger the warning because the bloc is never closed. |
Ah, OK. There are a number of issues here apparently. 🤔 @rrousselGit that's a great example and points out a short-coming in our current implementation. I'm pretty sure this won't fire at all currently BlocProvider.value(
value: MyBloc(),
); And nor would this unassigned File('foo.txt').openWrite(); (which seems like a bug to me.) Maybe we should take a step back and try and specify exactly the desired analysis. I'm wondering if maybe Tabling fixing BlocProvider(
builder: (_) => MyBloc(), // OK
child: MyChild(),
),
final counterBloc = BlocProvider.of<CounterBloc>(context); // OK
BlocProvider.value(
value: MyBloc(), // LINT
);
final counterBloc = MyBloc(); // LINT
|
@pq I think the snippets you've provided cover the bloc-specific cases and desired behavior 👍 |
If something as specific as
Which then expends the discussion into how |
@rrousselGit I don't think this is a Flutter specific topic and it isn't just scoped to a widget's build. In my opinion, keeping a widget's build pure is a separate topic. In this case, maybe |
The topic is not Flutter specific, but the proposed solution is. Take this snippet: BlocProvider(
builder: (_) => MyBloc(), // OK
child: MyChild(),
),
final counterBloc = BlocProvider.of<CounterBloc>(context); // OK
BlocProvider.value(
value: MyBloc(), // LINT
);
final counterBloc = MyBloc(); // LINT It falls in the same situation as: ChangeNotifierProvider(
builder: (_) => MyChangeNotifier(), // OK
child: MyChild(),
),
final counterBloc = Provider.of<CounterBloc>(context); // OK
ChangeNotifierProvider.value(
value: MyChangeNotifier(), // LINT
);
final counterBloc = MyChangeNotifier(); // LINT Same thing with |
@rrousselGit can you elaborate on I agree that there is a lot in common between In any case, I also prefer not to have a |
@pq are there any updates on this? Thanks! |
Hi @felangel. Sorry no, this stalled out without a consensus on direction. Let's re-open the conversation now. @rrousselGit: any additional thoughts? |
@rrousselGit: any additional thoughts on this one? |
bump |
Sorry @felangel. We've been focussed elsewhere. @rrousselGit: do you have any additional thoughts on this? |
Additional, no
But I'm still convinced that the situation shouldn't be flutter_bloc
specific.
IMO the fix should be "if the sink comes from a function, or is returned by
the function that creates it, we don't need to warn"
…On Tue, 26 May 2020, 16:20 Phil Quitslund, ***@***.***> wrote:
Sorry @felangel <https://github.com/felangel>. We've been focussed
elsewhere. @rrousselGit <https://github.com/rrousselGit>: do you have any
additional thoughts on this?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#57882>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AEZ3I3JHMMAVZNDWBJE7HQDRTPM3VANCNFSM4GRL6XIA>
.
|
Thanks! See also parallel conversation in #58175. |
Hi, any news on that? 🎅 |
@pq late to the party here, but i'm running into this same error. it sounds like i should just ignore the error for now since there's no way around it? it's only a yellow error and my code is working fine |
This one is triggering for me: class RecordService {
StreamController<Duration>? _progress$; // here
Stream<Duration> record() {
_progress$ = StreamController();
Timer.periodic(const Duration(seconds: 1), (timer) {
if (_progress$ != null) {
_progress$!.add(Duration(seconds: timer.tick));
}
else {
timer.cancel();
}
});
return _progress$!.stream.asBroadcastStream();
}
Future<String> stop() async {
await _progress$!.close();
_progress$ = null;
return 'path';
}
} |
For what it's worth, this seems to happen if the No warning: class Abc {
// No warning here
final _streamController = StreamController<String>();
void dispose() {
this._streamController.close();
}
} Warning: class Abc<T> {
// Warning: Close instances of `dart.core.Sink`
final _streamController = StreamController<String>();
void dispose() {
this._streamController.close();
}
} |
* Added `userAgentPackageName` implementation Improved headers implementation Deprecated `NonCachingNetworkTileProvider` in favour of `NetworkNoRetryTileProvider` Updated example pages with changes Improved documentation * Temporarily fixed multiple User-Agent headers Fixed usage of `NetworkTileProvider` Fixed deprecation notice invalid symbol reference * Removed some old TODOs Simplified `_positionedForOverlay` (solved TODO) Improved maintainability Improved documentation * Removed old deprecations (`placeholderImage` and `attributionBuilder`) * Atempt to fix `HttpOverrides` issue - unsuccessful: dart-lang/sdk#49382 (comment) * Fixed issues Added custom `ImageProvider`s Reduced reliance on 'universal_io' library Prepared for review * Fixed web platform support Seperated tile_provider.dart for web and other plaforms Removed 'universal_io' dependency Updated CHANGELOG * Fixed 'Refused to set unsafe header' error * Improved in-code documentation * Removed deprecated API remenant `attributionAlignment` from `TileLayerOptions` * Fix false positive linter warning: see https://github.com/dart-lang/linter/issues/1381 * Improved documentation Refactored base `TileProvider` into independent file
From @jaumard on November 20, 2018 12:37
With the following code:
dart analyzer still warn about sink not closed, but it is. Or do I miss something ?
ENV:
Dart VM version: 2.1.0-dev.9.4.flutter-f9ebf21297 (Thu Nov 8 23:00:07 2018 +0100) on "macos_x64"
Copied from original issue: #35221
The text was updated successfully, but these errors were encountered: