Skip to content
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

[eslint-plugin-react-hooks] Fix cyclic caching for loops containing a… #16853

Merged
merged 4 commits into from Feb 25, 2020

Conversation

M-Izadmehr
Copy link
Contributor

This MR Fixes a bug (#16832) in the eslint-plugin-react-hooks, where caching of cycles is performed wrong in some cases.

Example: https://codesandbox.io/s/exciting-bhabha-mqj7q

Description
If the user uses an if statement inside a for ... of obj statement, and uses a correct hook afterwards, the eslint shows an error that:
React Hook "${hook}" is called conditionally. React Hooks must be called in the exact same order in every component render.

Reports
I guess that it is already known issue because, inside the ESLintRulesOfHooks.js - L562, it is already known that in some cases caching of cyclic paths in code path, might result in the wrong errors.

Also (#16832) reports this case too.

Reason
Eslint uses CodePathSegment which is similar to doubly linked list. Based on the CodePathSegment AST different types of cyclic segments might happen. In the special case of ForInStatement there are two paths from obj identifier to the next segment. In such a graph, in order to traverse all the paths from start to end, we need to not only remember the current segment, but also the whole path.

The current code uses a simple caching just by name of segments (and not the list of segment history) as a result, whenever it faces a cycle, it breaks the cycle by returning 0. As a result, there might be several conditions, where the segment might have cyclic and not cyclic paths to end. In the current code, if the first path is cyclic all the non-cyclic ones are thrown away. And depending on the starting point and endpoint of AST, we might have different results.

For example for the demo code, the result of RulesOfHooks.js - L404, the value of all allPathsFromStartToEnd is calculated as 2 instead of 3

Solution
We need caching of responses and also saving cyclic paths for later logic, In the new code, I added a different caching mechanism, which also remembers the path history too. The effect of the performance is still negligible because even for the most difficult test including 1099511627776 paths from start to end of the code, it only increases the time about 0.3s on MacBookPro.

@facebook-github-bot
Copy link

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed.

If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks!

@sizebot
Copy link

sizebot commented Sep 22, 2019

No significant bundle size changes to report.

Generated by 🚫 dangerJS against 7e28144

@facebook-github-bot
Copy link

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!


cache.set(segment.id, paths);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think unnecessary diff in here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why, but I am not sure why it considers this line as changed:)

Co-Authored-By: Luke Kang <kidkkr@icloud.com>
@stale
Copy link

stale bot commented Jan 9, 2020

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution.

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Jan 9, 2020
@stale
Copy link

stale bot commented Jan 16, 2020

Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you!

@stale stale bot closed this Jan 16, 2020
@TrySound
Copy link
Contributor

@gaearon This problem is still relevant.

@gaearon gaearon reopened this Feb 25, 2020
@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Feb 25, 2020
@gaearon gaearon merged commit bf13d3e into facebook:master Feb 25, 2020
@gaearon
Copy link
Collaborator

gaearon commented Feb 25, 2020

Thanks!

@M-Izadmehr
Copy link
Contributor Author

I almost forgot about this :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants