Version 2.16.0-133.0.dev
Merge commit '6e27367656c263fcce5fcb91586b3ea4a85e98d3' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
index 5f96489..e512626 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
@@ -40,117 +40,133 @@
/// Return `true` if the described element is a constructor.
bool get isConstructor => kind == ElementKind.constructorKind;
- /// Return `true` if the given [node] appears to be consistent with this kind
- /// of element.
+ /// Return `true` if the given [node] appears to be consistent with the
+ /// element being described.
bool matches(AstNode node) {
- // TODO(brianwilkerson) Check the resolved element if one exists for more
+ // TODO(brianwilkerson) Check the resolved element, if one exists, for more
// accurate results.
switch (kind) {
case ElementKind.classKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.constantKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.constructorKind:
- if (node is Annotation) {
- var className = _nameFromIdentifier(node.name);
- var constructorName = node.constructorName ?? '';
- if (components[0] == constructorName && components[1] == className) {
- return true;
- }
- } else if (node is InstanceCreationExpression) {
- var name = node.constructorName;
- var className = _nameFromIdentifier(name.type2.name);
- var constructorName = name.name?.name ?? '';
- if (components[0] == constructorName && components[1] == className) {
- return true;
- }
- } else if (node is MethodInvocation) {
- var target = node.target;
- if (target == null) {
- if (components[0] == '' && components[1] == node.methodName.name) {
- return true;
- }
- } else if (target is Identifier) {
- var className = _nameFromIdentifier(target);
- var constructorName = node.methodName.name;
- if (components[0] == constructorName &&
- components[1] == className) {
- return true;
- }
- }
- }
- return false;
+ return _matchesConstructor(node);
case ElementKind.enumKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.extensionKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.fieldKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.functionKind:
- if (node is MethodInvocation) {
- if (node.realTarget == null &&
- components[0] == node.methodName.name) {
- return true;
- }
- }
- return false;
+ return _matchesFunction(node);
case ElementKind.getterKind:
- // TODO: Handle this case.
+ // TODO(brianwilkerson) Handle this case.
return false;
case ElementKind.methodKind:
- if (node is MethodInvocation) {
- if (components[0] == node.methodName.name) {
- var target = node.realTarget;
- if (target == null) {
- // TODO(brianwilkerson) If `node.target == null` then the invocation
- // should be in a subclass of the element's class.
- return true;
- } else {
- var type = target.staticType;
- if (type == null && target is SimpleIdentifier) {
- var element = target.staticElement;
- // TODO(brianwilkerson) Handle more than `ClassElement`.
- if (element is ClassElement) {
- type = element.thisType;
- }
- }
- if (type == null) {
- // We can't get more specific type information, so we assume
- // that the method might have been in the element's class.
+ return _matchesMethod(node);
+ case ElementKind.mixinKind:
+ // TODO(brianwilkerson) Handle this case.
+ return false;
+ case ElementKind.setterKind:
+ // TODO(brianwilkerson) Handle this case.
+ return false;
+ case ElementKind.typedefKind:
+ // TODO(brianwilkerson) Handle this case.
+ return false;
+ case ElementKind.variableKind:
+ // TODO(brianwilkerson) Handle this case.
+ return false;
+ }
+ }
+
+ /// Return `true` if the given [node] appears to be consistent with the
+ /// constructor being described.
+ bool _matchesConstructor(AstNode node) {
+ if (node is Annotation) {
+ var className = _nameFromIdentifier(node.name);
+ var constructorName = node.constructorName ?? '';
+ if (components[0] == constructorName && components[1] == className) {
+ return true;
+ }
+ } else if (node is InstanceCreationExpression) {
+ var name = node.constructorName;
+ var className = _nameFromIdentifier(name.type2.name);
+ var constructorName = name.name?.name ?? '';
+ if (components[0] == constructorName && components[1] == className) {
+ return true;
+ }
+ } else if (node is MethodInvocation) {
+ var target = node.target;
+ if (target == null) {
+ if (components[0] == '' && components[1] == node.methodName.name) {
+ return true;
+ }
+ } else if (target is Identifier) {
+ var className = _nameFromIdentifier(target);
+ var constructorName = node.methodName.name;
+ if (components[0] == constructorName && components[1] == className) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /// Return `true` if the given [node] appears to be consistent with the
+ /// function being described.
+ bool _matchesFunction(AstNode node) {
+ if (node is MethodInvocation) {
+ if (node.realTarget == null && components[0] == node.methodName.name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// Return `true` if the given [node] appears to be consistent with the
+ /// method being described.
+ bool _matchesMethod(AstNode node) {
+ if (node is MethodInvocation) {
+ if (components[0] == node.methodName.name) {
+ var target = node.realTarget;
+ if (target == null) {
+ // TODO(brianwilkerson) If `node.target == null` then the invocation
+ // should be in a subclass of the element's class.
+ return true;
+ } else {
+ var type = target.staticType;
+ if (type == null && target is SimpleIdentifier) {
+ var element = target.staticElement;
+ // TODO(brianwilkerson) Handle more than `ClassElement`.
+ if (element is ClassElement) {
+ type = element.thisType;
+ }
+ }
+ if (type == null) {
+ // We can't get more specific type information, so we assume
+ // that the method might have been in the element's class.
+ return true;
+ }
+ if (components[1] == type.element?.name) {
+ return true;
+ }
+ if (type is InterfaceType) {
+ for (var supertype in type.allSupertypes) {
+ if (components[1] == supertype.element.name) {
return true;
}
- if (components[1] == type.element?.name) {
- return true;
- }
- if (type is InterfaceType) {
- for (var supertype in type.allSupertypes) {
- if (components[1] == supertype.element.name) {
- return true;
- }
- }
- }
}
}
}
- return false;
- case ElementKind.mixinKind:
- // TODO: Handle this case.
- return false;
- case ElementKind.setterKind:
- // TODO: Handle this case.
- return false;
- case ElementKind.typedefKind:
- // TODO: Handle this case.
- return false;
- case ElementKind.variableKind:
- // TODO: Handle this case.
- return false;
+ }
}
+ return false;
}
String _nameFromIdentifier(Identifier identifier) {
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 7abed7a..0186ba9 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -312,7 +312,7 @@
List<ProducerGenerator> _getGenerators(ErrorCode errorCode) {
if (errorCode is LintCode) {
- return FixProcessor.lintProducerMap[errorCode.name] ?? [];
+ return FixProcessor.lintProducerMap[errorCode.uniqueLintName] ?? [];
} else {
// todo (pq): consider support for multiGenerators
return FixProcessor.nonLintProducerMap[errorCode] ?? [];
@@ -326,6 +326,12 @@
/// used to create correction producers. The generators are then used to build
/// fixes for those diagnostics. The generators used for non-lint diagnostics
/// are in the [nonLintProducerMap].
+ ///
+ /// The keys of the map are the unique names of the lint codes without the
+ /// `LintCode.` prefix. Generally the unique name is the same as the name of
+ /// the lint, so most of the keys are constants defined by [LintNames]. But
+ /// when a lint produces multiple codes, each with a different unique name,
+ /// the unique name must be used here.
static final Map<String, List<ProducerGenerator>> lintProducerMap = {
LintNames.always_declare_return_types: [
AddReturnType.newInstance,
@@ -1355,7 +1361,7 @@
var errorCode = error.errorCode;
if (errorCode is LintCode) {
- var generators = lintProducerMap[errorCode.name] ?? [];
+ var generators = lintProducerMap[errorCode.uniqueLintName] ?? [];
for (var generator in generators) {
await compute(generator());
}
@@ -1428,3 +1434,12 @@
required this.fixCount,
});
}
+
+extension on LintCode {
+ String get uniqueLintName {
+ if (uniqueName.startsWith('LintCode.')) {
+ return uniqueName.substring(9);
+ }
+ return uniqueName;
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 2e361ad..8138fda 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -976,6 +976,57 @@
}
@override
+ void visitSuperFormalParameter(covariant SuperFormalParameterImpl node) {
+ SuperFormalParameterElementImpl element;
+ if (node.parent is DefaultFormalParameter) {
+ element = node.declaredElement as SuperFormalParameterElementImpl;
+ } else {
+ var nameNode = node.identifier;
+ if (_elementWalker != null) {
+ element =
+ _elementWalker!.getParameter() as SuperFormalParameterElementImpl;
+ } else {
+ // Only for recovery, this should not happen in valid code.
+ element = SuperFormalParameterElementImpl(
+ name: nameNode.name,
+ nameOffset: nameNode.offset,
+ parameterKind: node.kind,
+ );
+ _elementHolder.enclose(element);
+ element.isConst = node.isConst;
+ element.isExplicitlyCovariant = node.covariantKeyword != null;
+ element.isFinal = node.isFinal;
+ _setCodeRange(element, node);
+ }
+ nameNode.staticElement = element;
+ }
+
+ _setOrCreateMetadataElements(element, node.metadata);
+
+ _withElementHolder(ElementHolder(element), () {
+ _withElementWalker(
+ _elementWalker != null ? ElementWalker.forParameter(element) : null,
+ () {
+ _withNameScope(() {
+ _buildTypeParameterElements(node.typeParameters);
+ node.typeParameters?.accept(this);
+ node.type?.accept(this);
+ if (_elementWalker != null) {
+ node.parameters?.accept(this);
+ } else {
+ // Only for recovery, this should not happen in valid code.
+ element.type = node.type?.type ?? _dynamicType;
+ _withElementWalker(null, () {
+ node.parameters?.accept(this);
+ });
+ }
+ });
+ },
+ );
+ });
+ }
+
+ @override
void visitSwitchCase(SwitchCase node) {
_buildLabelElements(node.labels, false, true);
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index cd47b1b..1d7d77c 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -4159,6 +4159,15 @@
return;
}
+ // TODO(scheglov) Restore when working on errors.
+ if (_currentLibrary.featureSet.isEnabled(Feature.super_parameters)) {
+ if (constructor.parameters.parameters.any((parameter) {
+ return parameter.notDefault is SuperFormalParameter;
+ })) {
+ return;
+ }
+ }
+
// Ignore if the constructor has either an implicit super constructor
// invocation or a redirecting constructor invocation.
for (ConstructorInitializer constructorInitializer
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index 195647b..8a894ec 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -636,3 +636,14 @@
return class_(name).unnamedConstructor!;
}
}
+
+extension ExecutableElementExtensions on ExecutableElement {
+ SuperFormalParameterElement superFormalParameter(String name) {
+ for (var parameter in parameters) {
+ if (parameter is SuperFormalParameterElement && parameter.name == name) {
+ return parameter;
+ }
+ }
+ throw StateError('Not found: $name');
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 1b491ac..7d2c061 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -259,6 +259,7 @@
List<String> get experiments => [
EnableString.constructor_tearoffs,
EnableString.named_arguments_anywhere,
+ EnableString.super_parameters,
];
/// The path that is not in [workspaceRootPath], contains external packages.
diff --git a/pkg/analyzer/test/src/dart/resolution/super_formal_parameter_test.dart b/pkg/analyzer/test/src/dart/resolution/super_formal_parameter_test.dart
new file mode 100644
index 0000000..6a24380
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/super_formal_parameter_test.dart
@@ -0,0 +1,130 @@
+// 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.
+
+import 'package:analyzer/src/test_utilities/find_element.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(SuperFormalParameterTest);
+ });
+}
+
+@reflectiveTest
+class SuperFormalParameterTest extends PubPackageResolutionTest {
+ test_functionTyped() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ A(Object a);
+}
+
+class B extends A {
+ B(super.a<T>(int b));
+}
+''');
+
+ var B = findElement.unnamedConstructor('B');
+ var element = B.superFormalParameter('a');
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ element,
+ );
+
+ assertElement(
+ findNode.typeParameter('T>'),
+ element.typeParameters[0],
+ );
+
+ assertElement(
+ findNode.simpleFormalParameter('b));'),
+ element.parameters[0],
+ );
+ }
+
+ test_invalid_notConstructor() async {
+ await assertNoErrorsInCode(r'''
+void f(super.a) {}
+''');
+
+ var f = findElement.topFunction('f');
+ var element = f.superFormalParameter('a');
+ assertTypeDynamic(element.type);
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ element,
+ );
+ }
+
+ test_optionalNamed() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ A({int? a});
+}
+
+class B extends A {
+ B({super.a});
+}
+''');
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ findElement.unnamedConstructor('B').superFormalParameter('a'),
+ );
+ }
+
+ test_optionalPositional() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ A([int? a]);
+}
+
+class B extends A {
+ B([super.a]);
+}
+''');
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ findElement.unnamedConstructor('B').superFormalParameter('a'),
+ );
+ }
+
+ test_requiredNamed() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ A({required int a});
+}
+
+class B extends A {
+ B({required super.a});
+}
+''');
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ findElement.unnamedConstructor('B').superFormalParameter('a'),
+ );
+ }
+
+ test_requiredPositional() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ A(int a);
+}
+
+class B extends A {
+ B(super.a);
+}
+''');
+
+ assertElement(
+ findNode.superFormalParameter('super.a'),
+ findElement.unnamedConstructor('B').superFormalParameter('a'),
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 0c72655..759b9e5 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -58,6 +58,7 @@
import 'prefixed_identifier_test.dart' as prefixed_identifier;
import 'property_access_test.dart' as property_access;
import 'simple_identifier_test.dart' as simple_identifier;
+import 'super_formal_parameter_test.dart' as super_formal_parameter;
import 'top_level_variable_test.dart' as top_level_variable;
import 'top_type_inference_test.dart' as top_type_inference;
import 'try_statement_test.dart' as try_statement;
@@ -119,6 +120,7 @@
prefixed_identifier.main();
property_access.main();
simple_identifier.main();
+ super_formal_parameter.main();
top_level_variable.main();
top_type_inference.main();
try_statement.main();
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 9b74e08..3d50b66 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1525,6 +1525,23 @@
''');
}
+ test_class_constructor_parameters_super_invalid_topFunction() async {
+ var library = await checkLibrary('''
+void f(super.a) {}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ functions
+ f @5
+ parameters
+ requiredPositional final super.a @13
+ type: dynamic
+ superConstructorParameter: <null>
+ returnType: void
+''');
+ }
+
test_class_constructor_parameters_super_optionalNamed() async {
var library = await checkLibrary('''
class A {
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
index 04ab329..ca17b41 100644
--- a/pkg/analyzer_plugin/CHANGELOG.md
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.9.0
+- Support version `3.x` of the `analyzer` package
+
## 0.8.0
- Require SDK `2.14` to use `Object.hash()`.
- Require `yaml 3.1.0` to use `recover`.
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 41b859d..c8b99c8 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -1,15 +1,15 @@
name: analyzer_plugin
description: A framework and support code for building plugins for the analysis server.
-version: 0.8.0
+version: 0.9.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin
environment:
sdk: '>=2.14.0 <3.0.0'
dependencies:
- analyzer: ^2.4.0
+ analyzer: ^3.0.0
collection: ^1.15.0
- dart_style: ^2.0.0
+ dart_style: ^2.2.1
pub_semver: ^2.0.0
yaml: ^3.1.0
diff --git a/tools/VERSION b/tools/VERSION
index e95ca1b..5cbc6ee 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 132
+PRERELEASE 133
PRERELEASE_PATCH 0
\ No newline at end of file