diff --git a/pkg/analyzer/lib/src/dart/element/extensions.dart b/pkg/analyzer/lib/src/dart/element/extensions.dart index e644fc094297..b31e8f74b224 100644 --- a/pkg/analyzer/lib/src/dart/element/extensions.dart +++ b/pkg/analyzer/lib/src/dart/element/extensions.dart @@ -2,6 +2,7 @@ // 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/dart/analysis/features.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; @@ -116,6 +117,16 @@ extension ElementExtension on Element { } return false; } + + /// Return true if this element is a wildcard variable. + bool get isWildcardVariable => + name == '_' && + (this is LocalVariableElement || + this is TypeParameterElement || + (this is ParameterElement && + this is! FieldFormalParameterElement && + this is! SuperFormalParameterElement)) && + (library?.featureSet.isEnabled(Feature.wildcard_variables) ?? false); } extension ExecutableElementExtension on ExecutableElement { diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart index 557d766aa904..07e75e6eca3d 100644 --- a/pkg/analyzer/lib/src/dart/element/scope.dart +++ b/pkg/analyzer/lib/src/dart/element/scope.dart @@ -7,6 +7,7 @@ import 'package:analyzer/dart/analysis/features.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/scope.dart'; import 'package:analyzer/src/dart/element/element.dart'; +import 'package:analyzer/src/dart/element/extensions.dart'; import 'package:analyzer/src/summary2/combinator.dart'; import 'package:analyzer/src/utilities/extensions/collection.dart'; @@ -440,10 +441,3 @@ class _LibraryOrAugmentationImportScope implements Scope { return _nullPrefixScope.lookup(id); } } - -extension on Element { - bool get isWildcardVariable => - name == '_' && - (this is LocalVariableElement || this is ParameterElement) && - (library?.featureSet.isEnabled(Feature.wildcard_variables) ?? false); -} diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart index b6d15c1db21a..51f80ef1ff22 100644 --- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart +++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart @@ -9,6 +9,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/error/error.dart'; import 'package:analyzer/error/listener.dart'; import 'package:analyzer/src/dart/ast/ast.dart'; +import 'package:analyzer/src/dart/element/extensions.dart'; import 'package:analyzer/src/dart/element/inheritance_manager3.dart'; import 'package:analyzer/src/diagnostic/diagnostic_factory.dart'; import 'package:analyzer/src/error/codes.dart'; @@ -33,6 +34,8 @@ class DuplicateDefinitionVerifier { var exceptionParameter = node.exceptionParameter; var stackTraceParameter = node.stackTraceParameter; if (exceptionParameter != null && stackTraceParameter != null) { + var element = exceptionParameter.declaredElement; + if (element != null && element.isWildcardVariable) return; String exceptionName = exceptionParameter.name.lexeme; if (exceptionName == stackTraceParameter.name.lexeme) { _errorReporter.reportError(_diagnosticFactory @@ -533,7 +536,7 @@ class DuplicateDefinitionVerifier { void _checkDuplicateIdentifier( Map getterScope, Token identifier, {required Element element, Map? setterScope}) { - if (identifier.isSynthetic) { + if (identifier.isSynthetic || element.isWildcardVariable) { return; } diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart index 9fba60e24675..f64ddf9272b4 100644 --- a/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart +++ b/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart @@ -1894,6 +1894,30 @@ void f() { ]); } + test_block_localVariable_localVariable_wildcard() async { + await assertNoErrorsInCode(r''' +void f() { + var _ = 0; + var _ = 1; +} +'''); + } + + test_block_localVariable_localVariable_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +void f() { + var _ = 0; + var _ = 1; +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 74, 1, + contextMessages: [message(testFile, 61, 1)]), + ]); + } + test_block_localVariable_patternVariable() async { await assertErrorsInCode(r''' void f() { @@ -1908,6 +1932,27 @@ void f() { ]); } + test_block_localVariable_patternVariable_wildcard() async { + await assertNoErrorsInCode(r''' +void f() { + var _ = 0; + var (_) = 1; +} +'''); + } + + test_block_localVariable_patternVariable_wildcard_preWildcards() async { + await assertNoErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +void f() { + var _ = 0; + var (_) = 1; +} +'''); + } + test_block_patternVariable_localVariable() async { await assertErrorsInCode(r''' void f() { @@ -1947,6 +1992,26 @@ main() { ]); } + test_catch_wildcard() async { + await assertNoErrorsInCode(r''' +f() { + try {} catch (_, _) {} +}'''); + } + + test_catch_wildcard_preWildCards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +f() { + try {} catch (_, _) {} +}''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 69, 1, + contextMessages: [message(testFile, 66, 1)]), + ]); + } + test_emptyName() async { // Note: This code has two FunctionElements '() {}' with an empty name; this // tests that the empty string is not put into the scope (more than once). @@ -1972,6 +2037,28 @@ f() { ]); } + test_for_initializers_wildcard() async { + await assertNoErrorsInCode(r''' +f() { + for (int _ = 0, _ = 0; ;) {} +} +'''); + } + + test_for_initializers_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +f() { + for (int _ = 0, _ = 0; ;) {} +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 68, 1, + contextMessages: [message(testFile, 61, 1)]), + ]); + } + test_getter_single() async { await assertNoErrorsInCode(''' bool get a => true; @@ -1990,6 +2077,33 @@ class A { ]); } + test_parameters_constructor_field_first_wildcard() async { + await assertErrorsInCode(r''' +class A { + int? _; + A(this._, int _); +} +''', [ + error(WarningCode.UNUSED_FIELD, 17, 1), + ]); + } + + test_parameters_constructor_field_first_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + int? _; + A(this._, int _); +} +''', [ + error(WarningCode.UNUSED_FIELD, 61, 1), + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 80, 1, + contextMessages: [message(testFile, 73, 1)]), + ]); + } + test_parameters_constructor_field_second() async { await assertErrorsInCode(r''' class A { @@ -2002,6 +2116,68 @@ class A { ]); } + test_parameters_constructor_field_second_wildcard() async { + await assertErrorsInCode(r''' +class A { + int? _; + A(int _, this._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 17, 1), + ]); + } + + test_parameters_constructor_field_second_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + int? _; + A(int _, this._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 61, 1), + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 80, 1, + contextMessages: [message(testFile, 72, 1)]), + ]); + } + + test_parameters_constructor_super_first_wildcard() async { + await assertErrorsInCode(r''' +class A { + int? _; + A(this._); +} +class B extends A { + B(super._, super._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 17, 1), + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 74, 1, + contextMessages: [message(testFile, 65, 1)]), + ]); + } + + test_parameters_constructor_super_first_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + int? _; + A(this._); +} +class B extends A { + B(super._, super._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 61, 1), + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 118, 1, + contextMessages: [message(testFile, 109, 1)]), + ]); + } + test_parameters_functionTypeAlias() async { await assertErrorsInCode(r''' typedef void F(int a, double a); @@ -2011,6 +2187,24 @@ typedef void F(int a, double a); ]); } + test_parameters_functionTypeAlias_wildcard() async { + await assertNoErrorsInCode(r''' +typedef void F(int _, double _); +'''); + } + + test_parameters_functionTypeAlias_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef void F(int _, double _); +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 73, 1, + contextMessages: [message(testFile, 63, 1)]), + ]); + } + test_parameters_genericFunction() async { await assertErrorsInCode(r''' typedef F = void Function(int a, double a); @@ -2020,6 +2214,24 @@ typedef F = void Function(int a, double a); ]); } + test_parameters_genericFunction_wildcard() async { + await assertNoErrorsInCode(r''' +typedef F = void Function(int _, double _); +'''); + } + + test_parameters_genericFunction_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef F = void Function(int _, double _); +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 84, 1, + contextMessages: [message(testFile, 74, 1)]), + ]); + } + test_parameters_localFunction() async { await assertErrorsInCode(r''' main() { @@ -2033,6 +2245,31 @@ main() { ]); } + test_parameters_localFunction_wildcard() async { + await assertErrorsInCode(r''' +f() { + g(int _, double _) {}; +} +''', [ + error(WarningCode.UNUSED_ELEMENT, 8, 1), + ]); + } + + test_parameters_localFunction_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +f() { + g(int _, double _) {}; +} +''', [ + error(WarningCode.UNUSED_ELEMENT, 52, 1), + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 68, 1, + contextMessages: [message(testFile, 58, 1)]), + ]); + } + test_parameters_method() async { await assertErrorsInCode(r''' class A { @@ -2045,6 +2282,30 @@ class A { ]); } + test_parameters_method_wildcard() async { + await assertNoErrorsInCode(r''' +class A { + m(int _, double _) { + } +} +'''); + } + + test_parameters_method_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + m(int _, double _) { + } +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 72, 1, + contextMessages: [message(testFile, 62, 1)]), + ]); + } + test_parameters_topLevelFunction() async { await assertErrorsInCode(r''' f(int a, double a) {} @@ -2054,6 +2315,24 @@ f(int a, double a) {} ]); } + test_parameters_topLevelFunction_wildcard() async { + await assertNoErrorsInCode(r''' +f(int _, double _) {} +'''); + } + + test_parameters_topLevelFunction_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +f(int _, double _) {} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 60, 1, + contextMessages: [message(testFile, 50, 1)]), + ]); + } + test_switchCase_localVariable_localVariable() async { await assertErrorsInCode(r''' // @dart = 2.19 @@ -2089,6 +2368,36 @@ void f() { ]); } + test_switchDefault_localVariable_localVariable_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +void f() { + switch (0) { + default: + var _; + var _; + } +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 106, 1, + contextMessages: [message(testFile, 93, 1)]), + ]); + } + + test_switchDefault_localVariable_localVariable_wildcard() async { + await assertNoErrorsInCode(r''' +void f() { + switch (0) { + default: + var _; + var _; + } +} +'''); + } + test_switchPatternCase_localVariable_localVariable() async { await assertErrorsInCode(r''' void f() { @@ -2106,6 +2415,36 @@ void f() { ]); } + test_switchPatternCase_localVariable_localVariable_wildcard() async { + await assertNoErrorsInCode(r''' +void f() { + switch (0) { + case 0: + var _; + var _; + } +} +'''); + } + + test_switchPatternCase_localVariable_localVariable_wildcard_preWildCards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +void f() { + switch (0) { + case 0: + var _; + var _; + } +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 105, 1, + contextMessages: [message(testFile, 92, 1)]), + ]); + } + test_typeParameters_class() async { await assertErrorsInCode(r''' class A {} @@ -2115,6 +2454,24 @@ class A {} ]); } + test_typeParameters_class_wildcard() async { + await assertNoErrorsInCode(r''' +class A<_, _> {} +'''); + } + + test_typeParameters_class_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A<_, _> {} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 55, 1, + contextMessages: [message(testFile, 52, 1)]), + ]); + } + test_typeParameters_functionTypeAlias() async { await assertErrorsInCode(r''' typedef void F(); @@ -2124,6 +2481,24 @@ typedef void F(); ]); } + test_typeParameters_functionTypeAlias_wildcard() async { + await assertNoErrorsInCode(r''' +typedef void F<_, _>(); +'''); + } + + test_typeParameters_functionTypeAlias_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef void F<_, _>(); +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 62, 1, + contextMessages: [message(testFile, 59, 1)]), + ]); + } + test_typeParameters_genericFunction() async { await assertErrorsInCode(r''' typedef F = void Function(); @@ -2133,6 +2508,24 @@ typedef F = void Function(); ]); } + test_typeParameters_genericFunction_wildcard() async { + await assertNoErrorsInCode(r''' +typedef F = void Function<_, _>(); +'''); + } + + test_typeParameters_genericFunction_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef F = void Function<_, _>(); +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 73, 1, + contextMessages: [message(testFile, 70, 1)]), + ]); + } + test_typeParameters_genericTypedef_functionType() async { await assertErrorsInCode(r''' typedef F = void Function(); @@ -2142,6 +2535,24 @@ typedef F = void Function(); ]); } + test_typeParameters_genericTypedef_functionType_wildcard() async { + await assertNoErrorsInCode(r''' +typedef F<_, _> = void Function(); +'''); + } + + test_typeParameters_genericTypedef_functionType_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef F<_, _> = void Function(); +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 57, 1, + contextMessages: [message(testFile, 54, 1)]), + ]); + } + test_typeParameters_genericTypedef_interfaceType() async { await assertErrorsInCode(r''' typedef F = Map; @@ -2151,6 +2562,24 @@ typedef F = Map; ]); } + test_typeParameters_genericTypedef_interfaceType_wildcard() async { + await assertNoErrorsInCode(r''' +typedef F<_, _> = Map; +'''); + } + + test_typeParameters_genericTypedef_interfaceType_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +typedef F<_, _> = Map; +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 57, 1, + contextMessages: [message(testFile, 54, 1)]), + ]); + } + test_typeParameters_method() async { await assertErrorsInCode(r''' class A { @@ -2162,6 +2591,28 @@ class A { ]); } + test_typeParameters_method_wildcard() async { + await assertNoErrorsInCode(r''' +class A { + void m<_, _>() {} +} +'''); + } + + test_typeParameters_method_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + void m<_, _>() {} +} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 66, 1, + contextMessages: [message(testFile, 63, 1)]), + ]); + } + test_typeParameters_topLevelFunction() async { await assertErrorsInCode(r''' void f() {} @@ -2170,6 +2621,24 @@ void f() {} contextMessages: [message(testFile, 7, 1)]), ]); } + + test_typeParameters_topLevelFunction_wildcard() async { + await assertNoErrorsInCode(r''' +void f<_, _>() {} +'''); + } + + test_typeParameters_topLevelFunction_wildcard_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +void f<_, _>() {} +''', [ + error(CompileTimeErrorCode.DUPLICATE_DEFINITION, 54, 1, + contextMessages: [message(testFile, 51, 1)]), + ]); + } } @reflectiveTest diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart index 1b80c9ab4eb7..45a7c5ea7130 100644 --- a/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart +++ b/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart @@ -86,4 +86,34 @@ class A { contextMessages: [message(testFile, 30, 1)]), ]); } + + test_required_positional_preWildcards() async { + await assertErrorsInCode(r''' +// @dart = 3.4 +// (pre wildcard-variables) + +class A { + int? _; + A(this._, this._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 61, 1), + error(CompileTimeErrorCode.DUPLICATE_FIELD_FORMAL_PARAMETER, 81, 1, + contextMessages: [message(testFile, 73, 1)]), + ]); + } + + // TODO(pq): add more tests (https://github.com/dart-lang/sdk/issues/56092) + test_required_positional_wildcard() async { + await assertErrorsInCode(r''' +class A { + int? _; + A(this._, this._); +} +''', [ + error(WarningCode.UNUSED_FIELD, 17, 1), + error(CompileTimeErrorCode.DUPLICATE_FIELD_FORMAL_PARAMETER, 37, 1, + contextMessages: [message(testFile, 29, 1)]), + ]); + } }