Version 2.10.0-92.0.dev
Merge commit '0c5f2a35328fc0b285c01710b6ea7f3a7d2e0713' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 8c4699a..e6e8921 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -362,7 +362,16 @@
void doStatement_end(Expression condition);
/// Call this method just after visiting a binary `==` or `!=` expression.
- void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ ///
+ /// Return value indicates whether flow analysis believes that a successful
+ /// equality check is reachable. If `false` is returned, the client should
+ /// ensure that the `==` test behaves like `x == y && throw ...`.
+ ///
+ /// Note that if `notEqual` is `true`, then the return value describes the
+ /// behavior of the underlying `==` test. So if `notEqual` is `true` and
+ /// `false` is returned, the client should ensure that the `!=` test behaves
+ /// like `!(x == y && throw ...)`.
+ bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false});
@@ -475,7 +484,13 @@
/// Call this method after visiting the LHS of an if-null expression ("??")
/// or if-null assignment ("??=").
- void ifNullExpression_rightBegin(Expression leftHandSide);
+ ///
+ /// Return value indicates whether flow analysis believes that the right hand
+ /// side is reachable. If `false` is returned, the client should ensure that
+ /// `x ?? y` behaves like `x ?? throw ...` (or, correspondingly, that
+ /// `x ??= y` behaves like `x ??= throw ...`).
+ bool ifNullExpression_rightBegin(
+ Expression leftHandSide, Type leftHandSideType);
/// Call this method after visiting the "then" part of an if statement, and
/// before visiting the "else" part.
@@ -511,7 +526,16 @@
/// be the expression to which the "is" check was applied. [isNot] should be
/// a boolean indicating whether this is an "is" or an "is!" expression.
/// [type] should be the type being checked.
- void isExpression_end(
+ ///
+ /// Return value indicates whether flow analysis believes that a failure of
+ /// the `is` test is reachable. If `false` is returned, the client should
+ /// ensure that the `is` test behaves like `x is T || throw ...`.
+ ///
+ /// Note that if `isNot` is `true`, then the return value describes the
+ /// behavior of the underlying `if` test. So if `isNot` is `true` and `false`
+ /// is returned, the client should ensure that the `is!` test behaves like
+ /// `!(x is T || throw ...)`.
+ bool isExpression_end(
Expression isExpression, Expression subExpression, bool isNot, Type type);
/// Return whether the [variable] is definitely unassigned in the current
@@ -558,12 +582,22 @@
/// [target] should be the expression just before the null-aware operator, or
/// `null` if the null-aware access starts a cascade section.
///
+ /// [targetType] should be the type of the expression just before the
+ /// null-aware operator, and should be non-null even if the null-aware access
+ /// starts a cascade section.
+ ///
/// Note that [nullAwareAccess_end] should be called after the conclusion
/// of any null-shorting that is caused by the `?.`. So, for example, if the
/// code being analyzed is `x?.y?.z(x)`, [nullAwareAccess_rightBegin] should
/// be called once upon reaching each `?.`, but [nullAwareAccess_end] should
/// not be called until after processing the method call to `z(x)`.
- void nullAwareAccess_rightBegin(Expression target);
+ ///
+ /// Return value indicates whether flow analysis believes that a null target
+ /// is reachable. If `false` is returned, the client should ensure that
+ /// `x?.y` behaves like `x!.y`. (Note that this is necessary even if `y`
+ /// exists on `Object`--see
+ /// https://github.com/dart-lang/language/issues/1143#issuecomment-682096575.)
+ bool nullAwareAccess_rightBegin(Expression target, Type targetType);
/// Call this method when encountering an expression that is a `null` literal.
void nullLiteral(Expression expression);
@@ -811,15 +845,17 @@
}
@override
- void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false}) {
- _wrap(
+ return _wrap(
'equalityOp_end($wholeExpression, $rightOperand, $rightOperandType, '
'notEqual: $notEqual)',
() => _wrapped.equalityOp_end(
wholeExpression, rightOperand, rightOperandType,
- notEqual: notEqual));
+ notEqual: notEqual),
+ isQuery: true,
+ isPure: false);
}
@override
@@ -902,9 +938,14 @@
}
@override
- void ifNullExpression_rightBegin(Expression leftHandSide) {
- return _wrap('ifNullExpression_rightBegin($leftHandSide)',
- () => _wrapped.ifNullExpression_rightBegin(leftHandSide));
+ bool ifNullExpression_rightBegin(
+ Expression leftHandSide, Type leftHandSideType) {
+ return _wrap(
+ 'ifNullExpression_rightBegin($leftHandSide, $leftHandSideType)',
+ () => _wrapped.ifNullExpression_rightBegin(
+ leftHandSide, leftHandSideType),
+ isQuery: true,
+ isPure: false);
}
@override
@@ -931,12 +972,14 @@
}
@override
- void isExpression_end(Expression isExpression, Expression subExpression,
+ bool isExpression_end(Expression isExpression, Expression subExpression,
bool isNot, Type type) {
- _wrap(
+ return _wrap(
'isExpression_end($isExpression, $subExpression, $isNot, $type)',
- () => _wrapped.isExpression_end(
- isExpression, subExpression, isNot, type));
+ () =>
+ _wrapped.isExpression_end(isExpression, subExpression, isNot, type),
+ isQuery: true,
+ isPure: false);
}
@override
@@ -991,9 +1034,10 @@
}
@override
- void nullAwareAccess_rightBegin(Expression target) {
- _wrap('nullAwareAccess_rightBegin($target)',
- () => _wrapped.nullAwareAccess_rightBegin(target));
+ bool nullAwareAccess_rightBegin(Expression target, Type targetType) {
+ return _wrap('nullAwareAccess_rightBegin($target, $targetType)',
+ () => _wrapped.nullAwareAccess_rightBegin(target, targetType),
+ isQuery: true, isPure: false);
}
@override
@@ -2456,7 +2500,7 @@
}
@override
- void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false}) {
_EqualityOpContext<Variable, Type> context =
@@ -2471,14 +2515,16 @@
typeOperations.classifyType(rightOperandType);
if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
- return booleanLiteral(wholeExpression, !notEqual);
+ booleanLiteral(wholeExpression, !notEqual);
+ return true;
} else if ((leftOperandTypeClassification ==
TypeClassification.nullOrEquivalent &&
rightOperandTypeClassification == TypeClassification.nonNullable) ||
(rightOperandTypeClassification ==
TypeClassification.nullOrEquivalent &&
leftOperandTypeClassification == TypeClassification.nonNullable)) {
- return booleanLiteral(wholeExpression, notEqual);
+ booleanLiteral(wholeExpression, notEqual);
+ return false;
} else if (lhsInfo is _NullInfo<Variable, Type> &&
rhsInfo is _VariableReadInfo<Variable, Type>) {
assert(
@@ -2490,10 +2536,11 @@
equalityInfo =
_current.tryMarkNonNullable(typeOperations, lhsInfo._variable);
} else {
- return;
+ return true;
}
_storeExpressionInfo(wholeExpression,
notEqual ? equalityInfo : ExpressionInfo.invert(equalityInfo));
+ return equalityInfo.ifFalse.reachable;
}
@override
@@ -2619,7 +2666,8 @@
}
@override
- void ifNullExpression_rightBegin(Expression leftHandSide) {
+ bool ifNullExpression_rightBegin(
+ Expression leftHandSide, Type leftHandSideType) {
ExpressionInfo<Variable, Type> lhsInfo = _getExpressionInfo(leftHandSide);
FlowModel<Variable, Type> promoted;
if (lhsInfo is _VariableReadInfo<Variable, Type>) {
@@ -2630,7 +2678,12 @@
} else {
promoted = _current;
}
+ if (typeOperations.classifyType(leftHandSideType) ==
+ TypeClassification.nonNullable) {
+ _current = _current.setReachable(false);
+ }
_stack.add(new _SimpleContext<Variable, Type>(promoted));
+ return _current.reachable;
}
@override
@@ -2670,7 +2723,7 @@
}
@override
- void isExpression_end(Expression isExpression, Expression subExpression,
+ bool isExpression_end(Expression isExpression, Expression subExpression,
bool isNot, Type type) {
ExpressionInfo<Variable, Type> subExpressionInfo =
_getExpressionInfo(subExpression);
@@ -2678,12 +2731,13 @@
if (subExpressionInfo is _VariableReadInfo<Variable, Type>) {
variable = subExpressionInfo._variable;
} else {
- return;
+ return true;
}
ExpressionInfo<Variable, Type> expressionInfo =
_current.tryPromoteForTypeCheck(typeOperations, variable, type);
_storeExpressionInfo(isExpression,
isNot ? ExpressionInfo.invert(expressionInfo) : expressionInfo);
+ return expressionInfo.ifFalse.reachable;
}
@override
@@ -2760,8 +2814,16 @@
}
@override
- void nullAwareAccess_rightBegin(Expression target) {
- _stack.add(new _SimpleContext<Variable, Type>(_current));
+ bool nullAwareAccess_rightBegin(Expression target, Type targetType) {
+ assert(targetType != null);
+ bool shortingIsReachable = true;
+ FlowModel<Variable, Type> shortingModel = _current;
+ if (typeOperations.classifyType(targetType) ==
+ TypeClassification.nonNullable) {
+ shortingModel = shortingModel.setReachable(false);
+ shortingIsReachable = false;
+ }
+ _stack.add(new _SimpleContext<Variable, Type>(shortingModel));
if (target != null) {
ExpressionInfo<Variable, Type> targetInfo = _getExpressionInfo(target);
if (targetInfo is _VariableReadInfo<Variable, Type>) {
@@ -2770,6 +2832,7 @@
.ifTrue;
}
}
+ return shortingIsReachable;
}
@override
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 09e6023..d512956 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -185,15 +185,76 @@
var nullExpr = _Expression();
flow.nullLiteral(nullExpr);
var expr = _Expression();
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
+ var successIsReachable =
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
+ expect(successIsReachable, true);
flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
expect(flow.promotedType(x), isNull);
flow.ifStatement_end(true);
});
});
+ test('equalityOp(x != null) when x is non-nullable', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var varExpr = _Expression();
+ flow.variableRead(varExpr, x);
+ flow.equalityOp_rightBegin(varExpr, _Type('int'));
+ var nullExpr = _Expression();
+ flow.nullLiteral(nullExpr);
+ var expr = _Expression();
+ var successIsReachable =
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
+ expect(successIsReachable, false);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, false);
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_end(true);
+ });
+ });
+
+ test('equalityOp(<expr> == <expr>) has no special effect', () {
+ var h = _Harness();
+ h.run((flow) {
+ flow.equalityOp_rightBegin(_Expression(), _Type('int?'));
+ var expr = _Expression();
+ var successIsReachable = flow.equalityOp_end(
+ expr, _Expression(), _Type('int?'),
+ notEqual: false);
+ expect(successIsReachable, true);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
+ flow.ifStatement_end(true);
+ });
+ });
+
+ test('equalityOp(<expr> != <expr>) has no special effect', () {
+ var h = _Harness();
+ h.run((flow) {
+ flow.equalityOp_rightBegin(_Expression(), _Type('int?'));
+ var expr = _Expression();
+ var successIsReachable = flow
+ .equalityOp_end(expr, _Expression(), _Type('int?'), notEqual: true);
+ expect(successIsReachable, true);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
+ flow.ifStatement_end(true);
+ });
+ });
+
test('equalityOp(x != <null expr>) does not promote', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -224,15 +285,43 @@
var nullExpr = _Expression();
flow.nullLiteral(nullExpr);
var expr = _Expression();
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
+ var successIsReachable =
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
+ expect(successIsReachable, true);
flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
expect(flow.promotedType(x), isNull);
flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.ifStatement_end(true);
});
});
+ test('equalityOp(x == null) when x is non-nullable', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var varExpr = _Expression();
+ flow.variableRead(varExpr, x);
+ flow.equalityOp_rightBegin(varExpr, _Type('int'));
+ var nullExpr = _Expression();
+ flow.nullLiteral(nullExpr);
+ var expr = _Expression();
+ var successIsReachable =
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
+ expect(successIsReachable, false);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, false);
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_end(true);
+ });
+ });
+
test('equalityOp(null != x) promotes true branch', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -299,7 +388,9 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('Null'));
+ var successIsReachable =
+ flow.equalityOp_end(expr, null2, _Type('Null'));
+ expect(successIsReachable, true);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -315,7 +406,9 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+ var successIsReachable =
+ flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+ expect(successIsReachable, true);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -331,7 +424,8 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('int'));
+ var successIsReachable = flow.equalityOp_end(expr, null2, _Type('int'));
+ expect(successIsReachable, false);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -347,7 +441,9 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('int'), notEqual: true);
+ var successIsReachable =
+ flow.equalityOp_end(expr, null2, _Type('int'), notEqual: true);
+ expect(successIsReachable, false);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -363,7 +459,9 @@
flow.equalityOp_rightBegin(null1, _Type('int'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('Null'));
+ var successIsReachable =
+ flow.equalityOp_end(expr, null2, _Type('Null'));
+ expect(successIsReachable, false);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -379,7 +477,9 @@
flow.equalityOp_rightBegin(null1, _Type('int'));
var null2 = _Expression();
var expr = _Expression();
- flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+ var successIsReachable =
+ flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+ expect(successIsReachable, false);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -885,10 +985,14 @@
h.assignedVariables((vars) => vars.write(x));
h.run((flow) {
h.declare(x, initialized: true);
- flow.ifNullExpression_rightBegin(h.variableRead(x)());
+ var rhsIsReachable = flow.ifNullExpression_rightBegin(
+ h.variableRead(x)(), _Type('int?'));
+ expect(rhsIsReachable, true);
+ expect(flow.isReachable, true);
flow.write(x, _Type('int'));
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
});
});
@@ -898,10 +1002,14 @@
var x = h.addVar('x', 'int?');
h.run((flow) {
h.declare(x, initialized: true);
- flow.ifNullExpression_rightBegin(h.variableRead(x)());
+ var rhsIsReachable = flow.ifNullExpression_rightBegin(
+ h.variableRead(x)(), _Type('int?'));
+ expect(rhsIsReachable, true);
+ expect(flow.isReachable, true);
h.promote(x, 'int');
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
});
});
@@ -911,14 +1019,43 @@
var x = h.addVar('x', 'int?');
h.run((flow) {
h.declare(x, initialized: true);
- flow.ifNullExpression_rightBegin(h.expr());
+ var rhsIsReachable =
+ flow.ifNullExpression_rightBegin(h.expr(), _Type('int?'));
+ expect(rhsIsReachable, true);
+ expect(flow.isReachable, true);
h.promote(x, 'int');
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
+ expect(flow.isReachable, true);
expect(flow.promotedType(x), null);
});
});
+ test('ifNullExpression detects when RHS is unreachable', () {
+ var h = _Harness();
+ h.run((flow) {
+ var rhsIsReachable =
+ flow.ifNullExpression_rightBegin(h.expr(), _Type('int'));
+ expect(rhsIsReachable, false);
+ expect(flow.isReachable, false);
+ flow.ifNullExpression_end();
+ expect(flow.isReachable, true);
+ });
+ });
+
+ test('ifNullExpression determines reachability correctly for `Null` type',
+ () {
+ var h = _Harness();
+ h.run((flow) {
+ var rhsIsReachable =
+ flow.ifNullExpression_rightBegin(h.expr(), _Type('Null'));
+ expect(rhsIsReachable, true);
+ expect(flow.isReachable, true);
+ flow.ifNullExpression_end();
+ expect(flow.isReachable, true);
+ });
+ });
+
test('ifStatement_end(false) keeps else branch if then branch exits', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -932,11 +1069,12 @@
});
void _checkIs(
- String declaredType,
- String tryPromoteType,
- String expectedPromotedTypeThen,
- String expectedPromotedTypeElse,
- ) {
+ String declaredType,
+ String tryPromoteType,
+ String expectedPromotedTypeThen,
+ String expectedPromotedTypeElse,
+ bool expectedFailureReachable,
+ {bool inverted = false}) {
var h = _Harness();
var x = h.addVar('x', declaredType);
h.run((flow) {
@@ -944,14 +1082,18 @@
var read = _Expression();
flow.variableRead(read, x);
var expr = _Expression();
- flow.isExpression_end(expr, read, false, _Type(tryPromoteType));
+ var failureReachable =
+ flow.isExpression_end(expr, read, inverted, _Type(tryPromoteType));
+ expect(failureReachable, expectedFailureReachable);
flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, inverted ? expectedFailureReachable : true);
if (expectedPromotedTypeThen == null) {
expect(flow.promotedType(x), isNull);
} else {
expect(flow.promotedType(x).type, expectedPromotedTypeThen);
}
flow.ifStatement_elseBegin();
+ expect(flow.isReachable, inverted ? true : expectedFailureReachable);
if (expectedPromotedTypeElse == null) {
expect(flow.promotedType(x), isNull);
} else {
@@ -962,15 +1104,61 @@
}
test('isExpression_end promotes to a subtype', () {
- _checkIs('int?', 'int', 'int', 'Never?');
+ _checkIs('int?', 'int', 'int', 'Never?', true);
+ });
+
+ test('isExpression_end promotes to a subtype, inverted', () {
+ _checkIs('int?', 'int', 'Never?', 'int', true, inverted: true);
});
test('isExpression_end does not promote to a supertype', () {
- _checkIs('int', 'int?', null, 'Never');
+ _checkIs('int', 'int?', null, 'Never', false);
+ });
+
+ test('isExpression_end does not promote to a supertype, inverted', () {
+ _checkIs('int', 'int?', 'Never', null, false, inverted: true);
});
test('isExpression_end does not promote to an unrelated type', () {
- _checkIs('int', 'String', null, null);
+ _checkIs('int', 'String', null, null, true);
+ });
+
+ test('isExpression_end does not promote to an unrelated type, inverted',
+ () {
+ _checkIs('int', 'String', null, null, true, inverted: true);
+ });
+
+ test('isExpression_end does nothing if applied to a non-variable', () {
+ var h = _Harness();
+ h.run((flow) {
+ var subExpr = _Expression();
+ var expr = _Expression();
+ var failureReachable =
+ flow.isExpression_end(expr, subExpr, false, _Type('int'));
+ expect(failureReachable, true);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
+ flow.ifStatement_end(true);
+ });
+ });
+
+ test('isExpression_end does nothing if applied to a non-variable, inverted',
+ () {
+ var h = _Harness();
+ h.run((flow) {
+ var subExpr = _Expression();
+ var expr = _Expression();
+ var failureReachable =
+ flow.isExpression_end(expr, subExpr, true, _Type('int'));
+ expect(failureReachable, true);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.isReachable, true);
+ flow.ifStatement_elseBegin();
+ expect(flow.isReachable, true);
+ flow.ifStatement_end(true);
+ });
});
test('isExpression_end() does not promote write-captured vars', () {
@@ -1153,7 +1341,10 @@
h.declare(x, initialized: true);
var varExpr = _Expression();
flow.variableRead(varExpr, x);
- flow.nullAwareAccess_rightBegin(varExpr);
+ var shortIsReachable =
+ flow.nullAwareAccess_rightBegin(varExpr, _Type('int?'));
+ expect(shortIsReachable, true);
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.nullAwareAccess_end();
expect(flow.promotedType(x), isNull);
@@ -1167,7 +1358,10 @@
h.declare(x, initialized: true);
var varExpr = _Expression();
flow.variableRead(varExpr, x);
- flow.nullAwareAccess_rightBegin(null);
+ var shortIsReachable =
+ flow.nullAwareAccess_rightBegin(null, _Type('int?'));
+ expect(shortIsReachable, true);
+ expect(flow.isReachable, true);
expect(flow.promotedType(x), isNull);
flow.nullAwareAccess_end();
});
@@ -1181,7 +1375,10 @@
h.declare(x, initialized: true);
h.promote(x, 'int');
var lhs = _Expression();
- flow.nullAwareAccess_rightBegin(lhs);
+ var shortIsReachable =
+ flow.nullAwareAccess_rightBegin(lhs, _Type('int'));
+ expect(shortIsReachable, false);
+ expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.write(x, _Type('int?'));
expect(flow.promotedType(x), isNull);
@@ -1190,6 +1387,24 @@
});
});
+ test('nullAwareAccess_end ignores shorting if target is non-nullable', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var shortIsReachable =
+ flow.nullAwareAccess_rightBegin(_Expression(), _Type('int'));
+ expect(shortIsReachable, false);
+ expect(flow.isReachable, true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.nullAwareAccess_end();
+ // `x` should still be promoted because the target was non-nullable, so
+ // the null shorting path was unreachable.
+ expect(flow.promotedType(x).type, 'int');
+ });
+ });
+
test('parenthesizedExpression preserves promotion behaviors', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart
new file mode 100644
index 0000000..0cc336e
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart
@@ -0,0 +1,331 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void variable_if_null_reachable(int? i) {
+ i ?? 0;
+}
+
+void variable_if_null_assign_reachable(int? i) {
+ i ??= 0;
+}
+
+void variable_if_null_unreachable(int i) {
+ i ?? /*unreachable*/ 0;
+}
+
+void variable_if_null_assign_unreachable(int i) {
+ // Note: CFE reports that the update to `i` is unreachable; analyzer does not.
+ // This is ok; what matters is that the RHS is unreachable.
+ /*cfe.update: unreachable*/ i ??= /*unreachable*/ 0;
+}
+
+void variable_if_null_assign_unreachable_due_to_promotion(int? i) {
+ if (i == null) return;
+ // Note: CFE reports that the update to `i` is unreachable; analyzer does not.
+ // This is ok; what matters is that the RHS is unreachable.
+ /*cfe.update: unreachable*/ i ??= /*unreachable*/ 0;
+}
+
+/*member: topLevelNullable:doesNotComplete*/
+int? get topLevelNullable => 0;
+void set topLevelNullable(int? value) {}
+
+/*member: topLevelNonNullGet:doesNotComplete*/
+int get topLevelNonNullGet => 0;
+void set topLevelNonNullGet(int? value) {}
+
+void top_level_if_null_reachable() {
+ topLevelNullable ?? 0;
+}
+
+void top_level_if_null_assign_reachable() {
+ topLevelNullable ??= 0;
+}
+
+void top_level_if_null_unreachable() {
+ topLevelNonNullGet ?? /*unreachable*/ 0;
+}
+
+void top_level_if_null_assign_unreachable() {
+ // Note: CFE reports that the update to `topLevelNonNullGet` is unreachable;
+ // analyzer does not. This is ok; what matters is that the RHS is
+ // unreachable.
+ topLevelNonNullGet /*cfe.update: unreachable*/ ??= /*unreachable*/ 0;
+}
+
+class HasProperty<T> {
+ /*member: HasProperty.prop:doesNotComplete*/
+ T get prop => throw '';
+ set prop(T? value) {}
+}
+
+void property_if_null_reachable(HasProperty<int?> x) {
+ x.prop ?? 0;
+}
+
+void property_if_null_assign_reachable(HasProperty<int?> x) {
+ x.prop ??= 0;
+}
+
+void property_if_null_unreachable(HasProperty<int> x) {
+ x.prop ?? /*unreachable*/ 0;
+}
+
+void property_if_null_assign_unreachable(HasProperty<int> x) {
+ x.prop ??= /*unreachable*/ 0;
+}
+
+void null_aware_property_if_null_reachable(HasProperty<int?>? x) {
+ x?.prop ?? 0;
+}
+
+void null_aware_property_if_null_assign_reachable(HasProperty<int?>? x) {
+ x?.prop ??= 0;
+}
+
+void null_aware_property_if_null_not_shortened(HasProperty<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ x?.prop ?? 0;
+}
+
+void null_aware_property_if_null_assign_unreachable(HasProperty<int>? x) {
+ x?.prop ??= /*unreachable*/ 0;
+}
+
+class SuperIntQuestionProperty extends HasProperty<int?> {
+ void if_null_reachable() {
+ super.prop ?? 0;
+ }
+
+ void if_null_assign_reachable() {
+ super.prop ??= 0;
+ }
+}
+
+class SuperIntProperty extends HasProperty<int> {
+ void if_null_unreachable() {
+ super.prop ?? /*unreachable*/ 0;
+ }
+
+ void if_null_assign_unreachable() {
+ super.prop ??= /*unreachable*/ 0;
+ }
+}
+
+extension ExtensionProperty<T> on HasProperty<T> {
+ /*member: ExtensionProperty|get#extendedProp:doesNotComplete*/
+ T get extendedProp => prop;
+ set extendedProp(T? value) {
+ prop = value;
+ }
+}
+
+void extended_property_if_null_reachable(HasProperty<int?> x) {
+ x.extendedProp ?? 0;
+}
+
+void extended_property_if_null_assign_reachable(HasProperty<int?> x) {
+ x.extendedProp ??= 0;
+}
+
+void extended_property_if_null_unreachable(HasProperty<int> x) {
+ x.extendedProp ?? /*unreachable*/ 0;
+}
+
+void extended_property_if_null_assign_unreachable(HasProperty<int> x) {
+ x.extendedProp ??= /*unreachable*/ 0;
+}
+
+void null_aware_extended_property_if_null_reachable(HasProperty<int?>? x) {
+ x?.extendedProp ?? 0;
+}
+
+void null_aware_extended_property_if_null_assign_reachable(
+ HasProperty<int?>? x) {
+ x?.extendedProp ??= 0;
+}
+
+void null_aware_extended_property_if_null_not_shortened(HasProperty<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ x?.extendedProp ?? 0;
+}
+
+void null_aware_extended_property_if_null_assign_unreachable(
+ HasProperty<int>? x) {
+ x?.extendedProp ??= /*unreachable*/ 0;
+}
+
+void explicit_extended_property_if_null_reachable(HasProperty<int?> x) {
+ ExtensionProperty(x).extendedProp ?? 0;
+}
+
+void explicit_extended_property_if_null_assign_reachable(HasProperty<int?> x) {
+ ExtensionProperty(x).extendedProp ??= 0;
+}
+
+void explicit_extended_property_if_null_unreachable(HasProperty<int> x) {
+ ExtensionProperty(x).extendedProp ?? /*unreachable*/ 0;
+}
+
+void explicit_extended_property_if_null_assign_unreachable(HasProperty<int> x) {
+ ExtensionProperty(x).extendedProp ??= /*unreachable*/ 0;
+}
+
+void null_aware_explicit_extended_property_if_null_reachable(
+ HasProperty<int?>? x) {
+ ExtensionProperty(x)?.extendedProp ?? 0;
+}
+
+void null_aware_explicit_extended_property_if_null_assign_reachable(
+ HasProperty<int?>? x) {
+ ExtensionProperty(x)?.extendedProp ??= 0;
+}
+
+void null_aware_explicit_extended_property_if_null_not_shortened(
+ HasProperty<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ ExtensionProperty(x)?.extendedProp ?? 0;
+}
+
+void null_aware_explicit_extended_property_if_null_assign_unreachable(
+ HasProperty<int>? x) {
+ ExtensionProperty(x)?.extendedProp ??= /*unreachable*/ 0;
+}
+
+class Indexable<T> {
+ /*member: Indexable.[]:doesNotComplete*/
+ T operator [](int index) => throw '';
+ operator []=(int index, T? value) {}
+}
+
+void index_if_null_reachable(Indexable<int?> x) {
+ x[0] ?? 0;
+}
+
+void index_if_null_unreachable(Indexable<int> x) {
+ x[0] ?? /*unreachable*/ 0;
+}
+
+void index_if_null_assign_reachable(Indexable<int?> x) {
+ x[0] ??= 0;
+}
+
+void index_if_null_assign_unreachable(Indexable<int> x) {
+ x[0] ??= /*unreachable*/ 0;
+}
+
+void null_aware_index_if_null_reachable(Indexable<int?>? x) {
+ x?[0] ?? 0;
+}
+
+void null_aware_index_if_null_unreachable(Indexable<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ x?[0] ?? 0;
+}
+
+void null_aware_index_if_null_assign_reachable(Indexable<int?>? x) {
+ x?[0] ??= 0;
+}
+
+void null_aware_index_if_null_assign_unreachable(Indexable<int>? x) {
+ x?[0] ??= /*unreachable*/ 0;
+}
+
+class SuperIntQuestionIndex extends Indexable<int?> {
+ void if_null_reachable() {
+ super[0] ?? 0;
+ }
+
+ void if_null_assign_reachable() {
+ super[0] ??= 0;
+ }
+}
+
+class SuperIntIndex extends Indexable<int> {
+ void if_null_unreachable() {
+ super[0] ?? /*unreachable*/ 0;
+ }
+
+ void if_null_assign_unreachable() {
+ super[0] ??= /*unreachable*/ 0;
+ }
+}
+
+extension ExtensionIndex<T> on HasProperty<T> {
+ /*member: ExtensionIndex|[]:doesNotComplete*/
+ T operator [](int index) => prop;
+ operator []=(int index, T? value) {
+ prop = value;
+ }
+}
+
+void extended_index_if_null_reachable(HasProperty<int?> x) {
+ x[0] ?? 0;
+}
+
+void extended_index_if_null_assign_reachable(HasProperty<int?> x) {
+ x[0] ??= 0;
+}
+
+void extended_index_if_null_unreachable(HasProperty<int> x) {
+ x[0] ?? /*unreachable*/ 0;
+}
+
+void extended_index_if_null_assign_unreachable(HasProperty<int> x) {
+ x[0] ??= /*unreachable*/ 0;
+}
+
+void null_aware_extended_index_if_null_reachable(HasProperty<int?>? x) {
+ x?[0] ?? 0;
+}
+
+void null_aware_extended_index_if_null_assign_reachable(HasProperty<int?>? x) {
+ x?[0] ??= 0;
+}
+
+void null_aware_extended_index_if_null_not_shortened(HasProperty<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ x?[0] ?? 0;
+}
+
+void null_aware_extended_index_if_null_assign_unreachable(HasProperty<int>? x) {
+ x?[0] ??= /*unreachable*/ 0;
+}
+
+void explicit_extended_index_if_null_reachable(HasProperty<int?> x) {
+ ExtensionIndex(x)[0] ?? 0;
+}
+
+void explicit_extended_index_if_null_assign_reachable(HasProperty<int?> x) {
+ ExtensionIndex(x)[0] ??= 0;
+}
+
+void explicit_extended_index_if_null_unreachable(HasProperty<int> x) {
+ ExtensionIndex(x)[0] ?? /*unreachable*/ 0;
+}
+
+void explicit_extended_index_if_null_assign_unreachable(HasProperty<int> x) {
+ ExtensionIndex(x)[0] ??= /*unreachable*/ 0;
+}
+
+void null_aware_explicit_extended_index_if_null_reachable(
+ HasProperty<int?>? x) {
+ ExtensionIndex(x)?[0] ?? 0;
+}
+
+void null_aware_explicit_extended_index_if_null_assign_reachable(
+ HasProperty<int?>? x) {
+ ExtensionIndex(x)?[0] ??= 0;
+}
+
+void null_aware_explicit_extended_index_if_null_not_shortened(
+ HasProperty<int>? x) {
+ // If `??` participated in null-shortening, `0` would be unreachable.
+ ExtensionIndex(x)?[0] ?? 0;
+}
+
+void null_aware_explicit_extended_index_if_null_assign_unreachable(
+ HasProperty<int>? x) {
+ ExtensionIndex(x)?[0] ??= /*unreachable*/ 0;
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart
new file mode 100644
index 0000000..a204bf8
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void index_reachable(List<int>? f()) {
+ f()?[throw ''];
+ 0;
+}
+
+/*member: index_unreachable:doesNotComplete*/
+void index_unreachable(List<int> f()) {
+ f()?[throw ''];
+ /*stmt: unreachable*/ 0;
+}
+
+void cascaded_index_reachable(List<int>? f()) {
+ f()?..[throw ''];
+ 0;
+}
+
+/*member: cascaded_index_unreachable:doesNotComplete*/
+void cascaded_index_unreachable(List<int> f()) {
+ f()?..[throw ''];
+ /*stmt: unreachable*/ 0;
+}
+
+void method_invocation_reachable(int? f()) {
+ f()?.remainder(throw '');
+ 0;
+}
+
+/*member: method_invocation_unreachable:doesNotComplete*/
+void method_invocation_unreachable(int f()) {
+ f()?.remainder(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+void cascaded_method_invocation_reachable(int? f()) {
+ f()?..remainder(throw '');
+ 0;
+}
+
+/*member: cascaded_method_invocation_unreachable:doesNotComplete*/
+void cascaded_method_invocation_unreachable(int f()) {
+ f()?..remainder(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+void property_get_reachable(int? f()) {
+ f()?.hashCode.remainder(throw '');
+ 0;
+}
+
+/*member: property_get_unreachable:doesNotComplete*/
+void property_get_unreachable(int f()) {
+ f()?.hashCode.remainder(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+void cascaded_property_get_reachable(int? f()) {
+ f()?..hashCode.remainder(throw '');
+ 0;
+}
+
+/*member: cascaded_property_get_unreachable:doesNotComplete*/
+void cascaded_property_get_unreachable(int f()) {
+ f()?..hashCode.remainder(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+void property_get_invocation_reachable(List<void Function(dynamic)>? f()) {
+ // We need a special test case for this because it parses like a method
+ // invocation but the analyzer rewrites it as a property access followed by a
+ // function expression invocation.
+ f()?.first(throw '');
+ 0;
+}
+
+/*member: property_get_invocation_unreachable:doesNotComplete*/
+void property_get_invocation_unreachable(List<void Function(dynamic)> f()) {
+ // We need a special test case for this because it parses like a method
+ // invocation but the analyzer rewrites it as a property access followed by a
+ // function expression invocation.
+ f()?.first(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+void cascaded_property_get_invocation_reachable(
+ List<void Function(dynamic)>? f()) {
+ // We need a special test case for this because it parses like a method
+ // invocation but the analyzer rewrites it as a property access followed by a
+ // function expression invocation.
+ f()?..first(throw '');
+ 0;
+}
+
+/*member: cascaded_property_get_invocation_unreachable:doesNotComplete*/
+void cascaded_property_get_invocation_unreachable(
+ List<void Function(dynamic)> f()) {
+ // We need a special test case for this because it parses like a method
+ // invocation but the analyzer rewrites it as a property access followed by a
+ // function expression invocation.
+ f()?..first(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+class C {
+ int field = 0;
+}
+
+void property_set_reachable(C? f()) {
+ f()?.field = throw '';
+ 0;
+}
+
+/*member: property_set_unreachable:doesNotComplete*/
+void property_set_unreachable(C f()) {
+ f()?.field = throw '';
+ /*stmt: unreachable*/ 0;
+}
+
+void cascaded_property_set_reachable(C? f()) {
+ f()?..field = throw '';
+ 0;
+}
+
+/*member: cascaded_property_set_unreachable:doesNotComplete*/
+void cascaded_property_set_unreachable(C f()) {
+ f()?..field = throw '';
+ /*stmt: unreachable*/ 0;
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart
new file mode 100644
index 0000000..4edebe4
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C {
+ static void staticMethod(dynamic d) {}
+ /*member: C.staticGetter:doesNotComplete*/
+ static int get staticGetter => 0;
+ /*member: C.staticInvokableGetter:doesNotComplete*/
+ static void Function(dynamic d) get staticInvokableGetter => (_) {};
+ static void set staticSetter(int value) {}
+}
+
+/*member: method_invocation_unreachable:doesNotComplete*/
+void method_invocation_unreachable() {
+ C?.staticMethod(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+/*member: property_get_unreachable:doesNotComplete*/
+void property_get_unreachable() {
+ C?.staticGetter.remainder(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+/*member: property_get_invocation_unreachable:doesNotComplete*/
+void property_get_invocation_unreachable() {
+ // We need a special test case for this because it parses like a method
+ // invocation but the analyzer rewrites it as a property access followed by a
+ // function expression invocation.
+ C?.staticInvokableGetter(throw '');
+ /*stmt: unreachable*/ 0;
+}
+
+/*member: property_set_unreachable:doesNotComplete*/
+void property_set_unreachable() {
+ C?.staticSetter = throw '';
+ /*stmt: unreachable*/ 0;
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index d6330c2..f5e89d2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -16,22 +16,63 @@
class TransformSetParser {
static const String _changesKey = 'changes';
- static const String _componentsKey = 'components';
+ static const String _classKey = 'class';
+
+ static const String _constructorKey = 'constructor';
static const String _elementKey = 'element';
+ static const String _enumConstantKey = 'constant';
+
+ static const String _enumKey = 'enum';
+
+ static const String _extensionKey = 'extension';
+
+ static const String _fieldKey = 'field';
+
+ static const String _functionKey = 'function';
+
+ static const String _getterKey = 'getter';
+
+ static const String _inClassKey = 'inClass';
+
+ static const String _inEnumKey = 'inEnum';
+
+ static const String _inExtensionKey = 'inExtension';
+
+ static const String _inMixinKey = 'inMixin';
+
static const String _kindKey = 'kind';
+ static const String _methodKey = 'method';
+
+ static const String _mixinKey = 'mixin';
+
static const String _newNameKey = 'newName';
+ static const String _setterKey = 'setter';
+
static const String _titleKey = 'title';
static const String _transformsKey = 'transforms';
+ static const String _typedefKey = 'typedef';
+
static const String _urisKey = 'uris';
static const String _versionKey = 'version';
+ /// A table mapping top-level keys for member elements to the list of keys for
+ /// the possible containers of that element.
+ static const Map<String, List<String>> _containerKeyMap = {
+ _constructorKey: [_inClassKey],
+ _enumConstantKey: [_inEnumKey],
+ _fieldKey: [_inClassKey, _inExtensionKey, _inMixinKey],
+ _getterKey: [_inClassKey, _inExtensionKey, _inMixinKey],
+ _methodKey: [_inClassKey, _inExtensionKey, _inMixinKey],
+ _setterKey: [_inClassKey, _inExtensionKey, _inMixinKey],
+ };
+
static const String _renameKind = 'rename';
static const int currentVersion = 1;
@@ -91,6 +132,34 @@
}
}
+ /// Given a [map] and a set of [validKeys], ensure that only one of those keys
+ /// is in the map and return it. If more than one of the keys is in the map,
+ /// report a diagnostic.
+ String _singleKey(YamlMap map, List<String> validKeys) {
+ if (validKeys == null) {
+ return null;
+ }
+ var foundKeys = <String>[];
+ var keyToNodeMap = <String, YamlNode>{};
+ for (var keyNode in map.nodes.keys) {
+ if (keyNode is YamlScalar) {
+ var key = _translateString(keyNode);
+ if (key != null && validKeys.contains(key)) {
+ foundKeys.add(key);
+ keyToNodeMap[key] = keyNode;
+ }
+ }
+ }
+ if (foundKeys.isEmpty) {
+ return null;
+ }
+ for (var i = 1; i < foundKeys.length; i++) {
+ // var invalidNode = keyToNodeMap[foundKeys[i]];
+ // TODO(brianwilkerson) Report the invalid key.
+ }
+ return foundKeys[0];
+ }
+
/// Translate the [node] into a change. Return the resulting change, or `null`
/// if the [node] does not represent a valid change.
Change _translateChange(YamlNode node) {
@@ -118,15 +187,42 @@
if (node is YamlMap) {
var uris = _translateList(node.valueAt(_urisKey), _translateString);
if (uris == null) {
+ // TODO(brianwilkerson) Returning here prevents other errors from being
+ // reported.
// The error has already been reported.
return null;
}
- var components =
- _translateList(node.valueAt(_componentsKey), _translateString);
- if (components == null) {
+ var elementKey = _singleKey(node, [
+ _classKey,
+ _enumConstantKey,
+ _constructorKey,
+ _enumKey,
+ _extensionKey,
+ _fieldKey,
+ _functionKey,
+ _getterKey,
+ _methodKey,
+ _mixinKey,
+ _setterKey,
+ _typedefKey
+ ]);
+ var elementName = _translateString(node.valueAt(elementKey));
+ if (elementName == null) {
// The error has already been reported.
return null;
}
+ var components = [elementName];
+ var containerKey = _singleKey(node, _containerKeyMap[elementKey]);
+ var containerName = _translateString(node.valueAt(containerKey));
+ if (containerName == null) {
+ if ([_constructorKey, _enumConstantKey, _methodKey, _fieldKey]
+ .contains(elementKey)) {
+ // TODO(brianwilkerson) Report that no container was found.
+ return null;
+ }
+ } else {
+ components.insert(0, containerName);
+ }
return ElementDescriptor(libraryUris: uris, components: components);
} else if (node == null) {
// TODO(brianwilkerson) Report the missing YAML.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
index e483534..58dd53a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
@@ -25,8 +25,7 @@
element:
uris:
- '$importUri'
- components:
- - 'Old'
+ class: 'Old'
changes:
- kind: 'rename'
newName: 'New'
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 336979b..f36fef5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -18,6 +18,59 @@
@reflectiveTest
class TransformSetParserTest extends AbstractTransformSetParserTest {
+ void test_element_getter_inMixin() {
+ parse('''
+version: 1
+transforms:
+- title: 'Rename g'
+ element:
+ uris: ['test.dart']
+ getter: 'g'
+ inMixin: 'A'
+ changes: []
+''');
+ var transforms = result.transformsFor('g', ['test.dart']);
+ expect(transforms, hasLength(1));
+ var transform = transforms[0];
+ expect(transform.title, 'Rename g');
+ expect(transform.changes, isEmpty);
+ }
+
+ void test_element_getter_topLevel() {
+ parse('''
+version: 1
+transforms:
+- title: 'Rename g'
+ element:
+ uris: ['test.dart']
+ getter: 'g'
+ changes: []
+''');
+ var transforms = result.transformsFor('g', ['test.dart']);
+ expect(transforms, hasLength(1));
+ var transform = transforms[0];
+ expect(transform.title, 'Rename g');
+ expect(transform.changes, isEmpty);
+ }
+
+ void test_element_method_inClass() {
+ parse('''
+version: 1
+transforms:
+- title: 'Rename m'
+ element:
+ uris: ['test.dart']
+ method: 'm'
+ inClass: 'A'
+ changes: []
+''');
+ var transforms = result.transformsFor('m', ['test.dart']);
+ expect(transforms, hasLength(1));
+ var transform = transforms[0];
+ expect(transform.title, 'Rename m');
+ expect(transform.changes, isEmpty);
+ }
+
void test_incomplete() {
parse('''
version: 1
@@ -46,8 +99,7 @@
element:
uris:
- 'test.dart'
- components:
- - 'A'
+ class: 'A'
changes:
- kind: 'rename'
newName: 'B'
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
index 32b927a..28948d0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -31,7 +32,10 @@
''');
await assertHasFix('''
int f(int a, int b) => a;
-''');
+''', errorFilter: (e) {
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ return e.errorCode != HintCode.DEAD_CODE;
+ });
}
Future<void> test_nestedChild() async {
@@ -40,7 +44,10 @@
''');
await assertHasFix('''
int f(int a, int b) => a;
-''');
+''', errorFilter: (e) {
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ return e.errorCode != HintCode.DEAD_CODE;
+ });
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 3cf8743..0cacd29 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -466,7 +466,7 @@
var flow = _flowAnalysis?.flow;
if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_rightBegin(left);
+ flow.ifNullExpression_rightBegin(left, node.readType);
}
right?.accept(_resolver);
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index fe41371..ddab194 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -178,7 +178,7 @@
}
InferenceContext.setType(right, rightContextType);
- flow?.ifNullExpression_rightBegin(left);
+ flow?.ifNullExpression_rightBegin(left, leftType);
right.accept(_resolver);
right = node.rightOperand;
flow?.ifNullExpression_end();
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 1c2938f1..915f509 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -85,7 +85,7 @@
if (flow == null) return null;
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_rightBegin(node.leftHandSide);
+ flow.ifNullExpression_rightBegin(node.leftHandSide, node.readType);
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0c60e48..d1fedd3 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -850,7 +850,8 @@
node.target.accept(this);
if (node.isNullAware && _isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(
+ node.target, node.target.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
@@ -1447,7 +1448,8 @@
node.target?.accept(this);
if (_migratableAstInfoProvider.isIndexExpressionNullAware(node) &&
_isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(
+ node.target, node.realTarget.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
node.accept(elementResolver);
@@ -1534,12 +1536,18 @@
@override
void visitMethodInvocation(MethodInvocation node) {
- node.target?.accept(this);
+ var target = node.target;
+ target?.accept(this);
if (_migratableAstInfoProvider.isMethodInvocationNullAware(node) &&
_isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
- _unfinishedNullShorts.add(node.nullShortingTermination);
+ if (target is SimpleIdentifier && target.staticElement is ClassElement) {
+ // `?.` to access static methods is equivalent to `.`, so do nothing.
+ } else {
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(
+ target, node.realTarget.staticType ?? typeProvider.dynamicType);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
+ }
}
node.typeArguments?.accept(this);
@@ -1632,11 +1640,17 @@
// We visit the target, but do not visit the property name because it needs
// to be visited in the context of the property access node.
//
- node.target?.accept(this);
+ var target = node.target;
+ target?.accept(this);
if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
_isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
- _unfinishedNullShorts.add(node.nullShortingTermination);
+ if (target is SimpleIdentifier && target.staticElement is ClassElement) {
+ // `?.` to access static methods is equivalent to `.`, so do nothing.
+ } else {
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(
+ target, node.realTarget.staticType ?? typeProvider.dynamicType);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
+ }
}
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -2006,8 +2020,14 @@
if (function is PropertyAccess &&
_migratableAstInfoProvider.isPropertyAccessNullAware(function) &&
_isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(function);
- _unfinishedNullShorts.add(node.nullShortingTermination);
+ var target = function.target;
+ if (target is SimpleIdentifier && target.staticElement is ClassElement) {
+ // `?.` to access static methods is equivalent to `.`, so do nothing.
+ } else {
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(function,
+ function.realTarget.staticType ?? typeProvider.dynamicType);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
+ }
}
_functionExpressionInvocationResolver.resolve(node);
diff --git a/pkg/analyzer/lib/src/util/ast_data_extractor.dart b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
index 06fdab9..2147db8 100644
--- a/pkg/analyzer/lib/src/util/ast_data_extractor.dart
+++ b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
@@ -84,6 +84,13 @@
var memberName = element.name;
var className = element.enclosingElement.name;
return MemberId.internal(memberName, className: className);
+ } else if (element.enclosingElement is ExtensionElement) {
+ var memberName = element.name;
+ var extensionName = element.enclosingElement.name;
+ if (element is PropertyAccessorElement) {
+ memberName = '${element.isGetter ? 'get' : 'set'}#$memberName';
+ }
+ return MemberId.internal('$extensionName|$memberName');
}
throw UnimplementedError(
'TODO(paulberry): $element (${element.runtimeType})');
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index c616675..95d7b3e 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -445,19 +445,17 @@
test_async_expression_function_type() async {
await assertErrorsInCode('''
-import 'dart:async';
typedef Future<int> F(int i);
main() {
F f = (int i) async => i;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 64, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 43, 1),
]);
}
test_async_flattened() async {
await assertNoErrorsInCode('''
-import 'dart:async';
typedef Future<int> CreatesFutureInt();
main() {
CreatesFutureInt createFutureInt = () async => f();
@@ -470,7 +468,6 @@
test_async_future_dynamic_with_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<dynamic> f() async {
return;
}
@@ -479,7 +476,6 @@
test_async_future_dynamic_with_return_value() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<dynamic> f() async {
return 5;
}
@@ -488,14 +484,12 @@
test_async_future_dynamic_without_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<dynamic> f() async {}
''');
}
test_async_future_int_with_return_future_int() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<int> f() async {
return new Future<int>.value(5);
}
@@ -504,7 +498,6 @@
test_async_future_int_with_return_value() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<int> f() async {
return 5;
}
@@ -513,7 +506,6 @@
test_async_future_null_with_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<Null> f() async {
return;
}
@@ -522,14 +514,12 @@
test_async_future_null_without_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<Null> f() async {}
''');
}
test_async_future_object_with_return_value() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<Object> f() async {
return 5;
}
@@ -538,7 +528,6 @@
test_async_future_with_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future f() async {
return;
}
@@ -547,7 +536,6 @@
test_async_future_with_return_value() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future f() async {
return 5;
}
@@ -556,7 +544,6 @@
test_async_future_without_return() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future f() async {}
''');
}
@@ -607,25 +594,23 @@
test_await_flattened() async {
await assertErrorsInCode('''
-import 'dart:async';
Future<Future<int>> ffi() => null;
f() async {
Future<int> b = await ffi();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 82, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
]);
}
test_await_simple() async {
await assertErrorsInCode('''
-import 'dart:async';
Future<int> fi() => null;
f() async {
int a = await fi();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 65, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 44, 1),
]);
}
@@ -1099,7 +1084,6 @@
test_empty_generator_async() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Stream<int> f() async* {
}
''');
@@ -2147,8 +2131,6 @@
test_issue_24191() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
abstract class S extends Stream {}
f(S s) async {
await for (var v in s) {
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 0256b50..e29bb22 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -40,126 +40,116 @@
test_await_flattened() async {
await assertErrorsInCode('''
-import 'dart:async';
Future<Future<int>> ffi() => null;
f() async {
Future<int> b = await ffi();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 82, 1),
- ]);
- }
-
- test_await_simple() async {
- await assertErrorsInCode('''
-import 'dart:async';
-Future<int> fi() => null;
-f() async {
- String a = await fi(); // Warning: int not assignable to String
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 68, 1),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 72, 10),
- ]);
- }
-
- test_awaitForIn_declaredVariableRightType() async {
- await assertErrorsInCode('''
-import 'dart:async';
-f() async {
- Stream<int> stream;
- await for (int i in stream) {}
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 72, 1),
- ]);
- }
-
- test_awaitForIn_declaredVariableWrongType() async {
- await assertErrorsInCode('''
-import 'dart:async';
-f() async {
- Stream<String> stream;
- await for (int i in stream) {}
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 75, 1),
- error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 80, 6),
- ]);
- }
-
- test_awaitForIn_downcast() async {
- await assertErrorsInCode('''
-import 'dart:async';
-f() async {
- Stream<num> stream;
- await for (int i in stream) {}
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 72, 1),
- ]);
- }
-
- test_awaitForIn_dynamicVariable() async {
- await assertErrorsInCode('''
-import 'dart:async';
-f() async {
- Stream<int> stream;
- await for (var i in stream) {}
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 72, 1),
- ]);
- }
-
- test_awaitForIn_existingVariableRightType() async {
- await assertErrorsInCode('''
-import 'dart:async';
-f() async {
- Stream<int> stream;
- int i;
- await for (i in stream) {}
-}
-''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
]);
}
+ test_await_simple() async {
+ await assertErrorsInCode('''
+Future<int> fi() => null;
+f() async {
+ String a = await fi(); // Warning: int not assignable to String
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 47, 1),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 51, 10),
+ ]);
+ }
+
+ test_awaitForIn_declaredVariableRightType() async {
+ await assertErrorsInCode('''
+f() async {
+ Stream<int> stream;
+ await for (int i in stream) {}
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 51, 1),
+ ]);
+ }
+
+ test_awaitForIn_declaredVariableWrongType() async {
+ await assertErrorsInCode('''
+f() async {
+ Stream<String> stream;
+ await for (int i in stream) {}
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
+ error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 59, 6),
+ ]);
+ }
+
+ test_awaitForIn_downcast() async {
+ await assertErrorsInCode('''
+f() async {
+ Stream<num> stream;
+ await for (int i in stream) {}
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 51, 1),
+ ]);
+ }
+
+ test_awaitForIn_dynamicVariable() async {
+ await assertErrorsInCode('''
+f() async {
+ Stream<int> stream;
+ await for (var i in stream) {}
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 51, 1),
+ ]);
+ }
+
+ test_awaitForIn_existingVariableRightType() async {
+ await assertErrorsInCode('''
+f() async {
+ Stream<int> stream;
+ int i;
+ await for (i in stream) {}
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 40, 1),
+ ]);
+ }
+
test_awaitForIn_existingVariableWrongType() async {
await assertErrorsInCode('''
-import 'dart:async';
f() async {
Stream<String> stream;
int i;
await for (i in stream) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 64, 1),
- error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 85, 6),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 43, 1),
+ error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 64, 6),
]);
}
test_awaitForIn_streamOfDynamic() async {
await assertErrorsInCode('''
-import 'dart:async';
f() async {
Stream stream;
await for (int i in stream) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 67, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 46, 1),
]);
}
test_awaitForIn_upcast() async {
await assertErrorsInCode('''
-import 'dart:async';
f() async {
Stream<int> stream;
await for (num i in stream) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 72, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 51, 1),
]);
}
@@ -600,7 +590,6 @@
class StrongModeStaticTypeWarningCodeTest extends PubPackageResolutionTest {
test_legalAsyncGeneratorReturnType_function_supertypeOfStream() async {
await assertNoErrorsInCode('''
-import 'dart:async';
f() async* { yield 42; }
dynamic f2() async* { yield 42; }
Object f3() async* { yield 42; }
@@ -614,7 +603,6 @@
test_legalAsyncReturnType_function_supertypeOfFuture() async {
await assertNoErrorsInCode('''
-import 'dart:async';
f() async { return 42; }
dynamic f2() async { return 42; }
Object f3() async { return 42; }
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index e46eb3b..f219504 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -87,7 +87,6 @@
test_async_method_propagation() async {
String code = r'''
- import "dart:async";
class A {
Future f0() => new Future.value(3);
Future f1() async => new Future.value(3);
@@ -144,8 +143,6 @@
test_async_propagation() async {
String code = r'''
- import "dart:async";
-
Future f0() => new Future.value(3);
Future f1() async => new Future.value(3);
Future f2() async => await new Future.value(3);
@@ -3378,14 +3375,13 @@
test_genericMethod_then() async {
await assertErrorsInCode(r'''
-import 'dart:async';
String toString(int x) => x.toString();
main() {
Future<int> bar = null;
var foo = bar.then(toString);
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 102, 3),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 81, 3),
]);
expectInitializerType('foo', 'Future<String>');
@@ -3408,14 +3404,13 @@
test_genericMethod_then_propagatedType() async {
// Regression test for https://github.com/dart-lang/sdk/issues/25482.
await assertErrorsInCode(r'''
-import 'dart:async';
void main() {
Future<String> p;
var foo = p.then((r) => new Future<String>.value(3));
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 3),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 106, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 40, 3),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 85, 1),
]);
// Note: this correctly reports the error
// CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE when run with the driver;
@@ -3978,7 +3973,6 @@
test_foreachInference_var_stream() async {
await resolveTestCode(r'''
-import 'dart:async';
main() async {
Stream<int> stream = null;
await for (var v in stream) {
diff --git a/pkg/analyzer/test/src/dart/resolution/await_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/await_expression_test.dart
index fe0faac..e2baade 100644
--- a/pkg/analyzer/test/src/dart/resolution/await_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/await_expression_test.dart
@@ -17,8 +17,6 @@
class AwaitExpressionResolutionTest extends PubPackageResolutionTest {
test_future() async {
await assertNoErrorsInCode(r'''
-import 'dart:async';
-
f(Future<int> a) async {
await a;
}
@@ -57,8 +55,6 @@
test_futureQ() async {
await assertNoErrorsInCode(r'''
-import 'dart:async';
-
f(Future<int>? a) async {
await a;
}
diff --git a/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart b/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
index c1e4746..e60e478 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
@@ -22,13 +22,16 @@
var x = 0;
''');
- await assertNoErrorsInCode('''
+ await assertErrorsInCode('''
import 'a.dart';
f() {
x ??= 0;
}
-''');
+''', [
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 32, 2),
+ ]);
}
test_assignCompound_map() async {
@@ -51,6 +54,8 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 19, 1),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 19, 2),
]);
}
@@ -68,13 +73,16 @@
var x = 0;
''');
- await assertNoErrorsInCode('''
+ await assertErrorsInCode('''
import 'a.dart';
f() {
x ?? 0;
}
-''');
+''', [
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 31, 2),
+ ]);
}
test_binary_nonNullable() async {
@@ -84,6 +92,8 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 18, 1),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 18, 2),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart b/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
index 916d47f..3875476 100644
--- a/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
@@ -17,28 +17,26 @@
class ForInOfInvalidElementTypeTest extends PubPackageResolutionTest {
test_await_declaredVariableWrongType() async {
await assertErrorsInCode('''
-import 'dart:async';
f() async {
Stream<String> stream;
await for (int i in stream) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 75, 1),
- error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 80, 6),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
+ error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 59, 6),
]);
}
test_await_existingVariableWrongType() async {
await assertErrorsInCode('''
-import 'dart:async';
f() async {
Stream<String> stream;
int i;
await for (i in stream) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 64, 1),
- error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 85, 6),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 43, 1),
+ error(CompileTimeErrorCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 64, 6),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/illegal_async_generator_return_type_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_async_generator_return_type_test.dart
index ac52b34..c60b913 100644
--- a/pkg/analyzer/test/src/diagnostics/illegal_async_generator_return_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/illegal_async_generator_return_type_test.dart
@@ -31,11 +31,10 @@
test_function_subtypeOfStream() async {
await assertErrorsInCode('''
-import 'dart:async';
abstract class SubStream<T> implements Stream<T> {}
SubStream<int> f() async* {}
''', [
- error(CompileTimeErrorCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, 73, 14),
+ error(CompileTimeErrorCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, 52, 14),
]);
}
@@ -59,13 +58,12 @@
test_method_subtypeOfStream() async {
await assertErrorsInCode('''
-import 'dart:async';
abstract class SubStream<T> implements Stream<T> {}
class C {
SubStream<int> f() async* {}
}
''', [
- error(CompileTimeErrorCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, 85, 14),
+ error(CompileTimeErrorCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, 64, 14),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
index 3302326..01e30f0 100644
--- a/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
@@ -41,13 +41,12 @@
test_function_subtypeOfFuture() async {
await assertErrorsInCode('''
-import 'dart:async';
abstract class SubFuture<T> implements Future<T> {}
SubFuture<int> f() async {
return 0;
}
''', [
- error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 73, 14),
+ error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 52, 14),
]);
}
@@ -71,7 +70,6 @@
test_method_subtypeOfFuture() async {
await assertErrorsInCode('''
-import 'dart:async';
abstract class SubFuture<T> implements Future<T> {}
class C {
SubFuture<int> m() async {
@@ -79,7 +77,7 @@
}
}
''', [
- error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 85, 14),
+ error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 64, 14),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart b/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
index 7a58e23..eda7bec 100644
--- a/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
@@ -170,7 +170,6 @@
test_overriddenWithFuture() async {
// https://github.com/flutter/flutter/issues/11646
await assertNoErrorsInCode(r'''
-import 'dart:async';
import 'package:meta/meta.dart';
class A {
@mustCallSuper
@@ -191,7 +190,6 @@
test_overriddenWithFuture2() async {
// https://github.com/flutter/flutter/issues/11646
await assertNoErrorsInCode(r'''
-import 'dart:async';
import 'package:meta/meta.dart';
class A {
@mustCallSuper
diff --git a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
index 1caa9cc..df5882b 100644
--- a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
@@ -84,6 +84,8 @@
}
''', [
_notAssignedError(22, 1),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 28, 2),
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 28, 1),
]);
}
@@ -96,6 +98,8 @@
}
''', [
_notAssignedError(22, 1),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 28, 2),
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 28, 1),
_notAssignedError(28, 1),
]);
@@ -118,7 +122,11 @@
(v = 0) ?? 0;
v;
}
-''', [error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 33, 1)]);
+''', [
+ error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 33, 1),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 33, 7),
+ ]);
}
test_binaryExpression_ifNull_right() async {
@@ -130,6 +138,8 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 32, 7),
+ // See https://github.com/dart-lang/sdk/issues/43263.
+ error(HintCode.DEAD_CODE, 32, 13),
_notAssignedError(43, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/return_in_generator_test.dart b/pkg/analyzer/test/src/diagnostics/return_in_generator_test.dart
index bdc49f3..748f963 100644
--- a/pkg/analyzer/test/src/diagnostics/return_in_generator_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_in_generator_test.dart
@@ -36,7 +36,6 @@
test_asyncStar_blockBody_noValue() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Stream<int> f() async* {
return;
}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index 0552343..a668a46 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -409,10 +409,4 @@
int f() => A.x;
''');
}
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/42957')
- test_typeLiteral_conditionalAccess() {
- return super.test_typeLiteral_conditionalAccess();
- }
}
diff --git a/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
index 862460e..f89e480 100644
--- a/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/yield_of_invalid_type_test.dart
@@ -19,15 +19,13 @@
test_none_asyncStar_dynamic_to_streamInt() async {
await assertErrorsInCode(
'''
-import 'dart:async';
-
Stream<int> f() async* {
dynamic a = 0;
yield a;
}
''',
expectedErrorsByNullability(nullable: [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 72, 1),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 50, 1),
], legacy: []));
}
@@ -63,8 +61,6 @@
test_none_asyncStar_int_to_streamDynamic() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
Stream f() async* {
yield 0;
}
@@ -73,8 +69,6 @@
test_none_asyncStar_int_to_streamInt() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
yield 0;
}
@@ -83,13 +77,11 @@
test_none_asyncStar_int_to_streamString() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Stream<String> f() async* {
yield 0;
}
''', [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 58, 1),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 36, 1),
]);
}
@@ -161,14 +153,12 @@
test_none_syncStar_int_to_stream() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() sync* {
yield 0;
}
''', [
- error(CompileTimeErrorCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE, 22, 11),
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 54, 1),
+ error(CompileTimeErrorCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE, 0, 11),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 32, 1),
]);
}
@@ -192,8 +182,6 @@
test_star_asyncStar_dynamic_to_streamDynamic() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
Stream f() async* {
yield* g();
}
@@ -204,8 +192,6 @@
test_star_asyncStar_dynamic_to_streamInt() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
yield* g();
}
@@ -237,34 +223,28 @@
test_star_asyncStar_iterableInt_to_streamInt() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
var a = <int>[];
yield* a;
}
''', [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 75, 1),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 53, 1),
]);
}
test_star_asyncStar_iterableString_to_streamInt() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
var a = <String>[];
yield* a;
}
''', [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 78, 1),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 56, 1),
]);
}
test_star_asyncStar_streamDynamic_to_dynamic() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
f() async* {
yield* g();
}
@@ -276,8 +256,6 @@
test_star_asyncStar_streamDynamic_to_streamInt() async {
await assertErrorsInCode(
'''
-import 'dart:async';
-
Stream<int> f() async* {
yield* g();
}
@@ -285,14 +263,12 @@
Stream g() => throw 0;
''',
expectedErrorsByNullability(nullable: [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 56, 3),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 34, 3),
], legacy: []));
}
test_star_asyncStar_streamInt_to_dynamic() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
f() async* {
yield* g();
}
@@ -303,8 +279,6 @@
test_star_asyncStar_streamInt_to_streamInt() async {
await assertNoErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
yield* g();
}
@@ -315,15 +289,13 @@
test_star_asyncStar_streamString_to_streamInt() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Stream<int> f() async* {
yield* g();
}
Stream<String> g() => throw 0;
''', [
- error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 56, 3),
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 34, 3),
]);
}
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 366c696..41ea625 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -18,8 +18,6 @@
class CheckerTest extends PubPackageResolutionTest {
test_awaitForInCastsStreamElementToVariable() async {
await assertErrorsInCode('''
-import 'dart:async';
-
abstract class MyStream<T> extends Stream<T> {
factory MyStream() => throw 0;
}
@@ -41,12 +39,12 @@
await for (int i in new MyStream<num>()) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 181, 1),
- error(CompileTimeErrorCode.FOR_IN_OF_INVALID_TYPE, 186, 4),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 235, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 309, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 373, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 438, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 159, 1),
+ error(CompileTimeErrorCode.FOR_IN_OF_INVALID_TYPE, 164, 4),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 213, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 287, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 351, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 416, 1),
]);
}
@@ -1008,7 +1006,6 @@
test_functionModifiers_async() async {
await assertErrorsInCode('''
-import 'dart:async';
import 'dart:math' show Random;
dynamic x;
@@ -1053,13 +1050,13 @@
return ((1 > 0) ? new Future<String>.value('hello') : "world");
}
''', [
- error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 224, 27),
- error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 454, 27),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 529, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 548, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 567, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 589, 1),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 593, 7),
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 203, 27),
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 433, 27),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 508, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 527, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 546, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 568, 1),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 572, 7),
]);
}
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 6c8f375..b7e1600 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -28,7 +28,6 @@
test_asyncClosureReturnType_flatten() async {
await assertNoErrorsInCode('''
-import 'dart:async';
Future<int> futureInt = null;
var f = () => futureInt;
var g = () async => futureInt;
@@ -73,7 +72,6 @@
test_blockBodiedLambdas_async_allReturnsAreFutures() async {
await assertErrorsInCode(r'''
-import 'dart:async';
import 'dart:math' show Random;
main() {
var f = () async {
@@ -87,8 +85,8 @@
Future<int> h = f();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 239, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 262, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 218, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 241, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -97,7 +95,6 @@
test_blockBodiedLambdas_async_allReturnsAreValues() async {
await assertErrorsInCode(r'''
-import 'dart:async';
import 'dart:math' show Random;
main() {
var f = () async {
@@ -111,8 +108,8 @@
Future<int> h = f();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 190, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 213, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 169, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 192, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -121,7 +118,6 @@
test_blockBodiedLambdas_async_mixOfValuesAndFutures() async {
await assertErrorsInCode(r'''
-import 'dart:async';
import 'dart:math' show Random;
main() {
var f = () async {
@@ -135,8 +131,8 @@
Future<int> h = f();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 213, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 236, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 192, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 215, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -145,7 +141,6 @@
test_blockBodiedLambdas_asyncStar() async {
await assertErrorsInCode(r'''
-import 'dart:async';
main() {
var f = () async* {
yield 1;
@@ -156,8 +151,8 @@
Stream<int> h = f();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 120, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 143, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 99, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 122, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -203,7 +198,6 @@
test_blockBodiedLambdas_inferBottom_async() async {
await assertErrorsInCode(r'''
-import 'dart:async';
main() async {
var f = () async { return null; };
Future y = f();
@@ -211,9 +205,9 @@
String s = await f();
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 82, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 108, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 126, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 87, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 105, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -222,7 +216,6 @@
test_blockBodiedLambdas_inferBottom_asyncStar() async {
await assertErrorsInCode(r'''
-import 'dart:async';
main() async {
var f = () async* { yield null; };
Stream y = f();
@@ -230,9 +223,9 @@
String s = await f().first;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 82, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 108, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 126, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 87, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 105, 1),
]);
var f = findLocalVariable(_resultUnit, 'f');
@@ -844,22 +837,19 @@
test_downwardsInferenceAsyncAwait() async {
await assertErrorsInCode('''
-import 'dart:async';
Future test() async {
dynamic d;
List<int> l0 = await [d];
List<int> l1 = await new Future.value([d]);
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 68, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 96, 2),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 47, 2),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 75, 2),
]);
}
test_downwardsInferenceForEach() async {
await assertErrorsInCode('''
-import 'dart:async';
-
abstract class MyStream<T> extends Stream<T> {
factory MyStream() => throw 0;
}
@@ -869,8 +859,8 @@
await for(int x in new MyStream()) {}
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 137, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 172, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 115, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 150, 1),
]);
}
@@ -1689,7 +1679,6 @@
test_futureOr_subtyping() async {
await assertErrorsInCode(r'''
-import 'dart:async';
void add(int x) {}
add2(int y) {}
main() {
@@ -1698,14 +1687,15 @@
var b = f.then(add2);
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 87, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 110, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 66, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 89, 1),
]);
}
test_futureThen() async {
String build({String declared, String downwards, String upwards}) => '''
import 'dart:async';
+
class MyFuture<T> implements Future<T> {
MyFuture() {}
MyFuture.value(T x) {}
@@ -1793,7 +1783,6 @@
test_futureThen_downwardsMethodTarget() async {
// Not working yet, see: https://github.com/dart-lang/sdk/issues/27114
await assertErrorsInCode(r'''
-import 'dart:async';
main() {
Future<int> f;
Future<List<int>> b = f
@@ -1802,13 +1791,12 @@
b = f.then((x) => []);
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 67, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 46, 1),
]);
}
test_futureThen_explicitFuture() async {
await assertErrorsInCode(r'''
-import "dart:async";
m1() {
Future<int> f;
var x = f.then<Future<List<int>>>((x) => []);
@@ -1820,10 +1808,10 @@
Future<List<int>> y = x;
}
''', [
- error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE, 88, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 113, 1),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 117, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 206, 1),
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE, 67, 2),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 92, 1),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 96, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 185, 1),
]);
}
@@ -1887,7 +1875,6 @@
test_futureThen_upwardsFromBlock() async {
// Regression test for https://github.com/dart-lang/sdk/issues/27113.
await assertErrorsInCode(r'''
-import 'dart:async';
main() {
Future<int> base;
var f = base.then((x) { return x == 0; });
@@ -1896,7 +1883,7 @@
b = g;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 146, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 125, 1),
]);
}
@@ -2018,8 +2005,6 @@
// We need to take a future union into account for both directions of
// generic method inference.
await assertErrorsInCode(r'''
-import 'dart:async';
-
foo() async {
Future<List<A>> f1 = null;
Future<List<A>> f2 = null;
@@ -2028,15 +2013,13 @@
class A {}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 110, 6),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 88, 6),
]);
}
test_futureUnion_downwardsGenericMethodWithGenericReturn() async {
// Regression test for https://github.com/dart-lang/sdk/issues/27284
await assertErrorsInCode(r'''
-import 'dart:async';
-
T id<T>(T x) => x;
main() async {
@@ -2044,15 +2027,13 @@
String s = await id(f);
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 86, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 64, 1),
]);
}
test_futureUnion_upwardsGenericMethods() async {
// Regression test for https://github.com/dart-lang/sdk/issues/27151
await assertErrorsInCode(r'''
-import 'dart:async';
-
main() async {
var b = new Future<B>.value(new B());
var c = new Future<C>.value(new C());
@@ -2067,7 +2048,7 @@
class B extends A {}
class C extends A {}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 229, 4),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 207, 4),
]);
}
@@ -2287,8 +2268,6 @@
test_genericMethods_IterableAndFuture() async {
await assertErrorsInCode('''
-import 'dart:async';
-
Future<int> make(int x) => (new Future(() => x));
main() {
@@ -2304,11 +2283,11 @@
=> list.fold<String>('', (x, y) => x + y.toString()));
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 205, 8),
- error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 279, 1),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 315, 8),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 377, 33),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 432, 8),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 183, 8),
+ error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 257, 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 293, 8),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 355, 33),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 410, 8),
]);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 74b894e..ec7bc61 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -1159,7 +1159,8 @@
lhsResult.inferredType, equalsName, node.fileOffset)
.member;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(node.left);
+ inferrer.flowAnalysis
+ .ifNullExpression_rightBegin(node.left, lhsResult.inferredType);
// - Let J = T0 if K is `?` else K.
// - Infer e1 in context J to get T1
ExpressionInferenceResult rhsResult;
@@ -2670,7 +2671,7 @@
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
ExpressionInferenceResult writeResult = inferrer
.inferExpression(node.write, typeContext, true, isVoidAllowed: true);
inferrer.flowAnalysis.ifNullExpression_end();
@@ -2742,7 +2743,7 @@
read = readResult.expression;
readType = readResult.inferredType;
}
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
ExpressionInferenceResult writeResult = inferrer
.inferExpression(node.write, typeContext, true, isVoidAllowed: true);
inferrer.flowAnalysis.ifNullExpression_end();
@@ -3098,7 +3099,7 @@
readResult.inferredType, "??=", node.readOffset);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
Member equalsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
@@ -3269,7 +3270,7 @@
..fileOffset = node.readOffset;
}
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
ExpressionInferenceResult valueResult = inferrer
.inferExpression(node.value, valueType, true, isVoidAllowed: true);
Expression value = inferrer.ensureAssignableResult(valueType, valueResult);
@@ -3423,7 +3424,7 @@
readResult.inferredType, "??=", node.readOffset);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
Member equalsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
@@ -4903,7 +4904,7 @@
isThisReceiver: node.receiver is ThisExpression);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
Member readEqualsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 0603833..2d855ee8 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -3814,14 +3814,15 @@
assert(_inferrer != null) {
// Ensure the initializer of [_nullAwareVariable] is promoted to
// non-nullable.
- _inferrer.flowAnalysis
- .nullAwareAccess_rightBegin(_nullAwareVariable.initializer);
+ _inferrer.flowAnalysis.nullAwareAccess_rightBegin(
+ _nullAwareVariable.initializer, _nullAwareVariable.type);
// Ensure [_nullAwareVariable] is promoted to non-nullable.
// TODO(johnniwinther): Avoid creating a [VariableGet] to promote the
// variable.
VariableGet read = new VariableGet(_nullAwareVariable);
_inferrer.flowAnalysis.variableRead(read, _nullAwareVariable);
- _inferrer.flowAnalysis.nullAwareAccess_rightBegin(read);
+ _inferrer.flowAnalysis
+ .nullAwareAccess_rightBegin(read, _nullAwareVariable.type);
}
/// Creates the null-guarded application of [nullAwareAction] with the
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 81e9982..c9f67ed 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -276,6 +276,7 @@
behaviors
behind
being
+believes
belong
belongs
below
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index c61bc53..b59c9c5 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -456,7 +456,7 @@
} else if (operatorType == TokenType.QUESTION_QUESTION) {
DecoratedType expressionType;
var leftType = _dispatch(leftOperand);
- _flowAnalysis.ifNullExpression_rightBegin(node.leftOperand);
+ _flowAnalysis.ifNullExpression_rightBegin(node.leftOperand, leftType);
try {
_guards.add(leftType.node);
DecoratedType rightType;
@@ -2210,8 +2210,8 @@
if (questionAssignNode != null) {
_guards.add(destinationType.node);
- _flowAnalysis
- .ifNullExpression_rightBegin(questionAssignNode.leftHandSide);
+ _flowAnalysis.ifNullExpression_rightBegin(
+ questionAssignNode.leftHandSide, destinationType);
}
DecoratedType sourceType;
try {
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 848036a..21f8df2 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -886,15 +886,22 @@
result = kDoesNotExist;
} else if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
if (follow_links) {
- HANDLE dir_handle =
+ HANDLE target_handle =
CreateFileW(name.wide(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dir_handle == INVALID_HANDLE_VALUE) {
+ if (target_handle == INVALID_HANDLE_VALUE) {
result = File::kIsLink;
} else {
- CloseHandle(dir_handle);
- result = File::kIsDirectory;
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!GetFileInformationByHandle(target_handle, &info)) {
+ CloseHandle(target_handle);
+ return File::kIsLink;
+ }
+ CloseHandle(target_handle);
+ return ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ ? File::kIsDirectory
+ : File::kIsFile;
}
} else {
result = kIsLink;
diff --git a/tests/language/constructor/missing_initializer_test.dart b/tests/language/constructor/missing_initializer_test.dart
index 3604aa8..3736c5f 100644
--- a/tests/language/constructor/missing_initializer_test.dart
+++ b/tests/language/constructor/missing_initializer_test.dart
@@ -32,6 +32,8 @@
}
class C = Object with A;
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER
// Has a generative constructor: default.
abstract class D {
diff --git a/tests/language/nnbd/const/regress43281_test.dart b/tests/language/nnbd/const/regress43281_test.dart
new file mode 100644
index 0000000..e2a400a
--- /dev/null
+++ b/tests/language/nnbd/const/regress43281_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/43281.
+
+void main() {
+ const s = {1, 2, 3, null};
+ Expect.equals(4, s.length);
+ Expect.isTrue(s is Set<int?>);
+}
diff --git a/tests/standalone/io/windows_file_system_links_test.dart b/tests/standalone/io/windows_file_system_links_test.dart
index ccf38e5..dcbc571 100644
--- a/tests/standalone/io/windows_file_system_links_test.dart
+++ b/tests/standalone/io/windows_file_system_links_test.dart
@@ -2,9 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:expect/expect.dart';
import "dart:io";
-import "dart:isolate";
+
+import 'package:expect/expect.dart';
testJunctionTypeDelete() {
var temp =
@@ -75,9 +75,57 @@
});
}
+void testLinkToFile() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ File file = new File(temp.path + Platform.pathSeparator + "test-file.tmp");
+ file.createSync();
+ // Create link pointing to the file above
+ Link link = new Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(file.path);
+
+ Link link2 = new Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isFileSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
+void testLinkToDirectory() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ Directory dir = Directory(temp.path + Platform.pathSeparator + "test-dir");
+ dir.createSync();
+ // Create link pointing to the file above
+ Link link = Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(dir.path);
+
+ Link link2 = Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isFileSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
main() {
// Links on other platforms are tested by file_system_[async_]links_test.
if (Platform.operatingSystem == 'windows') {
testJunctionTypeDelete();
+ testLinkToFile();
+ testLinkToDirectory();
}
}
diff --git a/tests/standalone_2/io/windows_file_system_links_test.dart b/tests/standalone_2/io/windows_file_system_links_test.dart
index ccf38e5..dcbc571 100644
--- a/tests/standalone_2/io/windows_file_system_links_test.dart
+++ b/tests/standalone_2/io/windows_file_system_links_test.dart
@@ -2,9 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:expect/expect.dart';
import "dart:io";
-import "dart:isolate";
+
+import 'package:expect/expect.dart';
testJunctionTypeDelete() {
var temp =
@@ -75,9 +75,57 @@
});
}
+void testLinkToFile() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ File file = new File(temp.path + Platform.pathSeparator + "test-file.tmp");
+ file.createSync();
+ // Create link pointing to the file above
+ Link link = new Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(file.path);
+
+ Link link2 = new Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isFileSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
+void testLinkToDirectory() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ Directory dir = Directory(temp.path + Platform.pathSeparator + "test-dir");
+ dir.createSync();
+ // Create link pointing to the file above
+ Link link = Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(dir.path);
+
+ Link link2 = Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isFileSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
main() {
// Links on other platforms are tested by file_system_[async_]links_test.
if (Platform.operatingSystem == 'windows') {
testJunctionTypeDelete();
+ testLinkToFile();
+ testLinkToDirectory();
}
}
diff --git a/tools/VERSION b/tools/VERSION
index ba3ae6a..b464eb3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 91
+PRERELEASE 92
PRERELEASE_PATCH 0
\ No newline at end of file