diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af.expect.md
new file mode 100644
index 0000000000..300fe4c181
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid -- this is a regression test.
+jest.useFakeTimers();
+beforeEach(() => {
+ jest.useRealTimers();
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid -- this is a regression test.
+jest.useFakeTimers();
+beforeEach(() => {
+ jest.useRealTimers();
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c.expect.md
new file mode 100644
index 0000000000..9c80a890ab
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c.expect.md
@@ -0,0 +1,40 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because hooks can be used in anonymous function arguments to
+// React.memo.
+const MemoizedFunction = React.memo((props) => {
+ useHook();
+ return ;
+});
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Unsupported input
+
+// Valid because hooks can be used in anonymous function arguments to
+// React.memo.
+const MemoizedFunction = React.memo((props) => {
+ const $ = useMemoCache(2);
+ useHook();
+ let t0;
+ if ($[0] !== props) {
+ t0 = ;
+ $[0] = props;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b.expect.md
new file mode 100644
index 0000000000..52517cb31d
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b.expect.md
@@ -0,0 +1,52 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
+ useEffect(() => {
+ useHookInsideCallback();
+ });
+ return ;
+});
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Unsupported input
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
+ const $ = useMemoCache(4);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = () => {
+ useHookInsideCallback();
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ useEffect(t0);
+ let t1;
+ if ($[1] !== props || $[2] !== ref) {
+ t1 = ;
+ $[1] = props;
+ $[2] = ref;
+ $[3] = t1;
+ } else {
+ t1 = $[3];
+ }
+ return t1;
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md
new file mode 100644
index 0000000000..2dd81654c4
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md
@@ -0,0 +1,159 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because the neither the conditions before or after the hook affect the hook call
+// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
+const useSomeHook = () => {};
+
+const SomeName = () => {
+ const filler = FILLER ?? FILLER ?? FILLER;
+ const filler2 = FILLER ?? FILLER ?? FILLER;
+ const filler3 = FILLER ?? FILLER ?? FILLER;
+ const filler4 = FILLER ?? FILLER ?? FILLER;
+ const filler5 = FILLER ?? FILLER ?? FILLER;
+ const filler6 = FILLER ?? FILLER ?? FILLER;
+ const filler7 = FILLER ?? FILLER ?? FILLER;
+ const filler8 = FILLER ?? FILLER ?? FILLER;
+
+ useSomeHook();
+
+ if (anyConditionCanEvenBeFalse) {
+ return null;
+ }
+
+ return (
+
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+
+ );
+};
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Unsupported input
+
+// Valid because the neither the conditions before or after the hook affect the hook call
+// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
+const useSomeHook = () => {};
+
+const SomeName = () => {
+ const $ = useMemoCache(1);
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+ (FILLER ?? FILLER, FILLER) ?? FILLER;
+
+ useSomeHook();
+ if (anyConditionCanEvenBeFalse) {
+ return null;
+ }
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = (
+
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+ {FILLER ? FILLER : FILLER}
+
+ );
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+};
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8.expect.md
new file mode 100644
index 0000000000..7ef06b9267
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8.expect.md
@@ -0,0 +1,51 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+const ComponentWithHookInsideCallback = React.memo((props) => {
+ useEffect(() => {
+ useHookInsideCallback();
+ });
+ return ;
+});
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Unsupported input
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+const ComponentWithHookInsideCallback = React.memo((props) => {
+ const $ = useMemoCache(3);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = () => {
+ useHookInsideCallback();
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ useEffect(t0);
+ let t1;
+ if ($[1] !== props) {
+ t1 = ;
+ $[1] = props;
+ $[2] = t1;
+ } else {
+ t1 = $[2];
+ }
+ return t1;
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e.expect.md
new file mode 100644
index 0000000000..bfab4aab23
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e.expect.md
@@ -0,0 +1,99 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because hooks can call hooks.
+function useHook() {
+ useState();
+}
+const whatever = function useHook() {
+ useState();
+};
+const useHook1 = () => {
+ useState();
+};
+let useHook2 = () => useState();
+useHook2 = () => {
+ useState();
+};
+({
+ useHook: () => {
+ useState();
+ },
+});
+({
+ useHook() {
+ useState();
+ },
+});
+const {
+ useHook3 = () => {
+ useState();
+ },
+} = {};
+({
+ useHook = () => {
+ useState();
+ },
+} = {});
+Namespace.useHook = () => {
+ useState();
+};
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because hooks can call hooks.
+function useHook() {
+ useState();
+}
+
+const whatever = function useHook() {
+ useState();
+};
+
+const useHook1 = () => {
+ useState();
+};
+
+let useHook2 = () => {
+ return useState();
+};
+useHook2 = () => {
+ useState();
+};
+
+({
+ useHook: () => {
+ useState();
+ },
+});
+({
+ useHook() {
+ useState();
+ },
+});
+const {
+ useHook3 = () => {
+ useState();
+ },
+} = {};
+({
+ useHook = () => {
+ useState();
+ },
+} = {});
+Namespace.useHook = () => {
+ useState();
+};
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f.expect.md
new file mode 100644
index 0000000000..222529f031
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f.expect.md
@@ -0,0 +1,41 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because hooks can be used in anonymous arrow-function arguments
+// to forwardRef.
+const FancyButton = React.forwardRef((props, ref) => {
+ useHook();
+ return ;
+});
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Unsupported input
+
+// Valid because hooks can be used in anonymous arrow-function arguments
+// to forwardRef.
+const FancyButton = React.forwardRef((props, ref) => {
+ const $ = useMemoCache(3);
+ useHook();
+ let t0;
+ if ($[0] !== props || $[1] !== ref) {
+ t0 = ;
+ $[0] = props;
+ $[1] = ref;
+ $[2] = t0;
+ } else {
+ t0 = $[2];
+ }
+ return t0;
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460.expect.md
new file mode 100644
index 0000000000..06190913b5
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460.expect.md
@@ -0,0 +1,101 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Currently invalid.
+// These are variations capturing the current heuristic--
+// we only allow hooks in PascalCase or useFoo functions.
+// We *could* make some of these valid. But before doing it,
+// consider specific cases documented above that contain reasoning.
+function a() {
+ useState();
+}
+const whatever = function b() {
+ useState();
+};
+const c = () => {
+ useState();
+};
+let d = () => useState();
+e = () => {
+ useState();
+};
+({
+ f: () => {
+ useState();
+ },
+});
+({
+ g() {
+ useState();
+ },
+});
+const {
+ j = () => {
+ useState();
+ },
+} = {};
+({
+ k = () => {
+ useState();
+ },
+} = {});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Unsupported input
+
+// Currently invalid.
+// These are variations capturing the current heuristic--
+// we only allow hooks in PascalCase or useFoo functions.
+// We *could* make some of these valid. But before doing it,
+// consider specific cases documented above that contain reasoning.
+function a() {
+ useState();
+}
+
+const whatever = function b() {
+ useState();
+};
+
+const c = () => {
+ useState();
+};
+
+let d = () => {
+ return useState();
+};
+e = () => {
+ useState();
+};
+
+({
+ f: () => {
+ useState();
+ },
+});
+({
+ g() {
+ useState();
+ },
+});
+const {
+ j = () => {
+ useState();
+ },
+} = {};
+({
+ k = () => {
+ useState();
+ },
+} = {});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-368024110a58.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-368024110a58.expect.md
new file mode 100644
index 0000000000..4a71e3c9c2
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-368024110a58.expect.md
@@ -0,0 +1,26 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+const FancyButton = forwardRef(function (props, ref) {
+ if (props.fancy) {
+ useCustomHook();
+ }
+ return ;
+});
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-8566f9a360e2.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-8566f9a360e2.expect.md
new file mode 100644
index 0000000000..97c2d87316
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-8566f9a360e2.expect.md
@@ -0,0 +1,26 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+const MemoizedButton = memo(function (props) {
+ if (props.fancy) {
+ useCustomHook();
+ }
+ return ;
+});
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-a0058f0b446d.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-a0058f0b446d.expect.md
new file mode 100644
index 0000000000..cf5f00f894
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-a0058f0b446d.expect.md
@@ -0,0 +1,25 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function ComponentWithConditionalHook() {
+ if (cond) {
+ Namespace.useConditionalHook();
+ }
+}
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-27c18dc8dad2.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-27c18dc8dad2.expect.md
new file mode 100644
index 0000000000..88fa4fbdcb
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-27c18dc8dad2.expect.md
@@ -0,0 +1,26 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+const FancyButton = React.forwardRef((props, ref) => {
+ if (props.fancy) {
+ useCustomHook();
+ }
+ return ;
+});
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-27c18dc8dad2.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-27c18dc8dad2.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-27c18dc8dad2.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-27c18dc8dad2.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-69521d94fa03.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-69521d94fa03.expect.md
new file mode 100644
index 0000000000..c7626edd61
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-69521d94fa03.expect.md
@@ -0,0 +1,28 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because the neither the condition nor the loop affect the hook call.
+function App(props) {
+ const someObject = { propA: true };
+ for (const propName in someObject) {
+ if (propName === true) {
+ } else {
+ }
+ }
+ const [myState, setMyState] = useState(null);
+}
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (12:12)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-69521d94fa03.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-69521d94fa03.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-69521d94fa03.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-69521d94fa03.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-93dc5d5e538a.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-93dc5d5e538a.expect.md
new file mode 100644
index 0000000000..c6ba4426d0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-93dc5d5e538a.expect.md
@@ -0,0 +1,27 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Valid because the loop doesn't change the order of hooks calls.
+function RegressionTest() {
+ const res = [];
+ const additionalCond = true;
+ for (let i = 0; i !== 10 && additionalCond; ++i) {
+ res.push(i);
+ }
+ React.useLayoutEffect(() => {});
+}
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (11:11)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-93dc5d5e538a.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-93dc5d5e538a.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-93dc5d5e538a.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-93dc5d5e538a.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-d0935abedc42.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-d0935abedc42.expect.md
new file mode 100644
index 0000000000..406fb8ace0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-d0935abedc42.expect.md
@@ -0,0 +1,25 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// This is valid because "use"-prefixed functions called in
+// unnamed function arguments are not assumed to be hooks.
+React.unknownFunction((foo, bar) => {
+ if (foo) {
+ useNotAHook(bar);
+ }
+});
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-d0935abedc42.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-d0935abedc42.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-d0935abedc42.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-d0935abedc42.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-e29c874aa913.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-e29c874aa913.expect.md
new file mode 100644
index 0000000000..83274b52ec
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-e29c874aa913.expect.md
@@ -0,0 +1,26 @@
+
+## Input
+
+```javascript
+// @skip
+// Unsupported input
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function useHook() {
+ try {
+ f();
+ useState();
+ } catch {}
+}
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (9:9)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e29c874aa913.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-e29c874aa913.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-e29c874aa913.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.rules-of-hooks-e29c874aa913.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0.expect.md
new file mode 100644
index 0000000000..1d1a58e602
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0.expect.md
@@ -0,0 +1,45 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function createHook() {
+ return function useHookWithConditionalHook() {
+ if (cond) {
+ useConditionalHook();
+ }
+ };
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function createHook() {
+ const $ = useMemoCache(1);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = function useHookWithConditionalHook() {
+ if (cond) {
+ useConditionalHook();
+ }
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-0a1dbff27ba0.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-0a1dbff27ba0.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b.expect.md
new file mode 100644
index 0000000000..0f8c4eef1b
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b.expect.md
@@ -0,0 +1,45 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function createComponent() {
+ return function ComponentWithHookInsideCallback() {
+ useEffect(() => {
+ useHookInsideCallback();
+ });
+ };
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function createComponent() {
+ const $ = useMemoCache(1);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = function ComponentWithHookInsideCallback() {
+ useEffect(() => {
+ useHookInsideCallback();
+ });
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-0de1224ce64b.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-0de1224ce64b.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8.expect.md
new file mode 100644
index 0000000000..2ec80a9fc9
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8.expect.md
@@ -0,0 +1,41 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous.
+// Normally, this would crash, but not if you use inline requires.
+// This *must* be invalid.
+// It's expected to have some false positives, but arguably
+// they are confusing anyway due to the use*() convention
+// already being associated with Hooks.
+useState();
+if (foo) {
+ const foo = React.useCallback(() => {});
+}
+useCustomHook();
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous.
+// Normally, this would crash, but not if you use inline requires.
+// This *must* be invalid.
+// It's expected to have some false positives, but arguably
+// they are confusing anyway due to the use*() convention
+// already being associated with Hooks.
+useState();
+if (foo) {
+ const foo = React.useCallback(() => {});
+}
+useCustomHook();
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-191029ac48c8.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-191029ac48c8.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c.expect.md
new file mode 100644
index 0000000000..ebc33e5ccf
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c.expect.md
@@ -0,0 +1,37 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// This is a false positive (it's valid) that unfortunately
+// we cannot avoid. Prefer to rename it to not start with "use"
+class Foo extends Component {
+ render() {
+ if (cond) {
+ FooStore.useFeatureFlag();
+ }
+ }
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// This is a false positive (it's valid) that unfortunately
+// we cannot avoid. Prefer to rename it to not start with "use"
+class Foo extends Component {
+ render() {
+ if (cond) {
+ FooStore.useFeatureFlag();
+ }
+ }
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-206e2811c87c.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-206e2811c87c.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7.expect.md
new file mode 100644
index 0000000000..c68c6e8ba0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7.expect.md
@@ -0,0 +1,43 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Technically this is a false positive.
+// We *could* make it valid (and it used to be).
+//
+// However, top-level Hook-like calls can be very dangerous
+// in environments with inline requires because they can mask
+// the runtime error by accident.
+// So we prefer to disallow it despite the false positive.
+
+const { createHistory, useBasename } = require("history-2.1.2");
+const browserHistory = useBasename(createHistory)({
+ basename: "/",
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Technically this is a false positive.
+// We *could* make it valid (and it used to be).
+//
+// However, top-level Hook-like calls can be very dangerous
+// in environments with inline requires because they can mask
+// the runtime error by accident.
+// So we prefer to disallow it despite the false positive.
+
+const { createHistory, useBasename } = require("history-2.1.2");
+const browserHistory = useBasename(createHistory)({
+ basename: "/",
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-28a7111f56a7.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-28a7111f56a7.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a.expect.md
new file mode 100644
index 0000000000..c0649482d8
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ useHook() {
+ useState();
+ }
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ useHook() {
+ useState();
+ }
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-2c51251df67a.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-2c51251df67a.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83.expect.md
new file mode 100644
index 0000000000..1cb7604edf
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83.expect.md
@@ -0,0 +1,41 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function createComponent() {
+ return function ComponentWithHookInsideCallback() {
+ function handleClick() {
+ useState();
+ }
+ };
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function createComponent() {
+ const $ = useMemoCache(1);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = function ComponentWithHookInsideCallback() {};
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-449a37146a83.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-449a37146a83.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa.expect.md
new file mode 100644
index 0000000000..2f576bb961
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa.expect.md
@@ -0,0 +1,34 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// These are neither functions nor hooks.
+function _normalFunctionWithHook() {
+ useHookInsideNormalFunction();
+}
+function _useNotAHook() {
+ useHookInsideNormalFunction();
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// These are neither functions nor hooks.
+function _normalFunctionWithHook() {
+ useHookInsideNormalFunction();
+}
+
+function _useNotAHook() {
+ useHookInsideNormalFunction();
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-5a7ac9a6e8fa.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-5a7ac9a6e8fa.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9.expect.md
new file mode 100644
index 0000000000..54cd30c3cc
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function ComponentWithHookInsideCallback() {
+ function handleClick() {
+ useState();
+ }
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function ComponentWithHookInsideCallback() {}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-76a74b4666e9.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-76a74b4666e9.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c.expect.md
new file mode 100644
index 0000000000..26c4a63175
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class ClassComponentWithHook extends React.Component {
+ render() {
+ React.useState();
+ }
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class ClassComponentWithHook extends React.Component {
+ render() {
+ React.useState();
+ }
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-8303403b8e4c.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-8303403b8e4c.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1.expect.md
new file mode 100644
index 0000000000..fdba1ca765
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1.expect.md
@@ -0,0 +1,33 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class ClassComponentWithFeatureFlag extends React.Component {
+ render() {
+ if (foo) {
+ useFeatureFlag();
+ }
+ }
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class ClassComponentWithFeatureFlag extends React.Component {
+ render() {
+ if (foo) {
+ useFeatureFlag();
+ }
+ }
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-99b5c750d1d1.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-99b5c750d1d1.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b.expect.md
new file mode 100644
index 0000000000..ecdca8a2a8
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ h = () => {
+ useState();
+ };
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ h = () => {
+ useState();
+ };
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-9c79feec4b9b.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-9c79feec4b9b.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0.expect.md
new file mode 100644
index 0000000000..403e200dd6
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// This is invalid because "use"-prefixed functions used in named
+// functions are assumed to be hooks.
+React.unknownFunction(function notAComponent(foo, bar) {
+ useProbablyAHook(bar);
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// This is invalid because "use"-prefixed functions used in named
+// functions are assumed to be hooks.
+React.unknownFunction(function notAComponent(foo, bar) {
+ useProbablyAHook(bar);
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-a63fd4f9dcc0.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-a63fd4f9dcc0.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e.expect.md
new file mode 100644
index 0000000000..20b1fd657b
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e.expect.md
@@ -0,0 +1,31 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class C {
+ m() {
+ This.useHook();
+ Super.useHook();
+ }
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+class C {
+ m() {
+ This.useHook();
+ Super.useHook();
+ }
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-acb56658fe7e.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-acb56658fe7e.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676.expect.md
new file mode 100644
index 0000000000..d9eaea7004
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676.expect.md
@@ -0,0 +1,33 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Currently invalid because it violates the convention and removes the "taint"
+// from a hook. We *could* make it valid to avoid some false positives but let's
+// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
+// cases which must remain invalid.
+function normalFunctionWithHook() {
+ useHookInsideNormalFunction();
+}
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Currently invalid because it violates the convention and removes the "taint"
+// from a hook. We *could* make it valid to avoid some false positives but let's
+// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
+// cases which must remain invalid.
+function normalFunctionWithHook() {
+ useHookInsideNormalFunction();
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-c59788ef5676.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-c59788ef5676.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450.expect.md
new file mode 100644
index 0000000000..d597564eb3
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450.expect.md
@@ -0,0 +1,45 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function createComponent() {
+ return function ComponentWithConditionalHook() {
+ if (cond) {
+ useConditionalHook();
+ }
+ };
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function createComponent() {
+ const $ = useMemoCache(1);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = function ComponentWithConditionalHook() {
+ if (cond) {
+ useConditionalHook();
+ }
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-d842d36db450.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-d842d36db450.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597.expect.md
new file mode 100644
index 0000000000..215bfbed28
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597.expect.md
@@ -0,0 +1,41 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function ComponentWithHookInsideCallback() {
+ useEffect(() => {
+ useHookInsideCallback();
+ });
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's a common misunderstanding.
+// We *could* make it valid but the runtime error could be confusing.
+function ComponentWithHookInsideCallback() {
+ const $ = useMemoCache(1);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = () => {
+ useHookInsideCallback();
+ };
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ useEffect(t0);
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-d952b82c2597.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-d952b82c2597.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63.expect.md
new file mode 100644
index 0000000000..10080ab54f
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ i() {
+ useState();
+ }
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ i() {
+ useState();
+ }
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-ddeca9708b63.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-ddeca9708b63.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8.expect.md
new file mode 100644
index 0000000000..8bb65427e0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8.expect.md
@@ -0,0 +1,46 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function renderItem() {
+ useState();
+}
+
+function List(props) {
+ return props.items.map(renderItem);
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
+// Passed but should have failed
+
+// Invalid because it's dangerous and might not warn otherwise.
+// This *must* be invalid.
+function renderItem() {
+ useState();
+}
+
+function List(props) {
+ const $ = useMemoCache(2);
+ let t0;
+ if ($[0] !== props.items) {
+ t0 = props.items.map(renderItem);
+ $[0] = props.items;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-e675f0a672d8.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-e675f0a672d8.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3.expect.md
new file mode 100644
index 0000000000..3b57c7a398
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ useHook = () => {
+ useState();
+ };
+});
+
+```
+
+## Code
+
+```javascript
+// @skip
+// Passed but should have failed
+
+(class {
+ useHook = () => {
+ useState();
+ };
+});
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-e69ffce323c3.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-e69ffce323c3.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-f6f37b63b2d4.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-f6f37b63b2d4
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.error.invalid-rules-of-hooks-f6f37b63b2d4.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/todo.invalid.invalid-rules-of-hooks-f6f37b63b2d4
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.expect.md
new file mode 100644
index 0000000000..be645aa92d
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.expect.md
@@ -0,0 +1,27 @@
+
+## Input
+
+```javascript
+import { identity } from "shared-runtime";
+
+const SCALE = 2;
+function Component(props) {
+ const { [props.name]: value } = props;
+ return value;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ name: "Sathya" }],
+};
+
+```
+
+
+## Error
+
+```
+[ReactForget] Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern (5:5)
+```
+
+
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.object-pattern-computed-key.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.object-pattern-computed-key.js
rename to compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.js
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.unnecessary-lambda-memoization.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.unnecessary-lambda-memoization.expect.md
index fa5f784072..ab141a1d6d 100644
--- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.unnecessary-lambda-memoization.expect.md
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.unnecessary-lambda-memoization.expect.md
@@ -26,9 +26,8 @@ import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(5);
const data = useFreeze();
- const c_0 = $[0] !== data.items;
let t1;
- if (c_0) {
+ if ($[0] !== data.items) {
let t0;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (item) => ;
@@ -43,9 +42,8 @@ function Component(props) {
t1 = $[1];
}
const items = t1;
- const c_3 = $[3] !== items;
let t2;
- if (c_3) {
+ if ($[3] !== items) {
t2 =
{items}
;
$[3] = items;
$[4] = t2;
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.useContext-mutate-context-in-callback.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.useContext-mutate-context-in-callback.expect.md
new file mode 100644
index 0000000000..4dcc0da17b
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/todo.useContext-mutate-context-in-callback.expect.md
@@ -0,0 +1,46 @@
+
+## Input
+
+```javascript
+function Component(props) {
+ const FooContext = useContext(Foo);
+ // This function should be memoized, but its mutable range is entangled
+ // with the useContext call. We can't memoize hooks, therefore the
+ // reactive scope around the hook + callback is pruned and we're left
+ // w no memoization of the callback.
+ //
+ // Ideally we'd determine that this isn't called during render and can
+ // therefore be considered "immutable" or otherwise safe to memoize
+ // independently
+ const onClick = () => {
+ FooContext.current = true;
+ };
+ return ;
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react";
+function Component(props) {
+ const $ = useMemoCache(2);
+ const FooContext = useContext(Foo);
+
+ const onClick = () => {
+ FooContext.current = true;
+ };
+ let t0;
+ if ($[0] !== onClick) {
+ t0 = ;
+ $[0] = onClick;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/packages/fixture-test-utils/src/fixture-utils.ts b/compiler/packages/fixture-test-utils/src/fixture-utils.ts
index 87f5b75cbc..112027c2e6 100644
--- a/compiler/packages/fixture-test-utils/src/fixture-utils.ts
+++ b/compiler/packages/fixture-test-utils/src/fixture-utils.ts
@@ -42,11 +42,7 @@ function stripExtension(filename: string, extensions: Array): string {
return filename;
}
-function shouldSkip(
- filter: TestFilter | null,
- filterId: string,
- filename: string
-) {
+function shouldSkip(filter: TestFilter | null, filterId: string) {
if (filter) {
if (filter.kind === "only" && filter.paths.indexOf(filterId) === -1) {
return true;
@@ -56,8 +52,6 @@ function shouldSkip(
) {
return true;
}
- } else if (filename.startsWith("todo.")) {
- return true;
}
return false;
}
@@ -117,10 +111,9 @@ export function getFixtures(
});
const fixtures: Map = new Map();
for (const filePath of inputFiles) {
- const filename = path.basename(filePath);
// Do not include extensions in unique identifier for fixture
const partialPath = stripExtension(filePath, INPUT_EXTENSIONS);
- if (shouldSkip(filter, partialPath, filename)) {
+ if (shouldSkip(filter, partialPath)) {
continue;
}
@@ -145,10 +138,9 @@ export function getFixtures(
cwd: FIXTURES_PATH,
});
for (const filePath of outputFiles) {
- const filename = path.basename(filePath);
// Do not include extensions in unique identifier for fixture
const partialPath = stripExtension(filePath, [OUTPUT_EXTENSION]);
- if (shouldSkip(filter, partialPath, filename)) {
+ if (shouldSkip(filter, partialPath)) {
continue;
}
diff --git a/compiler/packages/snap/src/compiler-worker.ts b/compiler/packages/snap/src/compiler-worker.ts
index 488e6b7596..0159b53bc1 100644
--- a/compiler/packages/snap/src/compiler-worker.ts
+++ b/compiler/packages/snap/src/compiler-worker.ts
@@ -53,8 +53,7 @@ export async function compile(
clearRequireCache();
}
version = compilerVersion;
- const { inputPath, outputPath, outputExists, basename } =
- fixture;
+ const { inputPath, outputPath, outputExists, basename } = fixture;
const input = inputPath != null ? await fs.readFile(inputPath, "utf8") : null;
const expected = outputExists ? await fs.readFile(outputPath, "utf8") : null;
@@ -109,7 +108,8 @@ export async function compile(
}
const output = writeOutputToString(input, code, error);
- const expectError = basename.startsWith("error.");
+ const expectError =
+ basename.startsWith("error.") || basename.startsWith("todo.error");
let unexpectedError: string | null = null;
if (expectError) {
if (error === null) {
diff --git a/compiler/packages/sprout/src/SproutTodoFilter.ts b/compiler/packages/sprout/src/SproutTodoFilter.ts
index df438f14a0..fd66cbc773 100644
--- a/compiler/packages/sprout/src/SproutTodoFilter.ts
+++ b/compiler/packages/sprout/src/SproutTodoFilter.ts
@@ -477,6 +477,37 @@ const skipFilter = new Set([
// nothing to compile/run
"repro-no-gating-import-without-compiled-functions",
+
+ // TODOs
+ "rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af",
+ "rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c",
+ "rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b",
+ "rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb",
+ "rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8",
+ "rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e",
+ "rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f",
+ "rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8",
+ "rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3",
+ "todo.unnecessary-lambda-memoization",
]);
export default skipFilter;
diff --git a/compiler/packages/sprout/src/runner.ts b/compiler/packages/sprout/src/runner.ts
index 0b7f0d6771..7314f2d4cf 100644
--- a/compiler/packages/sprout/src/runner.ts
+++ b/compiler/packages/sprout/src/runner.ts
@@ -6,16 +6,19 @@
*/
import chalk from "chalk";
-import { TestFixture } from "fixture-test-utils";
-import { getFixtures, readTestFilter } from "fixture-test-utils";
+import {
+ FILTER_FILENAME,
+ TestFixture,
+ getFixtures,
+ readTestFilter,
+} from "fixture-test-utils";
import { Worker } from "jest-worker";
import process from "process";
import * as readline from "readline";
-import * as RunnerWorker from "./runner-worker";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import SproutTodoFilter from "./SproutTodoFilter";
-import { FILTER_FILENAME } from "fixture-test-utils";
+import * as RunnerWorker from "./runner-worker";
const WORKER_PATH = require.resolve("./runner-worker");
readline.emitKeypressEvents(process.stdin);
@@ -186,7 +189,10 @@ export async function main(opts: RunnerOptions): Promise {
const validFixtures = new Map();
for (const [name, fixture] of allFixtures) {
- if (fixture.basename.startsWith("error.")) {
+ if (
+ fixture.basename.startsWith("error.") ||
+ fixture.basename.startsWith("todo.error.")
+ ) {
// skip
continue;
}