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;
}
}