Skip to content

Commit 5a33595

Browse files
Jenny Messerlycommit-bot@chromium.org
Jenny Messerly
authored andcommitted
[analyzer] fix #33119, add strict-raw-types flag
When the flag is enabled, warnings are issued for raw types, for example `List`. Raw types (those without explicit type arguments) are allowed if any of these are true, otherwise they are reported: - none of the type arguments are `dynamic`. - the type was inferred from a downwards context. - the class/typedef has `@optionalTypeArgs` from package:meta. Change-Id: I1e70dba5b3bf6118b274bbf72843e3578dbaa8fd Reviewed-on: https://dart-review.googlesource.com/c/75629 Auto-Submit: Jenny Messerly <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 76d31a2 commit 5a33595

File tree

12 files changed

+377
-10
lines changed

12 files changed

+377
-10
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ const List<ErrorCode> errorCodeValues = const [
325325
HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
326326
HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
327327
HintCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
328+
HintCode.STRICT_RAW_TYPE,
328329
HintCode.SUBTYPE_OF_SEALED_CLASS,
329330
HintCode.TYPE_CHECK_IS_NOT_NULL,
330331
HintCode.TYPE_CHECK_IS_NULL,

pkg/analyzer/lib/src/dart/error/hint_codes.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ class HintCode extends ErrorCode {
188188
"initializer.",
189189
correction: "Try specifying the type of the variable.");
190190

191+
/**
192+
* When "strict-raw-types" is enabled, raw types must be inferred via the
193+
* context type, or have type arguments other than dynamic.
194+
*/
195+
static const HintCode STRICT_RAW_TYPE = HintCode('STRICT_RAW_TYPE',
196+
"The generic type '{0}' should have explicit type arguments but doesn't.",
197+
correction: "Use explicit type arguments for '{0}'.");
198+
191199
/**
192200
* This hint is generated anywhere a @factory annotation is associated with
193201
* anything other than a method.

pkg/analyzer/lib/src/error/codes.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4666,6 +4666,10 @@ class StaticWarningCode extends ErrorCode {
46664666

46674667
/**
46684668
* This class has Strong Mode specific error codes.
4669+
*
4670+
* "Strong Mode" was the prototype for Dart 2's sound type system. Many of these
4671+
* errors became part of Dart 2. Some of them are optional flags, used for
4672+
* stricter checking.
46694673
*
46704674
* These error codes tend to use the same message across different severity
46714675
* levels, so they are grouped for clarity.

pkg/analyzer/lib/src/generated/element_resolver.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,12 @@ class ElementResolver extends SimpleAstVisitor<void> {
414414
_resolveMetadataForParameter(node);
415415
}
416416

417+
@override
418+
void visitGenericTypeAlias(GenericTypeAlias node) {
419+
resolveMetadata(node);
420+
return null;
421+
}
422+
417423
@override
418424
void visitImportDirective(ImportDirective node) {
419425
SimpleIdentifier prefixNode = node.prefix;

pkg/analyzer/lib/src/generated/engine.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,15 @@ class AnalysisOptionsImpl implements AnalysisOptions {
15111511
*/
15121512
bool strictInference = false;
15131513

1514+
/**
1515+
* Whether raw types (types without explicit type arguments, such as `List`)
1516+
* should be reported as potential problems.
1517+
*
1518+
* Raw types are a common source of `dynamic` being introduced implicitly.
1519+
* This often leads to cast failures later on in the program.
1520+
*/
1521+
bool strictRawTypes = false;
1522+
15141523
/**
15151524
* Initialize a newly created set of analysis options to have their default
15161525
* values.
@@ -1542,6 +1551,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
15421551
implicitCasts = options.implicitCasts;
15431552
implicitDynamic = options.implicitDynamic;
15441553
strictInference = options.strictInference;
1554+
strictRawTypes = options.strictRawTypes;
15451555
}
15461556
trackCacheDependencies = options.trackCacheDependencies;
15471557
disableCacheFlushing = options.disableCacheFlushing;
@@ -1717,6 +1727,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
17171727
buffer.addBool(implicitCasts);
17181728
buffer.addBool(implicitDynamic);
17191729
buffer.addBool(strictInference);
1730+
buffer.addBool(strictRawTypes);
17201731
buffer.addBool(strongModeHints);
17211732
buffer.addBool(useFastaParser);
17221733

@@ -1801,6 +1812,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
18011812
implicitCasts = true;
18021813
implicitDynamic = true;
18031814
strictInference = false;
1815+
strictRawTypes = false;
18041816
lint = false;
18051817
_lintRules = null;
18061818
patchPaths = {};

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
10001000
_checkTypeArgumentCount(typeArguments, 1,
10011001
StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS);
10021002
}
1003+
_checkForRawTypedLiteral(node);
10031004
_checkForImplicitDynamicTypedLiteral(node);
10041005
_checkForListElementTypeNotAssignable(node);
10051006

@@ -1020,6 +1021,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
10201021
_checkTypeArgumentCount(typeArguments, 2,
10211022
StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS);
10221023
}
1024+
_checkForRawTypedLiteral(node);
10231025
_checkForImplicitDynamicTypedLiteral(node);
10241026
_checkForMapTypeNotAssignable(node);
10251027
_checkForNonConstMapAsExpressionStatement(node);
@@ -1225,6 +1227,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
12251227
_checkTypeArgumentCount(typeArguments, 1,
12261228
StaticTypeWarningCode.EXPECTED_ONE_SET_TYPE_ARGUMENTS);
12271229
}
1230+
_checkForRawTypedLiteral(node);
12281231
_checkForImplicitDynamicTypedLiteral(node);
12291232
_checkForSetElementTypeNotAssignable(node);
12301233

@@ -1246,6 +1249,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
12461249
_checkTypeArgumentCount(typeArguments, 2,
12471250
StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS);
12481251
}
1252+
_checkForRawTypedLiteral(node);
12491253
_checkForImplicitDynamicTypedLiteral(node);
12501254
_checkForMapTypeNotAssignable3(node);
12511255
_checkForNonConstMapAsExpressionStatement3(node);
@@ -1261,6 +1265,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
12611265
_checkTypeArgumentCount(typeArguments, 1,
12621266
StaticTypeWarningCode.EXPECTED_ONE_SET_TYPE_ARGUMENTS);
12631267
}
1268+
_checkForRawTypedLiteral(node);
12641269
_checkForImplicitDynamicTypedLiteral(node);
12651270
_checkForSetElementTypeNotAssignable3(node);
12661271
}
@@ -1358,6 +1363,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
13581363
@override
13591364
void visitTypeName(TypeName node) {
13601365
_checkForTypeArgumentNotMatchingBounds(node);
1366+
_checkForRawTypeName(node);
13611367
super.visitTypeName(node);
13621368
}
13631369

@@ -4506,11 +4512,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
45064512
Map<LibraryElement, Map<String, String>> mixedInNames =
45074513
<LibraryElement, Map<String, String>>{};
45084514

4509-
/**
4510-
* Report an error and return `true` if the given [name] is a private name
4511-
* (which is defined in the given [library]) and it conflicts with another
4512-
* definition of that name inherited from the superclass.
4513-
*/
4515+
/// Report an error and return `true` if the given [name] is a private name
4516+
/// (which is defined in the given [library]) and it conflicts with another
4517+
/// definition of that name inherited from the superclass.
45144518
bool isConflictingName(
45154519
String name, LibraryElement library, TypeName typeName) {
45164520
if (Identifier.isPrivateName(name)) {
@@ -4998,6 +5002,93 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
49985002
CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, parameter);
49995003
}
50005004

5005+
/// Similar to [_checkForRawTypeName] but for list/map/set literals.
5006+
void _checkForRawTypedLiteral(TypedLiteral node) {
5007+
if (!_options.strictRawTypes || node == null) return;
5008+
if (node.typeArguments != null) {
5009+
// Type has explicit type arguments.
5010+
return;
5011+
}
5012+
var type = node.staticType;
5013+
return _checkForRawTypeErrors(node, type, type.element, node);
5014+
}
5015+
5016+
/// Given a [node] without type arguments that refers to [element], issues
5017+
/// an error if [type] is a generic type, and the type arguments were not
5018+
/// supplied from inference or a non-dynamic default instantiation.
5019+
///
5020+
/// This function is used by other node-specific raw type checking functions
5021+
/// (for example [_checkForRawTypeName]), and should only be called when
5022+
/// we already know [AnalysisOptionsImpl.strictRawTypes] is true and [node]
5023+
/// has no explicit `typeArguments`.
5024+
///
5025+
/// [inferenceContextNode] is the node that has the downwards context type,
5026+
/// if any. For example an [InstanceCreationExpression].
5027+
///
5028+
/// The raw type error [HintCode.STRICT_RAW_TYPE] will *not* be reported when
5029+
/// any of the following are true:
5030+
///
5031+
/// - [inferenceContextNode] has an inference context type that does not
5032+
/// contain `?`
5033+
/// - [type] does not have any `dynamic` type arguments.
5034+
/// - the element is marked with `@optionalTypeArgs` from "package:meta".
5035+
void _checkForRawTypeErrors(AstNode node, DartType type, Element element,
5036+
Expression inferenceContextNode) {
5037+
assert(_options.strictRawTypes);
5038+
// Check if this type has type arguments and at least one is dynamic.
5039+
// If so, we may need to issue a strict-raw-types error.
5040+
if (type is ParameterizedType &&
5041+
type.typeArguments.any((t) => t.isDynamic)) {
5042+
// If we have an inference context node, check if the type was inferred
5043+
// from it. Some cases will not have a context type, such as the type
5044+
// annotation `List` in `List list;`
5045+
if (inferenceContextNode != null) {
5046+
var contextType = InferenceContext.getContext(inferenceContextNode);
5047+
if (contextType != null && UnknownInferredType.isKnown(contextType)) {
5048+
// Type was inferred from downwards context: not an error.
5049+
return;
5050+
}
5051+
}
5052+
if (element.metadata.isNotEmpty) {
5053+
for (var annotation in element.metadata) {
5054+
var e = annotation.element;
5055+
// TODO(jmesserly): similar "package:meta" annotations are added to
5056+
// the element as boolean getters, that may be worth considering.
5057+
if (e?.name == 'optionalTypeArgs' &&
5058+
e.librarySource.uri.toString() == 'package:meta/meta.dart') {
5059+
// Type is marked with `@optionalTypeArgs`: not an error.
5060+
return;
5061+
}
5062+
}
5063+
}
5064+
_errorReporter.reportErrorForNode(HintCode.STRICT_RAW_TYPE, node, [type]);
5065+
}
5066+
}
5067+
5068+
/// Checks a type annotation for a raw generic type, and reports the
5069+
/// appropriate error if [AnalysisOptionsImpl.strictRawTypes] is set.
5070+
///
5071+
/// This checks if [node] refers to a generic type and does not have explicit
5072+
/// or inferred type arguments. When that happens, it reports error code
5073+
/// [StrongModeCode.STRICT_RAW_TYPE].
5074+
void _checkForRawTypeName(TypeName node) {
5075+
if (!_options.strictRawTypes || node == null) return;
5076+
if (node.typeArguments != null) {
5077+
// Type has explicit type arguments.
5078+
return;
5079+
}
5080+
var parent = node.parent;
5081+
InstanceCreationExpression inferenceContextNode;
5082+
if (parent is ConstructorName) {
5083+
var grandparent = parent.parent;
5084+
if (grandparent is InstanceCreationExpression) {
5085+
inferenceContextNode = grandparent;
5086+
}
5087+
}
5088+
return _checkForRawTypeErrors(
5089+
node, node.type, node.name.staticElement, inferenceContextNode);
5090+
}
5091+
50015092
/**
50025093
* Check whether the given constructor [declaration] is the redirecting
50035094
* generative constructor and references itself directly or indirectly. The

pkg/analyzer/lib/src/summary/link.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,9 @@ class AnalysisOptionsForLink implements AnalysisOptionsImpl {
427427
@override
428428
bool get strictInference => false;
429429

430+
@override
431+
bool get strictRawTypes => false;
432+
430433
@deprecated
431434
@override
432435
bool get previewDart2 => true;

pkg/analyzer/lib/src/task/options.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class AnalyzerOptions {
6060

6161
// Language options (see AnalysisOptionsImpl for documentation).
6262
static const String strictInference = 'strict-inference';
63+
static const String strictRawTypes = 'strict-raw-types';
6364

6465
/// Ways to say `ignore`.
6566
static const List<String> ignoreSynonyms = const ['ignore', 'false'];
@@ -94,6 +95,7 @@ class AnalyzerOptions {
9495
/// Supported `analyzer` language options.
9596
static const List<String> languageOptions = const [
9697
strictInference,
98+
strictRawTypes
9799
];
98100
}
99101

@@ -704,6 +706,9 @@ class _OptionsProcessor {
704706
if (feature == AnalyzerOptions.strictInference) {
705707
options.strictInference = boolValue;
706708
}
709+
if (feature == AnalyzerOptions.strictRawTypes) {
710+
options.strictRawTypes = boolValue;
711+
}
707712
}
708713
}
709714

pkg/analyzer/test/src/context/builder_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,7 @@ environment:
953953
expect(actual.implicitCasts, expected.implicitCasts);
954954
expect(actual.implicitDynamic, expected.implicitDynamic);
955955
expect(actual.strictInference, expected.strictInference);
956+
expect(actual.strictRawTypes, expected.strictRawTypes);
956957
expect(actual.trackCacheDependencies, expected.trackCacheDependencies);
957958
expect(actual.disableCacheFlushing, expected.disableCacheFlushing);
958959
}

pkg/analyzer/test/src/task/options_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ analyzer:
373373
analyzer:
374374
language:
375375
unsupported: true
376-
''', [AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE]);
376+
''', [AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES]);
377377
}
378378

379379
test_analyzer_strong_mode_unsupported_value() {

0 commit comments

Comments
 (0)