Version 2.14.0-122.0.dev
Merge commit 'df5d0a5f4e321a6b0ffaa58815e8694f44c8c583' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 35641bf..f524ec3 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-05-11T11:47:02.674706",
+ "generated": "2021-05-17T10:34:01.378194",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -413,6 +413,12 @@
"languageVersion": "2.12"
},
{
+ "name": "lints",
+ "rootUri": "../third_party/pkg/lints",
+ "packageUri": "lib/",
+ "languageVersion": "2.12"
+ },
+ {
"name": "logging",
"rootUri": "../third_party/pkg/logging",
"packageUri": "lib/",
diff --git a/.packages b/.packages
index 1631e03..2a1f1af 100644
--- a/.packages
+++ b/.packages
@@ -60,6 +60,7 @@
json_rpc_2:third_party/pkg/json_rpc_2/lib
kernel:pkg/kernel/lib
linter:third_party/pkg/linter/lib
+lints:third_party/pkg/lints/lib
logging:third_party/pkg/logging/lib
markdown:third_party/pkg/markdown/lib
matcher:third_party/pkg/matcher/lib
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a1ba65..9a9d3ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -182,19 +182,18 @@
#### `dart:collection`
-- The `SplayTreeMap` was changed to allow `null` as key if the `compare`
- function allows it. It now checks that a new key can be used as an
- argument to the `compare` function when the member is added,
- *even if the map is empty* (in which case it just compares the key
- to itself).
-- The `SplayTreeSet` was changed to checks that a new element can be used as an
- argument to the `compare` function when the member is added,
- *even if the set is empty* (in which case it just compares the element
- to itself).
+* The `SplayTreeMap` was changed to allow `null` as key if the `compare`
+ function allows it. It now checks that a new key can be used as an argument
+ to the `compare` function when the member is added, *even if the map is
+ empty* (in which case it just compares the key to itself).
+
+* The `SplayTreeSet` was changed to checks that a new element can be used as
+ an argument to the `compare` function when the member is added, *even if the
+ set is empty* (in which case it just compares the element to itself).
#### `dart:developer`
-- Added `serverWebSocketUri` property to `ServiceProtocolInfo`.
+* Added `serverWebSocketUri` property to `ServiceProtocolInfo`.
### Dart VM
@@ -202,21 +201,21 @@
#### Analyzer
-- Static analyses with "error" severity can once again be ignored with
- comments like `// ignore: code` and `// ignore_for_file: code`. To declare
- that certain analysis codes, or codes with certain severities ("error",
- "warning", and "info") cannot be ignored with such comments, list them in
- `analysis_options.yaml`, under the `analyzer` heading, with a new YAML key,
- `cannot-ignore`. For example, to declare that "error" codes and
- `unused_import` cannot be ignored, write the following into
- `analysis_options.yaml`:
+* Static analyses with "error" severity can once again be ignored with
+ comments like `// ignore: code` and `// ignore_for_file: code`. To declare
+ that certain analysis codes, or codes with certain severities ("error",
+ "warning", and "info") cannot be ignored with such comments, list them in
+ `analysis_options.yaml`, under the `analyzer` heading, with a new YAML key,
+ `cannot-ignore`. For example, to declare that "error" codes and
+ `unused_import` cannot be ignored, write the following into
+ `analysis_options.yaml`:
- ```yaml
- analyzer:
- cannot-ignore:
- - error
- - unused_import
- ```
+ ```yaml
+ analyzer:
+ cannot-ignore:
+ - error
+ - unused_import
+ ```
#### dart format
@@ -227,19 +226,17 @@
Updated the Linter to `1.2.1`, which includes:
-- improvements to `iterable_contains_unrelated_type` to better support `List`
- content checks.
-- fixes to `camel_case_types` and `prefer_mixin` to support non-function
- type aliases.
-- fixed `prefer_mixin` to properly make exceptions for `dart.collection`
- legacy mixins.
-- new lint: `use_build_context_synchronously` (experimental).
-- new lint: `avoid_multiple_declarations_per_line`.
-- full library migration to null-safety.
-- new lint: `use_if_null_to_convert_nulls_to_bools`.
-- new lint: `deprecated_consistency`.
-- new lint: `use_named_constants`.
-- deprecation of `avoid_as`.
+* Improved `iterable_contains_unrelated_type` to better support `List` content
+ checks.
+* Fixed `camel_case_types` and `prefer_mixin` to support non-function type
+ aliases.
+* Fixed `prefer_mixin` to properly make exceptions for `dart.collection`
+ legacy mixins.
+* Added new lints `avoid_multiple_declarations_per_line`,
+ `use_if_null_to_convert_nulls_to_bools`, `deprecated_consistency`,
+ `use_named_constants`, `use_build_context_synchronously` (experimental).
+* Deprecated `avoid_as`.
+* Migrated library to null-safety.
### Other libraries
diff --git a/DEPS b/DEPS
index f0a9838..614956d 100644
--- a/DEPS
+++ b/DEPS
@@ -126,6 +126,7 @@
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_rev": "7e00f893440a72de0637970325e4ea44bd1e8c8e",
"linter_tag": "1.4.0",
+ "lints_tag": "f9670df2a66e0ec12eb51554e70c1cbf56c8f5d0",
"logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_rev": "9c4beaac96d8f008078e00b027915f81b665d2de",
@@ -391,6 +392,8 @@
Var("dart_git") + "json_rpc_2.git" + "@" + Var("json_rpc_2_rev"),
Var("dart_root") + "/third_party/pkg/linter":
Var("dart_git") + "linter.git" + "@" + Var("linter_tag"),
+ Var("dart_root") + "/third_party/pkg/lints":
+ Var("dart_git") + "lints.git" + "@" + Var("lints_tag"),
Var("dart_root") + "/third_party/pkg/logging":
Var("dart_git") + "logging.git" + "@" + Var("logging_rev"),
Var("dart_root") + "/third_party/pkg/markdown":
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_missing_required_argument_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_missing_required_argument_test.dart
index 593c68c..ac92cd1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_missing_required_argument_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_missing_required_argument_test.dart
@@ -33,7 +33,6 @@
Future<void> test_constructor_flutter_children() async {
await resolveTestCode('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required List<Widget> children});
@@ -45,7 +44,6 @@
''');
await assertHasFix('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required List<Widget> children});
@@ -60,7 +58,6 @@
Future<void> test_constructor_flutter_hasTrailingComma() async {
await resolveTestCode('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required int a, @required int b});
@@ -72,7 +69,6 @@
''');
await assertHasFix('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required int a, @required int b});
@@ -335,7 +331,6 @@
Future<void> test_param_child() async {
await resolveTestCode('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required String foo, @required Widget child});
@@ -349,7 +344,6 @@
''');
await assertHasFix('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required String foo, @required Widget child});
@@ -367,7 +361,6 @@
Future<void> test_param_children() async {
await resolveTestCode('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required String foo, @required List<Widget> children});
@@ -381,7 +374,6 @@
''');
await assertHasFix('''
import 'package:flutter/widgets.dart';
-import 'package:meta/meta.dart';
class MyWidget extends Widget {
MyWidget({@required String foo, @required List<Widget> children});
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index f56612b..a0f2061 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -592,6 +592,7 @@
HintCode.UNIGNORABLE_IGNORE,
HintCode.UNNECESSARY_CAST,
HintCode.UNNECESSARY_IGNORE,
+ HintCode.UNNECESSARY_IMPORT,
HintCode.UNNECESSARY_NO_SUCH_METHOD,
HintCode.UNNECESSARY_NULL_COMPARISON_FALSE,
HintCode.UNNECESSARY_NULL_COMPARISON_TRUE,
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 49162d7..73797af 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -299,6 +299,8 @@
verifier.generateDuplicateShownHiddenNameHints(errorReporter);
verifier.generateUnusedImportHints(errorReporter);
verifier.generateUnusedShownNameHints(errorReporter);
+ verifier.generateUnnecessaryImportHints(
+ errorReporter, _usedImportedElementsList);
}
// Unused local elements.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 6924788..f6fae99 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -3040,33 +3040,11 @@
ExecutableElementImpl(String name, int offset, {Reference? reference})
: super(name, offset, reference: reference);
- /// Initialize using the given linked node.
- ExecutableElementImpl.forLinkedNode(
- ElementImpl enclosing, Reference reference, AstNode? linkedNode)
- : super.forLinkedNode(enclosing, reference, linkedNode) {
- if (linkedNode is MethodDeclarationImpl) {
- linkedNode.name.staticElement = this;
- } else if (linkedNode is FunctionDeclarationImpl) {
- linkedNode.name.staticElement = this;
- }
- }
-
- @override
- String get displayName {
- if (linkedNode != null) {
- return reference!.name;
- }
- return super.displayName;
- }
-
@override
Element get enclosingElement => super.enclosingElement!;
@override
bool get hasImplicitReturnType {
- if (linkedNode != null) {
- return linkedContext!.hasImplicitReturnType(linkedNode!);
- }
return hasModifier(Modifier.IMPLICIT_TYPE);
}
@@ -3077,18 +3055,11 @@
@override
bool get isAbstract {
- if (linkedNode != null) {
- return !isExternal &&
- enclosingUnit.linkedContext!.isAbstract(linkedNode!);
- }
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isAsynchronous {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.isAsynchronous(linkedNode!);
- }
return hasModifier(Modifier.ASYNCHRONOUS);
}
@@ -3099,9 +3070,6 @@
@override
bool get isExternal {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.isExternal(linkedNode!);
- }
return hasModifier(Modifier.EXTERNAL);
}
@@ -3112,9 +3080,6 @@
@override
bool get isGenerator {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.isGenerator(linkedNode!);
- }
return hasModifier(Modifier.GENERATOR);
}
@@ -3137,22 +3102,10 @@
@override
String get name {
- if (linkedNode != null) {
- return reference!.name;
- }
return super.name!;
}
@override
- int get nameOffset {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.getNameOffset(linkedNode!);
- }
-
- return super.nameOffset;
- }
-
- @override
List<ParameterElement> get parameters =>
ElementTypeProvider.current.getExecutableParameters(this);
@@ -3175,22 +3128,6 @@
/// In most cases, the [parameters] getter should be used instead.
List<ParameterElement> get parametersInternal {
linkedData?.read(this);
- if (!identical(_parameters, _Sentinel.parameterElement)) {
- return _parameters;
- }
-
- if (linkedNode != null) {
- var context = enclosingUnit.linkedContext!;
- var containerRef = reference!.getChild('@parameter');
- var formalParameters = context.getFormalParameters(linkedNode!);
- _parameters = ParameterElementImpl.forLinkedNodeList(
- this,
- context,
- containerRef,
- formalParameters,
- );
- }
-
return _parameters;
}
@@ -3740,8 +3677,8 @@
FunctionType? _type;
GenericFunctionTypeElementImpl.forLinkedNode(
- ElementImpl enclosingElement, Reference? reference, AstNode linkedNode)
- : super.forLinkedNode(enclosingElement, reference, linkedNode) {
+ ElementImpl enclosingElement, AstNode linkedNode)
+ : super.forLinkedNode(enclosingElement, null, linkedNode) {
if (linkedNode is GenericFunctionTypeImpl) {
linkedNode.declaredElement = this;
}
@@ -5133,26 +5070,10 @@
NonParameterVariableElementImpl(String name, int offset)
: super(name, offset);
- NonParameterVariableElementImpl.forLinkedNode(
- ElementImpl enclosing, Reference reference, AstNode linkedNode)
- : super.forLinkedNode(enclosing, reference, linkedNode);
-
@override
Element get enclosingElement => super.enclosingElement!;
- @override
- bool get hasImplicitType {
- if (linkedNode != null) {
- return linkedContext!.hasImplicitType(linkedNode!);
- }
- return super.hasImplicitType;
- }
-
bool get hasInitializer {
- if (linkedNode != null) {
- return linkedContext!
- .hasInitializer(linkedNode as VariableDeclarationImpl);
- }
return hasModifier(Modifier.HAS_INITIALIZER);
}
@@ -5160,31 +5081,6 @@
set hasInitializer(bool hasInitializer) {
setModifier(Modifier.HAS_INITIALIZER, hasInitializer);
}
-
- @override
- String get name {
- if (linkedNode != null) {
- return reference!.name;
- }
- return super.name;
- }
-
- @override
- int get nameOffset {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.getNameOffset(linkedNode!);
- }
-
- return super.nameOffset;
- }
-
- @override
- DartType get type => ElementTypeProvider.current.getVariableType(this);
-
- @override
- set type(DartType type) {
- _type = type;
- }
}
/// A concrete implementation of a [ParameterElement].
@@ -5910,10 +5806,6 @@
/// [offset].
PropertyInducingElementImpl(String name, int offset) : super(name, offset);
- PropertyInducingElementImpl.forLinkedNode(
- ElementImpl enclosing, Reference reference, AstNode linkedNode)
- : super.forLinkedNode(enclosing, reference, linkedNode);
-
bool get hasTypeInferred => hasModifier(Modifier.HAS_TYPE_INFERRED);
set hasTypeInferred(bool value) {
@@ -5925,9 +5817,6 @@
@override
bool get isLate {
- if (linkedNode != null) {
- return enclosingUnit.linkedContext!.isLate(linkedNode!);
- }
return hasModifier(Modifier.LATE);
}
@@ -5939,19 +5828,6 @@
linkedData?.read(this);
if (_type != null) return _type!;
- if (linkedNode != null) {
- // While performing inference during linking, the first step is to collect
- // dependencies. During this step we resolve the expression, but we might
- // reference elements that don't have their types inferred yet. So, here
- // we give some type. A better solution would be to infer recursively, but
- // we are not doing this yet.
- if (_type == null) {
- assert(linkedContext!.isLinking);
- return DynamicTypeImpl.instance;
- }
-
- return _type!;
- }
if (isSynthetic && _type == null) {
if (getter != null) {
_type = getter!.returnType;
@@ -6301,10 +6177,8 @@
type.declaredElement as GenericFunctionTypeElementImpl?;
// TODO(scheglov) Do we need this?
// We probably should set it when linking and when applying.
- // TODO(scheglov) And remove the reference!.
_aliasedElement ??= GenericFunctionTypeElementImpl.forLinkedNode(
this,
- reference!.getChild('@function'),
type,
);
} else if (isNonFunctionTypeAliasesEnabled) {
@@ -6317,10 +6191,9 @@
..returnType = DynamicTypeImpl.instance;
}
} else {
- // TODO(scheglov) Same as above (both).
+ // TODO(scheglov) Same as above.
_aliasedElement = GenericFunctionTypeElementImpl.forLinkedNode(
this,
- reference!.getChild('@function'),
linkedNode,
);
}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 3df1687..da49e89 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -2684,6 +2684,12 @@
"Try removing the name from the list, or removing the whole comment "
"if this is the only name in the list.");
+ static const HintCode UNNECESSARY_IMPORT = HintCode(
+ 'UNNECESSARY_IMPORT',
+ "The import of '{0}' is unnecessary as all of the used elements are also "
+ "provided by the import of '{1}'.",
+ correction: 'Try removing the import directive.');
+
/**
* Unnecessary `noSuchMethod` declaration.
*/
diff --git a/pkg/analyzer/lib/src/error/imports_verifier.dart b/pkg/analyzer/lib/src/error/imports_verifier.dart
index 6759bd2..4568292 100644
--- a/pkg/analyzer/lib/src/error/imports_verifier.dart
+++ b/pkg/analyzer/lib/src/error/imports_verifier.dart
@@ -126,6 +126,7 @@
return false;
}
+ /// Records use of an unprefixed [element].
void _recordUsedElement(Element element) {
// Ignore if an unknown library.
var containingLibrary = element.library;
@@ -353,6 +354,20 @@
});
}
+ /// Report an [HintCode.UNNECESSARY_IMPORT] hint for each unnecessary import.
+ ///
+ /// Only call this method after unused imports have been determined by
+ /// [removeUsedElements].
+ void generateUnnecessaryImportHints(ErrorReporter errorReporter,
+ List<UsedImportedElements> usedImportedElementsList) {
+ var usedImports = {..._allImports}..removeAll(_unusedImports);
+
+ var verifier = _UnnecessaryImportsVerifier(_namespaceMap, usedImports);
+ verifier.processUsedElements(
+ usedImportedElementsList, _prefixElementMap, _allImports);
+ verifier.reportImports(errorReporter);
+ }
+
/// Report an [HintCode.UNUSED_IMPORT] hint for each unused import.
///
/// Only call this method after all of the compilation units have been visited
@@ -433,17 +448,12 @@
// shouldn't confuse by also reporting an unused prefix.
_unusedImports.remove(importDirective);
}
- var namespace = _computeNamespace(importDirective);
+ var namespace = _namespaceMap.computeNamespace(importDirective);
if (namespace == null) {
continue;
}
for (var element in elements) {
- var elementFromNamespace =
- namespace.getPrefixed(prefix.name, element.name!);
- if (elementFromNamespace != null) {
- if (_isShadowing(element, elementFromNamespace)) {
- continue;
- }
+ if (namespace.providesPrefixed(prefix.name, element)) {
_unusedImports.remove(importDirective);
_removeFromUnusedShownNamesMap(element, importDirective);
}
@@ -458,15 +468,11 @@
}
// Find import directives using namespaces.
for (ImportDirective importDirective in _allImports) {
- var namespace = _computeNamespace(importDirective);
+ var namespace = _namespaceMap.computeNamespace(importDirective);
if (namespace == null) {
continue;
}
- var elementFromNamespace = namespace.get(element.name!);
- if (elementFromNamespace != null) {
- if (_isShadowing(element, elementFromNamespace)) {
- continue;
- }
+ if (namespace.provides(element)) {
_unusedImports.remove(importDirective);
_removeFromUnusedShownNamesMap(element, importDirective);
}
@@ -477,14 +483,14 @@
if (everythingIsKnownToBeUsed()) {
return;
}
+ var elementName = extensionElement.name!;
// Find import directives using namespaces.
for (ImportDirective importDirective in _allImports) {
- var namespace = _computeNamespace(importDirective);
+ var namespace = _namespaceMap.computeNamespace(importDirective);
if (namespace == null) {
continue;
}
var prefix = importDirective.prefix?.name;
- var elementName = extensionElement.name!;
if (prefix == null) {
if (namespace.get(elementName) == extensionElement) {
_unusedImports.remove(importDirective);
@@ -552,45 +558,6 @@
}
}
- /// Lookup and return the [Namespace] from the [_namespaceMap].
- ///
- /// If the map does not have the computed namespace, compute it and cache it
- /// in the map. If [importDirective] is not resolved or is not resolvable,
- /// `null` is returned.
- ///
- /// @param importDirective the import directive used to compute the returned
- /// namespace
- /// @return the computed or looked up [Namespace]
- Namespace? _computeNamespace(ImportDirective importDirective) {
- var namespace = _namespaceMap[importDirective];
- if (namespace == null) {
- // If the namespace isn't in the namespaceMap, then compute and put it in
- // the map.
- var importElement = importDirective.element;
- if (importElement != null) {
- namespace = importElement.namespace;
- _namespaceMap[importDirective] = namespace;
- }
- }
- return namespace;
- }
-
- /// Returns whether [e1] shadows [e2], assuming each is an imported element,
- /// and that each is imported with the same prefix.
- ///
- /// Returns false if the source of either element is `null`.
- bool _isShadowing(Element e1, Element e2) {
- var source1 = e1.source;
- if (source1 == null) {
- return false;
- }
- var source2 = e2.source;
- if (source2 == null) {
- return false;
- }
- return !source1.isInSystemLibrary && source2.isInSystemLibrary;
- }
-
/// Remove [element] from the list of names shown by [importDirective].
void _removeFromUnusedShownNamesMap(
Element element, ImportDirective importDirective) {
@@ -633,3 +600,189 @@
/// The set of extensions defining members that are referenced.
final Set<ExtensionElement> usedExtensions = {};
}
+
+/// A class which verifies (and reports) whether any import directives are
+/// unnecessary.
+///
+/// In a given library, every import directive has a set of "used elements," the
+/// subset of elements provided by the import which are used in the library. In
+/// a given library, an import directive is "unnecessary" if there exists at
+/// least one other import directive with the same prefix as the aforementioned
+/// import directive, and a "used elements" set which is a proper superset of
+/// the aforementioned import directive's "used elements" set.
+class _UnnecessaryImportsVerifier {
+ /// The cache of [Namespace]s for [ImportDirective]s.
+ final Map<ImportDirective, Namespace> _namespaceMap;
+
+ /// The set of imports which provide at least one element used in the library.
+ final Set<ImportDirective> _usedImports;
+
+ /// The mapping of each import to its "used elements" set.
+ ///
+ /// This is computed in [processUsedElements].
+ final Map<ImportDirective, Set<Element>> _usedElementSets = {};
+
+ _UnnecessaryImportsVerifier(this._namespaceMap, this._usedImports);
+
+ /// Determines the "used elements" set for each import directive in
+ /// [allImports].
+ void processUsedElements(
+ List<UsedImportedElements> usedImportedElementsList,
+ Map<PrefixElement, List<ImportDirective>> prefixElementMap,
+ List<ImportDirective> allImports,
+ ) {
+ assert(_usedElementSets.isEmpty);
+ for (var usedElements in usedImportedElementsList) {
+ _processPrefixedElements(usedElements, prefixElementMap);
+ _processUnprefixedElements(usedElements);
+ _processExtensionElements(usedElements, allImports);
+ }
+ }
+
+ /// Reports the import directives which are unnecessary.
+ void reportImports(ErrorReporter errorReporter) {
+ for (var importDirective in _usedImports) {
+ if (!_usedElementSets.containsKey(importDirective)) continue;
+ for (var otherImport in _usedImports) {
+ if (otherImport == importDirective) continue;
+ if (importDirective.prefix?.name != otherImport.prefix?.name) continue;
+ if (!_usedElementSets.containsKey(otherImport)) continue;
+ var importElementSet = _usedElementSets[importDirective]!;
+ var otherElementSet = _usedElementSets[otherImport]!;
+ if (otherElementSet.containsAll(importElementSet)) {
+ if (otherElementSet.length > importElementSet.length) {
+ StringLiteral uri = importDirective.uri;
+ errorReporter.reportErrorForNode(HintCode.UNNECESSARY_IMPORT, uri,
+ [uri.stringValue, otherImport.uri.stringValue]);
+ // Break out of the loop of "other imports" to prevent reporting
+ // UNNECESSARY_IMPORT on [importDirective] multiple times.
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void _processExtensionElements(
+ UsedImportedElements usedElements, List<ImportDirective> allImports) {
+ for (ExtensionElement extensionElement in usedElements.usedExtensions) {
+ var elementName = extensionElement.name;
+ if (elementName == null) break;
+ // Find import directives using namespaces.
+ for (ImportDirective importDirective in allImports) {
+ var namespace = _namespaceMap.computeNamespace(importDirective);
+ if (namespace == null) {
+ continue;
+ }
+ var prefix = importDirective.prefix?.name;
+ if (prefix == null) {
+ if (namespace.get(elementName) == extensionElement) {
+ _usedElementSets
+ .putIfAbsent(importDirective, () => {})
+ .add(extensionElement);
+ }
+ } else {
+ // An extension might be used solely because one or more instance
+ // members are referenced, which does not require explicit use of
+ // the prefix. We still indicate that the import directive is used.
+ if (namespace.getPrefixed(prefix, elementName) == extensionElement) {
+ _usedElementSets
+ .putIfAbsent(importDirective, () => {})
+ .add(extensionElement);
+ }
+ }
+ }
+ }
+ }
+
+ void _processPrefixedElements(UsedImportedElements usedElements,
+ Map<PrefixElement, List<ImportDirective>> prefixElementMap) {
+ usedElements.prefixMap
+ .forEach((PrefixElement prefix, List<Element> elements) {
+ var importsForPrefix = prefixElementMap[prefix];
+ if (importsForPrefix == null) {
+ return;
+ }
+ for (var importDirective in importsForPrefix) {
+ var namespace = _namespaceMap.computeNamespace(importDirective);
+ if (namespace == null) {
+ continue;
+ }
+ for (var element in elements) {
+ if (namespace.providesPrefixed(prefix.name, element)) {
+ _usedElementSets
+ .putIfAbsent(importDirective, () => {})
+ .add(element);
+ }
+ }
+ }
+ });
+ }
+
+ void _processUnprefixedElements(UsedImportedElements usedElements) {
+ for (var element in usedElements.elements) {
+ for (var importDirective in _usedImports) {
+ var namespace = _namespaceMap.computeNamespace(importDirective);
+ if (namespace == null) {
+ continue;
+ }
+ if (namespace.provides(element)) {
+ _usedElementSets.putIfAbsent(importDirective, () => {}).add(element);
+ }
+ }
+ }
+ }
+}
+
+extension on Map<ImportDirective, Namespace> {
+ /// Lookup and return the [Namespace] in this Map.
+ ///
+ /// If this map does not have the computed namespace, compute it and cache it
+ /// in this map. If [importDirective] is not resolved or is not resolvable,
+ /// `null` is returned.
+ Namespace? computeNamespace(ImportDirective importDirective) {
+ var namespace = this[importDirective];
+ if (namespace == null) {
+ var importElement = importDirective.element;
+ if (importElement != null) {
+ namespace = importElement.namespace;
+ this[importDirective] = namespace;
+ }
+ }
+ return namespace;
+ }
+}
+
+extension on Namespace {
+ /// Returns whether this provides [element], taking into account system
+ /// library shadowing.
+ bool provides(Element element) {
+ var elementFromNamespace = get(element.name!);
+ return elementFromNamespace != null &&
+ !_isShadowing(element, elementFromNamespace);
+ }
+
+ /// Returns whether this provides [element] with [prefix], taking into account
+ /// system library shadowing.
+ bool providesPrefixed(String prefix, Element element) {
+ var elementFromNamespace = getPrefixed(prefix, element.name!);
+ return elementFromNamespace != null &&
+ !_isShadowing(element, elementFromNamespace);
+ }
+
+ /// Returns whether [e1] shadows [e2], assuming each is an imported element,
+ /// and that each is imported with the same prefix.
+ ///
+ /// Returns false if the source of either element is `null`.
+ bool _isShadowing(Element e1, Element e2) {
+ var source1 = e1.source;
+ if (source1 == null) {
+ return false;
+ }
+ var source2 = e2.source;
+ if (source2 == null) {
+ return false;
+ }
+ return !source1.isInSystemLibrary && source2.isInSystemLibrary;
+ }
+}
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 3f10367..d4aa9f2 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -219,7 +219,11 @@
_linker.elementNodes[element] = node;
_enclosingContext.addParameter(null, element);
}
- element.hasImplicitType = node.type == null && node.parameters == null;
+
+ // TODO(scheglov) https://github.com/dart-lang/sdk/issues/46039
+ // element.hasImplicitType = node.type == null && node.parameters == null;
+ element.hasImplicitType = false;
+
element.isExplicitlyCovariant = node.covariantKeyword != null;
element.isFinal = node.isFinal;
element.metadata = _buildAnnotations(node.metadata);
@@ -631,18 +635,31 @@
required PropertyAccessorElementImpl accessorElement,
}) {
var enclosingRef = _enclosingContext.reference;
- var isTopLevel = enclosingRef.isUnit;
- var containerName = isTopLevel ? '@variable' : '@field';
- var containerRef = enclosingRef.getChild(containerName);
+ var enclosingElement = _enclosingContext.element;
- var propertyRef = containerRef.getChild(name);
- var property = propertyRef.element as PropertyInducingElementImpl?;
- if (property == null) {
- var variable = TopLevelVariableElementImpl(name, -1);
- variable.isSynthetic = true;
- variable.isFinal = accessorElement.isGetter;
- property = variable;
- _enclosingContext.addTopLevelVariable(name, variable);
+ PropertyInducingElementImpl? property;
+ if (enclosingElement is CompilationUnitElement) {
+ var containerRef = enclosingRef.getChild('@variable');
+ var propertyRef = containerRef.getChild(name);
+ property = propertyRef.element as PropertyInducingElementImpl?;
+ if (property == null) {
+ var variable = TopLevelVariableElementImpl(name, -1);
+ variable.isSynthetic = true;
+ variable.isFinal = accessorElement.isGetter;
+ _enclosingContext.addTopLevelVariable(name, variable);
+ property = variable;
+ }
+ } else {
+ var containerRef = enclosingRef.getChild('@field');
+ var propertyRef = containerRef.getChild(name);
+ property = propertyRef.element as PropertyInducingElementImpl?;
+ if (property == null) {
+ var field = FieldElementImpl(name, -1);
+ field.isSynthetic = true;
+ field.isFinal = accessorElement.isGetter;
+ _enclosingContext.addField(name, field);
+ property = field;
+ }
}
accessorElement.variable = property;
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index ecb1d5b..64c3567 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -37,10 +37,6 @@
/// Indicates whether the library is opted into NNBD.
final bool isNNBD;
- /// The depth-first number of the next [GenericFunctionType] node.
- int _nextGenericFunctionTypeId = 0;
-
- Reference? reference;
Scope scope;
ReferenceResolver(
@@ -50,8 +46,7 @@
this.unitReference,
this.isNNBD,
this.scope,
- ) : _typeSystem = libraryElement.typeSystem,
- reference = unitReference;
+ ) : _typeSystem = libraryElement.typeSystem;
@override
void visitBlockFunctionBody(BlockFunctionBody node) {}
@@ -59,10 +54,8 @@
@override
void visitClassDeclaration(ClassDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ClassElementImpl;
- reference = element.reference;
element.accessors; // create elements
element.constructors; // create elements
element.methods; // create elements
@@ -82,16 +75,13 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
void visitClassTypeAlias(ClassTypeAlias node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ClassElementImpl;
- reference = element.reference;
_createTypeParameterElements(element, node.typeParameters);
scope = TypeParameterScope(scope, element.typeParameters);
@@ -104,7 +94,6 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
@@ -116,10 +105,8 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ConstructorElementImpl;
- reference = element.reference;
element.parameters; // create elements
scope = TypeParameterScope(scope, element.typeParameters);
@@ -128,7 +115,6 @@
node.parameters.accept(this);
scope = outerScope;
- reference = outerReference;
}
@override
@@ -150,10 +136,8 @@
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ExtensionElementImpl;
- reference = element.reference;
_createTypeParameterElements(element, node.typeParameters);
scope = TypeParameterScope(scope, element.typeParameters);
@@ -168,7 +152,6 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
@@ -179,10 +162,8 @@
@override
void visitFieldFormalParameter(FieldFormalParameter node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as FieldFormalParameterElementImpl;
- reference = element.reference;
element.parameters; // create elements
_createTypeParameterElements(element, node.typeParameters);
@@ -194,7 +175,6 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
@@ -205,10 +185,8 @@
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ExecutableElementImpl;
- reference = element.reference;
element.parameters; // create elements
_createTypeParameterElements(
@@ -223,7 +201,6 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
@@ -235,10 +212,8 @@
@override
void visitFunctionTypeAlias(FunctionTypeAlias node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as TypeAliasElementImpl;
- reference = element.reference;
_createTypeParameterElements(element, node.typeParameters);
scope = TypeParameterScope(outerScope, element.typeParameters);
@@ -247,23 +222,19 @@
node.typeParameters?.accept(this);
var function = element.aliasedElement as GenericFunctionTypeElementImpl;
- reference = function.reference;
function.parameters; // create elements
node.parameters.accept(this);
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ParameterElementImpl;
- reference = element.reference;
element.parameters; // create elements
_createTypeParameterElements(element, node.typeParameters);
@@ -275,23 +246,15 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
void visitGenericFunctionType(GenericFunctionType node) {
var nodeImpl = node as GenericFunctionTypeImpl;
var outerScope = scope;
- var outerReference = reference;
-
- // TODO(scheglov) remove reference
- var id = _nextGenericFunctionTypeId++;
- var containerRef = unitReference.getChild('@genericFunctionType');
- reference = containerRef.getChild('$id');
var element = GenericFunctionTypeElementImpl.forLinkedNode(
unitReference.element as CompilationUnitElementImpl,
- reference,
node,
);
element.parameters; // create elements
@@ -309,16 +272,13 @@
nodesToBuildType.addTypeBuilder(builder);
scope = outerScope;
- reference = outerReference;
}
@override
void visitGenericTypeAlias(GenericTypeAlias node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as TypeAliasElementImpl;
- reference = element.reference;
_createTypeParameterElements(element, node.typeParameters);
scope = TypeParameterScope(outerScope, element.typeParameters);
@@ -335,7 +295,6 @@
}
scope = outerScope;
- reference = outerReference;
}
@override
@@ -346,10 +305,8 @@
@override
void visitMethodDeclaration(MethodDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as ExecutableElementImpl;
- reference = element.reference;
element.parameters; // create elements
_createTypeParameterElements(element, node.typeParameters);
@@ -363,16 +320,13 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
var outerScope = scope;
- var outerReference = reference;
var element = node.declaredElement as MixinElementImpl;
- reference = element.reference;
element.accessors; // create elements
element.constructors; // create elements
element.methods; // create elements
@@ -391,7 +345,6 @@
nodesToBuildType.addDeclaration(node);
scope = outerScope;
- reference = outerReference;
}
@override
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index d63db66..158f28a 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -7,6 +7,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -132,7 +133,7 @@
_ConstructorInferenceNode(this._walker, this._constructor) {
for (var parameter in _constructor.parameters) {
if (parameter is FieldFormalParameterElementImpl) {
- if (parameter.hasImplicitType) {
+ if (_hasImplicitType(parameter)) {
var field = parameter.field;
if (field != null) {
_parameters.add(
@@ -172,6 +173,18 @@
}
isEvaluated = true;
}
+
+ /// TODO(scheglov) https://github.com/dart-lang/sdk/issues/46039
+ bool _hasImplicitType(FieldFormalParameterElementImpl parameter) {
+ var parameterNode = _walker._linker.getLinkingNode(parameter);
+ if (parameterNode is DefaultFormalParameter) {
+ parameterNode = parameterNode.parameter;
+ }
+ return parameterNode is FieldFormalParameterImpl &&
+ parameterNode.type == null &&
+ parameterNode.parameters == null;
+ // return parameter.hasImplicitType;
+ }
}
/// A field formal parameter with a non-nullable field.
diff --git a/pkg/analyzer/test/src/diagnostics/avoid_types_as_parameter_names_test.dart b/pkg/analyzer/test/src/diagnostics/avoid_types_as_parameter_names_test.dart
new file mode 100644
index 0000000..f6563a0
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/avoid_types_as_parameter_names_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, 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/src/dart/error/lint_codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+/// TODO(scheglov) Remove the file after fixing the linter.
+/// https://github.com/dart-lang/sdk/issues/46039
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(AvoidTypesAsParameterNamesTest);
+ });
+}
+
+@reflectiveTest
+class AvoidTypesAsParameterNamesTest extends PubPackageResolutionTest {
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackageAnalysisOptionsFile(
+ AnalysisOptionsFileConfig(
+ lints: [
+ 'avoid_types_as_parameter_names',
+ ],
+ ),
+ );
+ }
+
+ test_fieldFormalParameter() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ final int num;
+ const A(this.num);
+}
+''');
+ }
+
+ test_simpleFormalParameter_function() async {
+ await assertErrorsInCode(r'''
+void f(int) {}
+''', [
+ error(LintCode('avoid_types_as_parameter_names', ''), 7, 3),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_import_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_import_test.dart
index 427f023..85eb884 100644
--- a/pkg/analyzer/test/src/diagnostics/duplicate_import_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/duplicate_import_test.dart
@@ -63,7 +63,6 @@
library L;
import 'lib1.dart';
import 'lib1.dart' hide A;
-A a = A();
B b = B();
''');
@@ -75,12 +74,13 @@
newFile('$testPackageLibPath/lib1.dart', content: r'''
library lib1;
class A {}
-class B {}''');
+class B {}
+''');
newFile('$testPackageLibPath/lib2.dart', content: r'''
library L;
import 'lib1.dart';
-import 'lib1.dart' show A;
+import 'lib1.dart' show A; // ignore: unnecessary_import
A a = A();
B b = B();
''');
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart
index 00b7f90..89c5750 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -24,6 +25,10 @@
}
''', [
error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+ // TODO(srawlins): Don't report this from within a mixin.
+ // TODO(scheglov) https://github.com/dart-lang/sdk/issues/46039
+ error(
+ CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, 29, 6),
]);
var element = findElement.mixin('M');
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 29b0461..5be1286 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -34,6 +34,8 @@
import 'async_for_in_wrong_context_test.dart' as async_for_in_wrong_context;
import 'async_keyword_used_as_identifier_test.dart'
as async_keyword_used_as_identifier;
+import 'avoid_types_as_parameter_names_test.dart'
+ as avoid_types_as_parameter_names;
import 'await_in_late_local_variable_initializer_test.dart'
as await_in_late_local_variable_initializer;
import 'await_in_wrong_context_test.dart' as await_in_wrong_context;
@@ -646,6 +648,7 @@
import 'unignorable_ignore_test.dart' as unignorable_ignore;
import 'unnecessary_cast_test.dart' as unnecessary_cast;
import 'unnecessary_ignore_test.dart' as unnecessary_ignore;
+import 'unnecessary_import_test.dart' as unnecessary_import;
import 'unnecessary_no_such_method_test.dart' as unnecessary_no_such_method;
import 'unnecessary_non_null_assertion_test.dart'
as unnecessary_non_null_assertion;
@@ -709,6 +712,7 @@
assignment_to_type.main();
async_for_in_wrong_context.main();
async_keyword_used_as_identifier.main();
+ avoid_types_as_parameter_names.main();
await_in_late_local_variable_initializer.main();
await_in_wrong_context.main();
binary_operator_written_out.main();
@@ -1115,6 +1119,7 @@
undefined_setter.main();
undefined_shown_name.main();
unignorable_ignore.main();
+ unnecessary_import.main();
unnecessary_cast.main();
unnecessary_ignore.main();
unnecessary_no_such_method.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unnecessary_import_test.dart b/pkg/analyzer/test/src/diagnostics/unnecessary_import_test.dart
new file mode 100644
index 0000000..b6071fc
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unnecessary_import_test.dart
@@ -0,0 +1,228 @@
+// Copyright (c) 2021, 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/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(UnnecessaryImportTest);
+ });
+}
+
+@reflectiveTest
+class UnnecessaryImportTest extends PubPackageResolutionTest {
+ test_annotationOnDirective() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class A {
+ const A() {}
+}
+''');
+ await assertNoErrorsInCode(r'''
+@A()
+import 'lib1.dart';
+''');
+ }
+
+ test_as() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: '''
+export 'lib1.dart';
+class B {}
+''');
+ await assertNoErrorsInCode('''
+import 'lib1.dart';
+import 'lib2.dart' as two;
+f(A a, two.B b) {}
+''');
+ }
+
+ test_as_differentPrefixes() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: '''
+export 'lib1.dart';
+class B {}
+''');
+ await assertNoErrorsInCode('''
+import 'lib1.dart' as one;
+import 'lib2.dart' as two;
+f(one.A a, two.B b) {}
+''');
+ }
+
+ test_as_equalPrefixes_referenced() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: r'''
+class B {}
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' as one;
+import 'lib2.dart' as one;
+f(one.A a, one.B b) {}
+''');
+ }
+
+ test_as_equalPrefixes_referenced_via_export() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: r'''
+class B {}
+''');
+ newFile('$testPackageLibPath/lib3.dart', content: r'''
+export 'lib2.dart';
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' as one;
+import 'lib3.dart' as one;
+f(one.A a, one.B b) {}
+''');
+ }
+
+ test_as_equalPrefixes_unreferenced() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: r'''
+class B {}
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' as one;
+import 'lib2.dart' as one; // ignore: unused_import
+f(one.A a) {}
+''');
+ }
+
+ test_as_show_multipleElements() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class A {}
+class B {}
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' as one show A, B;
+f(one.A a, one.B b) {}
+''');
+ }
+
+ test_as_showTopLevelFunction() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class One {}
+topLevelFunction() {}
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' hide topLevelFunction;
+import 'lib1.dart' as one show topLevelFunction;
+f(One o) {
+ one.topLevelFunction();
+}
+''');
+ }
+
+ test_as_showTopLevelFunction_multipleDirectives() async {
+ newFile('$testPackageLibPath/lib1.dart', content: r'''
+class One {}
+topLevelFunction() {}
+''');
+ await assertNoErrorsInCode(r'''
+import 'lib1.dart' hide topLevelFunction;
+import 'lib1.dart' as one show topLevelFunction;
+import 'lib1.dart' as two show topLevelFunction;
+f(One o) {
+ one.topLevelFunction();
+ two.topLevelFunction();
+}
+''');
+ }
+
+ test_as_systemShadowing() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class File {}
+''');
+ await assertNoErrorsInCode('''
+import 'dart:io' as io;
+import 'lib1.dart' as io;
+g(io.Directory d, io.File f) {}
+''');
+ }
+
+ test_as_unnecessary() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: '''
+export 'lib1.dart';
+class B {}
+''');
+ await assertErrorsInCode('''
+import 'lib1.dart' as p;
+import 'lib2.dart' as p;
+f(p.A a, p.B b) {}
+''', [
+ error(HintCode.UNNECESSARY_IMPORT, 7, 11),
+ ]);
+ }
+
+ test_duplicteImport_differentPrefix() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+class B {}
+''');
+ await assertNoErrorsInCode('''
+import 'lib1.dart';
+import 'lib1.dart' as p;
+f(A a1, p.A a2, B b) {}
+''');
+ }
+
+ test_hide() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: '''
+export 'lib1.dart' hide A;
+class B {}
+''');
+ await assertNoErrorsInCode('''
+import 'lib1.dart';
+import 'lib2.dart';
+f(A a, B b) {}
+''');
+ }
+
+ test_systemShadowing() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class File {}
+''');
+ await assertNoErrorsInCode('''
+import 'dart:io';
+import 'lib1.dart';
+g(Directory d, File f) {}
+''');
+ }
+
+ test_unnecessaryImport() async {
+ newFile('$testPackageLibPath/lib1.dart', content: '''
+class A {}
+''');
+ newFile('$testPackageLibPath/lib2.dart', content: '''
+export 'lib1.dart';
+class B {}
+''');
+ await assertErrorsInCode('''
+import 'lib1.dart';
+import 'lib2.dart';
+f(A a, B b) {}
+''', [
+ error(HintCode.UNNECESSARY_IMPORT, 7, 11),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 978991d..38c1c87 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -922,7 +922,8 @@
}
}
- if (e.enclosingElement is ClassElement) {
+ if (e.enclosingElement is ClassElement ||
+ e.enclosingElement is ExtensionElement) {
writeDocumentation(e, ' ');
writeMetadata(e, ' ', '\n');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 8734347..2cf8b1b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -13106,6 +13106,21 @@
''');
}
+ test_type_inference_using_extension_getter() async {
+ var library = await checkLibrary('''
+extension on String {
+ int get foo => 0;
+}
+var v = 'a'.foo;
+''');
+ checkElementText(library, '''
+extension on String {
+ int get foo {}
+}
+int v;
+''');
+ }
+
test_type_invalid_topLevelVariableElement_asType() async {
var library = await checkLibrary('''
class C<T extends V> {}
diff --git a/pkg/dartdev/README.md b/pkg/dartdev/README.md
index eaee08f..6679562 100644
--- a/pkg/dartdev/README.md
+++ b/pkg/dartdev/README.md
@@ -3,7 +3,7 @@
```
A command-line utility for Dart development.
-Usage: dart [<vm-flags>] <command|dart-file> [<arguments>]
+Usage: dart [vm-options] <command|dart-file> [arguments]
Global options:
-h, --help Print this usage information.
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 5e581c5..cbe7945 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -69,12 +69,14 @@
allowTrailingOptions: false,
);
+ final bool verbose;
+
static const String dartdevDescription =
'A command-line utility for Dart development';
- DartdevRunner(List<String> args) : super('dart', '$dartdevDescription.') {
- final bool verbose = args.contains('-v') || args.contains('--verbose');
-
+ DartdevRunner(List<String> args)
+ : verbose = args.contains('-v') || args.contains('--verbose'),
+ super('dart', '$dartdevDescription.') {
argParser.addFlag('verbose',
abbr: 'v', negatable: false, help: 'Show additional command output.');
argParser.addFlag('version',
@@ -112,7 +114,7 @@
@override
String get invocation =>
- 'dart [<vm-flags>] <command|dart-file> [<arguments>]';
+ 'dart ${verbose ? '[vm-options] ' : ''}<command|dart-file> [arguments]';
@visibleForTesting
Analytics get analytics => _analytics;
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 3292669..ea90429 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -36,7 +36,7 @@
static final int _return = '\r'.codeUnitAt(0);
AnalyzeCommand({bool verbose = false})
- : super(cmdName, 'Analyze Dart code in a directory.') {
+ : super(cmdName, 'Analyze Dart code in a directory.', verbose) {
argParser
..addFlag('fatal-infos',
help: 'Treat info level issues as fatal.', negatable: false)
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index c7e2e8f..3b476e4 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -67,7 +67,7 @@
static const String cmdName = 'js';
CompileJSCommand({bool verbose})
- : super(cmdName, 'Compile Dart to JavaScript.') {
+ : super(cmdName, 'Compile Dart to JavaScript.', verbose) {
argParser
..addOption(
commonOptions['outputFile'].flag,
@@ -173,7 +173,7 @@
this.fileExt,
this.formatName,
bool verbose,
- }) : super(commandName, 'Compile Dart $help') {
+ }) : super(commandName, 'Compile Dart $help', verbose) {
argParser
..addOption(
commonOptions['outputFile'].flag,
@@ -267,7 +267,7 @@
this.format,
this.help,
bool verbose,
- }) : super(commandName, 'Compile Dart $help') {
+ }) : super(commandName, 'Compile Dart $help', verbose) {
argParser
..addOption(
commonOptions['outputFile'].flag,
@@ -348,15 +348,15 @@
}
abstract class CompileSubcommandCommand extends DartdevCommand {
- CompileSubcommandCommand(String name, String description,
+ CompileSubcommandCommand(String name, String description, bool verbose,
{bool hidden = false})
- : super(name, description, hidden: hidden);
+ : super(name, description, verbose, hidden: hidden);
}
class CompileCommand extends DartdevCommand {
static const String cmdName = 'compile';
CompileCommand({bool verbose = false})
- : super(cmdName, 'Compile Dart to various formats.') {
+ : super(cmdName, 'Compile Dart to various formats.', verbose) {
addSubcommand(CompileJSCommand(
verbose: verbose,
));
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index d387bd4..c7a3ca9 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -24,7 +24,7 @@
generators.map((generator) => generator.id).toList();
CreateCommand({bool verbose = false})
- : super(cmdName, 'Create a new Dart project.') {
+ : super(cmdName, 'Create a new Dart project.', verbose) {
argParser.addOption(
'template',
allowed: legalTemplateIds,
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index a9feca7..546d5fa 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -26,7 +26,7 @@
To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed changes for a project, or ['dart fix --apply'] to apply the changes.''';
- FixCommand({bool verbose = false}) : super(cmdName, cmdDescription) {
+ FixCommand({bool verbose = false}) : super(cmdName, cmdDescription, verbose) {
argParser.addFlag('dry-run',
abbr: 'n',
defaultsTo: false,
diff --git a/pkg/dartdev/lib/src/commands/language_server.dart b/pkg/dartdev/lib/src/commands/language_server.dart
index 924ae19..2821682 100644
--- a/pkg/dartdev/lib/src/commands/language_server.dart
+++ b/pkg/dartdev/lib/src/commands/language_server.dart
@@ -25,7 +25,7 @@
https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server''';
LanguageServerCommand({bool verbose = false})
- : super(commandName, commandDescription, hidden: !verbose);
+ : super(commandName, commandDescription, verbose, hidden: !verbose);
@override
ArgParser createArgParser() {
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index d996c3c..f6015bd 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -41,6 +41,7 @@
: super(
cmdName,
'Run a Dart program.',
+ verbose,
) {
// NOTE: When updating this list of flags, be sure to add any VM flags to
// the list of flags in Options::ProcessVMDebuggingOptions in
@@ -167,7 +168,8 @@
}
@override
- String get invocation => '${super.invocation} <dart file | package target>';
+ String get invocation =>
+ '${super.invocation} [<dart-file|package-target> [args]]';
@override
FutureOr<int> run() async {
diff --git a/pkg/dartdev/lib/src/commands/test.dart b/pkg/dartdev/lib/src/commands/test.dart
index 7261896..c6711c7 100644
--- a/pkg/dartdev/lib/src/commands/test.dart
+++ b/pkg/dartdev/lib/src/commands/test.dart
@@ -17,7 +17,7 @@
class TestCommand extends DartdevCommand {
static const String cmdName = 'test';
- TestCommand() : super(cmdName, 'Run tests for a project.');
+ TestCommand() : super(cmdName, 'Run tests for a project.', false);
// This argument parser is here solely to ensure that VM specific flags are
// provided before any command and to provide a more consistent help message
diff --git a/pkg/dartdev/lib/src/core.dart b/pkg/dartdev/lib/src/core.dart
index 9a62f6d..2da96fc 100644
--- a/pkg/dartdev/lib/src/core.dart
+++ b/pkg/dartdev/lib/src/core.dart
@@ -21,13 +21,15 @@
abstract class DartdevCommand extends Command<int> {
final String _name;
final String _description;
+ final bool _verbose;
Project _project;
@override
final bool hidden;
- DartdevCommand(this._name, this._description, {this.hidden = false});
+ DartdevCommand(this._name, this._description, this._verbose,
+ {this.hidden = false});
@override
String get name => _name;
@@ -40,6 +42,17 @@
@override
ArgParser get argParser => _argParser ??= createArgParser();
+ @override
+ String get invocation {
+ if (_verbose) {
+ final splitInvocation = super.invocation.split(' ');
+ splitInvocation.insert(1, '[vm-options]');
+ return splitInvocation.join(' ');
+ } else {
+ return super.invocation;
+ }
+ }
+
/// Create the ArgParser instance for this command.
///
/// Subclasses can override this in order to create a customized ArgParser.
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 8017a0c..fdd5bac 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -19,6 +19,9 @@
const String _analyzeUsageText =
'Usage: dart analyze [arguments] [<directory>]';
+const String _analyzeVerboseUsageText =
+ 'Usage: dart [vm-options] analyze [arguments] [<directory>]';
+
const String _unusedImportAnalysisOptions = '''
analyzer:
errors:
@@ -72,6 +75,16 @@
expect(result.stdout, contains(_analyzeUsageText));
});
+ test('--help --verbose', () {
+ p = project();
+ var result = p.runSync(['analyze', '--help', '--verbose']);
+
+ expect(result.exitCode, 0);
+ expect(result.stderr, isEmpty);
+ expect(result.stdout, contains(_analyzeDescriptionText));
+ expect(result.stdout, contains(_analyzeVerboseUsageText));
+ });
+
test('multiple directories', () {
p = project();
var result = p.runSync(['analyze', '/no/such/dir1/', '/no/such/dir2/']);
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 6b47a28..4bf62f0 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -45,6 +45,27 @@
['compile', '--help'],
);
expect(result.stdout, contains('Compile Dart'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart compile <subcommand> [arguments]',
+ ),
+ );
+ expect(result.exitCode, 0);
+ });
+
+ test('--help --verbose', () {
+ final p = project();
+ final result = p.runSync(
+ ['compile', '--help', '--verbose'],
+ );
+ expect(result.stdout, contains('Compile Dart'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart [vm-options] compile <subcommand> [arguments]',
+ ),
+ );
expect(result.exitCode, 0);
});
diff --git a/pkg/dartdev/test/commands/create_test.dart b/pkg/dartdev/test/commands/create_test.dart
index 86b2d48..969120c 100644
--- a/pkg/dartdev/test/commands/create_test.dart
+++ b/pkg/dartdev/test/commands/create_test.dart
@@ -23,6 +23,36 @@
tearDown(() => p?.dispose());
+ test('--help', () {
+ p = project();
+ var result = p.runSync(['create', '--help']);
+
+ expect(result.stdout, contains('Create a new Dart project.'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart create [arguments] <directory>',
+ ),
+ );
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
+ test('--help --verbose', () {
+ p = project();
+ var result = p.runSync(['create', '--help', '--verbose']);
+
+ expect(result.stdout, contains('Create a new Dart project.'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart [vm-options] create [arguments] <directory>',
+ ),
+ );
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
test('default template exists', () {
expect(CreateCommand.legalTemplateIds,
contains(CreateCommand.defaultTemplateId));
diff --git a/pkg/dartdev/test/commands/fix_test.dart b/pkg/dartdev/test/commands/fix_test.dart
index 69b11c9..97cddf9 100644
--- a/pkg/dartdev/test/commands/fix_test.dart
+++ b/pkg/dartdev/test/commands/fix_test.dart
@@ -60,7 +60,7 @@
return p.runSync(['fix', ...args], workingDir: workingDir);
}
- test('help', () {
+ test('--help', () {
p = project(mainSrc: 'int get foo => 1;\n');
var result = runFix([p.dirPath, '--help']);
@@ -68,7 +68,31 @@
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
expect(
- result.stdout, contains('Apply automated fixes to Dart source code.'));
+ result.stdout,
+ contains(
+ 'Apply automated fixes to Dart source code.',
+ ),
+ );
+ expect(result.stdout, contains('Usage: dart fix [arguments]'));
+ });
+
+ test('--help --verbose', () {
+ p = project(mainSrc: 'int get foo => 1;\n');
+
+ var result = runFix([p.dirPath, '--help', '--verbose']);
+
+ expect(result.exitCode, 0);
+ expect(result.stderr, isEmpty);
+ expect(
+ result.stdout,
+ contains(
+ 'Apply automated fixes to Dart source code.',
+ ),
+ );
+ expect(
+ result.stdout,
+ contains('Usage: dart [vm-options] fix [arguments]'),
+ );
});
test('none', () {
diff --git a/pkg/dartdev/test/commands/flag_test.dart b/pkg/dartdev/test/commands/flag_test.dart
index 0475ee3..bfcc02c 100644
--- a/pkg/dartdev/test/commands/flag_test.dart
+++ b/pkg/dartdev/test/commands/flag_test.dart
@@ -66,8 +66,8 @@
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
expect(result.stdout, contains(DartdevRunner.dartdevDescription));
- expect(result.stdout,
- contains('Usage: dart [<vm-flags>] <command|dart-file> [<arguments>]'));
+ expect(
+ result.stdout, contains('Usage: dart <command|dart-file> [arguments]'));
expect(result.stdout, contains('Global options:'));
expect(result.stdout, contains('Available commands:'));
expect(result.stdout, contains('analyze '));
@@ -104,8 +104,8 @@
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
expect(result.stdout, contains(DartdevRunner.dartdevDescription));
- expect(result.stdout,
- contains('Usage: dart [<vm-flags>] <command|dart-file> [<arguments>]'));
+ expect(
+ result.stdout, contains('Usage: dart <command|dart-file> [arguments]'));
expect(result.stdout, contains('Global options:'));
expect(result.stdout, contains('Available commands:'));
expect(result.stdout, contains('analyze '));
@@ -120,6 +120,8 @@
var result = p.runSync(['help', '--verbose']);
expect(result.exitCode, 0);
+ expect(result.stdout,
+ contains('Usage: dart [vm-options] <command|dart-file> [arguments]'));
expect(result.stdout, contains('migrate '));
});
@@ -128,6 +130,8 @@
var result = p.runSync(['help', '-v']);
expect(result.exitCode, 0);
+ expect(result.stdout,
+ contains('Usage: dart [vm-options] <command|dart-file> [arguments]'));
expect(result.stdout, contains('migrate '));
});
}
diff --git a/pkg/dartdev/test/commands/migrate_test.dart b/pkg/dartdev/test/commands/migrate_test.dart
index 500d587..94795be 100644
--- a/pkg/dartdev/test/commands/migrate_test.dart
+++ b/pkg/dartdev/test/commands/migrate_test.dart
@@ -26,9 +26,31 @@
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
expect(
- result.stdout, contains('Perform null safety migration on a project.'));
- expect(result.stdout,
- contains('Usage: dart migrate [arguments] [project or directory]'));
+ result.stdout,
+ contains('Perform null safety migration on a project.'),
+ );
+ expect(
+ result.stdout,
+ contains('Usage: dart migrate [arguments] [project or directory]'),
+ );
+ });
+
+ test('--help --verbose', () {
+ p = project();
+ var result = p.runSync(['migrate', '--help', '--verbose']);
+
+ expect(result.exitCode, 0);
+ expect(result.stderr, isEmpty);
+ expect(
+ result.stdout,
+ contains('Perform null safety migration on a project.'),
+ );
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart [vm-options] migrate [arguments] [project or directory]',
+ ),
+ );
});
test('directory implicit', () {
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index f10f092..cfccec8 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -28,6 +28,28 @@
expect(result.stdout, contains('Run a Dart program.'));
expect(result.stdout, contains('Debugging options:'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart run [arguments] [<dart-file|package-target> [args]]',
+ ),
+ );
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
+ test('--help --verbose', () {
+ p = project();
+ var result = p.runSync(['run', '--help', '--verbose']);
+
+ expect(result.stdout, contains('Run a Dart program.'));
+ expect(result.stdout, contains('Debugging options:'));
+ expect(
+ result.stdout,
+ contains(
+ 'Usage: dart [vm-options] run [arguments] [<dart-file|package-target> [args]]',
+ ),
+ );
expect(result.stderr, isEmpty);
expect(result.exitCode, 0);
});
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index bfdec77..f1b09ac 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -152,7 +152,7 @@
final bool verbose;
MigrateCommand({this.verbose = false})
- : super(cmdName, '$cmdDescription\n\n$migrationGuideLink') {
+ : super(cmdName, '$cmdDescription\n\n$migrationGuideLink', verbose) {
MigrationCli._defineOptions(argParser, !verbose);
}
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 9d98016..9f62c2d 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.dart
@@ -77,10 +77,6 @@
Uint8List convert(String string, [int start = 0, int? end]) {
var stringLength = string.length;
end = RangeError.checkValidRange(start, end, stringLength);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
var length = end - start;
var result = Uint8List(length);
for (var i = 0; i < length; i++) {
@@ -167,10 +163,6 @@
/// `start` to `end` (`end` not inclusive) is used as input to the conversion.
String convert(List<int> bytes, [int start = 0, int? end]) {
end = RangeError.checkValidRange(start, end, bytes.length);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
for (var i = start; i < end; i++) {
var byte = bytes[i];
if ((byte & ~_subsetMask) != 0) {
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index 5fcab0a..c4420c6 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -96,10 +96,6 @@
/// * Validate that the length is correct (a multiple of four).
String normalize(String source, [int start = 0, int? end]) {
end = RangeError.checkValidRange(start, end, source.length);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
const percent = 0x25;
const equals = 0x3d;
StringBuffer? buffer;
@@ -407,10 +403,6 @@
if (buffer == null || buffer.length < bufferLength) {
bufferCache = buffer = Uint8List(bufferLength);
}
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (buffer == null) {
- throw "unreachable";
- }
// Return a view of the buffer, so it has the requested length.
return Uint8List.view(buffer.buffer, buffer.offsetInBytes, bufferLength);
}
@@ -490,10 +482,6 @@
/// The [Uint8List.buffer] may be larger than the decoded bytes.
Uint8List convert(String input, [int start = 0, int? end]) {
end = RangeError.checkValidRange(start, end, input.length);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
if (start == end) return Uint8List(0);
var decoder = _Base64Decoder();
var buffer = decoder.decode(input, start, end)!;
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 317e6c1..69b63a0 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -185,11 +185,6 @@
}
if (replacement != null) {
result ??= StringBuffer();
- // TODO(38725): Remove workaround when assignment promotion is
- // implemented
- if (result == null) {
- throw "unreachable";
- }
if (i > start) result.write(text.substring(start, i));
result.write(replacement);
start = i + 1;
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index fa0be3f..85f0ab6 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -27,10 +27,6 @@
/// (`0 <= start <= end <= lines.length`).
static Iterable<String> split(String lines, [int start = 0, int? end]) sync* {
end = RangeError.checkValidRange(start, end, lines.length);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
var sliceStart = start;
var char = 0;
for (var i = start; i < end; i++) {
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index bbfba77..57a2dac 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -88,10 +88,6 @@
Uint8List convert(String string, [int start = 0, int? end]) {
var stringLength = string.length;
end = RangeError.checkValidRange(start, end, stringLength);
- // TODO(38725): Remove workaround when assignment promotion is implemented
- if (end == null) {
- throw RangeError("Invalid range");
- }
var length = end - start;
if (length == 0) return Uint8List(0);
// Create a new encoder with a length that is guaranteed to be big enough.
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index df48112..5d07d41 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -475,8 +475,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null)
- throw "unreachable"; // TODO(38725): Remove when promotion works.
return data.buffer.asByteData(
data.offsetInBytes + start * elementSize, (end - start) * elementSize);
}
@@ -771,7 +769,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
return data.buffer.asInt8List(
data.offsetInBytes + start * elementSize, (end - start) * elementSize);
}
@@ -882,7 +879,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
return data.buffer.asUint8List(
data.offsetInBytes + start * elementSize, (end - start) * elementSize);
}
@@ -1002,7 +998,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
return data.buffer.asUint8ClampedList(
data.offsetInBytes + start * elementSize, (end - start) * elementSize);
}
@@ -1120,7 +1115,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1244,7 +1238,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1367,7 +1360,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1491,7 +1483,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1614,7 +1605,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1738,7 +1728,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1862,7 +1851,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -1979,7 +1967,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -2095,7 +2082,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -2217,7 +2203,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
@@ -2345,7 +2330,6 @@
int elementSize = data.elementSizeInBytes;
end = RangeError.checkValidRange(
start, end, data.lengthInBytes ~/ elementSize);
- if (end == null) throw "unreachable"; // TODO(38725)
int byteLength = (end - start) * elementSize;
if (byteLength % bytesPerElement != 0) {
throw ArgumentError("The number of bytes to view must be a multiple of " +
diff --git a/tools/VERSION b/tools/VERSION
index 317622d..51c8ca9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 121
+PRERELEASE 122
PRERELEASE_PATCH 0
\ No newline at end of file