void visitParenthesizedExpression()

in lib/src/rules/unnecessary_parenthesis.dart [50:150]


  void visitParenthesizedExpression(ParenthesizedExpression node) {
    var parent = node.parent;
    var expression = node.expression;
    if (expression is SimpleIdentifier) {
      if (parent is PropertyAccess) {
        if (parent.propertyName.name == 'hashCode' ||
            parent.propertyName.name == 'runtimeType') {
          // Code like `(String).hashCode` is allowed.
          return;
        }
      } else if (parent is MethodInvocation) {
        if (parent.methodName.name == 'noSuchMethod' ||
            parent.methodName.name == 'toString') {
          // Code like `(String).noSuchMethod()` is allowed.
          return;
        }
      }
      rule.reportLint(node);
      return;
    }

    // https://github.com/dart-lang/linter/issues/2944
    if (expression is FunctionExpression) {
      if (parent is MethodInvocation ||
          parent is PropertyAccess ||
          parent is BinaryExpression ||
          parent is IndexExpression) {
        return;
      }
    }

    if (expression is ConstructorReference) {
      if (parent is! FunctionExpressionInvocation ||
          parent.typeArguments == null) {
        rule.reportLint(node);
        return;
      }
    }

    if (parent is ParenthesizedExpression) {
      rule.reportLint(node);
      return;
    }

    // `a..b=(c..d)` is OK.
    if (expression is CascadeExpression ||
        node.thisOrAncestorMatching(
                (n) => n is Statement || n is CascadeExpression)
            is CascadeExpression) {
      return;
    }

    // Constructor field initializers are rather unguarded by delimiting
    // tokens, which can get confused with a function expression. See test
    // cases for issues #1395 and #1473.
    if (parent is ConstructorFieldInitializer &&
        _containsFunctionExpression(node)) {
      return;
    }

    if (parent is Expression) {
      if (parent is BinaryExpression) return;
      if (parent is ConditionalExpression) return;
      if (parent is CascadeExpression) return;
      if (parent is FunctionExpressionInvocation) return;

      // A prefix expression (! or -) can have an argument wrapped in
      // "unnecessary" parens if that argument has potentially confusing
      // whitespace after its first token.
      if (parent is PrefixExpression &&
          _expressionStartsWithWhitespace(node.expression)) return;

      // Another case of the above exception, something like
      // `!(const [7]).contains(5);`, where the _parent's_ parent is the
      // PrefixExpression.
      if (parent is MethodInvocation) {
        var target = parent.target;
        if (parent.parent is PrefixExpression &&
            target == node &&
            _expressionStartsWithWhitespace(node.expression)) return;
      }

      // Something like `({1, 2, 3}).forEach(print);`.
      // The parens cannot be removed because then the curly brackets are not
      // interpreted as a set-or-map literal.
      if (parent is PropertyAccess || parent is MethodInvocation) {
        var target = (parent as dynamic).target;
        if (target == node &&
            node.expression is SetOrMapLiteral &&
            parent.parent is ExpressionStatement) return;
      }

      if (parent.precedence < node.expression.precedence) {
        rule.reportLint(node);
        return;
      }
    } else {
      rule.reportLint(node);
      return;
    }
  }