Version 2.15.0-95.0.dev
Merge commit 'e319cfa6aa2a15ee2b87e7168bb2f2ffda31e7ea' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index b5bdf0d..a0caf52 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -416,16 +416,7 @@
return false;
}
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
- String name = code.name;
- if (ignoreInfo.ignoredAt(name, errorLine)) {
- return true;
- }
- String uniqueName = code.uniqueName;
- int period = uniqueName.indexOf('.');
- if (period >= 0) {
- uniqueName = uniqueName.substring(period + 1);
- }
- return uniqueName != name && ignoreInfo.ignoredAt(uniqueName, errorLine);
+ return ignoreInfo.ignoredAt(code, errorLine);
}
return errors.where((AnalysisError e) => !isIgnored(e)).toList();
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index 9057b2c..1ffe3d4 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -443,14 +443,7 @@
inner.invertVariance();
var returnType = type.returnType.accept(inner);
-
- var alias = type.alias;
- var newAlias = alias != null
- ? InstantiatedTypeAliasElementImpl(
- element: alias.element,
- typeArguments: _mapList(alias.typeArguments),
- )
- : null;
+ var alias = _mapAlias(type.alias);
if (useCounter == before) return type;
@@ -459,7 +452,7 @@
parameters: parameters,
returnType: returnType,
nullabilitySuffix: type.nullabilitySuffix,
- alias: newAlias,
+ alias: alias,
);
}
@@ -509,12 +502,13 @@
@override
DartType visitInterfaceType(InterfaceType type) {
- if (type.typeArguments.isEmpty) {
+ if (type.typeArguments.isEmpty && type.alias == null) {
return type;
}
int before = useCounter;
var typeArguments = _mapList(type.typeArguments);
+ var alias = _mapAlias(type.alias);
if (useCounter == before) {
return type;
}
@@ -523,6 +517,7 @@
element: type.element,
typeArguments: typeArguments,
nullabilitySuffix: type.nullabilitySuffix,
+ alias: alias,
);
}
@@ -569,6 +564,17 @@
@override
DartType visitVoidType(VoidType type) => type;
+ InstantiatedTypeAliasElementImpl? _mapAlias(
+ InstantiatedTypeAliasElement? alias,
+ ) {
+ if (alias != null) {
+ return InstantiatedTypeAliasElementImpl(
+ element: alias.element,
+ typeArguments: _mapList(alias.typeArguments),
+ );
+ }
+ }
+
List<DartType> _mapList(List<DartType> types) {
return types.map((e) => e.accept(this)).toList();
}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 359d754..2b2efd4 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -413,7 +413,7 @@
bool isIgnored(AnalysisError error) {
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
- return ignoreInfo.ignoredAt(error.errorCode.name, errorLine);
+ return ignoreInfo.ignoredAt(error.errorCode, errorLine);
}
return errors.where((AnalysisError e) => !isIgnored(e)).toList();
diff --git a/pkg/analyzer/lib/src/error/ignore_validator.dart b/pkg/analyzer/lib/src/error/ignore_validator.dart
index 5b9844a..0c0d4ec 100644
--- a/pkg/analyzer/lib/src/error/ignore_validator.dart
+++ b/pkg/analyzer/lib/src/error/ignore_validator.dart
@@ -46,28 +46,44 @@
// Report and remove any un-ignorable or duplicated names.
//
var namesIgnoredForFile = <String>{};
+ var typesIgnoredForFile = <String>{};
var unignorable = <DiagnosticName>[];
- var duplicated = <DiagnosticName>[];
- for (var ignoredName in ignoredForFile) {
- var name = ignoredName.name;
- if (_unignorableNames.contains(name)) {
- unignorable.add(ignoredName);
- } else if (!namesIgnoredForFile.add(name)) {
- duplicated.add(ignoredName);
+ var duplicated = <IgnoredElement>[];
+ for (var ignoredElement in ignoredForFile) {
+ if (ignoredElement is DiagnosticName) {
+ var name = ignoredElement.name;
+ if (_unignorableNames.contains(name)) {
+ unignorable.add(ignoredElement);
+ } else if (!namesIgnoredForFile.add(name)) {
+ duplicated.add(ignoredElement);
+ }
+ } else if (ignoredElement is DiagnosticType) {
+ if (!typesIgnoredForFile.add(ignoredElement.type)) {
+ duplicated.add(ignoredElement);
+ }
}
}
_reportUnknownAndDuplicateIgnores(unignorable, duplicated, ignoredForFile);
for (var ignoredOnLine in ignoredOnLineMap.values) {
var namedIgnoredOnLine = <String>{};
- var unignorable = <DiagnosticName>[];
- var duplicated = <DiagnosticName>[];
- for (var ignoredName in ignoredOnLine) {
- var name = ignoredName.name;
- if (_unignorableNames.contains(name)) {
- unignorable.add(ignoredName);
- } else if (namesIgnoredForFile.contains(name) ||
- !namedIgnoredOnLine.add(name)) {
- duplicated.add(ignoredName);
+ var typesIgnoredOnLine = <String>{};
+ var unignorable = <IgnoredElement>[];
+ var duplicated = <IgnoredElement>[];
+ for (var ignoredElement in ignoredOnLine) {
+ if (ignoredElement is DiagnosticName) {
+ var name = ignoredElement.name;
+ if (_unignorableNames.contains(name)) {
+ unignorable.add(ignoredElement);
+ } else if (namesIgnoredForFile.contains(name) ||
+ !namedIgnoredOnLine.add(name)) {
+ duplicated.add(ignoredElement);
+ }
+ } else if (ignoredElement is DiagnosticType) {
+ var type = ignoredElement.type;
+ if (typesIgnoredForFile.contains(type) ||
+ !typesIgnoredOnLine.add(type)) {
+ duplicated.add(ignoredElement);
+ }
}
}
_reportUnknownAndDuplicateIgnores(unignorable, duplicated, ignoredOnLine);
@@ -96,8 +112,8 @@
/// Report the names that are [unignorable] or [duplicated] and remove them
/// from the [list] of names from which they were extracted.
- void _reportUnknownAndDuplicateIgnores(List<DiagnosticName> unignorable,
- List<DiagnosticName> duplicated, List<DiagnosticName> list) {
+ void _reportUnknownAndDuplicateIgnores(List<IgnoredElement> unignorable,
+ List<IgnoredElement> duplicated, List<IgnoredElement> list) {
// TODO(brianwilkerson) Uncomment the code below after the unignorable
// ignores in the Flutter code base have been cleaned up.
// for (var unignorableName in unignorable) {
@@ -106,16 +122,26 @@
// unignorableName.offset, name.length, [name]);
// list.remove(unignorableName);
// }
- for (var ignoredName in duplicated) {
- var name = ignoredName.name;
- _errorReporter.reportErrorForOffset(
- HintCode.DUPLICATE_IGNORE, ignoredName.offset, name.length, [name]);
- list.remove(ignoredName);
+ for (var ignoredElement in duplicated) {
+ if (ignoredElement is DiagnosticName) {
+ var name = ignoredElement.name;
+ _errorReporter.reportErrorForOffset(HintCode.DUPLICATE_IGNORE,
+ ignoredElement.offset, name.length, [name]);
+ list.remove(ignoredElement);
+ } else if (ignoredElement is DiagnosticType) {
+ _errorReporter.reportErrorForOffset(
+ HintCode.DUPLICATE_IGNORE,
+ ignoredElement.offset,
+ ignoredElement.length,
+ [ignoredElement.type],
+ );
+ list.remove(ignoredElement);
+ }
}
}
/// Report the [ignoredNames] as being unnecessary.
- void _reportUnnecessaryIgnores(List<DiagnosticName> ignoredNames) {
+ void _reportUnnecessaryIgnores(List<IgnoredElement> ignoredNames) {
// TODO(brianwilkerson) Uncomment the code below after the unnecessary
// ignores in the Flutter code base have been cleaned up.
// for (var ignoredName in ignoredNames) {
@@ -140,8 +166,9 @@
}
}
-extension on List<DiagnosticName> {
+extension on List<IgnoredElement> {
void removeByName(String name) {
- removeWhere((ignoredName) => ignoredName.name == name);
+ removeWhere((ignoredElement) =>
+ ignoredElement is DiagnosticName && ignoredElement.name == name);
}
}
diff --git a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
index b2e5b12..4b37ce5 100644
--- a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
+++ b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
@@ -4,14 +4,14 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/ast/token.dart';
/// The name and location of a diagnostic name in an ignore comment.
-class DiagnosticName {
+class DiagnosticName implements IgnoredElement {
/// The name of the diagnostic being ignored.
final String name;
- /// The offset of the diagnostic in the source file.
final int offset;
/// Initialize a newly created diagnostic name to have the given [name] and
@@ -19,10 +19,40 @@
DiagnosticName(this.name, this.offset);
/// Return `true` if this diagnostic name matches the given error code.
- bool matches(String errorCode) => name == errorCode;
+ @override
+ bool matches(ErrorCode errorCode) {
+ if (name == errorCode.name.toLowerCase()) {
+ return true;
+ }
+ var uniqueName = errorCode.uniqueName;
+ var period = uniqueName.indexOf('.');
+ if (period >= 0) {
+ uniqueName = uniqueName.substring(period + 1);
+ }
+ return name == uniqueName.toLowerCase();
+ }
}
-/// Information about analysis `//ignore:` and `//ignore_for_file` comments
+class DiagnosticType implements IgnoredElement {
+ final String type;
+
+ final int offset;
+
+ final int length;
+
+ DiagnosticType(String type, this.offset, this.length)
+ : type = type.toLowerCase();
+
+ @override
+ bool matches(ErrorCode errorCode) =>
+ type == errorCode.type.name.toLowerCase();
+}
+
+abstract class IgnoredElement {
+ bool matches(ErrorCode errorCode);
+}
+
+/// Information about analysis `//ignore:` and `//ignore_for_file:` comments
/// within a source file.
class IgnoreInfo {
/// A regular expression for matching 'ignore' comments.
@@ -36,13 +66,13 @@
static final RegExp IGNORE_FOR_FILE_MATCHER =
RegExp(r'//[ ]*ignore_for_file:');
- /// A table mapping line numbers to the diagnostics that are ignored on that
- /// line.
- final Map<int, List<DiagnosticName>> _ignoredOnLine = {};
+ /// A table mapping line numbers to the elements (diagnostics and diagnostic
+ /// types) that are ignored on that line.
+ final Map<int, List<IgnoredElement>> _ignoredOnLine = {};
- /// A list containing all of the diagnostics that are ignored for the whole
- /// file.
- final List<DiagnosticName> _ignoredForFile = [];
+ /// A list containing all of the elements (diagnostics and diagnostic types)
+ /// that are ignored for the whole file.
+ final List<IgnoredElement> _ignoredForFile = [];
/// Initialize a newly created instance of this class to represent the ignore
/// comments in the given compilation [unit].
@@ -62,9 +92,9 @@
}
_ignoredOnLine
.putIfAbsent(lineNumber, () => [])
- .addAll(comment.diagnosticNames);
+ .addAll(comment.ignoredElements);
} else if (lexeme.contains('ignore_for_file:')) {
- _ignoredForFile.addAll(comment.diagnosticNames);
+ _ignoredForFile.addAll(comment.ignoredElements);
}
}
}
@@ -75,26 +105,24 @@
/// Return a list containing all of the diagnostics that are ignored for the
/// whole file.
- List<DiagnosticName> get ignoredForFile => _ignoredForFile.toList();
+ List<IgnoredElement> get ignoredForFile => _ignoredForFile.toList();
/// Return a table mapping line numbers to the diagnostics that are ignored on
/// that line.
- Map<int, List<DiagnosticName>> get ignoredOnLine {
- Map<int, List<DiagnosticName>> ignoredOnLine = {};
+ Map<int, List<IgnoredElement>> get ignoredOnLine {
+ Map<int, List<IgnoredElement>> ignoredOnLine = {};
for (var entry in _ignoredOnLine.entries) {
ignoredOnLine[entry.key] = entry.value.toList();
}
return ignoredOnLine;
}
- /// Return `true` if the [errorCode] (case-insensitive) is ignored at the
- /// given [line].
- bool ignoredAt(String errorCode, int line) {
+ /// Return `true` if the [errorCode] is ignored at the given [line].
+ bool ignoredAt(ErrorCode errorCode, int line) {
var ignoredDiagnostics = _ignoredOnLine[line];
if (ignoredForFile.isEmpty && ignoredDiagnostics == null) {
return false;
}
- errorCode = errorCode.toLowerCase();
if (ignoredForFile.any((name) => name.matches(errorCode))) {
return true;
}
@@ -135,21 +163,28 @@
/// more restrictive in this test.
static final _errorCodeNameRegExp = RegExp(r'^[a-zA-Z][_a-z0-9A-Z]*$');
+ static final _errorTypeRegExp =
+ RegExp(r'^type[ ]*=[ ]*lint', caseSensitive: false);
+
/// Return the diagnostic names contained in this comment, assuming that it is
/// a correctly formatted ignore comment.
- Iterable<DiagnosticName> get diagnosticNames sync* {
- bool isValidErrorCodeName(String text) {
- return text.contains(_errorCodeNameRegExp);
- }
-
+ Iterable<IgnoredElement> get ignoredElements sync* {
int offset = lexeme.indexOf(':') + 1;
var names = lexeme.substring(offset).split(',');
offset += this.offset;
for (var name in names) {
var trimmedName = name.trim();
- if (trimmedName.isNotEmpty && isValidErrorCodeName(trimmedName)) {
- var innerOffset = name.indexOf(trimmedName);
- yield DiagnosticName(trimmedName.toLowerCase(), offset + innerOffset);
+ if (trimmedName.isNotEmpty) {
+ if (trimmedName.contains(_errorCodeNameRegExp)) {
+ var innerOffset = name.indexOf(trimmedName);
+ yield DiagnosticName(trimmedName.toLowerCase(), offset + innerOffset);
+ } else {
+ var match = _errorTypeRegExp.matchAsPrefix(trimmedName);
+ if (match != null) {
+ var innerOffset = name.indexOf(trimmedName);
+ yield DiagnosticType('lint', offset + innerOffset, name.length);
+ }
+ }
}
offset += name.length + 1;
}
diff --git a/pkg/analyzer/test/generated/elements_types_mixin.dart b/pkg/analyzer/test/generated/elements_types_mixin.dart
index 5b8ad2f..c201074 100644
--- a/pkg/analyzer/test/generated/elements_types_mixin.dart
+++ b/pkg/analyzer/test/generated/elements_types_mixin.dart
@@ -587,6 +587,16 @@
return element;
}
+ DartType typeAliasTypeNone(
+ TypeAliasElement element, {
+ List<DartType> typeArguments = const [],
+ }) {
+ return element.instantiate(
+ typeArguments: typeArguments,
+ nullabilitySuffix: NullabilitySuffix.none,
+ );
+ }
+
TypeParameterElementImpl typeParameter(String name,
{DartType? bound, Variance? variance}) {
var element = TypeParameterElementImpl.synthetic(name);
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
index b7a1e9c..01bcf82 100644
--- a/pkg/analyzer/test/generated/error_suppression_test.dart
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -2,7 +2,9 @@
// 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/error/error.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:linter/src/rules/avoid_types_as_parameter_names.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/context_collection_resolution.dart';
@@ -15,13 +17,26 @@
@reflectiveTest
class ErrorSuppressionTest extends PubPackageResolutionTest {
+ static final ErrorCode _lintCode = AvoidTypesAsParameterNames().lintCode;
+
String get ignoredCode => 'unused_element';
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackageAnalysisOptionsFile(
+ AnalysisOptionsFileConfig(
+ experiments: experiments,
+ lints: ['avoid_types_as_parameter_names'],
+ ),
+ );
+ }
+
test_error_code_mismatch() async {
await assertErrorsInCode('''
// ignore: $ignoredCode
int x = '';
-int _y = 0; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int _y = 0; //INVALID_ASSIGNMENT
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 34, 2),
error(HintCode.UNUSED_ELEMENT, 42, 2),
@@ -225,6 +240,62 @@
]);
}
+ test_type_ignore_badType() async {
+ await assertErrorsInCode('''
+// ignore: type=wrong
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''', [
+ error(_lintCode, 34, 3),
+ ]);
+ }
+
+ test_type_ignore_match() async {
+ await assertNoErrorsInCode('''
+// ignore: type=lint
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''');
+ }
+
+ test_type_ignore_mismatch() async {
+ await assertErrorsInCode('''
+// ignore: type=lint
+int _x = 1;
+''', [
+ error(HintCode.UNUSED_ELEMENT, 25, 2),
+ ]);
+ }
+
+ test_type_ignoreForFile_match() async {
+ await assertNoErrorsInCode('''
+// ignore_for_file: type=lint
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''');
+ }
+
+ test_type_ignoreForFile_match_upperCase() async {
+ await assertNoErrorsInCode('''
+// ignore_for_file: TYPE=LINT
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''');
+ }
+
+ test_type_ignoreForFile_match_withWhitespace() async {
+ await assertNoErrorsInCode('''
+// ignore_for_file: type = lint
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''');
+ }
+
+ test_type_ignoreForFile_mismatch() async {
+ await assertErrorsInCode('''
+// ignore_for_file: type=lint
+int a = 0;
+int _x = 1;
+''', [
+ error(HintCode.UNUSED_ELEMENT, 45, 2),
+ ]);
+ }
+
test_undefined_function_within_flutter_can_be_ignored() async {
await assertErrorsInFile(
'$workspaceRootPath/flutterlib/flutter.dart',
diff --git a/pkg/analyzer/test/src/dart/element/type_algebra_test.dart b/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
index 15bf4c5..a096499 100644
--- a/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
@@ -117,6 +117,61 @@
_assertIdenticalType(typeProvider.dynamicType, {T: intNone});
}
+ test_function_fromAlias_hasRef() async {
+ // typedef Alias<T> = void Function();
+ var T = typeParameter('T');
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [T],
+ aliasedType: functionTypeNone(
+ returnType: voidNone,
+ ),
+ );
+
+ var U = typeParameter('U');
+ var type = typeAliasTypeNone(Alias, typeArguments: [
+ typeParameterTypeNone(U),
+ ]);
+ assertType(type, 'void Function() via Alias<U>');
+ _assertSubstitution(type, {U: intNone}, 'void Function() via Alias<int>');
+ }
+
+ test_function_fromAlias_noRef() async {
+ // typedef Alias<T> = void Function();
+ var T = typeParameter('T');
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [T],
+ aliasedType: functionTypeNone(
+ returnType: voidNone,
+ ),
+ );
+
+ var type = typeAliasTypeNone(Alias, typeArguments: [doubleNone]);
+ assertType(type, 'void Function() via Alias<double>');
+
+ var U = typeParameter('U');
+ _assertIdenticalType(type, {U: intNone});
+ }
+
+ test_function_fromAlias_noTypeParameters() async {
+ // typedef Alias<T> = void Function();
+ var T = typeParameter('T');
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [T],
+ aliasedType: functionTypeNone(
+ returnType: voidNone,
+ ),
+ );
+
+ var type = typeAliasTypeNone(Alias, typeArguments: [intNone]);
+ assertType(type, 'void Function() via Alias<int>');
+
+ var U = typeParameter('U');
+ _assertIdenticalType(type, {U: intNone});
+ }
+
test_function_noSubstitutions() async {
var type = functionTypeNone(
parameters: [
@@ -265,6 +320,63 @@
_assertIdenticalType(type, {U: doubleNone});
}
+ test_interface_noTypeParameters_fromAlias_hasRef() async {
+ // class A {}
+ var A = class_(name: 'A');
+
+ // typedef Alias<T> = A;
+ var T = typeParameter('T');
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [T],
+ aliasedType: interfaceTypeNone(A),
+ );
+
+ var U = typeParameter('U');
+ var type = typeAliasTypeNone(Alias, typeArguments: [
+ typeParameterTypeNone(U),
+ ]);
+ assertType(type, 'A via Alias<U>');
+ _assertSubstitution(type, {U: intNone}, 'A via Alias<int>');
+ }
+
+ test_interface_noTypeParameters_fromAlias_noRef() async {
+ // class A {}
+ var A = class_(name: 'A');
+
+ // typedef Alias<T> = A;
+ var T = typeParameter('T');
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [T],
+ aliasedType: interfaceTypeNone(A),
+ );
+
+ var type = typeAliasTypeNone(Alias, typeArguments: [doubleNone]);
+ assertType(type, 'A via Alias<double>');
+
+ var U = typeParameter('U');
+ _assertIdenticalType(type, {U: intNone});
+ }
+
+ test_interface_noTypeParameters_fromAlias_noTypeParameters() async {
+ // class A {}
+ var A = class_(name: 'A');
+
+ // typedef Alias = A;
+ var Alias = typeAlias(
+ name: 'Alias',
+ typeParameters: [],
+ aliasedType: interfaceTypeNone(A),
+ );
+
+ var type = typeAliasTypeNone(Alias);
+ assertType(type, 'A via Alias');
+
+ var T = typeParameter('T');
+ _assertIdenticalType(type, {T: intNone});
+ }
+
test_typeParameter_nullability() async {
var tElement = typeParameter('T');
@@ -370,9 +482,7 @@
class _Base extends AbstractTypeSystemNullSafetyTest {
void assertType(DartType type, String expected) {
- var typeStr = type.getDisplayString(
- withNullability: true,
- );
+ var typeStr = _typeStr(type);
expect(typeStr, expected);
}
@@ -383,5 +493,21 @@
) {
var result = substitute(type, substitution);
assertType(result, expected);
+ expect(result, isNot(same(type)));
+ }
+
+ static String _typeStr(DartType type) {
+ var result = type.getDisplayString(withNullability: true);
+
+ var alias = type.alias;
+ if (alias != null) {
+ result += ' via ${alias.element.name}';
+ var typeArgumentStrList = alias.typeArguments.map(_typeStr).toList();
+ if (typeArgumentStrList.isNotEmpty) {
+ result += '<${typeArgumentStrList.join(', ')}>';
+ }
+ }
+
+ return result;
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_ignore_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_ignore_test.dart
index 66d84e5..98eace4 100644
--- a/pkg/analyzer/test/src/diagnostics/duplicate_ignore_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/duplicate_ignore_test.dart
@@ -15,7 +15,18 @@
@reflectiveTest
class DuplicateIgnoreTest extends PubPackageResolutionTest {
- test_file() async {
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackageAnalysisOptionsFile(
+ AnalysisOptionsFileConfig(
+ experiments: experiments,
+ lints: ['avoid_types_as_parameter_names'],
+ ),
+ );
+ }
+
+ test_name_file() async {
await assertErrorsInCode(r'''
// ignore_for_file: unused_local_variable, unused_local_variable
void f() {
@@ -26,7 +37,7 @@
]);
}
- test_line() async {
+ test_name_line() async {
await assertErrorsInCode(r'''
void f() {
// ignore: unused_local_variable, unused_local_variable
@@ -37,7 +48,7 @@
]);
}
- test_lineAndFile() async {
+ test_name_lineAndFile() async {
await assertErrorsInCode(r'''
// ignore_for_file: unused_local_variable
void f() {
@@ -48,4 +59,34 @@
error(HintCode.DUPLICATE_IGNORE, 66, 21),
]);
}
+
+ test_type_file() async {
+ await assertErrorsInCode(r'''
+// ignore_for_file: type=lint, TYPE=LINT
+void f(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''', [
+ error(HintCode.DUPLICATE_IGNORE, 31, 10),
+ ]);
+ }
+
+ test_type_line() async {
+ await assertErrorsInCode(r'''
+void f() {}
+// ignore: type=lint, TYPE=LINT
+void g(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''', [
+ error(HintCode.DUPLICATE_IGNORE, 34, 10),
+ ]);
+ }
+
+ test_type_lineAndFile() async {
+ await assertErrorsInCode(r'''
+// ignore_for_file: type=lint
+void f() {}
+// ignore: type=lint
+void g(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
+''', [
+ error(HintCode.DUPLICATE_IGNORE, 53, 10),
+ ]);
+ }
}
diff --git a/tools/VERSION b/tools/VERSION
index 389bae8..9c78614 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 94
+PRERELEASE 95
PRERELEASE_PATCH 0
\ No newline at end of file