function verify(left, right, propsReferences) {
      if (!right) {
        return
      }

      const rightNode = utils.skipChainExpression(right)

      if (
        wrapperExpressionTypes.has(rightNode.type) &&
        isPropsMemberAccessed(rightNode, propsReferences)
      ) {
        // e.g. `const foo = { x: props.x }`
        report(rightNode, 'getProperty', propsReferences.scopeName)
        return
      }

      // Get the expression that provides the value.
      /** @type {Expression | Super} */
      let expression = rightNode
      while (expression.type === 'MemberExpression') {
        expression = utils.skipChainExpression(expression.object)
      }
      /** A list of expression nodes to verify */
      const expressions =
        expression.type === 'TemplateLiteral'
          ? expression.expressions
          : expression.type === 'ConditionalExpression'
            ? [expression.test, expression.consequent, expression.alternate]
            : expression.type === 'Identifier'
              ? [expression]
              : []

      if (
        (left.type === 'ArrayPattern' || left.type === 'ObjectPattern') &&
        expressions.some(
          (expr) =>
            expr.type === 'Identifier' && propsReferences.refs.props.has(expr)
        )
      ) {
        // e.g. `const {foo} = props`
        report(left, 'getProperty', propsReferences.scopeName)
        return
      }

      const reportNode = expressions.find((expr) =>
        isPropsMemberAccessed(expr, propsReferences)
      )
      if (reportNode) {
        report(reportNode, 'getProperty', propsReferences.scopeName)
      }
    }
@param {Pattern} left
@param {Expression | null} right
@param {ScopePropsReferences} propsReferences