Skip to content

Commit 7ada5fc

Browse files
committed
Fix lookup in constructor
1 parent 129acf4 commit 7ada5fc

File tree

3 files changed

+39
-36
lines changed

3 files changed

+39
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Keep generator/async flags
1212
- Fix renaming failure in some cases
1313
- Fix local variable conflict when the name was introduced in an inner block.
14+
- Fix `this.props`, `this.setState`, and so on not being accounted for when they are declared in the constructor.
1415

1516
## 0.1.4
1617

src/analysis/this_fields.ts

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function analyzeThisFields(path: NodePath<ClassDeclaration>): ThisFields
4747
const staticFields = new Map<string, StaticFieldSite[]>();
4848
const getStaticField = (name: string) => getOr(staticFields, name, () => []);
4949
let constructor: NodePath<ClassMethod> | undefined = undefined;
50+
const bodies: NodePath[] = [];
5051
// 1st pass: look for class field definitions
5152
for (const itemPath of path.get("body").get("body")) {
5253
if (isNamedClassElement(itemPath)) {
@@ -66,6 +67,9 @@ export function analyzeThisFields(path: NodePath<ClassDeclaration>): ThisFields
6667
hasWrite: undefined,
6768
hasSideEffect: !!itemPath.node.value && estimateSideEffect(itemPath.node.value),
6869
});
70+
if (valuePath) {
71+
bodies.push(valuePath);
72+
}
6973
} else if (isClassMethodOrDecl(itemPath)) {
7074
const kind = itemPath.node.kind ?? "method";
7175
if (kind === "method") {
@@ -79,6 +83,12 @@ export function analyzeThisFields(path: NodePath<ClassDeclaration>): ThisFields
7983
hasWrite: undefined,
8084
hasSideEffect: false,
8185
});
86+
if (isClassMethodLike(itemPath)) {
87+
for (const paramPath of itemPath.get("params")) {
88+
bodies.push(paramPath);
89+
}
90+
bodies.push(itemPath.get("body"));
91+
}
8292
} else if (kind === "get" || kind === "set") {
8393
throw new AnalysisError(`Not implemented yet: getter / setter`);
8494
} else if (kind === "constructor") {
@@ -169,6 +179,7 @@ export function analyzeThisFields(path: NodePath<ClassDeclaration>): ThisFields
169179
hasWrite: undefined,
170180
hasSideEffect: estimateSideEffect(stmt.node.expression.right),
171181
});
182+
bodies.push(exprPath.get("right"));
172183
}
173184
}
174185

@@ -212,42 +223,8 @@ export function analyzeThisFields(path: NodePath<ClassDeclaration>): ThisFields
212223
});
213224
});
214225
}
215-
for (const itemPath of path.get("body").get("body")) {
216-
if (isNamedClassElement(itemPath)) {
217-
if (itemPath.node.static) {
218-
continue;
219-
}
220-
if (isClassPropertyLike(itemPath)) {
221-
const valuePath = itemPath.get("value");
222-
if (valuePath.isExpression()) {
223-
traverseItem(valuePath);
224-
}
225-
} else if (isClassMethodLike(itemPath)) {
226-
const kind = itemPath.node.kind ?? "method";
227-
if (kind === "method") {
228-
for (const paramPath of itemPath.get("params")) {
229-
traverseItem(paramPath);
230-
}
231-
traverseItem(itemPath.get("body"));
232-
} else if (kind === "get" || kind === "set") {
233-
throw new AnalysisError(`Not implemented yet: getter / setter`);
234-
} else if (kind === "constructor") {
235-
// Skip
236-
} else {
237-
throw new AnalysisError(`Not implemented yet: ${kind}`);
238-
}
239-
} else if (itemPath.isTSDeclareMethod()) {
240-
// skip
241-
} else if (isClassAccessorProperty(itemPath)) {
242-
throw new AnalysisError(`Not implemented yet: class accessor property`);
243-
}
244-
} else if (isStaticBlock(itemPath)) {
245-
throw new AnalysisError(`Not implemented yet: static block`);
246-
} else if (itemPath.isTSIndexSignature()) {
247-
// Ignore
248-
} else {
249-
throw new AnalysisError(`Unknown class element`);
250-
}
226+
for (const body of bodies) {
227+
traverseItem(body);
251228
}
252229

253230
for (const [name, fieldSites] of thisFields) {

src/index.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,31 @@ describe("react-declassify", () => {
678678
`;
679679
expect(transform(input)).toBe(output);
680680
});
681+
682+
it("transforms setState in constructor", () => {
683+
const input = dedent`\
684+
class C extends React.Component {
685+
constructor(props) {
686+
super(props);
687+
this.reset = () => {
688+
this.setState({ foo: 42 });
689+
};
690+
}
691+
render() {
692+
}
693+
}
694+
`;
695+
const output = dedent`\
696+
const C = () => {
697+
const [foo, setFoo] = React.useState();
698+
699+
function reset() {
700+
setFoo(42);
701+
}
702+
};
703+
`;
704+
expect(transform(input)).toBe(output);
705+
});
681706
});
682707

683708
describe("Ref transformation", () => {

0 commit comments

Comments
 (0)