linter: Introduce no_raw_types replacing strict-raw-types
Work towards https://github.com/dart-lang/sdk/issues/63516 I have code here to deprecate the `analyzer/language/strict-raw-types` setting. But I disabled it, as I realized we first need to ship an SDK to Flutter that offers the lint rule, before we deprecate the setting, which will cause CI to fail (like a Dart->Flutter roll). When the deprecation is enabled, we can also ship the automated fix. Change-Id: I17d1ea9aba96063059e37891c05d4a8bd3f02737 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509063 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
Samuel Rawlins
parent
2e682b9e9d
commit
4c6fe56ae3
@@ -2290,6 +2290,11 @@ no_literal_bool_comparisons:
|
||||
status: hasFix
|
||||
no_logic_in_create_state:
|
||||
status: noFix
|
||||
no_raw_types:
|
||||
status: needsFix
|
||||
notes: |-
|
||||
There are a few basic cases where we can look at another expression's type
|
||||
in order to find a replacement, like `C c = C<int>()`.
|
||||
no_runtimetype_tostring:
|
||||
status: noFix
|
||||
no_self_assignments:
|
||||
|
||||
@@ -812,23 +812,16 @@ class _LanguageOptionValidator extends OptionsValidator {
|
||||
var language = analyzer.valueAt(AnalysisOptionsFileKeys.language);
|
||||
if (language is YamlMap) {
|
||||
language.nodes.forEach((k, v) {
|
||||
String? key;
|
||||
bool validKey = false;
|
||||
if (k is YamlScalar) {
|
||||
key = k.value?.toString();
|
||||
if (!AnalysisOptionsFileKeys.languageOptions.contains(key)) {
|
||||
_builder.reportError(
|
||||
reporter,
|
||||
AnalysisOptionsFileKeys.language,
|
||||
k,
|
||||
);
|
||||
} else {
|
||||
// If we have a valid key, go on and check the value.
|
||||
validKey = true;
|
||||
}
|
||||
if (k is! YamlScalar) return;
|
||||
var key = k.value?.toString();
|
||||
if (!AnalysisOptionsFileKeys.languageOptions.contains(key)) {
|
||||
_builder.reportError(reporter, AnalysisOptionsFileKeys.language, k);
|
||||
return;
|
||||
}
|
||||
if (validKey && v is YamlScalar) {
|
||||
if (v.toBool() == null) {
|
||||
|
||||
if (v is YamlScalar) {
|
||||
var value = v.toBool();
|
||||
if (value == null) {
|
||||
// `null` is not a valid key, so we can safely assume `key` is
|
||||
// non-`null`.
|
||||
reporter.report(
|
||||
@@ -840,6 +833,17 @@ class _LanguageOptionValidator extends OptionsValidator {
|
||||
)
|
||||
.atSourceSpan(v.span),
|
||||
);
|
||||
} else if (key == AnalysisOptionsFileKeys.strictRawTypes && value) {
|
||||
// TODO(srawlins): Enable once the `no_raw_types` lint rule is
|
||||
// available in Flutter main, so that developers have something to
|
||||
// migrate to.
|
||||
if (1 == 2) {
|
||||
reporter.report(
|
||||
diag.analysisOptionDeprecated
|
||||
.withArguments(optionName: key!)
|
||||
.atSourceSpan(k.span),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -308,6 +308,26 @@ analyzer:
|
||||
);
|
||||
}
|
||||
|
||||
@FailingTest(reason: 'Enable when we deprecate strict-raw-types')
|
||||
test_analyzer_language_strictRawTypes_deprecated() {
|
||||
validate(
|
||||
'''
|
||||
analyzer:
|
||||
language:
|
||||
strict-raw-types: true
|
||||
''',
|
||||
[diag.analysisOptionDeprecated],
|
||||
);
|
||||
}
|
||||
|
||||
test_analyzer_language_strictRawTypes_notDeprecatedIfFalse() {
|
||||
validate('''
|
||||
analyzer:
|
||||
language:
|
||||
strict-raw-types: false
|
||||
''', []);
|
||||
}
|
||||
|
||||
test_analyzer_language_supports_empty() {
|
||||
validate('''
|
||||
analyzer:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// 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/element/type.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'diagnostic.dart' as diag;
|
||||
|
||||
|
||||
@@ -1930,6 +1930,21 @@ const LinterLintWithoutArguments noopPrimitiveOperations =
|
||||
expectedTypes: [],
|
||||
);
|
||||
|
||||
/// Parameters:
|
||||
/// Type type: the name of the generic type
|
||||
const DiagnosticWithArguments<
|
||||
LocatableDiagnostic Function({required DartType type})
|
||||
>
|
||||
noRawTypes = LinterLintTemplate(
|
||||
name: 'no_raw_types',
|
||||
problemMessage:
|
||||
"The generic type '{0}' should have explicit type arguments but doesn't.",
|
||||
correctionMessage: "Use explicit type arguments for '{0}'.",
|
||||
uniqueName: 'no_raw_types',
|
||||
withArguments: _withArgumentsNoRawTypes,
|
||||
expectedTypes: [ExpectedType.type],
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
const LinterLintWithoutArguments noRuntimetypeTostring =
|
||||
LinterLintWithoutArguments(
|
||||
@@ -4326,6 +4341,10 @@ LocatableDiagnostic _withArgumentsNonConstantIdentifierNames({
|
||||
return LocatableDiagnosticImpl(diag.nonConstantIdentifierNames, [p0]);
|
||||
}
|
||||
|
||||
LocatableDiagnostic _withArgumentsNoRawTypes({required DartType type}) {
|
||||
return LocatableDiagnosticImpl(diag.noRawTypes, [type]);
|
||||
}
|
||||
|
||||
LocatableDiagnostic _withArgumentsOneMemberAbstracts({required Object p0}) {
|
||||
return LocatableDiagnosticImpl(diag.oneMemberAbstracts, [p0]);
|
||||
}
|
||||
|
||||
@@ -317,6 +317,8 @@ abstract final class LintNames {
|
||||
|
||||
static const String no_logic_in_create_state = 'no_logic_in_create_state';
|
||||
|
||||
static const String no_raw_types = 'no_raw_types';
|
||||
|
||||
static const String no_runtimetype_tostring = 'no_runtimetype_tostring';
|
||||
|
||||
static const String no_self_assignments = 'no_self_assignments';
|
||||
|
||||
@@ -119,6 +119,7 @@ import 'rules/no_leading_underscores_for_library_prefixes.dart';
|
||||
import 'rules/no_leading_underscores_for_local_identifiers.dart';
|
||||
import 'rules/no_literal_bool_comparisons.dart';
|
||||
import 'rules/no_logic_in_create_state.dart';
|
||||
import 'rules/no_raw_types.dart';
|
||||
import 'rules/no_runtimeType_toString.dart';
|
||||
import 'rules/no_self_assignments.dart';
|
||||
import 'rules/no_wildcard_variable_uses.dart';
|
||||
@@ -385,6 +386,7 @@ void registerLintRules() {
|
||||
..registerLintRule(NoLeadingUnderscoresForLocalIdentifiers())
|
||||
..registerLintRule(NoLiteralBoolComparisons())
|
||||
..registerLintRule(NoLogicInCreateState())
|
||||
..registerLintRule(NoRawTypes())
|
||||
..registerLintRule(NoRuntimeTypeToString())
|
||||
..registerLintRule(NoSelfAssignments())
|
||||
..registerLintRule(NoWildcardVariableUses())
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2026, 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/analysis_rule/analysis_rule.dart';
|
||||
import 'package:analyzer/analysis_rule/rule_context.dart';
|
||||
import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/visitor.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
|
||||
import '../analyzer.dart';
|
||||
import '../diagnostic.dart' as diag;
|
||||
|
||||
const _desc = r'Avoid raw types.';
|
||||
|
||||
class NoRawTypes extends AnalysisRule {
|
||||
new() : super(name: LintNames.no_raw_types, description: _desc);
|
||||
|
||||
@override
|
||||
DiagnosticCode get diagnosticCode => diag.noRawTypes;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(
|
||||
RuleVisitorRegistry registry,
|
||||
RuleContext context,
|
||||
) {
|
||||
var visitor = _Visitor(this);
|
||||
registry.addNamedType(this, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
final AnalysisRule rule;
|
||||
|
||||
new(this.rule);
|
||||
|
||||
@override
|
||||
void visitNamedType(NamedType node) {
|
||||
var parent = node.parent;
|
||||
if (parent is ConstructorName &&
|
||||
parent.parent is InstanceCreationExpression) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.typeArguments != null) return;
|
||||
|
||||
var type = node.type;
|
||||
if (type == null) return;
|
||||
|
||||
var element = node.element;
|
||||
if (element == null) return;
|
||||
|
||||
List<DartType> typeArguments;
|
||||
var alias = type.alias;
|
||||
if (alias != null) {
|
||||
typeArguments = alias.typeArguments;
|
||||
} else if (type is InterfaceType) {
|
||||
typeArguments = type.typeArguments;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!typeArguments.any((t) => t is DynamicType)) return;
|
||||
if (element.metadata.hasOptionalTypeArgs) return;
|
||||
|
||||
if (node.parentEscapingTypeArguments
|
||||
case AsExpression() ||
|
||||
CastPattern() ||
|
||||
IsExpression() ||
|
||||
ObjectPattern() ||
|
||||
TypeLiteral()) {
|
||||
// Do not report a "strict raw type" warning in this case; too noisy,
|
||||
// especially in the case of unstructured data parsing, like JSON and
|
||||
// YAML.
|
||||
return;
|
||||
}
|
||||
|
||||
rule.reportAtNode(node, arguments: [type]);
|
||||
}
|
||||
}
|
||||
|
||||
extension on NamedType {
|
||||
AstNode get parentEscapingTypeArguments {
|
||||
var ancestor = parent!;
|
||||
while (ancestor is TypeArgumentList || ancestor is NamedType) {
|
||||
if (ancestor.parent case var grandancestor?) {
|
||||
ancestor = grandancestor;
|
||||
} else {
|
||||
return ancestor;
|
||||
}
|
||||
}
|
||||
return ancestor;
|
||||
}
|
||||
}
|
||||
@@ -7878,6 +7878,57 @@ LinterLintCode:
|
||||
}
|
||||
}
|
||||
```
|
||||
noRawTypes:
|
||||
type: lint
|
||||
parameters:
|
||||
Type type: the name of the generic type
|
||||
problemMessage: "The generic type '#type' should have explicit type arguments but doesn't."
|
||||
correctionMessage: "Use explicit type arguments for '#type'."
|
||||
state:
|
||||
stable: "3.13"
|
||||
categories: [errorProne]
|
||||
hasPublishedDocs: false
|
||||
documentation: |-
|
||||
#### Description
|
||||
|
||||
The analyzer produces this diagnostic when a generic type is used without
|
||||
explicit type arguments, meaning it is a raw type.
|
||||
|
||||
#### Example
|
||||
|
||||
The following code produces this diagnostic because the generic class `C`
|
||||
is used without a type argument:
|
||||
|
||||
```dart
|
||||
class C<T> {}
|
||||
[!C!] c = C<int>();
|
||||
```
|
||||
|
||||
#### Common fixes
|
||||
|
||||
Provide explicit type arguments:
|
||||
|
||||
```dart
|
||||
class C<T> {}
|
||||
C<int> c = C<int>();
|
||||
```
|
||||
deprecatedDetails: |-
|
||||
**DON'T** use raw types.
|
||||
|
||||
A raw type is a type annotation for a generic type which omits type
|
||||
arguments. Developers may mistakenly believe that the type arguments are
|
||||
inferred, but in fact each type parameter's bound is used, which can lead
|
||||
to lost type information.
|
||||
|
||||
**BAD:**
|
||||
```dart
|
||||
List list = [1, 2, 3];
|
||||
```
|
||||
|
||||
**GOOD:**
|
||||
```dart
|
||||
List<int> list = [1, 2, 3];
|
||||
```
|
||||
noRuntimetypeTostring:
|
||||
type: lint
|
||||
parameters: none
|
||||
|
||||
@@ -157,6 +157,7 @@ import 'no_leading_underscores_for_local_identifiers_test.dart'
|
||||
as no_leading_underscores_for_local_identifiers;
|
||||
import 'no_literal_bool_comparisons_test.dart' as no_literal_bool_comparisons;
|
||||
import 'no_logic_in_create_state_test.dart' as no_logic_in_create_state;
|
||||
import 'no_raw_types_test.dart' as no_raw_types;
|
||||
import 'no_runtimeType_toString_test.dart' as no_runtimeType_toString;
|
||||
import 'no_self_assignments_test.dart' as no_self_assignments;
|
||||
import 'no_wildcard_variable_uses_test.dart' as no_wildcard_variable_uses;
|
||||
@@ -454,6 +455,7 @@ void main() {
|
||||
no_leading_underscores_for_local_identifiers.main();
|
||||
no_literal_bool_comparisons.main();
|
||||
no_logic_in_create_state.main();
|
||||
no_raw_types.main();
|
||||
no_runtimeType_toString.main();
|
||||
no_self_assignments.main();
|
||||
no_wildcard_variable_uses.main();
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
// Copyright (c) 2026, 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:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../rule_test_support.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(NoRawTypesTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class NoRawTypesTest extends LintRuleTest {
|
||||
@override
|
||||
bool get addMetaPackageDep => true;
|
||||
|
||||
@override
|
||||
String get lintRule => LintNames.no_raw_types;
|
||||
|
||||
test_asExpression() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f(dynamic x) {
|
||||
print(x as List);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_asExpression_typeArgument() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f(dynamic x) {
|
||||
print(x as List<List>);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_castPattern() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f((Object, ) l) {
|
||||
var (_ as List, ) = l;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_castPattern_typeArgument() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f((Object, ) l) {
|
||||
var (_ as List<List>, ) = l;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_constantPattern() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f(C<int> c) {
|
||||
switch (c) {
|
||||
case const C():
|
||||
}
|
||||
}
|
||||
|
||||
class C<T> {
|
||||
const C();
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_functionParts_optionalTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
class C<T> {}
|
||||
C f(int a) => C();
|
||||
void g(C a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_extensionType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension type E<T>(int i) {}
|
||||
|
||||
void f() {
|
||||
<List<[!E!]>>[];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_extensionType_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
extension type E<T>(int i) {}
|
||||
|
||||
void f() {
|
||||
<List<E<int>>>[];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_extensionTypeImplements_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension type E(List<int> i) implements [!Iterable!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_extensionTypeImplementsExtensionType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension type E<T>(Iterable<T> i) {}
|
||||
|
||||
extension type F(List<int> j) implements [!E!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_extensionTypeRepresentationType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension type E([!List!] i) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f() {
|
||||
var a = <[!List!]>[];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_genericTypeArgument_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f() {
|
||||
var a = <List<int>>[];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_instanceCreation() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
var c = List.empty();
|
||||
''');
|
||||
}
|
||||
|
||||
test_isExpression() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f(dynamic x) {
|
||||
print(x is List);
|
||||
print(x is List<dynamic>);
|
||||
print(x is List<List>);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_localVariable_extensionType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension type E<T>(int i) {}
|
||||
|
||||
void f() {
|
||||
[!E!] e = E(1);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_localVariable_extensionType_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
extension type E<T>(int i) {}
|
||||
|
||||
void f() {
|
||||
E<int> e = E<int>(1);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_localVariable_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f() {
|
||||
[!List!] a = [1, 2, 3];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_localVariable_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f() {
|
||||
List<Object> a = [1, 2, 3];
|
||||
print(a);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_mixinApplication_missing() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
mixin class C<T> {}
|
||||
class D = Object with [!C!];
|
||||
''');
|
||||
}
|
||||
|
||||
test_mixinApplication_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
mixin class C<T> {}
|
||||
class D = Object with C<int>;
|
||||
''');
|
||||
}
|
||||
|
||||
test_nonFunctionTypeAlias_explicitTypeArg() async {
|
||||
await assertNoDiagnostics('''
|
||||
typedef List2<T> = List<T>;
|
||||
void f(List2<int> a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_nonFunctionTypeAlias_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown('''
|
||||
typedef List2<T> = List<T>;
|
||||
void f([!List2!] a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_nonFunctionTypeAlias_optionalTypeArgs() async {
|
||||
await assertNoDiagnostics('''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
typedef List2<T> = List<T>;
|
||||
void f(List2 a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_objectPattern() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f(Object o) {
|
||||
switch (o) {
|
||||
case List():
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_default_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f({[!List!] a = const []}) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_fieldFormal_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C {
|
||||
Object a;
|
||||
C([!List!] this.a);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_functionTyped_parameter_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f(void a([!List!] p)) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_functionTyped_returnType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f([!List!] a()) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_primaryDeclaring_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C(final [!List!] a);
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_simple_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void f([!List!] a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_parameter_super_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
abstract class C {
|
||||
Object a;
|
||||
C(this.a);
|
||||
}
|
||||
class D extends C {
|
||||
D([!List!] super.a);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_returnType_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
[!List!] f(int a) => [1, 2, 3];
|
||||
''');
|
||||
}
|
||||
|
||||
test_superclassWith_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
mixin class C<T> {}
|
||||
class D extends Object with [!C!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_superclassWith_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
mixin class C<T> {}
|
||||
class D extends Object with C<int> {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_topLevelField_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
[!List!] a = [];
|
||||
''');
|
||||
}
|
||||
|
||||
test_topLevelField_optionalTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
class C<T> {}
|
||||
C a = C();
|
||||
C get g => C();
|
||||
void set s(C a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_topLevelField_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
List<int> a = [];
|
||||
List<num> get g => [];
|
||||
void set s(List<double> a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_topLevelGetter_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
[!List!] get g => [];
|
||||
''');
|
||||
}
|
||||
|
||||
test_topLevelSetter_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
void set s([!List!] a) {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeAlias_classic_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
typedef T F1<T>(T _);
|
||||
[!F1!] func = (a) => a;
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeAlias_modern_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
typedef F1<T> = T Function(T);
|
||||
[!F1!] func = (a) => a;
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeAlias_modern_optionalTypeArgs() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
typedef T F1<T>(T _);
|
||||
@optionalTypeArgs
|
||||
typedef F2<T> = T Function(T);
|
||||
F1 f1 = (a) => a;
|
||||
F2 f2 = (a) => a;
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeAlias_modern_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
typedef T F1<T>(T _);
|
||||
typedef F2<T> = T Function(T);
|
||||
typedef F3 = T Function<T>(T);
|
||||
F1<int> f1 = (a) => a;
|
||||
F2<int> f2 = (a) => a;
|
||||
F3 f3 = <T>(T a) => a;
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInClassDeclaration_optionalTypeArgs() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
mixin class C<T> {}
|
||||
class D extends C {}
|
||||
class E extends Object with C {}
|
||||
class F = Object with C;
|
||||
class G implements C {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInConstructorName() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C {
|
||||
C();
|
||||
C.named();
|
||||
}
|
||||
|
||||
var c = C();
|
||||
var d = C.named();
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInExtendedType_anonymous_missing() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension on [!List!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInExtendedType_missing() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
extension E on [!List!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInExtendedType_optionalTypeArgs() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
import 'package:meta/meta.dart';
|
||||
@optionalTypeArgs
|
||||
class C<T> {}
|
||||
extension E on C {}
|
||||
extension on C {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInExtendedType_present() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
extension E<T> on List<T> {}
|
||||
extension F on List<int> {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInInterface_missing() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C<T> {}
|
||||
class D implements [!C!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInInterface_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C<T> {}
|
||||
class D implements C<int> {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInSuperclass_missing() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C<T> {}
|
||||
class D extends [!C!] {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeInSuperclass_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C<T> {}
|
||||
class D extends C<int> {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeLiteral_raw() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
void f() {
|
||||
var t = List;
|
||||
print(t);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeParameterBound_missingTypeArg() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C<T> {}
|
||||
class D<T extends [!C!]> {}
|
||||
''');
|
||||
}
|
||||
|
||||
test_typeParameterBound_withTypeArg() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C<T> {}
|
||||
class D<S, T extends C<S>> {}
|
||||
''');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user