diff --git a/pkg/analyzer/lib/error/listener.dart b/pkg/analyzer/lib/error/listener.dart index d17980b716e6..ae189f5ef7d4 100644 --- a/pkg/analyzer/lib/error/listener.dart +++ b/pkg/analyzer/lib/error/listener.dart @@ -11,6 +11,7 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/diagnostic/diagnostic.dart'; import 'package:analyzer/error/error.dart'; import 'package:analyzer/source/source.dart'; +import 'package:analyzer/src/dart/element/type.dart'; import 'package:analyzer/src/diagnostic/diagnostic.dart'; import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; @@ -340,8 +341,10 @@ class ErrorReporter { Map> typeGroups = {}; for (int i = 0; i < arguments.length; i++) { var argument = arguments[i]; - if (argument is DartType) { - String displayName = argument.getDisplayString(); + if (argument is TypeImpl) { + String displayName = argument.getDisplayString( + preferTypeAlias: true, + ); List<_TypeToConvert> types = typeGroups.putIfAbsent(displayName, () => <_TypeToConvert>[]); types.add(_TypeToConvert(i, argument, displayName)); diff --git a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart index 72d28b4461fa..17ee32844d92 100644 --- a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart +++ b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart @@ -21,10 +21,14 @@ class ElementDisplayStringBuilder { /// Whether to allow a display string to be written in multiple lines. final bool _multiline; + /// Whether to write instantiated type alias when available. + final bool preferTypeAlias; + ElementDisplayStringBuilder({ @Deprecated('Only non-nullable by default mode is supported') bool withNullability = true, bool multiline = false, + required this.preferTypeAlias, }) : _withNullability = withNullability, _multiline = multiline; @@ -179,6 +183,10 @@ class ElementDisplayStringBuilder { } void writeFunctionType(FunctionType type) { + if (_maybeWriteTypeAlias(type)) { + return; + } + type = _uniqueTypeParameters(type); _writeType(type.returnType); @@ -201,6 +209,10 @@ class ElementDisplayStringBuilder { } void writeInterfaceType(InterfaceType type) { + if (_maybeWriteTypeAlias(type)) { + return; + } + _write(type.element.name); _writeTypeArguments(type.typeArguments); _writeNullability(type.nullabilitySuffix); @@ -245,6 +257,10 @@ class ElementDisplayStringBuilder { } void writeRecordType(RecordType type) { + if (_maybeWriteTypeAlias(type)) { + return; + } + var positionalFields = type.positionalFields; var namedFields = type.namedFields; var fieldCount = positionalFields.length + namedFields.length; @@ -355,6 +371,18 @@ class ElementDisplayStringBuilder { _write('void'); } + bool _maybeWriteTypeAlias(DartType type) { + if (preferTypeAlias) { + if (type.alias case var alias?) { + _write(alias.element.name); + _writeTypeArguments(alias.typeArguments); + _writeNullability(type.nullabilitySuffix); + return true; + } + } + return false; + } + void _write(String str) { _buffer.write(str); } diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart index 5dde963bfab9..240196b8c2c0 100644 --- a/pkg/analyzer/lib/src/dart/element/element.dart +++ b/pkg/analyzer/lib/src/dart/element/element.dart @@ -2486,9 +2486,11 @@ abstract class ElementImpl implements Element { @Deprecated('Only non-nullable by default mode is supported') bool withNullability = true, bool multiline = false, + bool preferTypeAlias = false, }) { var builder = ElementDisplayStringBuilder( multiline: multiline, + preferTypeAlias: preferTypeAlias, ); appendTo(builder); return builder.toString(); diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart index fb1555829911..3a49dbe194e2 100644 --- a/pkg/analyzer/lib/src/dart/element/member.dart +++ b/pkg/analyzer/lib/src/dart/element/member.dart @@ -713,9 +713,11 @@ abstract class Member implements Element { @Deprecated('Only non-nullable by default mode is supported') bool withNullability = true, bool multiline = false, + bool preferTypeAlias = false, }) { var builder = ElementDisplayStringBuilder( multiline: multiline, + preferTypeAlias: preferTypeAlias, ); appendTo(builder); return builder.toString(); diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart index 041a2eefff2a..faf40e9008c0 100644 --- a/pkg/analyzer/lib/src/dart/element/type.dart +++ b/pkg/analyzer/lib/src/dart/element/type.dart @@ -1342,10 +1342,12 @@ abstract class TypeImpl implements DartType { String getDisplayString({ @Deprecated('Only non-nullable by default mode is supported') bool withNullability = true, + bool preferTypeAlias = false, }) { var builder = ElementDisplayStringBuilder( // ignore:deprecated_member_use_from_same_package withNullability: withNullability, + preferTypeAlias: preferTypeAlias, ); appendTo(builder); return builder.toString(); diff --git a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart index ec3bed0bd5f8..49f1eae723d3 100644 --- a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart +++ b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart @@ -84,6 +84,48 @@ I x = E.v; ]); } + test_invalid_message_preferTypeAlias_functionType() async { + await assertErrorsInCode(''' +typedef A = T Function(); + +void f(A a) { + A b = a; +} +''', [ + error(WarningCode.UNUSED_LOCAL_VARIABLE, 61, 1), + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 65, 1, + messageContains: ['A', 'A']), + ]); + } + + test_invalid_message_preferTypeAlias_interfaceType() async { + await assertErrorsInCode(''' +typedef A = List; + +void f(A a) { + A b = a; +} +''', [ + error(WarningCode.UNUSED_LOCAL_VARIABLE, 56, 1), + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 60, 1, + messageContains: ['A', 'A']), + ]); + } + + test_invalid_message_preferTypeAlias_recordType() async { + await assertErrorsInCode(''' +typedef A = (T, T); + +void f(A a) { + A b = a; +} +''', [ + error(WarningCode.UNUSED_LOCAL_VARIABLE, 55, 1), + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 59, 1, + messageContains: ['A', 'A']), + ]); + } + test_invalid_noCall_functionContext() async { await assertErrorsInCode(''' class C {}