function markPropTypesAsUsed(node, parentNames) {
    parentNames = parentNames || [];
    let type;
    let name;
    let allNames;
    let properties;
    if (astUtil.isMemberExpression(node)) {
      name = getPropertyName(context, node, utils, checkAsyncSafeLifeCycles);
      if (name) {
        allNames = parentNames.concat(name);
        const parent = node.parent;
        if (
        // Match props.foo.bar, don't match bar[props.foo]
          parent.type === 'MemberExpression'
            && 'object' in parent
            && parent.object === node
        ) {
          markPropTypesAsUsed(parent, allNames);
        }
        // Handle the destructuring part of `const {foo} = props.a.b`
        if (
          astUtil.isVariableDeclarator(parent)
            && parent.id.type === 'ObjectPattern'
        ) {
          parent.id.parent = parent; // patch for bug in eslint@4 in which ObjectPattern has no parent
          markPropTypesAsUsed(parent.id, allNames);
        }

        // const a = props.a
        if (
          astUtil.isVariableDeclarator(parent)
            && parent.id.type === 'Identifier'
        ) {
          propVariables.set(parent.id.name, allNames);
        }
        // Do not mark computed props as used.
        type = name !== '__COMPUTED_PROP__' ? 'direct' : null;
      }
    } else if (astUtil.isFunctionLike(node)) {
      if (node.params.length > 0) {
        type = 'destructuring';
        const propParam = isSetStateUpdater(node) ? node.params[1] : node.params[0];
        properties = propParam.type === 'AssignmentPattern'
          ? propParam.left.properties
          : propParam.properties;
      }
    } else if (astUtil.isObjectPattern(node)) {
      type = 'destructuring';
      properties = node.properties;
    } else if (node.type !== 'TSEmptyBodyFunctionExpression') {
      throw new Error(`${node.type} ASTNodes are not handled by markPropTypesAsUsed`);
    }

    const component = components.get(utils.getParentComponent(node));
    const usedPropTypes = (component && component.usedPropTypes) || [];
    let ignoreUnusedPropTypesValidation = (component && component.ignoreUnusedPropTypesValidation) || false;

    if (type === 'direct') {
      // Ignore Object methods
      if (!(name in Object.prototype)) {
        const reportedNode = node.property;
        usedPropTypes.push({
          name,
          allNames,
          node: reportedNode,
        });
      }
    } else if (type === 'destructuring') {
      for (let k = 0, l = (properties || []).length; k < l; k++) {
        if (hasSpreadOperator(context, properties[k]) || properties[k].computed) {
          ignoreUnusedPropTypesValidation = true;
          break;
        }
        const propName = astUtil.getKeyValue(context, properties[k]);

        if (!propName || properties[k].type !== 'Property') {
          break;
        }

        usedPropTypes.push({
          allNames: parentNames.concat([propName]),
          name: propName,
          node: properties[k],
        });

        if (properties[k].value.type === 'ObjectPattern') {
          markPropTypesAsUsed(properties[k].value, parentNames.concat([propName]));
        } else if (properties[k].value.type === 'Identifier') {
          propVariables.set(properties[k].value.name, parentNames.concat(propName));
        }
      }
    }

    components.set(component ? component.node : node, {
      usedPropTypes,
      ignoreUnusedPropTypesValidation,
    });
  }
Mark a prop type as used
@param {ASTNode} node The AST node being marked.
@param {string[]} [parentNames]