Repository: facebook/react
File: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts (TypeScript)

Code before:
      return;
    }

    if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
      const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
      const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
      const nestedName =
        nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
          ? nestedFnNameExpr.node.name
          : '<anonymous>';
      if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
        CompilerError.throwDiagnostic({
          category: ErrorCategory.Factories,
          severity: ErrorSeverity.InvalidReact,
          reason: `Components and hooks cannot be created dynamically`,
          description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
          details: [
            {
              kind: 'error',
              message: 'this function dynamically created a component/hook',
              loc: fn.node.loc ?? null,
            },
            {
              kind: 'error',
              message: 'the component is created here',
              loc: nestedFn.node.loc ?? null,
            },
          ],
        });
      }
    }

    nestedFn.skip();
  };

  fn.traverse({
    FunctionDeclaration: validateNestedFunction,
    FunctionExpression: validateNestedFunction,
    ArrowFunctionExpression: validateNestedFunction,
  });
}

function getReactFunctionType(
  fn: BabelFn,
  pass: CompilerPass,
): ReactFunctionType | null {
  const hookPattern = pass.opts.environment.hookPattern;
  if (fn.node.body.type === 'BlockStatement') {
    const optInDirectives = tryFindDirectiveEnablingMemoization(
      fn.node.body.directives,
      pass.opts,

Review comment (suggestion):
I wonder about trying to target the location of the function name, and falling back to the full function scope only if there was no name. Unfortunately Babel doesn't provide a location for the `function` keyword that we could target.

Code after:
      return;
    }

    if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
      const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
      const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
      const nestedName =
        nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
          ? nestedFnNameExpr.node.name
          : '<anonymous>';
      if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
        CompilerError.throwDiagnostic({
          category: ErrorCategory.Factories,
          severity: ErrorSeverity.InvalidReact,
          reason: `Components and hooks cannot be created dynamically`,
          description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
          details: [
            {
              kind: 'error',
              message: 'this function dynamically created a component/hook',
              loc: parentNameExpr?.node.loc ?? fn.node.loc ?? null,
            },
            {
              kind: 'error',
              message: 'the component is created here',
              loc: nestedFnNameExpr?.node.loc ?? nestedFn.node.loc ?? null,
            },
          ],
        });
      }
    }

    nestedFn.skip();
  };

  fn.traverse({
    FunctionDeclaration: validateNestedFunction,
    FunctionExpression: validateNestedFunction,
    ArrowFunctionExpression: validateNestedFunction,
  });
}

function getReactFunctionType(
  fn: BabelFn,
  pass: CompilerPass,
): ReactFunctionType | null {
  const hookPattern = pass.opts.environment.hookPattern;
  if (fn.node.body.type === 'BlockStatement') {
    const optInDirectives = tryFindDirectiveEnablingMemoization(
      fn.node.body.directives,
      pass.opts,