@samitouri / QOS-React-1 / commits / cd7d236682

[forgive] Emit AutoDepsDecoration event when inferring effect deps (#32997)

Emits a new event for decorating inferred effect dependencies. Co-authored-by: Jordan Brown <jmbrown@meta.com> --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32997). * #33002 * #33001 * #33000 * #32999 * #32998 * __->__ #32997 * #32996 --------- Co-authored-by: Jordan Brown <jmbrown@meta.com>

lauren committed Apr 23, 2025 at 20:51 UTC cd7d236682ff3ba4996a5e1568f148bd6ac91862
2 files changed +47 -1
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts
+7 -1
@@ -182,7 +182,8 @@ export type LoggerEvent =
182 | CompileDiagnosticEvent
183 | CompileSkipEvent
184 | PipelineErrorEvent
185 - | TimingEvent;
185 + | TimingEvent
186 + | AutoDepsDecorations;
187
188 export type CompileErrorEvent = {
189 kind: 'CompileError';
@@ -219,6 +220,11 @@ export type TimingEvent = {
220 kind: 'Timing';
221 measurement: PerformanceMeasure;
222 };
223 +export type AutoDepsDecorations = {
224 + kind: 'AutoDepsDecorations';
225 + useEffectCallExpr: t.SourceLocation | null;
226 + decorations: Array<t.SourceLocation | null>;
227 +};
228
229 export type Logger = {
230 logEvent: (filename: string | null, event: LoggerEvent) => void;
compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts
+40
@@ -188,6 +188,7 @@ export function inferEffectDependencies(fn: HIRFunction): void {
188 * the `infer-effect-deps/pruned-nonreactive-obj` fixture for an
189 * explanation.
190 */
191 + const usedDeps = [];
192 for (const dep of scopeInfo.deps) {
193 if (
194 ((isUseRefType(dep.identifier) ||
@@ -207,8 +208,19 @@ export function inferEffectDependencies(fn: HIRFunction): void {
208 );
209 newInstructions.push(...instructions);
210 effectDeps.push(place);
211 + usedDeps.push(dep);
212 }
213
214 + // For LSP autodeps feature.
215 + fn.env.logger?.logEvent(fn.env.filename, {
216 + kind: 'AutoDepsDecorations',
217 + useEffectCallExpr:
218 + typeof value.loc !== 'symbol' ? value.loc : null,
219 + decorations: collectDepUsages(usedDeps, fnExpr.value).map(loc =>
220 + typeof loc !== 'symbol' ? loc : null,
221 + ),
222 + });
223 +
224 newInstructions.push({
225 id: makeInstructionId(0),
226 loc: GeneratedSource,
@@ -340,3 +352,31 @@ function inferReactiveIdentifiers(fn: HIRFunction): Set<IdentifierId> {
352 }
353 return reactiveIds;
354 }
355 +
356 +function collectDepUsages(
357 + deps: Array<ReactiveScopeDependency>,
358 + fnExpr: FunctionExpression,
359 +): Array<SourceLocation> {
360 + const identifiers: Map<IdentifierId, ReactiveScopeDependency> = new Map();
361 + const loadedDeps: Set<IdentifierId> = new Set();
362 + const sourceLocations = [];
363 + for (const dep of deps) {
364 + identifiers.set(dep.identifier.id, dep);
365 + }
366 +
367 + for (const [, block] of fnExpr.loweredFunc.func.body.blocks) {
368 + for (const instr of block.instructions) {
369 + if (instr.value.kind === 'LoadLocal') {
370 + loadedDeps.add(instr.lvalue.identifier.id);
371 + }
372 + for (const place of eachInstructionOperand(instr)) {
373 + if (loadedDeps.has(place.identifier.id)) {
374 + // TODO(@jbrown215): handle member exprs!!
375 + sourceLocations.push(place.identifier.loc);
376 + }
377 + }
378 + }
379 + }
380 +
381 + return sourceLocations;
382 +}