Version 2.13.0-223.0.dev
Merge commit '8fb98b25c1649fbaa64ce77315d181b16bc92a7f' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index b5a1027..ef6a1ef 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -107,7 +107,7 @@
ConvertPartOfToUri.newInstance,
ConvertToDoubleQuotes.newInstance,
ConvertToFieldParameter.newInstance,
- ConvertToMutilineString.newInstance,
+ ConvertToMultilineString.newInstance,
ConvertToNormalParameter.newInstance,
ConvertToSingleQuotes.newInstance,
ConvertToExpressionFunctionBody.newInstance,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
index 7665de9..0ca4062 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -29,6 +27,9 @@
var rightOperand = comparison.rightOperand;
if (leftOperand is MethodInvocation && _isInteger(rightOperand)) {
var value = _integerValue(rightOperand);
+ if (value == null) {
+ return;
+ }
var methodName = leftOperand.methodName;
var deletionRange = range.endEnd(leftOperand, rightOperand);
var notOffset = -1;
@@ -48,6 +49,9 @@
});
} else if (_isInteger(leftOperand) && rightOperand is MethodInvocation) {
var value = _integerValue(leftOperand);
+ if (value == null) {
+ return;
+ }
var methodName = rightOperand.methodName;
var deletionRange = range.startStart(leftOperand, rightOperand);
var notOffset = -1;
@@ -71,17 +75,20 @@
/// Return the value of the given [expression], given that [_isInteger]
/// returned `true`.
- int _integerValue(Expression expression) {
+ int? _integerValue(Expression expression) {
if (expression is IntegerLiteral) {
return expression.value;
} else if (expression is PrefixExpression &&
expression.operator.type == TokenType.MINUS) {
var operand = expression.operand;
if (operand is IntegerLiteral) {
- return -operand.value;
+ var value = operand.value;
+ if (value != null) {
+ return -value;
+ }
}
}
- throw StateError('invalid integer value');
+ return null;
}
TokenType _invertedTokenType(TokenType type) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
index fd38a12..ed84716e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -31,13 +29,13 @@
return;
}
// prepare return statement
- List<Statement> statements = (body as BlockFunctionBody).block.statements;
+ List<Statement> statements = body.block.statements;
if (statements.length != 1) {
return;
}
var onlyStatement = statements.first;
// prepare returned expression
- Expression returnExpression;
+ Expression? returnExpression;
if (onlyStatement is ReturnStatement) {
returnExpression = onlyStatement.expression;
} else if (onlyStatement is ExpressionStatement) {
@@ -53,15 +51,17 @@
return;
}
+ final returnExpression_final = returnExpression;
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.node(body), (builder) {
if (body.isAsynchronous) {
builder.write('async ');
}
builder.write('=> ');
- builder.write(utils.getNodeText(returnExpression));
- if (body.parent is! FunctionExpression ||
- body.parent.parent is FunctionDeclaration) {
+ builder.write(utils.getNodeText(returnExpression_final));
+ var parent = body.parent;
+ if (parent is! FunctionExpression ||
+ parent.parent is FunctionDeclaration) {
builder.write(';');
}
});
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_field_parameter.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_field_parameter.dart
index ef999da..447adee 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_field_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_field_parameter.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -19,87 +17,128 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- if (node == null) {
- return;
- }
- // prepare ConstructorDeclaration
- var constructor = node.thisOrAncestorOfType<ConstructorDeclaration>();
- if (constructor == null) {
- return;
- }
- var parameterList = constructor.parameters;
- List<ConstructorInitializer> initializers = constructor.initializers;
// prepare parameter
- SimpleFormalParameter parameter;
- if (node.parent is SimpleFormalParameter &&
- node.parent.parent is FormalParameterList &&
- node.parent.parent.parent is ConstructorDeclaration) {
- parameter = node.parent;
+ var context = _findParameter(node);
+ if (context == null) {
+ return;
}
- if (node is SimpleIdentifier &&
- node.parent is ConstructorFieldInitializer) {
- var name = (node as SimpleIdentifier).name;
- ConstructorFieldInitializer initializer = node.parent;
- if (initializer.expression == node) {
- for (var formalParameter in parameterList.parameters) {
- if (formalParameter is SimpleFormalParameter &&
- formalParameter.identifier.name == name) {
- parameter = formalParameter;
- }
- }
- }
- }
- // analyze parameter
- if (parameter != null) {
- var parameterName = parameter.identifier.name;
- var parameterElement = parameter.declaredElement;
- // check number of references
- var visitor = _ReferenceCounter(parameterElement);
- for (var initializer in initializers) {
- initializer.accept(visitor);
- }
- if (visitor.count != 1) {
- return;
- }
- // find the field initializer
- ConstructorFieldInitializer parameterInitializer;
- for (var initializer in initializers) {
- if (initializer is ConstructorFieldInitializer) {
- var expression = initializer.expression;
- if (expression is SimpleIdentifier &&
- expression.name == parameterName) {
- parameterInitializer = initializer;
- }
- }
- }
- if (parameterInitializer == null) {
- return;
- }
- var fieldName = parameterInitializer.fieldName.name;
- await builder.addDartFileEdit(file, (builder) {
- // replace parameter
- builder.addSimpleReplacement(range.node(parameter), 'this.$fieldName');
- // remove initializer
- var initializerIndex = initializers.indexOf(parameterInitializer);
- if (initializers.length == 1) {
- builder
- .addDeletion(range.endEnd(parameterList, parameterInitializer));
- } else {
- if (initializerIndex == 0) {
- var next = initializers[initializerIndex + 1];
- builder.addDeletion(range.startStart(parameterInitializer, next));
- } else {
- var prev = initializers[initializerIndex - 1];
- builder.addDeletion(range.endEnd(prev, parameterInitializer));
- }
- }
- });
+ // analyze parameter
+ var parameterName = context.identifier.name;
+ var parameterElement = context.parameter.declaredElement!;
+ var initializers = context.constructor.initializers;
+
+ // check number of references
+ var visitor = _ReferenceCounter(parameterElement);
+ for (var initializer in initializers) {
+ initializer.accept(visitor);
}
+ if (visitor.count != 1) {
+ return;
+ }
+ // find the field initializer
+ ConstructorFieldInitializer? parameterInitializer;
+ for (var initializer in initializers) {
+ if (initializer is ConstructorFieldInitializer) {
+ var expression = initializer.expression;
+ if (expression is SimpleIdentifier &&
+ expression.name == parameterName) {
+ parameterInitializer = initializer;
+ }
+ }
+ }
+ if (parameterInitializer == null) {
+ return;
+ }
+ var fieldName = parameterInitializer.fieldName.name;
+
+ final context_final = context;
+ final parameterInitializer_final = parameterInitializer;
+ await builder.addDartFileEdit(file, (builder) {
+ // replace parameter
+ builder.addSimpleReplacement(
+ range.node(context_final.parameter),
+ 'this.$fieldName',
+ );
+ // remove initializer
+ var initializerIndex = initializers.indexOf(parameterInitializer_final);
+ if (initializers.length == 1) {
+ builder.addDeletion(
+ range.endEnd(
+ context_final.constructor.parameters,
+ parameterInitializer_final,
+ ),
+ );
+ } else {
+ if (initializerIndex == 0) {
+ var next = initializers[initializerIndex + 1];
+ builder.addDeletion(
+ range.startStart(parameterInitializer_final, next),
+ );
+ } else {
+ var prev = initializers[initializerIndex - 1];
+ builder.addDeletion(
+ range.endEnd(prev, parameterInitializer_final),
+ );
+ }
+ }
+ });
}
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
static ConvertToFieldParameter newInstance() => ConvertToFieldParameter();
+
+ static _Context? _findParameter(AstNode node) {
+ var parent = node.parent;
+ if (parent is SimpleFormalParameter) {
+ var identifier = parent.identifier;
+ if (identifier == null) return null;
+
+ var formalParameterList = parent.parent;
+ if (formalParameterList is! FormalParameterList) return null;
+
+ var constructor = formalParameterList.parent;
+ if (constructor is! ConstructorDeclaration) return null;
+
+ return _Context(
+ parameter: parent,
+ identifier: identifier,
+ constructor: constructor,
+ );
+ }
+
+ if (node is SimpleIdentifier && parent is ConstructorFieldInitializer) {
+ var constructor = parent.parent;
+ if (constructor is! ConstructorDeclaration) return null;
+
+ if (parent.expression == node) {
+ for (var formalParameter in constructor.parameters.parameters) {
+ if (formalParameter is SimpleFormalParameter) {
+ var identifier = formalParameter.identifier;
+ if (identifier != null && identifier.name == node.name) {
+ return _Context(
+ parameter: formalParameter,
+ identifier: identifier,
+ constructor: constructor,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+class _Context {
+ final SimpleFormalParameter parameter;
+ final SimpleIdentifier identifier;
+ final ConstructorDeclaration constructor;
+
+ _Context({
+ required this.parameter,
+ required this.identifier,
+ required this.constructor,
+ });
}
class _ReferenceCounter extends RecursiveAstVisitor<void> {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
index 7b197a4..76b0ad1 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
@@ -2,11 +2,10 @@
// 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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -27,8 +26,7 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- var node = this.node;
- while (node != null) {
+ for (var node in this.node.withParents) {
if (node is FunctionTypeAlias) {
return _convertFunctionTypeAlias(builder, node);
} else if (node is FunctionTypedFormalParameter) {
@@ -38,7 +36,6 @@
// when the selection is inside a parameter list.
return null;
}
- node = node.parent;
}
}
@@ -47,7 +44,7 @@
bool _allParametersHaveTypes(FormalParameterList parameters) {
for (var parameter in parameters.parameters) {
if (parameter is DefaultFormalParameter) {
- parameter = (parameter as DefaultFormalParameter).parameter;
+ parameter = parameter.parameter;
}
if (parameter is SimpleFormalParameter) {
if (parameter.type == null) {
@@ -65,10 +62,13 @@
if (!_allParametersHaveTypes(node.parameters)) {
return;
}
- String returnType;
- if (node.returnType != null) {
- returnType = utils.getNodeText(node.returnType);
+
+ String? returnType;
+ var returnTypeNode = node.returnType;
+ if (returnTypeNode != null) {
+ returnType = utils.getNodeText(returnTypeNode);
}
+
var functionName = utils.getRangeText(
range.startEnd(node.name, node.typeParameters ?? node.name));
var parameters = utils.getNodeText(node.parameters);
@@ -81,7 +81,7 @@
// add change
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
- range.startStart(node.typedefKeyword.next, node.semicolon),
+ range.startStart(node.typedefKeyword.next!, node.semicolon),
replacement);
});
}
@@ -93,8 +93,9 @@
}
var required = node.requiredKeyword != null ? 'required ' : '';
var covariant = node.covariantKeyword != null ? 'covariant ' : '';
+ var returnTypeNode = node.returnType;
var returnType =
- node.returnType != null ? '${utils.getNodeText(node.returnType)} ' : '';
+ returnTypeNode != null ? '${utils.getNodeText(returnTypeNode)} ' : '';
var functionName = utils.getRangeText(range.startEnd(
node.identifier, node.typeParameters ?? node.identifier));
var parameters = utils.getNodeText(node.parameters);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_if_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_if_null.dart
index 19e52d8..d8ca1d2 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_if_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_if_null.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_int_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_int_literal.dart
index ed675e7..1a9f163 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_int_literal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_int_literal.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -25,16 +23,18 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- if (node is! DoubleLiteral) {
+ var literal = node;
+ if (literal is! DoubleLiteral) {
return;
}
- DoubleLiteral literal = node;
- int intValue;
+
+ int? intValue;
try {
- intValue = literal.value?.truncate();
+ intValue = literal.value.truncate();
} catch (e) {
// Double cannot be converted to int
}
+
if (intValue == null || intValue != literal.value) {
return;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_list_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_list_literal.dart
index ba140fa..45ae0af 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_list_literal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_list_literal.dart
@@ -2,12 +2,11 @@
// 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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -29,9 +28,14 @@
// Ensure that this is the default constructor defined on `List`.
//
var creation = node.thisOrAncestorOfType<InstanceCreationExpression>();
- if (creation == null ||
- node.offset > creation.argumentList.offset ||
- creation.staticType.element != typeProvider.listElement ||
+ if (creation == null) {
+ return;
+ }
+
+ var type = creation.staticType;
+ if (node.offset > creation.argumentList.offset ||
+ type is! InterfaceType ||
+ type.element != typeProvider.listElement ||
creation.constructorName.name != null ||
creation.argumentList.arguments.isNotEmpty) {
return;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart
index 76221ea..5919c43 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart
@@ -2,13 +2,12 @@
// 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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -31,11 +30,16 @@
// `LinkedHashMap`.
//
var creation = node.thisOrAncestorOfType<InstanceCreationExpression>();
- if (creation == null ||
- node.offset > creation.argumentList.offset ||
+ if (creation == null) {
+ return;
+ }
+
+ var type = creation.staticType;
+ if (node.offset > creation.argumentList.offset ||
creation.constructorName.name != null ||
creation.argumentList.arguments.isNotEmpty ||
- !_isMapClass(creation.staticType.element)) {
+ type is! InterfaceType ||
+ !_isMapClass(type.element)) {
return;
}
//
@@ -57,11 +61,10 @@
/// Return `true` if the [element] represents either the class `Map` or
/// `LinkedHashMap`.
- bool _isMapClass(Element element) =>
- element is ClassElement &&
- (element == typeProvider.mapElement ||
- (element.name == 'LinkedHashMap' &&
- element.library.name == 'dart.collection'));
+ bool _isMapClass(ClassElement element) =>
+ element == typeProvider.mapElement ||
+ (element.name == 'LinkedHashMap' &&
+ element.library.name == 'dart.collection');
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static ConvertToMapLiteral newInstance() => ConvertToMapLiteral();
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart
index 0dd99aa..51861d9 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -11,7 +9,7 @@
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
-class ConvertToMutilineString extends CorrectionProducer {
+class ConvertToMultilineString extends CorrectionProducer {
@override
AssistKind get assistKind => DartAssistKind.CONVERT_TO_MULTILINE_STRING;
@@ -19,7 +17,7 @@
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is InterpolationElement) {
- node = (node as InterpolationElement).parent;
+ node = node.parent!;
}
if (node is SingleStringLiteral) {
var literal = node;
@@ -42,5 +40,5 @@
}
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
- static ConvertToMutilineString newInstance() => ConvertToMutilineString();
+ static ConvertToMultilineString newInstance() => ConvertToMultilineString();
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_named_arguments.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_named_arguments.dart
index a4af1c4..228d9f9 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_named_arguments.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_named_arguments.dart
@@ -2,13 +2,12 @@
// 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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -22,7 +21,7 @@
var argumentList = node.parent;
if (argumentList is ArgumentList) {
// Prepare parameters.
- List<ParameterElement> parameters;
+ List<ParameterElement>? parameters;
var parent = argumentList.parent;
if (parent is FunctionExpressionInvocation) {
var invokeType = parent.staticInvokeType;
@@ -61,10 +60,10 @@
argumentList.arguments.skip(numberOfPositionalParameters);
for (var argument in extraArguments) {
if (argument is! NamedExpression) {
- ParameterElement uniqueNamedParameter;
+ ParameterElement? uniqueNamedParameter;
for (var namedParameter in namedParameters) {
if (typeSystem.isSubtypeOf(
- argument.staticType, namedParameter.type)) {
+ argument.typeOrThrow, namedParameter.type)) {
if (uniqueNamedParameter == null) {
uniqueNamedParameter = namedParameter;
} else {
@@ -84,8 +83,9 @@
}
await builder.addDartFileEdit(file, (builder) {
- for (var argument in argumentToParameter.keys) {
- var parameter = argumentToParameter[argument];
+ for (var entry in argumentToParameter.entries) {
+ var argument = entry.key;
+ var parameter = entry.value;
builder.addSimpleInsertion(argument.offset, '${parameter.name}: ');
}
});
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_normal_parameter.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_normal_parameter.dart
index b220afd..d7a7c65 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_normal_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_normal_parameter.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -17,38 +15,41 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- if (node is SimpleIdentifier &&
- node.parent is FieldFormalParameter &&
- node.parent.parent is FormalParameterList &&
- node.parent.parent.parent is ConstructorDeclaration) {
- ConstructorDeclaration constructor = node.parent.parent.parent;
- FormalParameterList parameterList = node.parent.parent;
- FieldFormalParameter parameter = node.parent;
- var parameterElement = parameter.declaredElement;
- var name = (node as SimpleIdentifier).name;
- // prepare type
- var type = parameterElement.type;
+ var identifier = node;
+ if (identifier is! SimpleIdentifier) return;
- await builder.addDartFileEdit(file, (builder) {
- // replace parameter
- if (type.isDynamic) {
- builder.addSimpleReplacement(range.node(parameter), name);
- } else {
- builder.addReplacement(range.node(parameter), (builder) {
- builder.writeType(type);
- builder.write(' ');
- builder.write(name);
- });
- }
- // add field initializer
- List<ConstructorInitializer> initializers = constructor.initializers;
- if (initializers.isEmpty) {
- builder.addSimpleInsertion(parameterList.end, ' : $name = $name');
- } else {
- builder.addSimpleInsertion(initializers.last.end, ', $name = $name');
- }
- });
- }
+ var parameter = identifier.parent;
+ if (parameter is! FieldFormalParameter) return;
+
+ var parameterList = parameter.parent;
+ if (parameterList is! FormalParameterList) return;
+
+ var constructor = parameterList.parent;
+ if (constructor is! ConstructorDeclaration) return;
+
+ var parameterElement = parameter.declaredElement!;
+ var name = identifier.name;
+ var type = parameterElement.type;
+
+ await builder.addDartFileEdit(file, (builder) {
+ // replace parameter
+ if (type.isDynamic) {
+ builder.addSimpleReplacement(range.node(parameter), name);
+ } else {
+ builder.addReplacement(range.node(parameter), (builder) {
+ builder.writeType(type);
+ builder.write(' ');
+ builder.write(name);
+ });
+ }
+ // add field initializer
+ List<ConstructorInitializer> initializers = constructor.initializers;
+ if (initializers.isEmpty) {
+ builder.addSimpleInsertion(parameterList.end, ' : $name = $name');
+ } else {
+ builder.addSimpleInsertion(initializers.last.end, ', $name = $name');
+ }
+ });
}
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware.dart
index 5307774..013e4fe 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -28,15 +26,17 @@
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
- if (node.parent is BinaryExpression &&
- node.parent.parent is ConditionalExpression) {
- node = node.parent.parent;
+ var parent = node.parent;
+ if (parent is BinaryExpression) {
+ var grandParent = parent.parent;
+ if (grandParent is ConditionalExpression) {
+ node = grandParent;
+ }
}
if (node is! ConditionalExpression) {
return;
}
- ConditionalExpression conditional = node;
- var condition = conditional.condition.unParenthesized;
+ var condition = node.condition.unParenthesized;
SimpleIdentifier identifier;
Expression nullExpression;
Expression nonNullExpression;
@@ -67,21 +67,20 @@
// is the save variable being compared to `null`.
//
if (condition.operator.type == TokenType.EQ_EQ) {
- nullExpression = conditional.thenExpression;
- nonNullExpression = conditional.elseExpression;
+ nullExpression = node.thenExpression;
+ nonNullExpression = node.elseExpression;
} else if (condition.operator.type == TokenType.BANG_EQ) {
- nonNullExpression = conditional.thenExpression;
- nullExpression = conditional.elseExpression;
- }
- if (nullExpression == null || nonNullExpression == null) {
+ nonNullExpression = node.thenExpression;
+ nullExpression = node.elseExpression;
+ } else {
return;
}
if (nullExpression.unParenthesized is! NullLiteral) {
return;
}
var unwrappedExpression = nonNullExpression.unParenthesized;
- Expression target;
- Token operator;
+ Expression? target;
+ Token? operator;
if (unwrappedExpression is MethodInvocation) {
target = unwrappedExpression.target;
operator = unwrappedExpression.operator;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart
index 8f54f38..920b2f2 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_null_aware_spread.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -16,7 +14,7 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- var parent = coveredNode.parent;
+ var parent = coveredNode?.parent;
if (parent is SpreadElement && !parent.isNullAware) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleInsertion(parent.spreadOperator.end, '?');
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_package_import.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_package_import.dart
index 074e90c..a40b1b2 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_package_import.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_package_import.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -27,7 +25,7 @@
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is StringLiteral) {
- node = node.parent;
+ node = node.parent!;
}
if (node is ImportDirective) {
var importDirective = node;
@@ -45,7 +43,8 @@
// Don't offer to convert a 'package:' URI to itself.
try {
- if (Uri.parse(importDirective.uriContent).scheme == 'package') {
+ var uriContent = importDirective.uriContent;
+ if (uriContent == null || Uri.parse(uriContent).scheme == 'package') {
return;
}
} on FormatException {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_relative_import.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_relative_import.dart
index a312a32..48a99d7 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_relative_import.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_relative_import.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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -28,16 +26,14 @@
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is StringLiteral) {
- node = node.parent;
+ node = node.parent!;
}
if (node is! ImportDirective) {
return;
}
- ImportDirective importDirective = node;
-
// Ignore if invalid URI.
- if (importDirective.uriSource == null) {
+ if (node.uriSource == null) {
return;
}
@@ -49,7 +45,11 @@
Uri importUri;
try {
- importUri = Uri.parse(importDirective.uriContent);
+ var uriContent = node.uriContent;
+ if (uriContent == null) {
+ return;
+ }
+ importUri = Uri.parse(uriContent);
} on FormatException {
return;
}
@@ -75,9 +75,10 @@
from: path.dirname(sourceUri.path),
);
+ final node_final = node;
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
- range.node(importDirective.uri).getExpanded(-1),
+ range.node(node_final.uri).getExpanded(-1),
relativePath,
);
});
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_set_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_set_literal.dart
index fb2b42c..8796a16 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_set_literal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_set_literal.dart
@@ -2,12 +2,11 @@
// 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/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -62,8 +61,8 @@
var name = creation.constructorName.name;
var constructorTypeArguments =
creation.constructorName.type.typeArguments;
- TypeArgumentList elementTypeArguments;
- SourceRange elementsRange;
+ TypeArgumentList? elementTypeArguments;
+ SourceRange? elementsRange;
if (name == null) {
// Handle an invocation of the default constructor `Set()`.
} else if (name.name == 'from' || name.name == 'of') {
@@ -111,7 +110,7 @@
/// Return the invocation of `List.toSet` that is to be converted, or `null`
/// if the cursor is not inside a invocation of `List.toSet`.
- MethodInvocation _findInvocationOfToSet() {
+ MethodInvocation? _findInvocationOfToSet() {
var invocation = node.thisOrAncestorOfType<MethodInvocation>();
if (invocation == null ||
node.offset > invocation.argumentList.offset ||
@@ -124,12 +123,23 @@
/// Return the invocation of a `Set` constructor that is to be converted, or
/// `null` if the cursor is not inside the invocation of a constructor.
- InstanceCreationExpression _findSetCreation() {
+ InstanceCreationExpression? _findSetCreation() {
var creation = node.thisOrAncestorOfType<InstanceCreationExpression>();
+ if (creation == null) {
+ return null;
+ }
+
+ if (node.offset > creation.argumentList.offset) {
+ return null;
+ }
+
+ var type = creation.staticType;
+ if (type is! InterfaceType) {
+ return null;
+ }
+
// TODO(brianwilkerson) Consider also accepting uses of LinkedHashSet.
- if (creation == null ||
- node.offset > creation.argumentList.offset ||
- creation.staticType.element != typeProvider.setElement) {
+ if (type.element != typeProvider.setElement) {
return null;
}
return creation;
@@ -139,7 +149,7 @@
/// element that would cause a set to be inferred.
bool _hasUnambiguousElement(InstanceCreationExpression creation) {
var arguments = creation.argumentList.arguments;
- if (arguments == null || arguments.isEmpty) {
+ if (arguments.isEmpty) {
return false;
}
return _listHasUnambiguousElement(arguments[0]);
@@ -147,7 +157,7 @@
/// Return `true` if the [element] is sufficient to lexically make the
/// enclosing literal a set literal rather than a map.
- bool _isUnambiguousElement(CollectionElement element) {
+ bool _isUnambiguousElement(CollectionElement? element) {
if (element is ForElement) {
return _isUnambiguousElement(element.body);
} else if (element is IfElement) {
@@ -176,7 +186,7 @@
/// Return `true` if a set would be inferred if the literal replacing the
/// instance [creation] did not have explicit type arguments.
bool _setWouldBeInferred(InstanceCreationExpression creation) {
- var parent = creation.parent;
+ var parent = creation.parent!;
if (parent is VariableDeclaration) {
var parent2 = parent.parent;
if (parent2 is VariableDeclarationList &&
@@ -185,7 +195,7 @@
}
} else if (parent.parent is InvocationExpression) {
var parameterElement = creation.staticParameterElement;
- if (parameterElement?.type?.element == typeProvider.setElement) {
+ if (parameterElement?.type.element == typeProvider.setElement) {
return true;
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart
index eb508d4..de20ada 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -20,33 +18,46 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- var node = this.node;
- if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+ var methodName = node;
+ if (methodName is! SimpleIdentifier) {
return;
}
- var methodName = node as SimpleIdentifier;
- var invocation = node.parent as MethodInvocation;
+
+ var invocation = methodName.parent;
+ if (invocation is! MethodInvocation) {
+ return;
+ }
+
var arguments = invocation.argumentList.arguments;
- if (arguments.length != 1 || arguments[0] is! FunctionExpression) {
+ if (arguments.length != 1) {
return;
}
- var body = (arguments[0] as FunctionExpression).body;
- Expression returnValue;
+
+ var argument = arguments[0];
+ if (argument is! FunctionExpression) {
+ return;
+ }
+
+ Expression? returnValue;
+ var body = argument.body;
if (body is ExpressionFunctionBody) {
returnValue = body.expression;
} else if (body is BlockFunctionBody) {
var statements = body.block.statements;
- if (statements.length != 1 || statements[0] is! ReturnStatement) {
+ if (statements.length != 1) {
return;
}
- returnValue = (statements[0] as ReturnStatement).expression;
- } else {
- return;
+ var returnStatement = statements[0];
+ if (returnStatement is! ReturnStatement) {
+ return;
+ }
+ returnValue = returnStatement.expression;
}
+
if (returnValue is! IsExpression) {
return;
}
- var isExpression = returnValue as IsExpression;
+ var isExpression = returnValue;
if (isExpression.notOperator != null) {
return;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart
index 05d4f47..833a8db 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_class.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -14,7 +12,7 @@
import 'package:analyzer_plugin/utilities/range_factory.dart';
class CreateClass extends CorrectionProducer {
- String className;
+ String className = '';
@override
List<Object> get fixArguments => [className];
@@ -25,14 +23,14 @@
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
- Element prefixElement;
+ Element? prefixElement;
SimpleIdentifier nameNode;
- ArgumentList arguments;
+ ArgumentList? arguments;
+
if (node is Annotation) {
- var annotation = node as Annotation;
- var name = annotation.name;
- arguments = annotation.arguments;
- if (name == null || name.staticElement != null || arguments == null) {
+ var name = node.name;
+ arguments = node.arguments;
+ if (name.staticElement != null || arguments == null) {
// TODO(brianwilkerson) Consider supporting creating a class when the
// arguments are missing by also adding an empty argument list.
return;
@@ -59,9 +57,9 @@
var prefix = '';
var suffix = '';
var offset = -1;
- String filePath;
+ String? filePath;
if (prefixElement == null) {
- targetUnit = unit.declaredElement;
+ targetUnit = unit.declaredElement!;
var enclosingMember = node.thisOrAncestorMatching((node) =>
node is CompilationUnitMember && node.parent is CompilationUnit);
if (enclosingMember == null) {
@@ -76,7 +74,7 @@
var library = import.importedLibrary;
if (library != null) {
targetUnit = library.definingCompilationUnit;
- var targetSource = targetUnit.source;
+ var targetSource = targetUnit.source!;
try {
offset = targetSource.contents.data.length;
filePath = targetSource.fullName;
@@ -91,7 +89,7 @@
}
}
}
- if (offset < 0) {
+ if (filePath == null || offset < 0) {
return;
}
await builder.addDartFileEdit(filePath, (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor.dart
index 6526f89..e9be86a 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor.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/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -16,7 +14,8 @@
class CreateConstructor extends CorrectionProducer {
/// The name of the constructor being created.
- ConstructorName _constructorName;
+ /// TODO(migration) We set this node when we have the change.
+ late ConstructorName _constructorName;
@override
List<Object> get fixArguments => [_constructorName];
@@ -27,39 +26,43 @@
@override
Future<void> compute(ChangeBuilder builder) async {
final argumentList = node.parent is ArgumentList ? node.parent : node;
- if (argumentList is ArgumentList &&
- argumentList.parent is InstanceCreationExpression) {
- await _proposeFromInstanceCreation(builder, argumentList.parent);
+ if (argumentList is ArgumentList) {
+ var instanceCreation = argumentList.parent;
+ if (instanceCreation is InstanceCreationExpression) {
+ await _proposeFromInstanceCreation(builder, instanceCreation);
+ }
} else {
await _proposeFromConstructorName(builder);
}
}
Future<void> _proposeFromConstructorName(ChangeBuilder builder) async {
- SimpleIdentifier name;
- InstanceCreationExpression instanceCreation;
- if (node is SimpleIdentifier) {
- // name
- name = node as SimpleIdentifier;
- if (name.parent is ConstructorName) {
- _constructorName = name.parent as ConstructorName;
- if (_constructorName.name == name) {
- // Type.name
- if (_constructorName.parent is InstanceCreationExpression) {
- instanceCreation =
- _constructorName.parent as InstanceCreationExpression;
- // new Type.name()
- if (instanceCreation.constructorName != _constructorName) {
- return;
- }
+ var name = node;
+ if (name is! SimpleIdentifier) {
+ return;
+ }
+
+ InstanceCreationExpression? instanceCreation;
+ if (name.parent is ConstructorName) {
+ _constructorName = name.parent as ConstructorName;
+ if (_constructorName.name == name) {
+ // Type.name
+ if (_constructorName.parent is InstanceCreationExpression) {
+ instanceCreation =
+ _constructorName.parent as InstanceCreationExpression;
+ // new Type.name()
+ if (instanceCreation.constructorName != _constructorName) {
+ return;
}
}
}
}
+
// do we have enough information?
if (instanceCreation == null) {
return;
}
+
// prepare target interface type
var targetType = _constructorName.type.type;
if (targetType is! InterfaceType) {
@@ -67,23 +70,35 @@
}
// prepare target ClassDeclaration
- ClassElement targetElement = targetType.element;
+ var targetElement = targetType.element;
var targetResult = await sessionHelper.getElementDeclaration(targetElement);
+ if (targetResult == null) {
+ return;
+ }
var targetNode = targetResult.node;
if (targetNode is! ClassDeclaration) {
return;
}
+ var targetUnit = targetResult.resolvedUnit;
+ if (targetUnit == null) {
+ return;
+ }
+
// prepare location
- var targetLocation = CorrectionUtils(targetResult.resolvedUnit)
- .prepareNewConstructorLocation(targetNode);
+ var targetLocation =
+ CorrectionUtils(targetUnit).prepareNewConstructorLocation(targetNode);
+ if (targetLocation == null) {
+ return;
+ }
var targetFile = targetElement.source.fullName;
+ final instanceCreation_final = instanceCreation;
await builder.addDartFileEdit(targetFile, (builder) {
builder.addInsertion(targetLocation.offset, (builder) {
builder.write(targetLocation.prefix);
builder.writeConstructorDeclaration(targetElement.name,
- argumentList: instanceCreation.argumentList,
+ argumentList: instanceCreation_final.argumentList,
constructorName: name,
constructorNameGroupName: 'NAME');
builder.write(targetLocation.suffix);
@@ -112,14 +127,25 @@
// prepare target ClassDeclaration
var targetElement = constructorElement.enclosingElement;
var targetResult = await sessionHelper.getElementDeclaration(targetElement);
- var targetNode = targetResult?.node;
+ if (targetResult == null) {
+ return;
+ }
+ var targetNode = targetResult.node;
if (targetNode is! ClassDeclaration) {
return;
}
+ var targetUnit = targetResult.resolvedUnit;
+ if (targetUnit == null) {
+ return;
+ }
+
// prepare location
- var targetLocation = CorrectionUtils(targetResult.resolvedUnit)
- .prepareNewConstructorLocation(targetNode);
+ var targetLocation =
+ CorrectionUtils(targetUnit).prepareNewConstructorLocation(targetNode);
+ if (targetLocation == null) {
+ return;
+ }
var targetSource = targetElement.source;
var targetFile = targetSource.fullName;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index e8795a1f..02560a0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1732,15 +1732,15 @@
return fixes.isNotEmpty ? fixes.first : null;
}
- void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
- {List<Object> args, bool importsOnly = false}) {
+ void _addFixFromBuilder(ChangeBuilder builder, CorrectionProducer producer) {
if (builder == null) return;
var change = builder.sourceChange;
- if (change.edits.isEmpty && !importsOnly) {
+ if (change.edits.isEmpty) {
return;
}
+ var kind = producer.fixKind;
change.id = kind.id;
- change.message = formatList(kind.message, args);
+ change.message = formatList(kind.message, producer.fixArguments);
fixes.add(Fix(kind, change));
}
@@ -1764,8 +1764,7 @@
workspace: context.workspace, eol: context.utils.endOfLine);
try {
await producer.compute(builder);
- _addFixFromBuilder(builder, producer.fixKind,
- args: producer.fixArguments);
+ _addFixFromBuilder(builder, producer);
} on ConflictingEditException catch (exception, stackTrace) {
// Handle the exception by (a) not adding a fix based on the producer
// and (b) logging the exception.
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 84a6dbf..551ee3a 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -203,6 +203,7 @@
final Class listClass;
final Class typeClass;
final Procedure unsafeCastMethod;
+ final Procedure nativeEffectMethod;
final Class typedDataClass;
final Procedure typedDataBufferGetter;
final Procedure typedDataOffsetInBytesGetter;
@@ -294,6 +295,8 @@
typeClass = coreTypes.typeClass,
unsafeCastMethod =
index.getTopLevelMember('dart:_internal', 'unsafeCast'),
+ nativeEffectMethod =
+ index.getTopLevelMember('dart:_internal', '_nativeEffect'),
typedDataClass = index.getClass('dart:typed_data', 'TypedData'),
typedDataBufferGetter =
index.getMember('dart:typed_data', 'TypedData', 'get:buffer'),
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 1b69f26..20cfbe8 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -387,29 +387,29 @@
}
/// Prevents the struct from being tree-shaken in TFA by invoking its
- /// constructor in a let expression.
- ///
- /// TFA does not recognize this as dead code, only the VM does.
- /// TODO(http://dartbug.com/45607): Wrap with `_nativeEffect` to make the
- /// intent of this code clear.
+ /// constructor in a `_nativeEffect` expression.
Expression _invokeStructConstructor(
- Expression nestedExpression, Class structClass) {
- final constructor = structClass.constructors
+ Expression nestedExpression, Class compositeClass) {
+ final constructor = compositeClass.constructors
.firstWhere((c) => c.name == Name("#fromTypedDataBase"));
- return Let(
- VariableDeclaration.forValue(
- ConstructorInvocation(
- constructor,
- Arguments([
- StaticInvocation(
- uint8ListFactory,
- Arguments([
- ConstantExpression(IntConstant(1)),
- ]))
- ..fileOffset = nestedExpression.fileOffset,
- ]))
- ..fileOffset = nestedExpression.fileOffset,
- type: InterfaceType(structClass, Nullability.nonNullable)),
+ return BlockExpression(
+ Block([
+ ExpressionStatement(StaticInvocation(
+ nativeEffectMethod,
+ Arguments([
+ ConstructorInvocation(
+ constructor,
+ Arguments([
+ StaticInvocation(
+ uint8ListFactory,
+ Arguments([
+ ConstantExpression(IntConstant(1)),
+ ]))
+ ..fileOffset = nestedExpression.fileOffset,
+ ]))
+ ..fileOffset = nestedExpression.fileOffset
+ ])))
+ ]),
nestedExpression)
..fileOffset = nestedExpression.fileOffset;
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
index 66de23b..3469672 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/ffi_struct_constructors.dart.expect
@@ -65,13 +65,17 @@
}
static method testLookupFunctionReturn() → void {
final ffi::DynamicLibrary* dylib = [@vm.inferred-type.metadata=dart.ffi::DynamicLibrary?] ffi::DynamicLibrary::executable();
- final () →* self::Struct1* function1 = let final self::Struct1 #t1 = new self::Struct1::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)) in ffi::_asFunctionInternal<() →* self::Struct1*, () →* self::Struct1*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<() →* self::Struct1*>*>("function1"));
+ final () →* self::Struct1* function1 = block {
+ _in::_nativeEffect(new self::Struct1::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)));
+ } =>ffi::_asFunctionInternal<() →* self::Struct1*, () →* self::Struct1*>([@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup??] [@vm.inferred-type.metadata=dart.ffi::Pointer? (skip check)] dylib.{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<() →* self::Struct1*>*>("function1"));
final self::Struct1* struct1 = [@vm.call-site-attributes.metadata=receiverType:#lib::Struct1* Function()*] function1.call();
core::print(struct1);
}
static method testAsFunctionReturn() → void {
final ffi::Pointer<ffi::NativeFunction<() →* self::Struct2*>*>* pointer = [@vm.inferred-type.metadata=dart.ffi::Pointer?] ffi::Pointer::fromAddress<ffi::NativeFunction<() →* self::Struct2*>*>(3735928559);
- final () →* self::Struct2* function2 = let final self::Struct2 #t2 = new self::Struct2::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)) in ffi::_asFunctionInternal<() →* self::Struct2*, () →* self::Struct2*>(pointer);
+ final () →* self::Struct2* function2 = block {
+ _in::_nativeEffect(new self::Struct2::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)));
+ } =>ffi::_asFunctionInternal<() →* self::Struct2*, () →* self::Struct2*>(pointer);
final self::Struct2* struct2 = [@vm.call-site-attributes.metadata=receiverType:#lib::Struct2* Function()*] function2.call();
core::print(struct2);
}
@@ -79,7 +83,9 @@
return 42;
}
static method testFromFunctionArgument() → void {
- final ffi::Pointer<ffi::NativeFunction<(self::Struct3*) →* ffi::Int32*>*>* pointer = let final self::Struct3 #t3 = new self::Struct3::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)) in [@vm.inferred-type.metadata=dart.ffi::Pointer?] self::_#ffiCallback0;
+ final ffi::Pointer<ffi::NativeFunction<(self::Struct3*) →* ffi::Int32*>*>* pointer = block {
+ _in::_nativeEffect(new self::Struct3::#fromTypedDataBase([@vm.inferred-type.metadata=dart.typed_data::_Uint8List] typ::Uint8List::•(#C18)));
+ } =>[@vm.inferred-type.metadata=dart.ffi::Pointer?] self::_#ffiCallback0;
core::print(pointer);
}
static method testLookupFunctionArgument() → void {
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 11b7f60..507ce9d 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -279,6 +279,10 @@
return arguments->NativeArgAt(0);
}
+DEFINE_NATIVE_ENTRY(Internal_nativeEffect, 0, 1) {
+ UNREACHABLE();
+}
+
DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) {
UNREACHABLE();
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 3190883..fe0f192 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -333,6 +333,7 @@
V(GrowableList_setLength, 2) \
V(GrowableList_setData, 2) \
V(Internal_unsafeCast, 1) \
+ V(Internal_nativeEffect, 1) \
V(Internal_reachabilityFence, 1) \
V(Internal_collectAllGarbage, 0) \
V(Internal_makeListFixedLength, 1) \
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index d90c132..9dfcc4e 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -2643,7 +2643,7 @@
}
Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
- const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
const uint8_t flags = ReadFlags(); // read flags.
const bool is_invariant = (flags & kMethodInvocationFlagInvariant) != 0;
@@ -3007,7 +3007,9 @@
}
const auto recognized_kind = target.recognized_kind();
- if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
+ if (recognized_kind == MethodRecognizer::kNativeEffect) {
+ return BuildNativeEffect();
+ } else if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
return BuildFfiAsFunctionInternal();
} else if (CompilerState::Current().is_aot() &&
recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
@@ -5018,20 +5020,42 @@
return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildNativeEffect() {
+ const intptr_t argc = ReadUInt(); // Read argument count.
+ ASSERT(argc == 1); // Native side effect to ignore.
+ const intptr_t list_length = ReadListLength(); // Read types list length.
+ ASSERT(list_length == 0);
+
+ const intptr_t positional_count =
+ ReadListLength(); // Read positional argument count.
+ ASSERT(positional_count == 1);
+
+ BuildExpression(); // Consume expression but don't save the fragment.
+ Pop(); // Restore the stack.
+
+ const intptr_t named_args_len =
+ ReadListLength(); // Skip empty named arguments.
+ ASSERT(named_args_len == 0);
+
+ Fragment code;
+ code += NullConstant(); // Return type is void.
+ return code;
+}
+
Fragment StreamingFlowGraphBuilder::BuildFfiAsFunctionInternal() {
- const intptr_t argc = ReadUInt(); // read argument count.
- ASSERT(argc == 1); // pointer
- const intptr_t list_length = ReadListLength(); // read types list length.
- ASSERT(list_length == 2); // dart signature, then native signature
+ const intptr_t argc = ReadUInt(); // Read argument count.
+ ASSERT(argc == 1); // Pointer.
+ const intptr_t list_length = ReadListLength(); // Read types list length.
+ ASSERT(list_length == 2); // Dart signature, then native signature.
const TypeArguments& type_arguments =
- T.BuildTypeArguments(list_length); // read types.
+ T.BuildTypeArguments(list_length); // Read types.
Fragment code;
const intptr_t positional_count =
- ReadListLength(); // read positional argument count
+ ReadListLength(); // Read positional argument count.
ASSERT(positional_count == 1);
- code += BuildExpression(); // build first positional argument (pointer)
+ code += BuildExpression(); // Build first positional argument (pointer).
const intptr_t named_args_len =
- ReadListLength(); // skip (empty) named arguments list
+ ReadListLength(); // Skip empty named arguments list.
ASSERT(named_args_len == 0);
code += B->BuildFfiAsFunctionInternalCall(type_arguments);
return code;
@@ -5044,24 +5068,24 @@
//
// The FE also guarantees that all three arguments are constants.
- const intptr_t argc = ReadUInt(); // read argument count
- ASSERT(argc == 2); // target, exceptionalReturn
+ const intptr_t argc = ReadUInt(); // Read argument count.
+ ASSERT(argc == 2); // Target, exceptionalReturn.
- const intptr_t list_length = ReadListLength(); // read types list length
- ASSERT(list_length == 1); // native signature
+ const intptr_t list_length = ReadListLength(); // Read types list length.
+ ASSERT(list_length == 1); // The native signature.
const TypeArguments& type_arguments =
- T.BuildTypeArguments(list_length); // read types.
+ T.BuildTypeArguments(list_length); // Read types.
ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
const FunctionType& native_sig =
FunctionType::CheckedHandle(Z, type_arguments.TypeAt(0));
Fragment code;
const intptr_t positional_count =
- ReadListLength(); // read positional argument count
+ ReadListLength(); // Read positional argument count.
ASSERT(positional_count == 2);
// Read target expression and extract the target function.
- code += BuildExpression(); // build first positional argument (target)
+ code += BuildExpression(); // Build first positional argument (target).
Definition* target_def = B->Peek();
ASSERT(target_def->IsConstant());
const Closure& target_closure =
@@ -5081,7 +5105,7 @@
code += Drop();
const intptr_t named_args_len =
- ReadListLength(); // skip (empty) named arguments list
+ ReadListLength(); // Skip (empty) named arguments list.
ASSERT(named_args_len == 0);
const Function& result =
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 7f133f7..47f5bca 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -344,11 +344,14 @@
Fragment BuildFunctionNode(TokenPosition parent_position,
StringIndex name_index);
- // Build build FG for '_asFunctionInternal'. Reads an Arguments from the
+ // Build flow graph for '_nativeEffect'.
+ Fragment BuildNativeEffect();
+
+ // Build FG for '_asFunctionInternal'. Reads an Arguments from the
// Kernel buffer and pushes the resulting closure.
Fragment BuildFfiAsFunctionInternal();
- // Build build FG for '_nativeCallbackFunction'. Reads an Arguments from the
+ // Build FG for '_nativeCallbackFunction'. Reads an Arguments from the
// Kernel buffer and pushes the resulting Function object.
Fragment BuildFfiNativeCallbackFunction();
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 8a2fbbc..02acfb7 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -166,6 +166,7 @@
V(::, _abi, FfiAbi, 0x7c4ab775) \
V(::, _asFunctionInternal, FfiAsFunctionInternal, 0xbbcb235a) \
V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x3ff5ae9c) \
+ V(::, _nativeEffect, NativeEffect, 0x61e00b59) \
V(::, _loadInt8, FfiLoadInt8, 0x0f04dfd6) \
V(::, _loadInt16, FfiLoadInt16, 0xec44312d) \
V(::, _loadInt32, FfiLoadInt32, 0xee223fc3) \
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index c434ec9..7ee1e6b 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -163,11 +163,16 @@
T unsafeCast<T>(Object? v) native "Internal_unsafeCast";
// This function can be used to keep an object alive til that point.
-//
@pragma("vm:recognized", "other")
@pragma('vm:prefer-inline')
void reachabilityFence(Object object) native "Internal_reachabilityFence";
+// This function can be used to encode native side effects.
+//
+// The function call and it's argument are removed in flow graph construction.
+@pragma("vm:recognized", "other")
+void _nativeEffect(Object object) native "Internal_nativeEffect";
+
void sendAndExit(SendPort sendPort, var message)
native "SendPortImpl_sendAndExitInternal_";
diff --git a/tests/ffi/native_effect_test.dart b/tests/ffi/native_effect_test.dart
new file mode 100644
index 0000000..41d4aea
--- /dev/null
+++ b/tests/ffi/native_effect_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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.
+//
+// SharedObjects=ffi_test_functions
+
+// Tests that the dart:internal _nativeEffect flow graph builder works.
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+
+import 'dylib_utils.dart';
+
+void main() {
+ testReturnStruct1ByteInt();
+}
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Int8),
+ Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
+
+void testReturnStruct1ByteInt() {
+ final result = returnStruct1ByteInt(1);
+ Expect.equals(1, result.a0);
+}
+
+class Struct1ByteInt extends Struct {
+ @Int8()
+ external int a0;
+}
diff --git a/tests/ffi_2/native_effect_test.dart b/tests/ffi_2/native_effect_test.dart
new file mode 100644
index 0000000..1b88d14
--- /dev/null
+++ b/tests/ffi_2/native_effect_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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.
+//
+// SharedObjects=ffi_test_functions
+
+// Tests that the dart:internal _nativeEffect flow graph builder works.
+
+import 'dart:ffi';
+
+import "package:expect/expect.dart";
+
+import 'dylib_utils.dart';
+
+void main() {
+ testReturnStruct1ByteInt();
+}
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
+ Struct1ByteInt Function(Int8),
+ Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
+
+void testReturnStruct1ByteInt() {
+ final result = returnStruct1ByteInt(1);
+ Expect.equals(1, result.a0);
+}
+
+class Struct1ByteInt extends Struct {
+ @Int8()
+ int a0;
+}
diff --git a/tools/VERSION b/tools/VERSION
index 148a455..4df21bf 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 222
+PRERELEASE 223
PRERELEASE_PATCH 0
\ No newline at end of file