Version 2.13.0-228.0.dev
Merge commit '9b1583101ec9bdb39b66823eb303c6decd973e73' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index a7f5ac3..6ec266d 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -383,13 +383,9 @@
final Map<String, Type> _members = {};
- Node? _currentSwitch;
-
Map<String, Map<String, String>> _promotionExceptions = {};
- Statement? _currentBreakTarget;
-
- Statement? _currentContinueTarget;
+ late final _typeAnalyzer = _MiniAstTypeAnalyzer(this);
Harness({this.legacy = false, String? thisType})
: thisType = thisType == null ? null : Type(thisType);
@@ -482,8 +478,8 @@
this, assignedVariables)
: FlowAnalysis<Node, Statement, Expression, Var, Type>(
this, assignedVariables);
- b._visit(this);
- _flow.finish();
+ _typeAnalyzer.dispatchStatement(b);
+ _typeAnalyzer.finish();
}
@override
@@ -537,16 +533,6 @@
'TODO(paulberry): least upper bound of $type1 and $type2');
}
}
-
- void _visitLoopBody(Statement loop, Statement body) {
- var previousBreakTarget = _currentBreakTarget;
- var previousContinueTarget = _currentContinueTarget;
- _currentBreakTarget = loop;
- _currentContinueTarget = loop;
- body._visit(this);
- _currentBreakTarget = previousBreakTarget;
- _currentContinueTarget = previousContinueTarget;
- }
}
class LabeledStatement extends Statement {
@@ -564,9 +550,7 @@
@override
void _visit(Harness h) {
- h._flow.labeledStatement_begin(this);
- _body._visit(h);
- h._flow.labeledStatement_end();
+ h._typeAnalyzer.analyzeLabeledStatement(this, _body);
}
}
@@ -644,11 +628,6 @@
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
_body._preVisit(assignedVariables);
}
-
- void _visit(Harness h) {
- h._flow.switchStatement_beginCase(_hasLabel, h._currentSwitch!);
- _body._visit(h);
- }
}
abstract class TryBuilder {
@@ -701,9 +680,7 @@
@override
Type _visit(Harness h) {
- target._visit(h);
- h._flow.asExpression_end(target, type);
- return type;
+ return h._typeAnalyzer.analyzeTypeCast(this, target, type);
}
}
@@ -725,10 +702,7 @@
@override
void _visit(Harness h) {
- h._flow.assert_begin();
- h._flow.assert_afterCondition(condition.._visit(h));
- message?._visit(h);
- h._flow.assert_end();
+ h._typeAnalyzer.analyzeAssertStatement(condition, message);
}
}
@@ -750,9 +724,7 @@
@override
void _visit(Harness h) {
- for (var statement in statements) {
- statement._visit(h);
- }
+ h._typeAnalyzer.analyzeBlock(statements);
}
}
@@ -769,8 +741,7 @@
@override
Type _visit(Harness h) {
- h._flow.booleanLiteral(this, value);
- return Type('bool');
+ return h._typeAnalyzer.analyzeBoolLiteral(this, value);
}
}
@@ -787,7 +758,7 @@
@override
void _visit(Harness h) {
- h._flow.handleBreak(target ?? h._currentBreakTarget!);
+ h._typeAnalyzer.analyzeBreakStatement(target);
}
}
@@ -815,12 +786,6 @@
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
_body._preVisit(assignedVariables);
}
-
- void _visit(Harness h) {
- h._flow.tryCatchStatement_catchBegin(_exception, _stackTrace);
- _body._visit(h);
- h._flow.tryCatchStatement_catchEnd();
- }
}
class _CheckAssigned extends Statement {
@@ -928,13 +893,8 @@
@override
Type _visit(Harness h) {
- h._flow.conditional_conditionBegin();
- h._flow.conditional_thenBegin(condition.._visit(h), this);
- var ifTrueType = ifTrue._visit(h);
- h._flow.conditional_elseBegin(ifTrue);
- var ifFalseType = ifFalse._visit(h);
- h._flow.conditional_end(this, ifFalse);
- return h._lub(ifTrueType, ifFalseType);
+ return h._typeAnalyzer
+ .analyzeConditionalExpression(this, condition, ifTrue, ifFalse);
}
}
@@ -949,7 +909,7 @@
@override
void _visit(Harness h) {
- h._flow.handleContinue(h._currentContinueTarget!);
+ h._typeAnalyzer.analyzeContinueStatement();
}
}
@@ -977,15 +937,9 @@
@override
void _visit(Harness h) {
- var initializer = this.initializer;
- if (initializer == null) {
- h._flow.declare(variable, false);
- } else {
- var initializerType = initializer._visit(h);
- h._flow.declare(variable, true);
- h._flow.initialize(variable, initializerType, initializer,
- isFinal: isFinal, isLate: isLate);
- }
+ h._typeAnalyzer.analyzeVariableDeclaration(
+ this, variable.type, variable, initializer,
+ isFinal: isFinal, isLate: isLate);
}
}
@@ -1008,11 +962,7 @@
@override
void _visit(Harness h) {
- h._flow.doStatement_bodyBegin(this);
- h._visitLoopBody(this, body);
- h._flow.doStatement_conditionBegin();
- condition._visit(h);
- h._flow.doStatement_end(condition);
+ h._typeAnalyzer.analyzeDoLoop(this, body, condition);
}
}
@@ -1034,11 +984,9 @@
@override
Type _visit(Harness h) {
- var lhsType = lhs._visit(h);
- h._flow.equalityOp_rightBegin(lhs, lhsType);
- var rhsType = rhs._visit(h);
- h._flow.equalityOp_end(this, rhs, rhsType, notEqual: isInverted);
- return Type('bool');
+ var operatorName = isInverted ? '!=' : '==';
+ return h._typeAnalyzer
+ .analyzeBinaryExpression(this, lhs, operatorName, rhs);
}
}
@@ -1057,7 +1005,7 @@
@override
void _visit(Harness h) {
- expr._visit(h);
+ h._typeAnalyzer.analyzeExpressionStatement(expr);
}
}
@@ -1104,13 +1052,25 @@
@override
void _visit(Harness h) {
- initializer?._visit(h);
+ if (initializer != null) {
+ h._typeAnalyzer.dispatchStatement(initializer!);
+ } else {
+ h._typeAnalyzer.handleNoInitializer();
+ }
h._flow.for_conditionBegin(this);
- condition?._visit(h);
+ if (condition != null) {
+ h._typeAnalyzer.analyzeExpression(condition!);
+ } else {
+ h._typeAnalyzer.handleNoCondition();
+ }
h._flow.for_bodyBegin(forCollection ? null : this, condition);
- h._visitLoopBody(this, body);
+ h._typeAnalyzer._visitLoopBody(this, body);
h._flow.for_updaterBegin();
- updater?._visit(h);
+ if (updater != null) {
+ h._typeAnalyzer.analyzeExpression(updater!);
+ } else {
+ h._typeAnalyzer.handleNoStatement();
+ }
h._flow.for_end();
}
}
@@ -1154,13 +1114,14 @@
@override
void _visit(Harness h) {
- var iteratedType = h._getIteratedType(iterable._visit(h));
+ var iteratedType =
+ h._getIteratedType(h._typeAnalyzer.analyzeExpression(iterable));
h._flow.forEach_bodyBegin(this);
var variable = this.variable;
if (variable != null && !declaresVariable) {
h._flow.write(this, variable, iteratedType, null);
}
- h._visitLoopBody(this, body);
+ h._typeAnalyzer._visitLoopBody(this, body);
h._flow.forEach_end();
}
}
@@ -1179,7 +1140,7 @@
@override
Type _visit(Harness h) {
- var type = target._visit(h);
+ var type = h._typeAnalyzer.analyzeExpression(target);
h._flow.forwardExpression(this, target);
callback(h._flow.expressionInfoForTesting(this));
return type;
@@ -1222,16 +1183,7 @@
@override
void _visit(Harness h) {
- h._flow.ifStatement_conditionBegin();
- h._flow.ifStatement_thenBegin(condition.._visit(h), this);
- ifTrue._visit(h);
- if (ifFalse == null) {
- h._flow.ifStatement_end(false);
- } else {
- h._flow.ifStatement_elseBegin();
- ifFalse!._visit(h);
- h._flow.ifStatement_end(true);
- }
+ h._typeAnalyzer.analyzeIfStatement(this, condition, ifTrue, ifFalse);
}
}
@@ -1252,11 +1204,7 @@
@override
Type _visit(Harness h) {
- var lhsType = lhs._visit(h);
- h._flow.ifNullExpression_rightBegin(lhs, lhsType);
- var rhsType = rhs._visit(h);
- h._flow.ifNullExpression_end();
- return h._lub(h.promoteToNonNull(lhsType), rhsType);
+ return h._typeAnalyzer.analyzeIfNullExpression(this, lhs, rhs);
}
}
@@ -1277,8 +1225,8 @@
@override
Type _visit(Harness h) {
- h._flow.isExpression_end(this, target.._visit(h), isInverted, type);
- return Type('bool');
+ return h._typeAnalyzer
+ .analyzeTypeTest(this, target, type, isInverted: isInverted);
}
}
@@ -1300,7 +1248,7 @@
@override
void _visit(Harness h) {
h._flow.functionExpression_begin(this);
- body._visit(h);
+ h._typeAnalyzer.dispatchStatement(body);
h._flow.functionExpression_end();
}
}
@@ -1325,10 +1273,9 @@
@override
Type _visit(Harness h) {
- h._flow.logicalBinaryOp_begin();
- h._flow.logicalBinaryOp_rightBegin(lhs.._visit(h), this, isAnd: isAnd);
- h._flow.logicalBinaryOp_end(this, rhs.._visit(h), isAnd: isAnd);
- return Type('bool');
+ var operatorName = isAnd ? '&&' : '||';
+ return h._typeAnalyzer
+ .analyzeBinaryExpression(this, lhs, operatorName, rhs);
}
}
@@ -1348,6 +1295,344 @@
readWrite,
}
+class _MiniAstTypeAnalyzer {
+ final Harness _harness;
+
+ Statement? _currentBreakTarget;
+
+ Statement? _currentContinueTarget;
+
+ late final Type boolType = Type('bool');
+
+ late final Type neverType = Type('Never');
+
+ late final Type nullType = Type('Null');
+
+ _MiniAstTypeAnalyzer(this._harness);
+
+ FlowAnalysis<Node, Statement, Expression, Var, Type> get flow =>
+ _harness._flow;
+
+ Type get thisType => _harness.thisType!;
+
+ void analyzeAssertStatement(Expression condition, Expression? message) {
+ flow.assert_begin();
+ analyzeExpression(condition);
+ flow.assert_afterCondition(condition);
+ if (message != null) {
+ analyzeExpression(message);
+ } else {
+ handleNoMessage();
+ }
+ flow.assert_end();
+ }
+
+ Type analyzeBinaryExpression(
+ Expression node, Expression lhs, String operatorName, Expression rhs) {
+ bool isEquals = false;
+ bool isNot = false;
+ bool isLogical = false;
+ bool isAnd = false;
+ switch (operatorName) {
+ case '==':
+ isEquals = true;
+ break;
+ case '!=':
+ isEquals = true;
+ isNot = true;
+ operatorName = '==';
+ break;
+ case '&&':
+ isLogical = true;
+ isAnd = true;
+ break;
+ case '||':
+ isLogical = true;
+ break;
+ }
+ if (operatorName == '==') {
+ isEquals = true;
+ } else if (operatorName == '!=') {
+ isEquals = true;
+ isNot = true;
+ operatorName = '==';
+ }
+ if (isLogical) {
+ flow.logicalBinaryOp_begin();
+ }
+ var leftType = analyzeExpression(lhs);
+ if (isEquals) {
+ flow.equalityOp_rightBegin(lhs, leftType);
+ } else if (isLogical) {
+ flow.logicalBinaryOp_rightBegin(lhs, node, isAnd: isAnd);
+ }
+ var rightType = analyzeExpression(rhs);
+ if (isEquals) {
+ flow.equalityOp_end(node, rhs, rightType, notEqual: isNot);
+ } else if (isLogical) {
+ flow.logicalBinaryOp_end(node, rhs, isAnd: isAnd);
+ }
+ return boolType;
+ }
+
+ void analyzeBlock(Iterable<Statement> statements) {
+ for (var statement in statements) {
+ dispatchStatement(statement);
+ }
+ }
+
+ Type analyzeBoolLiteral(Expression node, bool value) {
+ flow.booleanLiteral(node, value);
+ return boolType;
+ }
+
+ void analyzeBreakStatement(Statement? target) {
+ flow.handleBreak(target ?? _currentBreakTarget!);
+ }
+
+ Type analyzeConditionalExpression(Expression node, Expression condition,
+ Expression ifTrue, Expression ifFalse) {
+ flow.conditional_conditionBegin();
+ analyzeExpression(condition);
+ flow.conditional_thenBegin(condition, node);
+ var ifTrueType = analyzeExpression(ifTrue);
+ flow.conditional_elseBegin(ifTrue);
+ var ifFalseType = analyzeExpression(ifFalse);
+ flow.conditional_end(node, ifFalse);
+ return leastUpperBound(ifTrueType, ifFalseType);
+ }
+
+ void analyzeContinueStatement() {
+ flow.handleContinue(_currentContinueTarget!);
+ }
+
+ void analyzeDoLoop(Statement node, Statement body, Expression condition) {
+ flow.doStatement_bodyBegin(node);
+ _visitLoopBody(node, body);
+ flow.doStatement_conditionBegin();
+ analyzeExpression(condition);
+ flow.doStatement_end(condition);
+ }
+
+ Type analyzeExpression(Expression expression) {
+ return dispatchExpression(expression);
+ }
+
+ void analyzeExpressionStatement(Expression expression) {
+ analyzeExpression(expression);
+ }
+
+ Type analyzeIfNullExpression(
+ Expression node, Expression lhs, Expression rhs) {
+ var leftType = analyzeExpression(lhs);
+ flow.ifNullExpression_rightBegin(lhs, leftType);
+ var rightType = analyzeExpression(rhs);
+ flow.ifNullExpression_end();
+ return leastUpperBound(
+ flow.typeOperations.promoteToNonNull(leftType), rightType);
+ }
+
+ void analyzeIfStatement(Statement node, Expression condition,
+ Statement ifTrue, Statement? ifFalse) {
+ flow.ifStatement_conditionBegin();
+ analyzeExpression(condition);
+ flow.ifStatement_thenBegin(condition, node);
+ dispatchStatement(ifTrue);
+ if (ifFalse == null) {
+ handleNoStatement();
+ flow.ifStatement_end(false);
+ } else {
+ flow.ifStatement_elseBegin();
+ dispatchStatement(ifFalse);
+ flow.ifStatement_end(true);
+ }
+ }
+
+ void analyzeLabeledStatement(Statement node, Statement body) {
+ flow.labeledStatement_begin(node);
+ dispatchStatement(body);
+ flow.labeledStatement_end();
+ }
+
+ Type analyzeLogicalNot(Expression node, Expression expression) {
+ analyzeExpression(expression);
+ flow.logicalNot_end(node, expression);
+ return boolType;
+ }
+
+ Type analyzeNonNullAssert(Expression node, Expression expression) {
+ var type = analyzeExpression(expression);
+ flow.nonNullAssert_end(expression);
+ return flow.typeOperations.promoteToNonNull(type);
+ }
+
+ Type analyzeNullLiteral(Expression node) {
+ flow.nullLiteral(node);
+ return nullType;
+ }
+
+ Type analyzeParenthesizedExpression(Expression node, Expression expression) {
+ var type = analyzeExpression(expression);
+ flow.parenthesizedExpression(node, expression);
+ return type;
+ }
+
+ Type analyzePropertyGet(
+ Expression node, Expression receiver, String propertyName) {
+ var receiverType = analyzeExpression(receiver);
+ var type = _lookupMember(node, receiverType, propertyName);
+ flow.propertyGet(node, receiver, propertyName, propertyName, type);
+ return type;
+ }
+
+ void analyzeReturnStatement() {
+ flow.handleExit();
+ }
+
+ void analyzeSwitchStatement(
+ _Switch node, Expression expression, List<SwitchCase> cases) {
+ analyzeExpression(expression);
+ flow.switchStatement_expressionEnd(node);
+ var previousBreakTarget = _currentBreakTarget;
+ _currentBreakTarget = node;
+ for (var case_ in cases) {
+ flow.switchStatement_beginCase(case_._hasLabel, node);
+ dispatchStatement(case_._body);
+ }
+ _currentBreakTarget = previousBreakTarget;
+ flow.switchStatement_end(isSwitchExhaustive(node));
+ }
+
+ Type analyzeThis(Expression node) {
+ var thisType = this.thisType;
+ flow.thisOrSuper(node, thisType);
+ return thisType;
+ }
+
+ Type analyzeThisPropertyGet(Expression node, String propertyName) {
+ var type = _lookupMember(node, thisType, propertyName);
+ flow.thisOrSuperPropertyGet(node, propertyName, propertyName, type);
+ return type;
+ }
+
+ Type analyzeThrow(Expression node, Expression expression) {
+ analyzeExpression(expression);
+ flow.handleExit();
+ return neverType;
+ }
+
+ void analyzeTryStatement(Statement node, Statement body,
+ Iterable<_CatchClause> catchClauses, Statement? finallyBlock) {
+ if (finallyBlock != null) {
+ flow.tryFinallyStatement_bodyBegin();
+ }
+ if (catchClauses.isNotEmpty) {
+ flow.tryCatchStatement_bodyBegin();
+ }
+ dispatchStatement(body);
+ if (catchClauses.isNotEmpty) {
+ flow.tryCatchStatement_bodyEnd(body);
+ for (var catch_ in catchClauses) {
+ flow.tryCatchStatement_catchBegin(
+ catch_._exception, catch_._stackTrace);
+ dispatchStatement(catch_._body);
+ flow.tryCatchStatement_catchEnd();
+ }
+ flow.tryCatchStatement_end();
+ }
+ if (finallyBlock != null) {
+ flow.tryFinallyStatement_finallyBegin(
+ catchClauses.isNotEmpty ? node : body);
+ dispatchStatement(finallyBlock);
+ flow.tryFinallyStatement_end();
+ } else {
+ handleNoStatement();
+ }
+ }
+
+ Type analyzeTypeCast(Expression node, Expression expression, Type type) {
+ analyzeExpression(expression);
+ flow.asExpression_end(expression, type);
+ return type;
+ }
+
+ Type analyzeTypeTest(Expression node, Expression expression, Type type,
+ {bool isInverted = false}) {
+ analyzeExpression(expression);
+ flow.isExpression_end(node, expression, isInverted, type);
+ return boolType;
+ }
+
+ void analyzeVariableDeclaration(
+ Statement node, Type type, Var variable, Expression? initializer,
+ {required bool isFinal, required bool isLate}) {
+ if (initializer == null) {
+ handleNoInitializer();
+ flow.declare(variable, false);
+ } else {
+ var initializerType = analyzeExpression(initializer);
+ flow.declare(variable, true);
+ flow.initialize(variable, initializerType, initializer,
+ isFinal: isFinal, isLate: isLate);
+ }
+ }
+
+ Type analyzeVariableGet(
+ Expression node, Var variable, void Function(Type?)? callback) {
+ var promotedType = flow.variableRead(node, variable);
+ callback?.call(promotedType);
+ return promotedType ?? variable.type;
+ }
+
+ void analyzeWhileLoop(Statement node, Expression condition, Statement body) {
+ flow.whileStatement_conditionBegin(node);
+ analyzeExpression(condition);
+ flow.whileStatement_bodyBegin(node, condition);
+ _visitLoopBody(node, body);
+ flow.whileStatement_end();
+ }
+
+ Type dispatchExpression(Expression expression) => expression._visit(_harness);
+
+ void dispatchStatement(Statement statement) => statement._visit(_harness);
+
+ void finish() {
+ flow.finish();
+ }
+
+ void handleNoCondition() {}
+
+ void handleNoInitializer() {}
+
+ void handleNoMessage() {}
+
+ void handleNoStatement() {}
+
+ bool isSwitchExhaustive(_Switch node) {
+ return node.isExhaustive;
+ }
+
+ Type leastUpperBound(Type t1, Type t2) => _harness._lub(t1, t2);
+
+ Type lookupInterfaceMember(Node node, Type receiverType, String memberName) {
+ return _harness.getMember(receiverType, memberName);
+ }
+
+ Type _lookupMember(Expression node, Type receiverType, String memberName) {
+ return lookupInterfaceMember(node, receiverType, memberName);
+ }
+
+ void _visitLoopBody(Statement loop, Statement body) {
+ var previousBreakTarget = _currentBreakTarget;
+ var previousContinueTarget = _currentContinueTarget;
+ _currentBreakTarget = loop;
+ _currentContinueTarget = loop;
+ dispatchStatement(body);
+ _currentBreakTarget = previousBreakTarget;
+ _currentContinueTarget = previousContinueTarget;
+ }
+}
+
class _NonNullAssert extends Expression {
final Expression operand;
@@ -1363,9 +1648,7 @@
@override
Type _visit(Harness h) {
- var type = operand._visit(h);
- h._flow.nonNullAssert_end(operand);
- return h.promoteToNonNull(type);
+ return h._typeAnalyzer.analyzeNonNullAssert(this, operand);
}
}
@@ -1384,8 +1667,7 @@
@override
Type _visit(Harness h) {
- h._flow.logicalNot_end(this, operand.._visit(h));
- return Type('bool');
+ return h._typeAnalyzer.analyzeLogicalNot(this, operand);
}
}
@@ -1407,9 +1689,9 @@
@override
Type _visit(Harness h) {
- var lhsType = lhs._visit(h);
+ var lhsType = h._typeAnalyzer.analyzeExpression(lhs);
h._flow.nullAwareAccess_rightBegin(isCascaded ? null : lhs, lhsType);
- var rhsType = rhs._visit(h);
+ var rhsType = h._typeAnalyzer.analyzeExpression(rhs);
h._flow.nullAwareAccess_end();
return h._lub(rhsType, Type('Null'));
}
@@ -1426,8 +1708,7 @@
@override
Type _visit(Harness h) {
- h._flow.nullLiteral(this);
- return Type('Null');
+ return h._typeAnalyzer.analyzeNullLiteral(this);
}
}
@@ -1446,9 +1727,7 @@
@override
Type _visit(Harness h) {
- var type = expr._visit(h);
- h._flow.parenthesizedExpression(this, expr);
- return type;
+ return h._typeAnalyzer.analyzeParenthesizedExpression(this, expr);
}
}
@@ -1482,10 +1761,7 @@
@override
Type _visit(Harness h) {
- var targetType = target._visit(h);
- var propertyType = h.getMember(targetType, propertyName);
- h._flow.propertyGet(this, target, propertyName, propertyName, propertyType);
- return propertyType;
+ return h._typeAnalyzer.analyzePropertyGet(this, target, propertyName);
}
@override
@@ -1506,7 +1782,7 @@
@override
void _visit(Harness h) {
- h._flow.handleExit();
+ h._typeAnalyzer.analyzeReturnStatement();
}
}
@@ -1542,18 +1818,7 @@
@override
void _visit(Harness h) {
- expression._visit(h);
- h._flow.switchStatement_expressionEnd(this);
- var oldSwitch = h._currentSwitch;
- var previousBreakTarget = h._currentBreakTarget;
- h._currentSwitch = this;
- h._currentBreakTarget = this;
- for (var case_ in cases) {
- case_._visit(h);
- }
- h._currentSwitch = oldSwitch;
- h._currentBreakTarget = previousBreakTarget;
- h._flow.switchStatement_end(isExhaustive);
+ h._typeAnalyzer.analyzeSwitchStatement(this, expression, cases);
}
}
@@ -1566,9 +1831,7 @@
@override
Type _visit(Harness h) {
- var thisType = h.thisType!;
- h._flow.thisOrSuper(this, thisType);
- return thisType;
+ return h._typeAnalyzer.analyzeThis(this);
}
}
@@ -1582,9 +1845,7 @@
@override
Type _visit(Harness h) {
- var type = h.getMember(h.thisType!, propertyName);
- h._flow.thisOrSuperPropertyGet(this, propertyName, propertyName, type);
- return type;
+ return h._typeAnalyzer.analyzeThisPropertyGet(this, propertyName);
}
}
@@ -1603,9 +1864,7 @@
@override
Type _visit(Harness h) {
- operand._visit(h);
- h._flow.handleExit();
- return Type('Never');
+ return h._typeAnalyzer.analyzeThrow(this, operand);
}
}
@@ -1653,26 +1912,7 @@
@override
void _visit(Harness h) {
- if (_finally != null) {
- h._flow.tryFinallyStatement_bodyBegin();
- }
- if (_catches.isNotEmpty) {
- h._flow.tryCatchStatement_bodyBegin();
- }
- _body._visit(h);
- if (_catches.isNotEmpty) {
- h._flow.tryCatchStatement_bodyEnd(_body);
- for (var catch_ in _catches) {
- catch_._visit(h);
- }
- h._flow.tryCatchStatement_end();
- }
- if (_finally != null) {
- h._flow
- .tryFinallyStatement_finallyBegin(_catches.isNotEmpty ? this : _body);
- _finally!._visit(h);
- h._flow.tryFinallyStatement_end();
- }
+ h._typeAnalyzer.analyzeTryStatement(this, _body, _catches, _finally);
}
}
@@ -1699,9 +1939,7 @@
@override
Type _visit(Harness h) {
- var readResult = h._flow.variableRead(this, variable);
- callback?.call(readResult);
- return readResult ?? variable.type;
+ return h._typeAnalyzer.analyzeVariableGet(this, variable, callback);
}
@override
@@ -1730,11 +1968,7 @@
@override
void _visit(Harness h) {
- h._flow.whileStatement_conditionBegin(this);
- condition._visit(h);
- h._flow.whileStatement_bodyBegin(this, condition);
- h._visitLoopBody(this, body);
- h._flow.whileStatement_end();
+ h._typeAnalyzer.analyzeWhileLoop(this, condition, body);
}
}
@@ -1755,7 +1989,7 @@
@override
Type _visit(Harness h) {
- var type = target._visit(h);
+ var type = h._typeAnalyzer.analyzeExpression(target);
h._flow.forwardExpression(this, target);
Type.withComparisonsAllowed(() {
callback(h._flow.whyNotPromoted(this)());
@@ -1815,9 +2049,13 @@
@override
Type _visit(Harness h) {
- before?._visit(h);
- var type = expr._visit(h);
- after?._visit(h);
+ if (before != null) {
+ h._typeAnalyzer.dispatchStatement(before!);
+ }
+ var type = h._typeAnalyzer.analyzeExpression(expr);
+ if (after != null) {
+ h._typeAnalyzer.dispatchStatement(after!);
+ }
h._flow.forwardExpression(this, expr);
return type;
}
@@ -1848,9 +2086,9 @@
if (rhs == null) {
// We are simulating an increment/decrement operation.
// TODO(paulberry): Make a separate node type for this.
- type = lhs._visit(h);
+ type = h._typeAnalyzer.analyzeExpression(lhs);
} else {
- type = rhs._visit(h);
+ type = h._typeAnalyzer.analyzeExpression(rhs);
}
lhs._visitWrite(h, this, type, rhs);
return type;
diff --git a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
index 679b457..9bd0039 100644
--- a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:math';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
@@ -21,6 +19,7 @@
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:collection/collection.dart';
/// An enumeration of possible statement completion kinds.
class DartStatementCompletion {
@@ -105,20 +104,23 @@
final StatementCompletionContext statementContext;
final CorrectionUtils utils;
- AstNode node;
- StatementCompletion completion;
+
+ /// TODO(brianwilkerson) Refactor the code so that the completion is returned
+ /// from the methods in which it's computed rather than being a field that we
+ /// have to test.
+ StatementCompletion? completion;
SourceChange change = SourceChange('statement-completion');
List<engine.AnalysisError> errors = [];
final Map<String, LinkedEditGroup> linkedPositionGroups =
<String, LinkedEditGroup>{};
- Position exitPosition;
+ Position? exitPosition;
StatementCompletionProcessor(this.statementContext)
: utils = CorrectionUtils(statementContext.resolveResult);
String get eol => utils.endOfLine;
- String get file => statementContext.resolveResult.path;
+ String get file => statementContext.resolveResult.path!;
LineInfo get lineInfo => statementContext.resolveResult.lineInfo;
@@ -126,29 +128,27 @@
Source get source => unitElement.source;
- CompilationUnit get unit => statementContext.resolveResult.unit;
+ CompilationUnit get unit => statementContext.resolveResult.unit!;
- CompilationUnitElement get unitElement =>
- statementContext.resolveResult.unit.declaredElement;
+ CompilationUnitElement get unitElement => unit.declaredElement!;
Future<StatementCompletion> compute() async {
- node = _selectedNode();
+ var node = _selectedNode();
if (node == null) {
return NO_COMPLETION;
}
node = node.thisOrAncestorMatching(
(n) => n is Statement || _isNonStatementDeclaration(n));
if (node == null) {
- return _complete_simpleEnter() ? completion : NO_COMPLETION;
+ return _complete_simpleEnter() ? completion! : NO_COMPLETION;
}
if (node is Block) {
- Block blockNode = node;
- if (blockNode.statements.isNotEmpty) {
- node = blockNode.statements.last;
+ if (node.statements.isNotEmpty) {
+ node = node.statements.last;
}
}
if (_isEmptyStatementOrEmptyBlock(node)) {
- node = node.parent;
+ node = node.parent!;
}
for (var error in statementContext.resolveResult.errors) {
if (error.offset >= node.offset && error.offset <= node.end) {
@@ -158,41 +158,41 @@
}
}
- _checkExpressions();
+ _checkExpressions(node);
if (node is Statement) {
if (errors.isEmpty) {
- if (_complete_ifStatement() ||
- _complete_forStatement2() ||
- _complete_whileStatement() ||
- _complete_controlFlowBlock()) {
- return completion;
+ if (_complete_ifStatement(node) ||
+ _complete_forStatement2(node) ||
+ _complete_whileStatement(node) ||
+ _complete_controlFlowBlock(node)) {
+ return completion!;
}
} else {
- if (_complete_ifStatement() ||
- _complete_doStatement() ||
- _complete_forStatement2() ||
- _complete_functionDeclarationStatement() ||
- _complete_switchStatement() ||
- _complete_tryStatement() ||
- _complete_whileStatement() ||
- _complete_controlFlowBlock() ||
- _complete_simpleSemicolon() ||
- _complete_methodCall()) {
- return completion;
+ if (_complete_ifStatement(node) ||
+ _complete_doStatement(node) ||
+ _complete_forStatement2(node) ||
+ _complete_functionDeclarationStatement(node) ||
+ _complete_switchStatement(node) ||
+ _complete_tryStatement(node) ||
+ _complete_whileStatement(node) ||
+ _complete_controlFlowBlock(node) ||
+ _complete_simpleSemicolon(node) ||
+ _complete_methodCall(node)) {
+ return completion!;
}
}
} else if (node is Declaration) {
if (errors.isNotEmpty) {
- if (_complete_classDeclaration() ||
- _complete_variableDeclaration() ||
- _complete_simpleSemicolon() ||
- _complete_functionDeclaration()) {
- return completion;
+ if (_complete_classDeclaration(node) ||
+ _complete_variableDeclaration(node) ||
+ _complete_simpleSemicolon(node) ||
+ _complete_functionDeclaration(node)) {
+ return completion!;
}
}
}
if (_complete_simpleEnter()) {
- return completion;
+ return completion!;
}
return NO_COMPLETION;
}
@@ -259,16 +259,16 @@
return text;
}
- void _checkExpressions() {
+ void _checkExpressions(AstNode node) {
// Note: This may queue edits that have to be accounted for later.
// See _lengthOfInsertions().
- AstNode errorMatching(errorCode, {partialMatch}) {
+ AstNode? errorMatching(errorCode, {partialMatch}) {
var error = _findError(errorCode, partialMatch: partialMatch);
if (error == null) {
return null;
}
var expr = _selectedNode();
- return (expr.thisOrAncestorOfType<StringInterpolation>() == null)
+ return (expr?.thisOrAncestorOfType<StringInterpolation>() == null)
? expr
: null;
}
@@ -306,9 +306,8 @@
errorMatching(ScannerErrorCode.EXPECTED_TOKEN, partialMatch: "']'");
if (expr != null) {
expr = expr.thisOrAncestorOfType<ListLiteral>();
- if (expr != null) {
- ListLiteral lit = expr;
- if (lit.rightBracket.isSynthetic) {
+ if (expr is ListLiteral) {
+ if (expr.rightBracket.isSynthetic) {
var src = utils.getNodeText(expr).trim();
var loc = expr.offset + src.length;
if (src.contains(eol)) {
@@ -351,14 +350,13 @@
*/
}
- bool _complete_classDeclaration() {
+ bool _complete_classDeclaration(AstNode node) {
if (node is! ClassDeclaration) {
return false;
}
- ClassDeclaration decl = node;
- if (decl.leftBracket.isSynthetic && errors.length == 1) {
+ if (node.leftBracket.isSynthetic && errors.length == 1) {
// The space before the left brace is assumed to exist, even if it does not.
- var sb = SourceBuilder(file, decl.end - 1);
+ var sb = SourceBuilder(file, node.end - 1);
sb.append(' ');
_appendEmptyBraces(sb, true);
_insertBuilder(sb);
@@ -368,19 +366,18 @@
return false;
}
- bool _complete_controlFlowBlock() {
+ bool _complete_controlFlowBlock(AstNode node) {
var expr = (node is ExpressionStatement)
- ? (node as ExpressionStatement).expression
- : (node is ReturnStatement
- ? (node as ReturnStatement).expression
- : null);
+ ? node.expression
+ : (node is ReturnStatement ? node.expression : null);
if (!(node is ReturnStatement || expr is ThrowExpression)) {
return false;
}
- if (node.parent is! Block) {
+ var parent = node.parent;
+ if (parent is! Block) {
return false;
}
- var outer = node.parent.parent;
+ var outer = parent.parent;
if (!(outer is DoStatement ||
outer is ForStatement ||
outer is IfStatement ||
@@ -399,12 +396,10 @@
// Because of this, check for length == 0 rather than isSynthetic.
if (expr == null || expr.length == 0) {
if (node is ReturnStatement) {
- insertOffset = (node as ReturnStatement).returnKeyword.end;
+ insertOffset = node.returnKeyword.end;
} else if (node is ExpressionStatement) {
insertOffset =
- ((node as ExpressionStatement).expression as ThrowExpression)
- .throwKeyword
- .end;
+ (node.expression as ThrowExpression).throwKeyword.end;
} else {
insertOffset = node.end; // Not reached.
}
@@ -417,71 +412,65 @@
delta = 1;
}
}
- var offset = _appendNewlinePlusIndentAt(node.parent.end);
+ var offset = _appendNewlinePlusIndentAt(parent.end);
exitPosition = Position(file, offset + delta + previousInsertions);
_setCompletion(DartStatementCompletion.COMPLETE_CONTROL_FLOW_BLOCK);
return true;
}
- bool _complete_doStatement() {
+ bool _complete_doStatement(AstNode node) {
if (node is! DoStatement) {
return false;
}
- DoStatement statement = node;
- var sb = _sourceBuilderAfterKeyword(statement.doKeyword);
- var hasWhileKeyword =
- statement.whileKeyword != null && !statement.whileKeyword.isSynthetic;
+ var sb = _sourceBuilderAfterKeyword(node, node.doKeyword);
+ var hasWhileKeyword = !node.whileKeyword.isSynthetic;
var exitDelta = 0;
- if (!_statementHasValidBody(statement.doKeyword, statement.body)) {
- var text = utils.getNodeText(statement.body);
+ if (!_statementHasValidBody(node.doKeyword, node.body)) {
+ var text = utils.getNodeText(node.body);
var delta = 0;
if (text.startsWith(';')) {
delta = 1;
- _addReplaceEdit(range.startLength(statement.body, delta), '');
+ _addReplaceEdit(range.startLength(node.body, delta), '');
if (hasWhileKeyword) {
- text = utils.getNodeText(statement);
+ text = utils.getNodeText(node);
if (text.indexOf(RegExp(r'do\s*;\s*while')) == 0) {
var end = text.indexOf('while');
var start = text.indexOf(';') + 1;
delta += end - start - 1;
- _addReplaceEdit(
- SourceRange(start + statement.offset, end - start), ' ');
+ _addReplaceEdit(SourceRange(start + node.offset, end - start), ' ');
}
}
sb = SourceBuilder(file, sb.offset + delta);
sb.append(' ');
}
- _appendEmptyBraces(sb,
- !(hasWhileKeyword && _isSyntheticExpression(statement.condition)));
+ _appendEmptyBraces(
+ sb, !(hasWhileKeyword && _isSyntheticExpression(node.condition)));
if (delta != 0) {
exitDelta = sb.length - delta;
}
- } else if (_isEmptyBlock(statement.body)) {
- sb = SourceBuilder(sb.file, statement.body.end);
+ } else if (_isEmptyBlock(node.body)) {
+ sb = SourceBuilder(sb.file, node.body.end);
}
- SourceBuilder sb2;
+ SourceBuilder? sb2;
if (hasWhileKeyword) {
- var stmt = _KeywordConditionBlockStructure(
- statement.whileKeyword,
- statement.leftParenthesis,
- statement.condition,
- statement.rightParenthesis,
- null);
- sb2 = _complete_keywordCondition(stmt);
+ var stmt = _KeywordConditionBlockStructure(node.whileKeyword,
+ node.leftParenthesis, node.condition, node.rightParenthesis, null);
+ sb2 = _complete_keywordCondition(node, stmt);
if (sb2 == null) {
return false;
}
if (sb2.length == 0) {
// true if condition is '()'
+ final exitPosition = this.exitPosition;
if (exitPosition != null) {
- if (statement.semicolon.isSynthetic) {
+ if (node.semicolon.isSynthetic) {
_insertBuilder(sb);
sb = SourceBuilder(file, exitPosition.offset + 1);
sb.append(';');
}
}
} else {
- if (sb.exitOffset == null && sb2?.exitOffset != null) {
+ if (sb.exitOffset == null && sb2.exitOffset != null) {
_insertBuilder(sb);
sb = sb2;
sb.append(';');
@@ -497,7 +486,7 @@
_insertBuilder(sb);
if (exitDelta != 0) {
exitPosition =
- Position(exitPosition.file, exitPosition.offset + exitDelta);
+ Position(exitPosition!.file, exitPosition!.offset + exitDelta);
}
_setCompletion(DartStatementCompletion.COMPLETE_DO_STMT);
return true;
@@ -514,6 +503,7 @@
throw StateError('Unrecognized for loop parts');
}
return _complete_forEachStatementRest(
+ forNode,
forNode.forKeyword,
forNode.leftParenthesis,
name,
@@ -524,11 +514,12 @@
}
bool _complete_forEachStatementRest(
+ AstNode node,
Token forKeyword,
Token leftParenthesis,
- AstNode name,
+ AstNode? name,
Token inKeyword,
- Expression iterable,
+ Expression? iterable,
Token rightParenthesis,
Statement body) {
if (inKeyword.isSynthetic) {
@@ -577,7 +568,7 @@
return false;
}
// keywordOnly (unit test name suffix that exercises this branch)
- sb = _sourceBuilderAfterKeyword(forNode.forKeyword);
+ sb = _sourceBuilderAfterKeyword(forNode, forNode.forKeyword);
sb.append('(');
sb.setExitOffset();
sb.append(')');
@@ -625,18 +616,19 @@
sb = SourceBuilder(file, forNode.rightParenthesis.offset);
} else if (forParts is ForPartsWithExpression &&
forParts.initialization is SimpleIdentifier &&
- forParts.initialization.beginToken.lexeme == 'in') {
+ forParts.initialization!.beginToken.lexeme == 'in') {
// looks like a for/each statement missing the loop variable
return _complete_forEachStatementRest(
+ forNode,
forNode.forKeyword,
forNode.leftParenthesis,
null,
- forParts.initialization.beginToken,
+ forParts.initialization!.beginToken,
null,
forNode.rightParenthesis,
forNode.body);
} else {
- var start = forParts.condition.offset + forParts.condition.length;
+ var start = forParts.condition!.offset + forParts.condition!.length;
var text = utils.getNodeText(forNode).substring(start - forNode.offset);
if (text.startsWith(RegExp(r'\s*\)'))) {
// missingLeftSeparator
@@ -651,12 +643,12 @@
}
}
}
- if (!_statementHasValidBody(forNode.forKeyword, forNode.body)) {
+ var body = forNode.body;
+ if (!_statementHasValidBody(forNode.forKeyword, body)) {
// keywordOnly, noError
sb.append(' ');
_appendEmptyBraces(sb, true /*exitPosition == null*/);
- } else if (forNode.body is Block) {
- Block body = forNode.body;
+ } else if (body is Block) {
if (body.rightBracket.end <= selectionOffset) {
// emptyInitializersAfterBody
errors = []; // Ignore errors; they are for previous statement.
@@ -668,8 +660,7 @@
return true;
}
- bool _complete_forStatement2() {
- var node = this.node;
+ bool _complete_forStatement2(AstNode node) {
if (node is ForStatement) {
var forLoopParts = node.forLoopParts;
if (forLoopParts is ForParts) {
@@ -681,7 +672,7 @@
return false;
}
- bool _complete_functionDeclaration() {
+ bool _complete_functionDeclaration(AstNode node) {
if (node is! MethodDeclaration && node is! FunctionDeclaration) {
return false;
}
@@ -698,11 +689,19 @@
int paramListEnd;
if (node is FunctionDeclaration) {
- FunctionDeclaration func = node;
- paramListEnd = computeExitPos(func.functionExpression.parameters);
+ var parameters = node.functionExpression.parameters;
+ if (parameters == null) {
+ return false;
+ }
+ paramListEnd = computeExitPos(parameters);
+ } else if (node is MethodDeclaration) {
+ var parameters = node.parameters;
+ if (parameters == null) {
+ return false;
+ }
+ paramListEnd = computeExitPos(parameters);
} else {
- MethodDeclaration meth = node;
- paramListEnd = computeExitPos(meth.parameters);
+ return false;
}
var sb = SourceBuilder(file, paramListEnd);
if (needsParen) {
@@ -715,26 +714,23 @@
return true;
}
- bool _complete_functionDeclarationStatement() {
+ bool _complete_functionDeclarationStatement(AstNode node) {
if (node is! FunctionDeclarationStatement) {
return false;
}
var error = _findError(ParserErrorCode.EXPECTED_TOKEN, partialMatch: "';'");
if (error != null) {
- FunctionDeclarationStatement stmt = node;
- var src = utils.getNodeText(stmt);
- var insertOffset = stmt.functionDeclaration.end - 1;
- if (stmt.functionDeclaration.functionExpression.body
- is ExpressionFunctionBody) {
- ExpressionFunctionBody fnb =
- stmt.functionDeclaration.functionExpression.body;
- var fnbOffset = fnb.functionDefinition.offset;
- var fnSrc = src.substring(fnbOffset - stmt.offset);
+ var src = utils.getNodeText(node);
+ var insertOffset = node.functionDeclaration.end - 1;
+ var body = node.functionDeclaration.functionExpression.body;
+ if (body is ExpressionFunctionBody) {
+ var fnbOffset = body.functionDefinition.offset;
+ var fnSrc = src.substring(fnbOffset - node.offset);
if (!fnSrc.startsWith('=>')) {
return false;
}
var delta = 0;
- if (fnb.expression.isSynthetic) {
+ if (body.expression.isSynthetic) {
if (!fnSrc.startsWith('=> ')) {
_addInsertEdit(insertOffset, ' ');
delta = 1;
@@ -754,12 +750,12 @@
return false;
}
- bool _complete_ifOrWhileStatement(
+ bool _complete_ifOrWhileStatement(AstNode node,
_KeywordConditionBlockStructure statement, StatementCompletionKind kind) {
- if (_statementHasValidBody(statement.keyword, statement.block)) {
+ if (_statementHasValidBody(statement.keyword, statement.block!)) {
return false;
}
- var sb = _complete_keywordCondition(statement);
+ var sb = _complete_keywordCondition(node, statement);
if (sb == null) {
return false;
}
@@ -768,24 +764,24 @@
_appendEmptyBraces(sb, exitPosition == null);
_insertBuilder(sb);
if (overshoot != 0) {
- exitPosition = _newPosition(exitPosition.offset - overshoot);
+ exitPosition = _newPosition(exitPosition!.offset - overshoot);
}
_setCompletion(kind);
return true;
}
- bool _complete_ifStatement() {
+ bool _complete_ifStatement(AstNode node) {
if (node is! IfStatement) {
return false;
}
- IfStatement ifNode = node;
- if (ifNode.elseKeyword != null) {
- if (selectionOffset >= ifNode.elseKeyword.end &&
- _isEmptyStatement(ifNode.elseStatement)) {
+ var elseKeyword = node.elseKeyword;
+ if (elseKeyword != null) {
+ if (selectionOffset >= elseKeyword.end &&
+ _isEmptyStatement(node.elseStatement)) {
var sb = SourceBuilder(file, selectionOffset);
- var src = utils.getNodeText(ifNode);
+ var src = utils.getNodeText(node);
if (!src
- .substring(ifNode.elseKeyword.end - node.offset)
+ .substring(elseKeyword.end - node.offset)
.startsWith(RegExp(r'[ \t]'))) {
sb.append(' ');
}
@@ -797,24 +793,24 @@
return false;
}
var stmt = _KeywordConditionBlockStructure(
- ifNode.ifKeyword,
- ifNode.leftParenthesis,
- ifNode.condition,
- ifNode.rightParenthesis,
- ifNode.thenStatement);
+ node.ifKeyword,
+ node.leftParenthesis,
+ node.condition,
+ node.rightParenthesis,
+ node.thenStatement);
return _complete_ifOrWhileStatement(
- stmt, DartStatementCompletion.COMPLETE_IF_STMT);
+ node, stmt, DartStatementCompletion.COMPLETE_IF_STMT);
}
- SourceBuilder _complete_keywordCondition(
- _KeywordConditionBlockStructure statement) {
+ SourceBuilder? _complete_keywordCondition(
+ AstNode node, _KeywordConditionBlockStructure statement) {
SourceBuilder sb;
if (statement.leftParenthesis.isSynthetic) {
if (!statement.rightParenthesis.isSynthetic) {
// Quite unlikely to see this so don't try to fix it.
return null;
}
- sb = _sourceBuilderAfterKeyword(statement.keyword);
+ sb = _sourceBuilderAfterKeyword(node, statement.keyword);
sb.append('(');
sb.setExitOffset();
sb.append(')');
@@ -841,18 +837,19 @@
return sb;
}
- bool _complete_methodCall() {
+ bool _complete_methodCall(AstNode node) {
var parenError =
_findError(ParserErrorCode.EXPECTED_TOKEN, partialMatch: "')'") ??
_findError(ScannerErrorCode.EXPECTED_TOKEN, partialMatch: "')'");
if (parenError == null) {
return false;
}
- AstNode argList =
- _selectedNode(at: selectionOffset).thisOrAncestorOfType<ArgumentList>();
+ var argList = _selectedNode(at: selectionOffset)
+ ?.thisOrAncestorOfType<ArgumentList>();
argList ??= _selectedNode(at: parenError.offset)
- .thisOrAncestorOfType<ArgumentList>();
- if (argList?.thisOrAncestorMatching((n) => n == node) == null) {
+ ?.thisOrAncestorOfType<ArgumentList>();
+ if (argList == null ||
+ argList.thisOrAncestorMatching((n) => n == node) == null) {
return false;
}
var previousInsertions = _lengthOfInsertions();
@@ -891,7 +888,7 @@
return true;
}
- bool _complete_simpleSemicolon() {
+ bool _complete_simpleSemicolon(AstNode node) {
if (errors.length != 1) {
return false;
}
@@ -908,41 +905,39 @@
return false;
}
- bool _complete_switchStatement() {
+ bool _complete_switchStatement(AstNode node) {
if (node is! SwitchStatement) {
return false;
}
SourceBuilder sb;
- SwitchStatement switchNode = node;
- if (switchNode.leftParenthesis.isSynthetic &&
- switchNode.rightParenthesis.isSynthetic) {
- exitPosition = Position(file, switchNode.switchKeyword.end + 2);
- var src = utils.getNodeText(switchNode);
+ if (node.leftParenthesis.isSynthetic && node.rightParenthesis.isSynthetic) {
+ exitPosition = Position(file, node.switchKeyword.end + 2);
+ var src = utils.getNodeText(node);
if (src
- .substring(switchNode.switchKeyword.end - switchNode.offset)
+ .substring(node.switchKeyword.end - node.offset)
.startsWith(RegExp(r'[ \t]+'))) {
- sb = SourceBuilder(file, switchNode.switchKeyword.end + 1);
+ sb = SourceBuilder(file, node.switchKeyword.end + 1);
} else {
- sb = SourceBuilder(file, switchNode.switchKeyword.end);
+ sb = SourceBuilder(file, node.switchKeyword.end);
sb.append(' ');
}
sb.append('()');
- } else if (switchNode.leftParenthesis.isSynthetic ||
- switchNode.rightParenthesis.isSynthetic) {
+ } else if (node.leftParenthesis.isSynthetic ||
+ node.rightParenthesis.isSynthetic) {
return false;
} else {
- sb = SourceBuilder(file, switchNode.rightParenthesis.offset + 1);
- if (_isSyntheticExpression(switchNode.expression)) {
- exitPosition = Position(file, switchNode.leftParenthesis.offset + 1);
+ sb = SourceBuilder(file, node.rightParenthesis.offset + 1);
+ if (_isSyntheticExpression(node.expression)) {
+ exitPosition = Position(file, node.leftParenthesis.offset + 1);
}
}
- if (switchNode
+ if (node
.leftBracket.isSynthetic /*&& switchNode.rightBracket.isSynthetic*/) {
// See https://github.com/dart-lang/sdk/issues/29391
sb.append(' ');
_appendEmptyBraces(sb, exitPosition == null);
} else {
- var member = _findInvalidElement(switchNode.members);
+ var member = _findInvalidElement(node.members);
if (member != null) {
if (member.colon.isSynthetic) {
var loc =
@@ -958,98 +953,103 @@
return true;
}
- bool _complete_tryStatement() {
+ bool _complete_tryStatement(AstNode node) {
if (node is! TryStatement) {
return false;
}
- TryStatement tryNode = node;
- SourceBuilder sb;
- CatchClause catchNode;
var addSpace = true;
- if (tryNode.body.leftBracket.isSynthetic) {
- var src = utils.getNodeText(tryNode);
+ if (node.body.leftBracket.isSynthetic) {
+ var src = utils.getNodeText(node);
+ SourceBuilder sb;
if (src
- .substring(tryNode.tryKeyword.end - tryNode.offset)
+ .substring(node.tryKeyword.end - node.offset)
.startsWith(RegExp(r'[ \t]+'))) {
// keywordSpace
- sb = SourceBuilder(file, tryNode.tryKeyword.end + 1);
+ sb = SourceBuilder(file, node.tryKeyword.end + 1);
} else {
// keywordOnly
- sb = SourceBuilder(file, tryNode.tryKeyword.end);
+ sb = SourceBuilder(file, node.tryKeyword.end);
sb.append(' ');
}
_appendEmptyBraces(sb, true);
_insertBuilder(sb);
- sb = null;
- } else if ((catchNode = _findInvalidElement(tryNode.catchClauses)) !=
- null) {
- if (catchNode.onKeyword != null) {
- if (catchNode.exceptionType.length == 0 ||
- null !=
- _findError(CompileTimeErrorCode.NON_TYPE_IN_CATCH_CLAUSE,
- partialMatch: "name 'catch")) {
- var src = utils.getNodeText(catchNode);
- if (src.startsWith(RegExp(r'on[ \t]+'))) {
- if (src.startsWith(RegExp(r'on[ \t][ \t]+'))) {
- // onSpaces
- exitPosition = Position(file, catchNode.onKeyword.end + 1);
- sb = SourceBuilder(file, catchNode.onKeyword.end + 2);
- addSpace = false;
+ } else {
+ SourceBuilder? sb;
+ var catchNode = _findInvalidElement(node.catchClauses);
+ if (catchNode != null) {
+ var onKeyword = catchNode.onKeyword;
+ var exceptionType = catchNode.exceptionType;
+ if (onKeyword != null && exceptionType != null) {
+ if (exceptionType.length == 0 ||
+ _findError(CompileTimeErrorCode.NON_TYPE_IN_CATCH_CLAUSE,
+ partialMatch: "name 'catch") !=
+ null) {
+ var src = utils.getNodeText(catchNode);
+ if (src.startsWith(RegExp(r'on[ \t]+'))) {
+ if (src.startsWith(RegExp(r'on[ \t][ \t]+'))) {
+ // onSpaces
+ exitPosition = Position(file, onKeyword.end + 1);
+ sb = SourceBuilder(file, onKeyword.end + 2);
+ addSpace = false;
+ } else {
+ // onSpace
+ sb = SourceBuilder(file, onKeyword.end + 1);
+ sb.setExitOffset();
+ }
} else {
- // onSpace
- sb = SourceBuilder(file, catchNode.onKeyword.end + 1);
+ // onOnly
+ sb = SourceBuilder(file, onKeyword.end);
+ sb.append(' ');
sb.setExitOffset();
}
} else {
- // onOnly
- sb = SourceBuilder(file, catchNode.onKeyword.end);
- sb.append(' ');
- sb.setExitOffset();
+ // onType
+ sb = SourceBuilder(file, exceptionType.end);
}
- } else {
- // onType
- sb = SourceBuilder(file, catchNode.exceptionType.end);
}
- }
- if (catchNode.catchKeyword != null) {
- // catchOnly
- var struct = _KeywordConditionBlockStructure(
- catchNode.catchKeyword,
- catchNode.leftParenthesis,
- catchNode.exceptionParameter,
- catchNode.rightParenthesis,
- catchNode.body);
+ var catchKeyword = catchNode.catchKeyword;
+ if (catchKeyword != null) {
+ // catchOnly
+ var struct = _KeywordConditionBlockStructure(
+ catchKeyword,
+ catchNode.leftParenthesis!,
+ catchNode.exceptionParameter!,
+ catchNode.rightParenthesis!,
+ catchNode.body);
+ if (sb != null) {
+ // onCatch
+ _insertBuilder(sb);
+ }
+ sb = _complete_keywordCondition(node, struct);
+ if (sb == null) {
+ return false;
+ }
+ }
if (sb != null) {
- // onCatch
+ if (catchNode.body.leftBracket.isSynthetic) {
+ // onOnly and others
+ if (addSpace) {
+ sb.append(' ');
+ }
+ _appendEmptyBraces(sb, exitPosition == null);
+ }
_insertBuilder(sb);
}
- sb = _complete_keywordCondition(struct);
- if (sb == null) {
- return false;
- }
- }
- if (catchNode.body.leftBracket.isSynthetic) {
- // onOnly and others
- if (addSpace) {
+ } else if (node.finallyKeyword != null) {
+ if (node.finallyBlock!.leftBracket.isSynthetic) {
+ // finallyOnly
+ sb = SourceBuilder(file, node.finallyKeyword!.end);
sb.append(' ');
+ _appendEmptyBraces(sb, true);
+ _insertBuilder(sb);
}
- _appendEmptyBraces(sb, exitPosition == null);
- }
- _insertBuilder(sb);
- } else if (tryNode.finallyKeyword != null) {
- if (tryNode.finallyBlock.leftBracket.isSynthetic) {
- // finallyOnly
- sb = SourceBuilder(file, tryNode.finallyKeyword.end);
- sb.append(' ');
- _appendEmptyBraces(sb, true);
- _insertBuilder(sb);
}
}
_setCompletion(DartStatementCompletion.COMPLETE_TRY_STMT);
return true;
}
- bool _complete_variableDeclaration() {
+ bool _complete_variableDeclaration(AstNode node) {
if (node is! VariableDeclaration) {
return false;
}
@@ -1059,36 +1059,25 @@
return true;
}
- bool _complete_whileStatement() {
+ bool _complete_whileStatement(AstNode node) {
if (node is! WhileStatement) {
return false;
}
- WhileStatement whileNode = node;
- if (whileNode != null) {
- var stmt = _KeywordConditionBlockStructure(
- whileNode.whileKeyword,
- whileNode.leftParenthesis,
- whileNode.condition,
- whileNode.rightParenthesis,
- whileNode.body);
- return _complete_ifOrWhileStatement(
- stmt, DartStatementCompletion.COMPLETE_WHILE_STMT);
- }
- return false;
+ var stmt = _KeywordConditionBlockStructure(node.whileKeyword,
+ node.leftParenthesis, node.condition, node.rightParenthesis, node.body);
+ return _complete_ifOrWhileStatement(
+ node, stmt, DartStatementCompletion.COMPLETE_WHILE_STMT);
}
- engine.AnalysisError _findError(ErrorCode code, {partialMatch}) {
- return errors.firstWhere(
- (err) =>
- err.errorCode == code &&
- (partialMatch == null ? true : err.message.contains(partialMatch)),
- orElse: () => null);
+ engine.AnalysisError? _findError(ErrorCode code, {partialMatch}) {
+ return errors.firstWhereOrNull((err) =>
+ err.errorCode == code &&
+ (partialMatch == null ? true : err.message.contains(partialMatch)));
}
- T _findInvalidElement<T extends AstNode>(NodeList<T> list) {
- return list.firstWhere(
- (item) => selectionOffset >= item.offset && selectionOffset <= item.end,
- orElse: () => null);
+ T? _findInvalidElement<T extends AstNode>(NodeList<T> list) {
+ return list.firstWhereOrNull((item) =>
+ selectionOffset >= item.offset && selectionOffset <= item.end);
}
void _insertBuilder(SourceBuilder builder, [int length = 0]) {
@@ -1110,7 +1099,7 @@
return stmt is Block && stmt.statements.isEmpty;
}
- bool _isEmptyStatement(AstNode stmt) {
+ bool _isEmptyStatement(AstNode? stmt) {
if (stmt is ExpressionStatement) {
var expression = stmt.expression;
if (expression is SimpleIdentifier) {
@@ -1137,7 +1126,7 @@
p?.parent?.parent is! Statement;
}
- bool _isSyntheticExpression(Expression expr) {
+ bool _isSyntheticExpression(Expression? expr) {
return expr is SimpleIdentifier && expr.isSynthetic;
}
@@ -1187,10 +1176,10 @@
}
}
- AstNode _selectedNode({int at}) =>
+ AstNode? _selectedNode({int? at}) =>
NodeLocator(at ?? selectionOffset).searchWithin(unit);
- void _setCompletion(StatementCompletionKind kind, [List args]) {
+ void _setCompletion(StatementCompletionKind kind, [List? args]) {
assert(exitPosition != null);
change.selection = exitPosition;
change.message = formatList(kind.message, args);
@@ -1199,12 +1188,13 @@
completion = StatementCompletion(kind, change);
}
- void _setCompletionAt(StatementCompletionKind kind, int offset, [List args]) {
+ void _setCompletionAt(StatementCompletionKind kind, int offset,
+ [List? args]) {
exitPosition = _newPosition(offset);
_setCompletion(kind, args);
}
- SourceBuilder _sourceBuilderAfterKeyword(Token keyword) {
+ SourceBuilder _sourceBuilderAfterKeyword(AstNode node, Token keyword) {
SourceBuilder sb;
var text = _baseNodeText(node);
text = text.substring(keyword.offset - node.offset);
@@ -1239,7 +1229,7 @@
final Token keyword;
final Token leftParenthesis, rightParenthesis;
final Expression condition;
- final Statement block;
+ final Statement? block;
_KeywordConditionBlockStructure(this.keyword, this.leftParenthesis,
this.condition, this.rightParenthesis, this.block);
diff --git a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
index 6d787d6..741715f 100644
--- a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
+++ b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/statement/statement_completion.dart';
import 'package:test/test.dart';
@@ -28,7 +26,7 @@
}
class StatementCompletionTest extends AbstractSingleUnitTest {
- SourceChange change;
+ late SourceChange change;
int _after(String source, String match) =>
source.indexOf(match) + match.length;
@@ -39,7 +37,7 @@
void _assertHasChange(
String message,
String expectedCode, [
- int Function(String) cmp,
+ int Function(String)? cmp,
]) {
if (change.message == message) {
if (change.edits.isNotEmpty) {
@@ -48,13 +46,13 @@
expect(resultCode, expectedCode.replaceAll('////', ''));
if (cmp != null) {
var offset = cmp(resultCode);
- expect(change.selection.offset, offset);
+ expect(change.selection!.offset, offset);
}
} else {
expect(testCode, expectedCode.replaceAll('////', ''));
if (cmp != null) {
var offset = cmp(testCode);
- expect(change.selection.offset, offset);
+ expect(change.selection!.offset, offset);
}
}
return;
diff --git a/tools/VERSION b/tools/VERSION
index d75cb56..646d39a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 227
+PRERELEASE 228
PRERELEASE_PATCH 0
\ No newline at end of file