Version 2.14.0-172.0.dev
Merge commit 'e453b4c64f8b683297e7f0c18e372033cb580ddc' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a3942c..13329a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -59,13 +59,32 @@
https://github.com/dart-lang/sdk/issues/46100
* The `dart create` command has been updated to create projects that use the new
- 'core' set of lints from `package:lints`. See https://dart.dev/go/core-lints
+ 'recommended' set of lints from `package:lints`. See https://dart.dev/go/core-lints
for more information about these lints.
#### Linter
-Updated the Linter to `1.4.0`, which includes:
+Updated the Linter to `1.5.0`, which includes:
+- (internal) migrated to `SecurityLintCode` instead of deprecated
+ `SecurityLintCodeWithUniqueName`.
+- (internal) fixed `avoid_types_as_parameter_names` to skip field formal
+ parameters.
+- fixed false positives in `prefer_interpolation_to_compose_strings` where
+ the left operand is not a String.
+- fixed false positives in `only_throw_errors` for misidentified type
+ variables.
+- new lint: `depend_on_referenced_packages`.
+- update `avoid_returning_null_for_future` to skip checks for null-safe
+ libraries.
+- new lint: `use_test_throws_matchers`.
+- relaxed `sort_child_properties_last` to accept closures after child.
+- performance improvements for `prefer_contains` and `prefer_is_empty`.
+- new lint: `noop_primitive_operations`.
+- marked `avoid_web_libraries_in_flutter` as stable.
+- new lint: `prefer_final_parameters`.
+- updated `prefer_initializing_formals` to allow assignments where identifier
+ names don't match.
- `directives_ordering` now checks ordering of `package:` imports in code
outside pub packages.
- simple reachability analysis added to `use_build_context_synchronously` to
diff --git a/DEPS b/DEPS
index f0269ec..cf9edd4 100644
--- a/DEPS
+++ b/DEPS
@@ -118,14 +118,14 @@
"http_multi_server_rev": "de1b312164c24a1690b46c6e97bd47eff40c4649",
"http_parser_rev": "7720bfd42a0c096734c5213478fdce92c62f0293",
"http_retry_rev": "845771af7bb5ab38ab740ce4a31f3b0c7680302b",
- "http_rev": "abb2bb182fbd7f03aafd1f889b902d7b3bdb8769",
+ "http_rev": "e89b190936d53d0e36148436283e28ba1091b35a",
"http_throttle_tag" : "1.0.2",
"icu_rev" : "81d656878ec611cb0b42d52c82e9dae93920d9ba",
"idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
"intl_tag": "0.17.0-nullsafety",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_rev": "7e00f893440a72de0637970325e4ea44bd1e8c8e",
- "linter_tag": "1.4.0",
+ "linter_tag": "1.5.0",
"lints_tag": "f9670df2a66e0ec12eb51554e70c1cbf56c8f5d0",
"logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index 4792bed..3550b96 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/instrumentation/service.dart';
@@ -12,6 +13,9 @@
///
/// Clients may not extend, implement or mix-in this class.
abstract class DartFixContext implements FixContext {
+ /// Return the extension cache used to find available extensions.
+ ExtensionCache get extensionCache;
+
/// Return the instrumentation service used to report errors that prevent a
/// fix from being composed.
InstrumentationService get instrumentationService;
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 344f997..db83350 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -686,6 +686,7 @@
path, server.doAnalysisError_listFromEngine(result));
}
analysisServer.getDocumentationCacheFor(result)?.cacheFromResult(result);
+ analysisServer.getExtensionCacheFor(result)?.cacheFromResult(result);
var unit = result.unit;
if (unit != null) {
if (analysisServer._hasAnalysisServiceSubscription(
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index b890a41..616bf9d 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -16,6 +16,7 @@
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/server/diagnostic_server.dart';
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/pub/pub_api.dart';
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
@@ -91,6 +92,10 @@
/// each context.
Map<AnalysisContext, DocumentationCache> documentationForContext = {};
+ /// A map from analysis contexts to the extension cache associated with
+ /// each context.
+ Map<AnalysisContext, ExtensionCache> extensionForContext = {};
+
/// The DiagnosticServer for this AnalysisServer. If available, it can be used
/// to start an http diagnostics server or return the port for an existing
/// server.
@@ -229,6 +234,7 @@
void addContextsToDeclarationsTracker() {
declarationsTracker?.discardContexts();
documentationForContext.clear();
+ extensionForContext.clear();
for (var driver in driverMap.values) {
declarationsTracker?.addContext(driver.analysisContext!);
driver.resetUriResolution();
@@ -347,6 +353,14 @@
return element;
}
+ /// Return the object used to cache information about extensions in the
+ /// context that produced the [result], or `null` if there is no cache for the
+ /// context.
+ ExtensionCache? getExtensionCacheFor(ResolvedUnitResult result) {
+ var context = result.session.analysisContext;
+ return extensionForContext.putIfAbsent(context, () => ExtensionCache());
+ }
+
/// Return a [Future] that completes with the resolved [AstNode] at the
/// given [offset] of the given [file], or with `null` if there is no node as
/// the [offset].
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 57d87fe..4e08659 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -636,7 +636,7 @@
result.path!,
name,
);
- });
+ }, extensionCache: server.getExtensionCacheFor(result));
List<Fix> fixes;
try {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 322e9d8d..b428985 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -312,7 +312,7 @@
unit.path!,
name,
);
- });
+ }, extensionCache: server.getExtensionCacheFor(unit));
final fixes = await fixContributor.computeFixes(context);
if (fixes.isNotEmpty) {
fixes.sort(Fix.SORT_BY_RELEVANCE);
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 17d912b..af14c73 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -836,6 +836,8 @@
final serverErrors = protocol.doAnalysisError_listFromEngine(result);
recordAnalysisErrors(path, serverErrors);
}
+ analysisServer.getDocumentationCacheFor(result)?.cacheFromResult(result);
+ analysisServer.getExtensionCacheFor(result)?.cacheFromResult(result);
final unit = result.unit;
if (unit != null) {
if (analysisServer.shouldSendClosingLabelsFor(path)) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart
new file mode 100644
index 0000000..96decc0
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart
@@ -0,0 +1,105 @@
+// 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/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+
+/// Cached data about the extensions defined in a single analysis context.
+class ExtensionCache {
+ /// A set containing the paths of the compilation units that have been cached.
+ /// The set is used to prevent caching the same data multiple times.
+ final Set<String> processedUnits = {};
+
+ /// A map from the name of a non-static public extension member to the set of
+ /// paths to libraries defining an extension member with that name.
+ final Map<String, Set<UnitInLibrary>> membersByName = {};
+
+ /// Initialize a newly created cache.
+ ExtensionCache();
+
+ /// Fill the cache with data from the [result].
+ void cacheFromResult(ResolvedUnitResult result) {
+ var element = result.unit?.declaredElement;
+ if (element != null) {
+ _cacheFromElement(element);
+ for (var library in result.libraryElement.importedLibraries) {
+ _cacheLibrary(library);
+ }
+ }
+ }
+
+ /// Fill the cache with data from the [compilationUnit].
+ void _cacheFromElement(CompilationUnitElement compilationUnit) {
+ // Record that we've cached data for the compilation unit.
+ var unitPath = _keyForUnit(compilationUnit);
+ processedUnits.add(unitPath);
+
+ // Flush any data that was previously cached for the compilation unit.
+ for (var set in membersByName.values) {
+ set.removeWhere((element) => element.unitPath == unitPath);
+ }
+
+ // Cache the data for the compilation unit.
+ var libraryPath = compilationUnit.librarySource.fullName;
+ for (var extension in compilationUnit.extensions) {
+ var extensionName = extension.name;
+ if (extensionName != null && !Identifier.isPrivateName(extensionName)) {
+ for (var member in extension.accessors) {
+ if (!member.isSynthetic) {
+ _recordMember(unitPath, libraryPath, member.displayName);
+ }
+ }
+ for (var member in extension.fields) {
+ if (!member.isSynthetic) {
+ _recordMember(unitPath, libraryPath, member.name);
+ }
+ }
+ for (var member in extension.methods) {
+ _recordMember(unitPath, libraryPath, member.name);
+ }
+ }
+ }
+ }
+
+ /// Cache the data for the given [library] and every library exported from it
+ /// if it hasn't already been cached.
+ void _cacheLibrary(LibraryElement library) {
+ if (_hasDataFor(library.definingCompilationUnit)) {
+ return;
+ }
+ for (var unit in library.units) {
+ _cacheFromElement(unit);
+ }
+ for (var exported in library.exportedLibraries) {
+ _cacheLibrary(exported);
+ }
+ }
+
+ /// Return `true` if the cache contains data for the [compilationUnit].
+ bool _hasDataFor(CompilationUnitElement compilationUnit) {
+ return processedUnits.contains(_keyForUnit(compilationUnit));
+ }
+
+ /// Return the key used in the [extensionCache] for the [compilationUnit].
+ String _keyForUnit(CompilationUnitElement compilationUnit) =>
+ compilationUnit.source.fullName;
+
+ /// Record that an extension member with the given [name] is defined in the
+ /// compilation unit with the [unitPath] in the library with the
+ /// [libraryPath].
+ void _recordMember(String unitPath, String libraryPath, String name) {
+ membersByName
+ .putIfAbsent(name, () => {})
+ .add(UnitInLibrary(unitPath, libraryPath));
+ }
+}
+
+/// A representation of a compilation unit in a library.
+class UnitInLibrary {
+ final String unitPath;
+ final String libraryPath;
+
+ UnitInLibrary(this.unitPath, this.libraryPath);
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index 8f452a1..036786e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -4,13 +4,10 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analysis_server/src/utilities/extensions/element.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/generic_inferrer.dart'
- show GenericInferrer;
-import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
/// A contributor that produces suggestions based on the members of an
@@ -87,7 +84,7 @@
if (type == null) {
// Without a type we can't find the extensions that apply. We shouldn't
// get to this point, but there's an NPE if we invoke
- // `_resolveExtendedType` when `type` is `null`, so we guard against it
+ // `resolvedExtendedType` when `type` is `null`, so we guard against it
// to ensure that we can return the suggestions from other providers.
return;
}
@@ -101,7 +98,7 @@
var nameScope = containingLibrary.scope;
for (var extension in nameScope.extensions) {
var extendedType =
- _resolveExtendedType(containingLibrary, extension, type);
+ extension.resolvedExtendedType(containingLibrary, type);
if (extendedType != null && typeSystem.isSubtypeOf(type, extendedType)) {
var inheritanceDistance = 0.0;
if (type is InterfaceType && extendedType is InterfaceType) {
@@ -141,34 +138,4 @@
accessor: accessor, inheritanceDistance: inheritanceDistance);
}
}
-
- /// Use the [type] of the object being extended in the [library] to compute
- /// the actual type extended by the [extension]. Return the computed type,
- /// or `null` if the type cannot be computed.
- DartType? _resolveExtendedType(
- LibraryElement library,
- ExtensionElement extension,
- DartType type,
- ) {
- var typeParameters = extension.typeParameters;
- var inferrer =
- GenericInferrer(library.typeSystem as TypeSystemImpl, typeParameters);
- inferrer.constrainArgument(
- type,
- extension.extendedType,
- 'extendedType',
- );
- var typeArguments = inferrer.infer(typeParameters,
- failAtError: true, genericMetadataIsEnabled: true);
- if (typeArguments == null) {
- return null;
- }
- var substitution = Substitution.fromPairs(
- typeParameters,
- typeArguments,
- );
- return substitution.substituteType(
- extension.extendedType,
- );
- }
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 0c52fb4..73ca312 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -6,6 +6,7 @@
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -393,6 +394,9 @@
/// Returns the EOL to use for this [CompilationUnit].
String get eol => utils.endOfLine;
+ /// Return the extension cache used to find available extensions.
+ ExtensionCache get extensionCache => _context.dartFixContext!.extensionCache;
+
String get file => _context.file;
Flutter get flutter => Flutter.instance;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 6c90568..69137bf 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -9,8 +9,11 @@
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analysis_server/src/utilities/extensions/element.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -24,26 +27,58 @@
@override
Iterable<CorrectionProducer> get producers sync* {
+ final node = this.node;
if (_importKind == _ImportKind.dartAsync) {
yield* _importLibrary(DartFixKind.IMPORT_ASYNC, Uri.parse('dart:async'));
} else if (_importKind == _ImportKind.forExtension) {
if (node is SimpleIdentifier) {
- var extensionName = (node as SimpleIdentifier).name;
+ var extensionName = node.name;
yield* _importLibraryForElement(
extensionName,
const [ElementKind.EXTENSION],
const [TopLevelDeclarationKind.extension]);
}
+ } else if (_importKind == _ImportKind.forExtensionMember) {
+ /// Return producers that will import extensions that apply to the
+ /// [targetType] and that define a member with the given [memberName].
+ Iterable<CorrectionProducer> importMatchingExtensions(
+ String memberName, DartType? targetType) sync* {
+ if (targetType == null) {
+ return;
+ }
+ var definingLibraries = extensionCache.membersByName[memberName];
+ if (definingLibraries != null) {
+ for (var definingLibrary in definingLibraries) {
+ var libraryPath = definingLibrary.libraryPath;
+ var uri = sessionHelper.session.uriConverter.pathToUri(libraryPath);
+ if (uri != null) {
+ yield* _importExtensionInLibrary(uri, targetType, memberName);
+ }
+ }
+ }
+ }
+
+ if (node is SimpleIdentifier) {
+ var memberName = node.name;
+ if (memberName.startsWith('_')) {
+ return;
+ }
+ yield* importMatchingExtensions(memberName, _targetType(node));
+ } else if (node is BinaryExpression) {
+ var memberName = node.operator.lexeme;
+ yield* importMatchingExtensions(
+ memberName, node.leftOperand.staticType);
+ }
} else if (_importKind == _ImportKind.forFunction) {
if (node is SimpleIdentifier) {
- if (node.parent is MethodInvocation) {
- var invocation = node.parent as MethodInvocation;
- if (invocation.realTarget != null || invocation.methodName != node) {
+ var parent = node.parent;
+ if (parent is MethodInvocation) {
+ if (parent.realTarget != null || parent.methodName != node) {
return;
}
}
- var name = (node as SimpleIdentifier).name;
+ var name = node.name;
yield* _importLibraryForElement(name, const [
ElementKind.FUNCTION,
ElementKind.TOP_LEVEL_VARIABLE
@@ -127,6 +162,45 @@
return null;
}
+ Iterable<CorrectionProducer> _importExtensionInLibrary(
+ Uri uri, DartType targetType, String memberName) sync* {
+ // Look to see whether the library at the [uri] is already imported. If it
+ // is, then we can check the extension elements without needing to perform
+ // additional analysis.
+ var foundImport = false;
+ for (var imp in libraryElement.imports) {
+ // prepare element
+ var importedLibrary = imp.importedLibrary;
+ if (importedLibrary == null || importedLibrary.source.uri != uri) {
+ continue;
+ }
+ foundImport = true;
+ for (var extension in importedLibrary.matchingExtensionsWithMember(
+ libraryElement, targetType, memberName)) {
+ // If the import has a combinator that needs to be updated, then offer
+ // to update it.
+ var combinators = imp.combinators;
+ if (combinators.length == 1) {
+ var combinator = combinators[0];
+ if (combinator is HideElementCombinator) {
+ // TODO(brianwilkerson) Support removing the extension name from a
+ // hide combinator.
+ } else if (combinator is ShowElementCombinator) {
+ yield _ImportLibraryShow(
+ uri.toString(), combinator, extension.name!);
+ }
+ }
+ }
+ }
+
+ // If the library at the [uri] is not already imported, we return a
+ // correction producer that will either add an import or not based on the
+ // result of analyzing the library.
+ if (!foundImport) {
+ yield _ImportLibraryContainingExtension(uri, targetType, memberName);
+ }
+ }
+
/// Returns a list of one or two import corrections.
///
/// If [relativeUri] is `null`, only one correction, with an absolute import
@@ -187,21 +261,22 @@
}
// may be update "show" directive
var combinators = imp.combinators;
- if (combinators.length == 1 && combinators[0] is ShowElementCombinator) {
- var showCombinator = combinators[0] as ShowElementCombinator;
- // prepare new set of names to show
- Set<String> showNames = SplayTreeSet<String>();
- showNames.addAll(showCombinator.shownNames);
- showNames.add(name);
- // prepare library name - unit name or 'dart:name' for SDK library
- var libraryName =
- libraryElement.definingCompilationUnit.source.uri.toString();
- if (libraryElement.isInSdk) {
- libraryName = libraryElement.source.shortName;
+ if (combinators.length == 1) {
+ var combinator = combinators[0];
+ if (combinator is HideElementCombinator) {
+ // TODO(brianwilkerson) Support removing the element name from a
+ // hide combinator.
+ } else if (combinator is ShowElementCombinator) {
+ // prepare library name - unit name or 'dart:name' for SDK library
+ var libraryName =
+ libraryElement.definingCompilationUnit.source.uri.toString();
+ if (libraryElement.isInSdk) {
+ libraryName = libraryElement.source.shortName;
+ }
+ // don't add this library again
+ alreadyImportedWithPrefix.add(libraryElement.source.fullName);
+ yield _ImportLibraryShow(libraryName, combinator, name);
}
- // don't add this library again
- alreadyImportedWithPrefix.add(libraryElement.source.fullName);
- yield _ImportLibraryShow(libraryName, showCombinator, showNames);
}
}
// Find new top-level declarations.
@@ -250,6 +325,47 @@
return false;
}
+ /// If the [node] might represent an access to a member of a type, return the
+ /// type of the object being accessed, otherwise return `null`.
+ DartType? _targetType(SimpleIdentifier node) {
+ var parent = node.parent;
+ if (parent is MethodInvocation && parent.methodName == node) {
+ var target = parent.realTarget;
+ if (target != null) {
+ return target.staticType;
+ }
+ } else if (parent is PropertyAccess && parent.propertyName == node) {
+ return parent.realTarget.staticType;
+ } else if (parent is PrefixedIdentifier && parent.identifier == node) {
+ return parent.prefix.staticType;
+ }
+ // If there is no explicit target, then return the type of an implicit
+ // `this`.
+ DartType? enclosingThisType(AstNode node) {
+ var parent = node.parent;
+ if (parent is ClassOrMixinDeclaration) {
+ return parent.declaredElement?.thisType;
+ } else if (parent is ExtensionDeclaration) {
+ return parent.extendedType.type;
+ }
+ }
+
+ while (parent != null) {
+ if (parent is MethodDeclaration) {
+ if (!parent.isStatic) {
+ return enclosingThisType(parent);
+ }
+ return null;
+ } else if (parent is FieldDeclaration) {
+ if (!parent.isStatic) {
+ return enclosingThisType(parent);
+ }
+ return null;
+ }
+ parent = parent.parent;
+ }
+ }
+
/// Return an instance of this class that will add an import of `dart:async`.
/// Used as a tear-off in `FixProcessor`.
static ImportLibrary dartAsync() => ImportLibrary(_ImportKind.dartAsync);
@@ -259,6 +375,9 @@
static ImportLibrary forExtension() =>
ImportLibrary(_ImportKind.forExtension);
+ static ImportLibrary forExtensionMember() =>
+ ImportLibrary(_ImportKind.forExtensionMember);
+
/// Return an instance of this class that will add an import for a top-level
/// function. Used as a tear-off in `FixProcessor`.
static ImportLibrary forFunction() => ImportLibrary(_ImportKind.forFunction);
@@ -273,8 +392,7 @@
static ImportLibrary forType() => ImportLibrary(_ImportKind.forType);
}
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import using an absolute URI.
class _ImportAbsoluteLibrary extends CorrectionProducer {
final FixKind _fixKind;
@@ -301,13 +419,53 @@
enum _ImportKind {
dartAsync,
forExtension,
+ forExtensionMember,
forFunction,
forTopLevelVariable,
forType
}
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import of a library containing an
+/// extension, but which does so only if the extension applies to a given type.
+class _ImportLibraryContainingExtension extends CorrectionProducer {
+ /// The URI of the library defining the extension.
+ Uri uri;
+
+ /// The type of the target that the extension must apply to.
+ DartType targetType;
+
+ /// The name of the member that the extension must declare.
+ String memberName;
+
+ /// The URI that is being proposed for the import directive.
+ String _uriText = '';
+
+ _ImportLibraryContainingExtension(this.uri, this.targetType, this.memberName);
+
+ @override
+ List<Object> get fixArguments => [_uriText];
+
+ @override
+ FixKind get fixKind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
+
+ @override
+ Future<void> compute(ChangeBuilder builder) async {
+ var result = await sessionHelper.session.getLibraryByUri2(uri.toString());
+ if (result is LibraryElementResult) {
+ var library = result.element;
+ if (library
+ .matchingExtensionsWithMember(libraryElement, targetType, memberName)
+ .isNotEmpty) {
+ await builder.addDartFileEdit(file, (builder) {
+ _uriText = builder.importLibrary(uri);
+ });
+ }
+ }
+ }
+}
+
+/// A correction processor that can add a prefix to an identifier defined in a
+/// library that is already imported but that is imported with a prefix.
class _ImportLibraryPrefix extends CorrectionProducer {
final LibraryElement _importedLibrary;
final PrefixElement _importPrefix;
@@ -334,16 +492,16 @@
}
}
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add a name to the show combinator of an
+/// existing import.
class _ImportLibraryShow extends CorrectionProducer {
final String _libraryName;
final ShowElementCombinator _showCombinator;
- final Set<String> _showNames;
+ final String _addedName;
- _ImportLibraryShow(this._libraryName, this._showCombinator, this._showNames);
+ _ImportLibraryShow(this._libraryName, this._showCombinator, this._addedName);
@override
List<Object> get fixArguments => [_libraryName];
@@ -353,7 +511,10 @@
@override
Future<void> compute(ChangeBuilder builder) async {
- var newShowCode = 'show ${_showNames.join(', ')}';
+ Set<String> showNames = SplayTreeSet<String>();
+ showNames.addAll(_showCombinator.shownNames);
+ showNames.add(_addedName);
+ var newShowCode = 'show ${showNames.join(', ')}';
var offset = _showCombinator.offset;
var length = _showCombinator.end - offset;
var libraryFile = resolvedResult.libraryElement.source.fullName;
@@ -363,8 +524,7 @@
}
}
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import using a relative URI.
class _ImportRelativeLibrary extends CorrectionProducer {
final FixKind _fixKind;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index f76a542..97e39a21 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/dart/analysis/results.dart';
@@ -129,11 +130,16 @@
@override
final AnalysisError error;
+ @override
+ final ExtensionCache extensionCache;
+
final List<TopLevelDeclaration> Function(String name)
getTopLevelDeclarationsFunction;
DartFixContextImpl(this.instrumentationService, this.workspace,
- this.resolveResult, this.error, this.getTopLevelDeclarationsFunction);
+ this.resolveResult, this.error, this.getTopLevelDeclarationsFunction,
+ {ExtensionCache? extensionCache})
+ : extensionCache = extensionCache ?? ExtensionCache();
@override
List<TopLevelDeclaration> getTopLevelDeclarations(String name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 4ebbaad..0ecd309 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -234,6 +234,7 @@
resolveResult,
error,
(name) => [],
+ extensionCache: context.extensionCache,
);
fixState = await _fixError(fixContext, fixState, generator(), error);
}
@@ -1131,6 +1132,7 @@
],
CompileTimeErrorCode.UNDEFINED_GETTER: [
DataDriven.newInstance,
+ ImportLibrary.forExtensionMember,
ImportLibrary.forTopLevelVariable,
ImportLibrary.forType,
],
@@ -1143,6 +1145,7 @@
],
CompileTimeErrorCode.UNDEFINED_METHOD: [
DataDriven.newInstance,
+ ImportLibrary.forExtensionMember,
ImportLibrary.forFunction,
ImportLibrary.forType,
],
@@ -1150,9 +1153,13 @@
ChangeArgumentName.newInstance,
DataDriven.newInstance,
],
+ CompileTimeErrorCode.UNDEFINED_OPERATOR: [
+ ImportLibrary.forExtensionMember,
+ ],
CompileTimeErrorCode.UNDEFINED_SETTER: [
DataDriven.newInstance,
- // TODO(brianwilkerson) Support ImportLibrary
+ // TODO(brianwilkerson) Support ImportLibrary for non-extension members.
+ ImportLibrary.forExtensionMember,
],
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS: [
DataDriven.newInstance,
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/element.dart b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
index 73e8eb8..764d8ab 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/element.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
@@ -2,7 +2,12 @@
// 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/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/generic_inferrer.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
extension ClassElementExtensions on ClassElement {
/// Return `true` if this element represents the class `Iterable` from
@@ -55,6 +60,58 @@
}
}
+extension ExtensionElementExtensions on ExtensionElement {
+ /// Use the [type] of the object being extended in the [library] to compute
+ /// the actual type extended by this [extension]. Return the computed type,
+ /// or `null` if the type can't be computed.
+ DartType? resolvedExtendedType(LibraryElement library, DartType type) {
+ final typeParameters = this.typeParameters;
+ var inferrer =
+ GenericInferrer(library.typeSystem as TypeSystemImpl, typeParameters);
+ inferrer.constrainArgument(
+ type,
+ extendedType,
+ 'extendedType',
+ );
+ var typeArguments = inferrer.infer(typeParameters,
+ failAtError: true, genericMetadataIsEnabled: true);
+ if (typeArguments == null) {
+ return null;
+ }
+ var substitution = Substitution.fromPairs(
+ typeParameters,
+ typeArguments,
+ );
+ return substitution.substituteType(
+ extendedType,
+ );
+ }
+}
+
+extension LibraryElementExtensions on LibraryElement {
+ /// Return the extensions in this library that can be applied, within the
+ /// [containingLibrary], to the [targetType] and that define a member with the
+ /// given [memberName].
+ Iterable<ExtensionElement> matchingExtensionsWithMember(
+ LibraryElement containingLibrary,
+ DartType targetType,
+ String memberName) sync* {
+ for (var unit in units) {
+ for (var extension in unit.extensions) {
+ var extensionName = extension.name;
+ if (extensionName != null && !Identifier.isPrivateName(extensionName)) {
+ var extendedType =
+ extension.resolvedExtendedType(containingLibrary, targetType);
+ if (extendedType != null &&
+ typeSystem.isSubtypeOf(targetType, extendedType)) {
+ yield extension;
+ }
+ }
+ }
+ }
+ }
+}
+
extension MethodElementExtensions on MethodElement {
/// Return `true` if this element represents the method `cast` from either
/// `Iterable`, `List`, `Map`, or `Set`.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
index 2c1d827..4e3c01b9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
@@ -79,6 +79,17 @@
''');
}
+ @failingTest
+ Future<void> test_propertyAccess() async {
+ // We should not offer to define a local variable named 'g'.
+ await resolveTestCode('''
+void f(String s) {
+ s.g;
+}
+''');
+ await assertNoFix();
+ }
+
Future<void> test_read_typeAssignment() async {
await resolveTestCode('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index 7ac6c2b..fd320f2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -3,10 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
import 'package:analysis_server/src/services/correction/change_workspace.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
@@ -172,9 +174,18 @@
/// A base class defining support for writing fix processor tests.
abstract class FixProcessorTest extends BaseFixProcessorTest {
+ /// The extension cache used for test purposes.
+ ExtensionCache extensionCache = ExtensionCache();
+
/// Return the kind of fixes being tested by this test class.
FixKind get kind;
+ Future<void> addUnimportedFile(String filePath, String content) async {
+ addSource(filePath, content);
+ var result = await session.getResolvedUnit2(filePath);
+ extensionCache.cacheFromResult(result as ResolvedUnitResult);
+ }
+
Future<void> assertHasFix(String expected,
{bool Function(AnalysisError)? errorFilter,
int? length,
@@ -429,6 +440,7 @@
var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
tracker.addContext(analysisContext);
+ extensionCache.cacheFromResult(testAnalysisResult);
var context = DartFixContextImpl(
TestInstrumentationService(),
@@ -440,6 +452,7 @@
provider.doTrackerWork();
return provider.get(analysisContext, testFile, name);
},
+ extensionCache: extensionCache,
);
return await DartFixContributor().computeFixes(context);
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index 98c939b..ccd65da 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -39,6 +39,201 @@
await assertNoFix();
}
+ Future<void> test_extension_notImported_field_onThisType_fromClass() async {
+ addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+ int m() => 0;
+}
+''');
+ addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+ await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+class D extends C {
+ int f = m();
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+class D extends C {
+ int f = m();
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_getter() async {
+ addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+ int get m => 0;
+}
+''');
+ await resolveTestCode('''
+void f(String s) {
+ s.m;
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+ s.m;
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_method() async {
+ addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+ void m() {}
+}
+''');
+ await resolveTestCode('''
+void f(String s) {
+ s.m();
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+ s.m();
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_method_extendsGeneric() async {
+ addUnimportedFile('/home/test/lib/lib.dart', '''
+import 'package:test/lib1.dart';
+
+extension E<T extends num> on List<T> {
+ void m() {}
+}
+''');
+ await resolveTestCode('''
+void f(List<int> l) {
+ l.m();
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(List<int> l) {
+ l.m();
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_method_onThisType_fromClass() async {
+ addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+ void m() {}
+}
+''');
+ addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+ await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+class D extends C {
+ void m2() {
+ m();
+ }
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+class D extends C {
+ void m2() {
+ m();
+ }
+}
+''');
+ }
+
+ Future<void>
+ test_extension_notImported_method_onThisType_fromExtension() async {
+ addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+ void m() {}
+}
+''');
+ addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+ await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+extension F on C {
+ void m2() {
+ m();
+ }
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+extension F on C {
+ void m2() {
+ m();
+ }
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_operator() async {
+ addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+ String operator -(String other) => this;
+}
+''');
+ await resolveTestCode('''
+void f(String s) {
+ s - '2';
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+ s - '2';
+}
+''');
+ }
+
+ Future<void> test_extension_notImported_setter() async {
+ addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+ set m(int v) {}
+}
+''');
+ await resolveTestCode('''
+void f(String s) {
+ s.m = 2;
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+ s.m = 2;
+}
+''');
+ }
+
Future<void> test_invalidUri_interpolation() async {
addSource('/home/test/lib/lib.dart', r'''
class Test {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
index e54adba..118b44f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
@@ -19,6 +19,98 @@
@override
FixKind get kind => DartFixKind.IMPORT_LIBRARY_SHOW;
+ Future<void> test_extension_notShown_getter() async {
+ addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+ int get m => 0;
+}
+''');
+ await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+ s.m;
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+ s.m;
+}
+''');
+ }
+
+ Future<void> test_extension_notShown_method() async {
+ addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+ void m() {}
+}
+''');
+ await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+ s.m();
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+ s.m();
+}
+''');
+ }
+
+ Future<void> test_extension_notShown_operator() async {
+ addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+ String operator -(String other) => this;
+}
+''');
+ await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+ s - '2';
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+ s - '2';
+}
+''');
+ }
+
+ Future<void> test_extension_notShown_setter() async {
+ addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+ set m(int v) {}
+}
+''');
+ await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+ s.m = 2;
+}
+''');
+ await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+ s.m = 2;
+}
+''');
+ }
+
Future<void> test_override_samePackage() async {
addSource('/home/test/lib/lib.dart', '''
class A {}
diff --git a/pkg/analyzer/lib/src/dart/error/todo_codes.dart b/pkg/analyzer/lib/src/dart/error/todo_codes.dart
index 3fbccd3..ef128be 100644
--- a/pkg/analyzer/lib/src/dart/error/todo_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/todo_codes.dart
@@ -30,9 +30,9 @@
* But not
* * todo
* * TODOS
- *
+ *
* It also supports wrapped TODOs where the next line is indented by a space:
- *
+ *
* /**
* * TODO(username): This line is
* * wrapped onto the next line
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 8696184..8a00fa9 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -55,6 +55,11 @@
object is CiderSearchMatch &&
path == object.path &&
const ListEquality<int>().equals(offsets, object.offsets);
+
+ @override
+ String toString() {
+ return '($path, $offsets)';
+ }
}
class FileContext {
diff --git a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
index 2b66120..a09335c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -305,6 +305,13 @@
}
@override
+ bool visitFunctionReference(FunctionReference node) {
+ // Note: `node.function` could be a reference to a method
+ // (`Target.methodName`) so we need to visit it in case the target exits.
+ return node.function.accept(this)!;
+ }
+
+ @override
bool visitGenericFunctionType(GenericFunctionType node) => false;
@override
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index a4f9b42..29d755d 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -3532,14 +3532,6 @@
typeArguments.leftBracket,
typeArguments.rightBracket,
);
- // Since analyzer visitors don't yet support constructor tear-offs, create
- // a FunctionExpressionInvocation with a synthetic argument list instead.
- // TODO(paulberry): once we have visitor support for constructor
- // tear-offs, fall through and return a FunctionReference instead since
- // that should lead to better quality error recovery.
- push(ast.functionExpressionInvocation(receiver, typeArguments,
- _syntheticArgumentList(typeArguments.rightBracket)));
- return;
}
push(ast.functionReference(
function: receiver, typeArguments: typeArguments));
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 54b29b2..43750b2 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -163,6 +163,12 @@
@override
void visitFunctionExpression(FunctionExpression node) {}
+ @override
+ void visitFunctionReference(covariant FunctionReferenceImpl node) {
+ // TODO(paulberry): implement
+ node.staticType = _dynamicType;
+ }
+
/// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
/// either the form <i>new T.id(a<sub>1</sub>, …, a<sub>n</sub>)</i> or the form <i>new
/// T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>
diff --git a/pkg/analyzer/test/generated/function_reference_parser_test.dart b/pkg/analyzer/test/generated/function_reference_parser_test.dart
index fe9091f..13d0d82 100644
--- a/pkg/analyzer/test/generated/function_reference_parser_test.dart
+++ b/pkg/analyzer/test/generated/function_reference_parser_test.dart
@@ -36,23 +36,9 @@
}
void test_feature_disabled() {
- var expression =
- (parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
- as ExpressionStatement)
- .expression;
- // TODO(paulberry): once we have visitor support for FunctionReference, this
- // should be parsed as a FunctionReference, so we should be able to validate
- // it using `expect_f_a_b`. But for now it's parsed as a
- // FunctionExpressionInvocation with synthetic arguments.
- var functionExpressionInvocation =
- expression as FunctionExpressionInvocation;
- expect(
- (functionExpressionInvocation.function as SimpleIdentifier).name, 'f');
- expect(functionExpressionInvocation.argumentList.arguments, isEmpty);
- var typeArgs = functionExpressionInvocation.typeArguments!.arguments;
- expect(typeArgs, hasLength(2));
- expect(((typeArgs[0] as TypeName).name as SimpleIdentifier).name, 'a');
- expect(((typeArgs[1] as TypeName).name as SimpleIdentifier).name, 'b');
+ expect_f_a_b((parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
+ as ExpressionStatement)
+ .expression);
listener.assertErrors([
expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 1, 6),
]);
diff --git a/pkg/analyzer/test/generated/simple_parser_test.dart b/pkg/analyzer/test/generated/simple_parser_test.dart
index 0198aa1..3a52b79 100644
--- a/pkg/analyzer/test/generated/simple_parser_test.dart
+++ b/pkg/analyzer/test/generated/simple_parser_test.dart
@@ -1449,8 +1449,8 @@
expect(body.expression, isMethodInvocation);
var methodInvocation = body.expression as MethodInvocationImpl;
var target = methodInvocation.target!;
- expect(target, isFunctionExpressionInvocation);
- expect(target.toSource(), 'C<E>()');
+ expect(target, isFunctionReference);
+ expect(target.toSource(), 'C<E>');
expect(methodInvocation.methodName.name, 'n');
expect(methodInvocation.argumentList, isNotNull);
expect(methodInvocation.typeArguments!.arguments, hasLength(1));
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 7a161cd..447f887 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -475,7 +475,7 @@
await assertErrorsInCode('''
Future<Future<int>> ffi() => null;
f() async {
- Future<int> b = await ffi();
+ Future<int> b = await ffi();
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
diff --git a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
index 01ca1e1..5e1206c 100644
--- a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
@@ -1507,7 +1507,7 @@
var library = await buildTestLibrary(a, r'''
class C {
var f;
-
+
C.test() : f = x;
}
''');
@@ -1567,7 +1567,7 @@
var library = await buildTestLibrary(a, r'''
class C extends A {
C.test() : this.named(x);
-
+
C.named(a);
}
''');
@@ -1579,7 +1579,7 @@
var library = await buildTestLibrary(a, r'''
class C extends A {
C.test() : this(x);
-
+
C(a);
}
''');
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 8251b43..63c5831 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -1327,7 +1327,7 @@
int get getter1 => null;
void set setter1(_) {}
void method1() {}
-
+
static int staticField;
static void staticMethod() {}
}
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index e1646c9..6f2cd6e 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -463,7 +463,7 @@
void func() {
print('hello');
}
-
+
void func2() {
func();
}
@@ -483,7 +483,7 @@
await resolveFile(bPath);
var result = fileResolver.findReferences(17, aPath);
var expected = <CiderSearchMatch>[
- CiderSearchMatch(aPath, [17, 69]),
+ CiderSearchMatch(aPath, [17, 68]),
CiderSearchMatch(bPath, [46])
];
expect(result, unorderedEquals(expected));
@@ -593,14 +593,14 @@
newFile(aPath, content: r'''
class Foo<T> {
List<T> l;
-
+
void bar(T t) {}
}
''');
await resolveFile(aPath);
var result = fileResolver.findReferences(10, aPath);
var expected = <CiderSearchMatch>[
- CiderSearchMatch(aPath, [10, 22, 42])
+ CiderSearchMatch(aPath, [10, 22, 40])
];
expect(result.map((e) => e.path),
unorderedEquals(expected.map((e) => e.path)));
diff --git a/pkg/analyzer/test/src/dart/resolution/comment_test.dart b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
index 0f894bf..173fa0a 100644
--- a/pkg/analyzer/test/src/dart/resolution/comment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
@@ -148,13 +148,13 @@
abstract class A {
/// [p1]
ma(int p1);
-
+
/// [p2]
mb(int p2);
-
+
/// [p3] and [p4]
mc(int p3, p4());
-
+
/// [p5]
md(int p5, {int p6});
}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 28b1f8c..a76e41a 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -652,7 +652,7 @@
class C<T extends MyFunction> {
T foo;
C(this.foo);
-
+
main() {
foo(0);
}
@@ -733,13 +733,13 @@
await assertErrorsInCode(r'''
class C {
static int foo = 0;
-
+
main() {
foo();
}
}
''', [
- error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 50, 3),
+ error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 48, 3),
]);
var invocation = findNode.functionExpressionInvocation('foo();');
@@ -1654,7 +1654,7 @@
class C<T extends A> {
T a;
C(this.a);
-
+
main() {
a.foo(0);
}
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index e86d332..094323e 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -99,7 +99,7 @@
class A {
int operator[](int index) => 0;
operator[]=(int index, num _) {}
-
+
void f() {
this[0]++;
}
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index c49b4a6..06fd33d 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -146,7 +146,7 @@
class A {
int operator[](int index) => 0;
operator[]=(int index, num _) {}
-
+
void f() {
++this[0];
}
diff --git a/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart b/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
index 83c2471..4a33901 100644
--- a/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
@@ -100,7 +100,7 @@
await assertNoErrorsInCode(r'''
main() {
Never;
-}
+}
''');
assertSimpleIdentifier(
findNode.simple('Never;'),
diff --git a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
index bb0999a..a24235f 100644
--- a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
+++ b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
@@ -2,8 +2,10 @@
// 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/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/find_node.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -143,6 +145,11 @@
/// See [ExitDetectorResolvedStatementTest] for tests that require the AST to be resolved.
@reflectiveTest
class ExitDetectorParsedStatementTest extends ParseBase {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = FeatureSet.forTesting(
+ sdkVersion: '2.13', additionalFeatures: [Feature.constructor_tearoffs]);
+
test_asExpression() async {
_assertFalse('a as Object;');
}
@@ -514,6 +521,18 @@
_assertTrue("(throw 42)(g);");
}
+ test_functionReference() async {
+ _assertFalse('a<int>;');
+ }
+
+ test_functionReference_method() async {
+ _assertFalse('(a).m<int>;');
+ }
+
+ test_functionReference_method_throw() async {
+ _assertTrue('(throw 42).m<int>;');
+ }
+
test_identifier_prefixedIdentifier() async {
_assertFalse('a.b;');
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
index 56b086d..40ba01a 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
@@ -216,7 +216,7 @@
await assertErrorsInCode('''
import 'package:meta/meta.dart';
-String top = A().f;
+String top = A().f;
class A{
@doNotStore
@@ -246,7 +246,7 @@
await assertErrorsInCode('''
import 'package:meta/meta.dart';
-String top = v;
+String top = v;
@doNotStore
String get v => '';
@@ -259,7 +259,7 @@
await assertErrorsInCode('''
import 'package:meta/meta.dart';
-String top = A().v();
+String top = A().v();
class A{
@doNotStore
diff --git a/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
index e1037ea..c0ecd09 100644
--- a/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
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';
@@ -26,10 +25,6 @@
Foo<int>.bar.baz();
}
''', [
- // TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
- // bogus, and should go away once we implement visitor and resolution
- // support for constructor tearoffs.
- error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 67, 3),
error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 70, 5),
]);
}
@@ -45,10 +40,6 @@
Foo<int>.bar.baz();
}
''', [
- // TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
- // bogus, and should go away once we implement visitor and resolution
- // support for constructor tearoffs.
- error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 80, 3),
error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 83, 5),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
index 3972ae7..7fbed0b 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
@@ -97,7 +97,7 @@
test_functionExpression_async_block_futureInt() async {
await assertErrorsInCode(r'''
-Future<int> Function() f = () async {};
+Future<int> Function() f = () async {};
''', [
error(HintCode.MISSING_RETURN, 27, 11),
]);
diff --git a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
index a173db7..be8cabb 100644
--- a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
@@ -68,7 +68,7 @@
newFile('$testPackageLibPath/a.dart', content: r'''
class A {
static set _foo(int _) {}
-
+
static int get _foo => 0;
}
''');
diff --git a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
index cdcd43d..1e8a99a 100644
--- a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
@@ -200,7 +200,7 @@
void f() {
// ignore:unused_label
label: var v = 0;
- v;
+ v;
}
''');
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
index 9722e80..cfbbbe3 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
@@ -165,7 +165,7 @@
}
String getV2() => _v;
-
+
@doNotStore
String getV3() => _v;
}
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
index c5c9ddf..ab0bbca 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
@@ -451,7 +451,7 @@
test_function_async_expression_dynamic__to_Future_int() async {
await assertNoErrorsInCode(r'''
-Future<int> f(dynamic a) async => a;
+Future<int> f(dynamic a) async => a;
''');
}
diff --git a/pkg/analyzer/test/src/diagnostics/todo_test.dart b/pkg/analyzer/test/src/diagnostics/todo_test.dart
index c2cb064..f61b675 100644
--- a/pkg/analyzer/test/src/diagnostics/todo_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/todo_test.dart
@@ -40,12 +40,12 @@
*/
/* TODO(a): Implement something
* that is too long for one line
- *
+ *
* This line is not part of the todo
*/
/* TODO: Implement something
* that is too long for one line
- *
+ *
* This line is not part of the todo
*/
}
@@ -56,7 +56,7 @@
text: 'TODO: Implement something that is too long for one line'),
error(TodoCode.TODO, 241, 64,
text: 'TODO(a): Implement something that is too long for one line'),
- error(TodoCode.TODO, 363, 61,
+ error(TodoCode.TODO, 362, 61,
text: 'TODO: Implement something that is too long for one line'),
]);
}
@@ -145,12 +145,12 @@
// TODO: Implement something
// that is too long for one line
-
+
// this is not part of the todo
// TODO: Implement something
// that is too long for one line
- //
+ //
// this is not part of the todo
}
''', [
@@ -158,7 +158,7 @@
text: 'TODO: Implement something that is too long for one line'),
error(TodoCode.TODO, 116, 61,
text: 'TODO: Implement something that is too long for one line'),
- error(TodoCode.TODO, 222, 61,
+ error(TodoCode.TODO, 220, 61,
text: 'TODO: Implement something that is too long for one line'),
]);
}
diff --git a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
index 1b663a6..cee7219 100644
--- a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
@@ -137,7 +137,7 @@
testRecovery('''
f() {
var x;
- x =
+ x =
}
''', [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN], '''
f() {
@@ -195,7 +195,7 @@
void test_conditionalExpression_else() {
testRecovery('''
-f() => x ? y :
+f() => x ? y :
''', [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN], '''
f() => x ? y : _s_;
''');
diff --git a/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart b/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
index 7ad97b0..005d55f 100644
--- a/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
+++ b/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
@@ -232,7 +232,7 @@
name: sample
dependencies:
foo:
- git:
+ git:
url: git@github.com:foo/foo.git
path: path/to/foo
''');
@@ -244,7 +244,7 @@
version: 0.1.0
dependencies:
foo:
- git:
+ git:
url: git@github.com:foo/foo.git
path: path/to/foo
''', [PubspecWarningCode.INVALID_DEPENDENCY]);
@@ -257,7 +257,7 @@
publish_to: none
dependencies:
foo:
- git:
+ git:
url: git@github.com:foo/foo.git
path: path/to/foo
''');
@@ -291,7 +291,7 @@
name: sample
dependencies:
foo:
- path:
+ path:
- baz
''');
}
@@ -425,7 +425,7 @@
version: 0.1.0
dev_dependencies:
foo:
- git:
+ git:
url: git@github.com:foo/foo.git
path: path/to/foo
''');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index bd6e007..7074657 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1175,7 +1175,7 @@
var library = await checkLibrary('''
class C {
int get x => 0;
- void set x(int value) {}
+ void set x(int value) {}
}
''');
checkElementText(
@@ -2194,7 +2194,7 @@
class A {}
class B {}
-
+
class Raw = Object with A, B;
/// Comment 1.
@@ -2226,33 +2226,33 @@
}
class B/*codeOffset=12, codeLength=10*/ {
}
-class alias Raw/*codeOffset=28, codeLength=29*/ extends Object with A, B {
+class alias Raw/*codeOffset=24, codeLength=29*/ extends Object with A, B {
synthetic const Raw() : super();
}
/// Comment 1.
/// Comment 2.
-class alias HasDocComment/*codeOffset=59, codeLength=69*/ extends Object with A, B {
+class alias HasDocComment/*codeOffset=55, codeLength=69*/ extends Object with A, B {
synthetic const HasDocComment() : super();
}
@Object()
-class alias HasAnnotation/*codeOffset=130, codeLength=49*/ extends Object with A, B {
+class alias HasAnnotation/*codeOffset=126, codeLength=49*/ extends Object with A, B {
synthetic const HasAnnotation() : super();
}
/// Comment 1.
/// Comment 2.
@Object()
-class alias AnnotationThenComment/*codeOffset=181, codeLength=87*/ extends Object with A, B {
+class alias AnnotationThenComment/*codeOffset=177, codeLength=87*/ extends Object with A, B {
synthetic const AnnotationThenComment() : super();
}
/// Comment 1.
/// Comment 2.
@Object()
-class alias CommentThenAnnotation/*codeOffset=270, codeLength=87*/ extends Object with A, B {
+class alias CommentThenAnnotation/*codeOffset=266, codeLength=87*/ extends Object with A, B {
synthetic const CommentThenAnnotation() : super();
}
/// Comment 2.
@Object()
-class alias CommentAroundAnnotation/*codeOffset=374, codeLength=74*/ extends Object with A, B {
+class alias CommentAroundAnnotation/*codeOffset=370, codeLength=74*/ extends Object with A, B {
synthetic const CommentAroundAnnotation() : super();
}
''',
@@ -2466,13 +2466,13 @@
int withoutInit;
- int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
+ int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
}
''');
checkElementText(
library,
r'''
-class C/*codeOffset=0, codeLength=116*/ {
+class C/*codeOffset=0, codeLength=115*/ {
int withInit/*codeOffset=12, codeLength=16*/;
int withoutInit/*codeOffset=33, codeLength=15*/;
int multiWithInit/*codeOffset=53, codeLength=21*/;
@@ -2794,7 +2794,7 @@
int withoutInit;
-int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
+int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
''');
checkElementText(
library,
@@ -14788,7 +14788,7 @@
test_unit_implicitVariable_getterFirst() async {
var library = await checkLibrary('''
int get x => 0;
-void set x(int value) {}
+void set x(int value) {}
''');
checkElementText(
library,
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d70bd51..e59913a9 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2065,21 +2065,21 @@
}
abstract class D extends Object with M<num> {}
-
+
class E extends D with M<int> {
int x;
}
-
+
class F extends D with M<int> {
num x;
}
''', [
error(CompileTimeErrorCode.INVALID_OVERRIDE, 124, 1),
- error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 186, 1),
- error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 186, 1),
- error(CompileTimeErrorCode.INVALID_OVERRIDE, 218, 1),
- error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 232, 1),
- error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 232, 1),
+ error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 184, 1),
+ error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 184, 1),
+ error(CompileTimeErrorCode.INVALID_OVERRIDE, 216, 1),
+ error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 228, 1),
+ error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 228, 1),
]);
}
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index d20ec18..0acae0a 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1148,7 +1148,7 @@
new F4(a: [[3]]);
new F4(a: [["hello"]]);
new F4(a: [["hello"], [3]]);
-
+
new F5([[[3]]]);
}
''', [
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index f6015bd..c4bd9f1 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -69,6 +69,12 @@
valueHelp: '[<port>[/<bind-address>]]',
)
..addFlag(
+ 'serve-devtools',
+ help: 'Serves an instance of the Dart DevTools debugger and profiler '
+ 'via the VM service at <vm-service-uri>/devtools.',
+ defaultsTo: true,
+ )
+ ..addFlag(
'pause-isolates-on-exit',
help: 'Pause isolates on exit when '
'running with --enable-vm-service.',
@@ -186,9 +192,7 @@
String ddsHost = '';
String ddsPort = '';
- // TODO(bkonyi): allow for users to choose not to launch DevTools
- // See https://github.com/dart-lang/sdk/issues/45867.
- const bool launchDevTools = true;
+ bool launchDevTools = argResults['serve-devtools'];
bool launchDds = false;
if (launchDdsArg != null) {
launchDds = true;
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index cfccec8..4cd3517 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -329,7 +329,7 @@
const devToolsMessagePrefix =
'The Dart DevTools debugger and profiler is available at: http://127.0.0.1:';
- test('spawn simple', () async {
+ test('dart run simple', () async {
p = project(mainSrc: "void main() { print('Hello World'); }");
ProcessResult result = p.runSync([
'run',
@@ -339,7 +339,7 @@
expect(result.stdout, contains(devToolsMessagePrefix));
});
- test('implicit spawn', () async {
+ test('dart simple', () async {
p = project(mainSrc: "void main() { print('Hello World'); }");
ProcessResult result = p.runSync([
'--enable-vm-service',
@@ -348,6 +348,67 @@
expect(result.stdout, contains(devToolsMessagePrefix));
});
+ test('dart run explicit', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ 'run',
+ '--serve-devtools',
+ '--enable-vm-service',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, contains(devToolsMessagePrefix));
+ });
+
+ test('dart explicit', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ '--serve-devtools',
+ '--enable-vm-service',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, contains(devToolsMessagePrefix));
+ });
+
+ test('dart run disabled', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ 'run',
+ '--enable-vm-service',
+ '--no-serve-devtools',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+ });
+
+ test('dart disabled', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ '--enable-vm-service',
+ '--no-serve-devtools',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+ });
+
+ test('dart run VM service not enabled', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ 'run',
+ '--serve-devtools',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+ });
+
+ test('dart VM service not enabled', () async {
+ p = project(mainSrc: "void main() { print('Hello World'); }");
+ ProcessResult result = p.runSync([
+ '--serve-devtools',
+ p.relativeFilePath,
+ ]);
+ expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+ });
+
test(
'spawn via SIGQUIT',
() async {
diff --git a/pkg/wasm/README.md b/pkg/wasm/README.md
index 1fcab7e..ecf418d 100644
--- a/pkg/wasm/README.md
+++ b/pkg/wasm/README.md
@@ -1,7 +1,6 @@
-# wasm
+Provides utilities for loading and running WASM modules
-This package provides utilities for loading and running WASM modules. It is
-built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime.
+Built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime.
## Setup
diff --git a/pkg/wasm/bin/setup.dart b/pkg/wasm/bin/setup.dart
index ad36423..868c189 100644
--- a/pkg/wasm/bin/setup.dart
+++ b/pkg/wasm/bin/setup.dart
@@ -27,6 +27,12 @@
return checkedOutSdkDir;
}
+ final homebrewOutSdkDir = exe.resolve('..');
+ final homebrewIncludeDir = homebrewOutSdkDir.resolve('include');
+ if (Directory(homebrewIncludeDir.path).existsSync()) {
+ return homebrewOutSdkDir;
+ }
+
// If neither returned above, we return the common case:
return commonSdkDir;
}
@@ -52,7 +58,7 @@
return 'libwasmer.so';
}
-getTargetTriple() async {
+Future<String> getTargetTriple() async {
final process = await Process.start('rustc', ['--print', 'cfg']);
process.stderr
.transform(utf8.decoder)
@@ -69,11 +75,14 @@
String arch = cfg['target_arch'] ?? 'unknown';
String vendor = cfg['target_vendor'] ?? 'unknown';
String os = cfg['target_os'] ?? 'unknown';
- String env = cfg['target_env'] ?? 'unknown';
- return '$arch-$vendor-$os-$env';
+ if (os == 'macos') os = 'darwin';
+ String? env = cfg['target_env'];
+ return [arch, vendor, os, env]
+ .where((element) => element != null && element.isNotEmpty)
+ .join('-');
}
-run(String exe, List<String> args) async {
+Future<void> run(String exe, List<String> args) async {
print('\n$exe ${args.join(' ')}\n');
final process = await Process.start(exe, args);
process.stdout
@@ -91,13 +100,13 @@
}
}
-main(List<String> args) async {
+Future<void> main(List<String> args) async {
if (args.length > 1) {
print('Usage: dart setup.dart [target-triple]');
exit(1);
}
- final target = args.length >= 1 ? args[0] : await getTargetTriple();
+ final target = args.isNotEmpty ? args[0] : await getTargetTriple();
final sdkDir = getSdkDir();
final binDir = Platform.script;
final outDir = getOutDir(binDir);
@@ -121,12 +130,13 @@
'--release'
]);
+ final dartApiDlImplFile =
+ File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'));
// Hack around a bug with dart_api_dl_impl.h include path in dart_api_dl.c.
- if (!File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'))
- .existsSync()) {
+ if (!dartApiDlImplFile.existsSync()) {
Directory(outDir.resolve('include/internal/').path)
.createSync(recursive: true);
- File.fromUri(sdkDir.resolve('include/runtime/dart_api_dl_impl.h'))
+ await dartApiDlImplFile
.copy(outDir.resolve('include/internal/dart_api_dl_impl.h').path);
}
diff --git a/pkg/wasm/example/brotli.dart b/pkg/wasm/example/brotli.dart
index e9520e3..d8cea14 100644
--- a/pkg/wasm/example/brotli.dart
+++ b/pkg/wasm/example/brotli.dart
@@ -6,9 +6,9 @@
// library. Usage:
// dart brotli.dart input.txt
-import 'dart:convert';
import "dart:io";
import "dart:typed_data";
+
import "package:wasm/wasm.dart";
// Brotli compression parameters.
diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart
index 8cff328..bc5e44c 100644
--- a/pkg/wasm/lib/src/function.dart
+++ b/pkg/wasm/lib/src/function.dart
@@ -2,10 +2,12 @@
// 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 'dart:ffi';
+
+import 'package:ffi/ffi.dart';
+
import 'runtime.dart';
import 'wasmer_api.dart';
-import 'dart:ffi';
-import 'package:ffi/ffi.dart';
/// WasmFunction is a callable function from a WasmInstance.
class WasmFunction {
@@ -19,7 +21,7 @@
WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
_args.ref.length = _argTypes.length;
_args.ref.data =
- _argTypes.length == 0 ? nullptr : calloc<WasmerVal>(_argTypes.length);
+ _argTypes.isEmpty ? nullptr : calloc<WasmerVal>(_argTypes.length);
_results.ref.length = _returnType == WasmerValKindVoid ? 0 : 1;
_results.ref.data =
_returnType == WasmerValKindVoid ? nullptr : calloc<WasmerVal>();
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
index 305d239..5687b2e 100644
--- a/pkg/wasm/lib/src/module.dart
+++ b/pkg/wasm/lib/src/module.dart
@@ -2,13 +2,15 @@
// 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 'runtime.dart';
-import 'function.dart';
-import 'wasmer_api.dart';
-import 'dart:typed_data';
import 'dart:ffi';
+import 'dart:typed_data';
+
import 'package:ffi/ffi.dart';
+import 'function.dart';
+import 'runtime.dart';
+import 'wasmer_api.dart';
+
/// WasmModule is a compiled module that can be instantiated.
class WasmModule {
late Pointer<WasmerStore> _store;
@@ -165,7 +167,6 @@
throw Exception("Import is not a function: $imp");
}
- var argTypes = runtime.getArgTypes(imp.funcType);
var returnType = runtime.getReturnType(imp.funcType);
var wasmFnImport = calloc<_WasmFnImport>();
wasmFnImport.ref.returnType = returnType;
@@ -241,7 +242,7 @@
var mem = runtime.externToMemory(e);
_exportedMemory = mem;
if (_wasiEnv != nullptr) {
- runtime.wasiEnvSetMemory(_wasiEnv as Pointer<WasmerWasiEnv>, mem);
+ runtime.wasiEnvSetMemory(_wasiEnv, mem);
}
}
}
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
index b8defab..1db3ef4 100644
--- a/pkg/wasm/lib/src/runtime.dart
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -699,7 +699,7 @@
Function _reader;
Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
int _length = 0;
- _WasiStreamIterator(this._env, this._reader) {}
+ _WasiStreamIterator(this._env, this._reader);
bool moveNext() {
_length = _reader(_env, _buf, _bufferLength);
@@ -712,7 +712,7 @@
class _WasiStreamIterable extends Iterable<List<int>> {
Pointer<WasmerWasiEnv> _env;
Function _reader;
- _WasiStreamIterable(this._env, this._reader) {}
+ _WasiStreamIterable(this._env, this._reader);
@override
Iterator<List<int>> get iterator => _WasiStreamIterator(_env, _reader);
}
diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart
index 0394c10..2798b90 100644
--- a/pkg/wasm/lib/src/tools/runtime_template.dart
+++ b/pkg/wasm/lib/src/tools/runtime_template.dart
@@ -390,7 +390,7 @@
Function _reader;
Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
int _length = 0;
- _WasiStreamIterator(this._env, this._reader) {}
+ _WasiStreamIterator(this._env, this._reader);
bool moveNext() {
_length = _reader(_env, _buf, _bufferLength);
@@ -403,7 +403,7 @@
class _WasiStreamIterable extends Iterable<List<int>> {
Pointer<WasmerWasiEnv> _env;
Function _reader;
- _WasiStreamIterable(this._env, this._reader) {}
+ _WasiStreamIterable(this._env, this._reader);
@override
Iterator<List<int>> get iterator => _WasiStreamIterator(_env, _reader);
}
diff --git a/pkg/wasm/pubspec.yaml b/pkg/wasm/pubspec.yaml
index ef31927..9cd60c7 100644
--- a/pkg/wasm/pubspec.yaml
+++ b/pkg/wasm/pubspec.yaml
@@ -1,7 +1,6 @@
name: wasm
version: 0.1.0
-description: Load and run wasm bytecode.
-author: Dart Team <misc@dartlang.org>
+description: Utilities for loading and running WASM modules from Dart code
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/wasm
environment:
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 55fef46..157b70f 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -155,6 +155,7 @@
" set of options which are often useful for debugging under Observatory.\n"
" These options are currently:\n"
" --enable-vm-service[=<port>[/<bind-address>]]\n"
+" --serve-devtools\n"
" --pause-isolates-on-exit\n"
" --pause-isolates-on-unhandled-exceptions\n"
" --warn-on-pause-with-no-debugger\n"
@@ -191,6 +192,7 @@
" set of options which are often useful for debugging under Observatory.\n"
" These options are currently:\n"
" --enable-vm-service[=<port>[/<bind-address>]]\n"
+" --serve-devtools\n"
" --pause-isolates-on-exit\n"
" --pause-isolates-on-unhandled-exceptions\n"
" --warn-on-pause-with-no-debugger\n"
@@ -416,6 +418,7 @@
bool enable_dartdev_analytics = false;
bool disable_dartdev_analytics = false;
+ bool serve_devtools = true;
// Parse out the vm options.
while (i < argc) {
@@ -444,6 +447,12 @@
// It is irelevant for the vm.
dart_options->AddArgument("--no-analytics");
skipVmOption = true;
+ } else if (IsOption(argv[i], "serve-devtools")) {
+ serve_devtools = true;
+ skipVmOption = true;
+ } else if (IsOption(argv[i], "no-serve-devtools")) {
+ serve_devtools = false;
+ skipVmOption = true;
}
if (!skipVmOption) {
temp_vm_options.AddArgument(argv[i]);
@@ -571,6 +580,16 @@
// run command. If 'run' is provided, it will be the first argument
// processed in this loop.
dart_options->AddArgument("run");
+
+ // Ensure we can enable / disable DevTools when invoking 'dart run'
+ // implicitly.
+ if (enable_vm_service_) {
+ if (serve_devtools) {
+ dart_options->AddArgument("--serve-devtools");
+ } else {
+ dart_options->AddArgument("--no-serve-devtools");
+ }
+ }
} else {
dart_options->AddArgument(argv[i]);
i++;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 94e834f..cf13c43 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -985,9 +985,12 @@
// Flip the two semi-spaces so that to_ is always the space for allocating
// objects.
- SemiSpace* from = to_;
-
- to_ = new SemiSpace(NewSizeInWords(from->max_capacity_in_words()));
+ SemiSpace* from;
+ {
+ MutexLocker ml(&space_lock_);
+ from = to_;
+ to_ = new SemiSpace(NewSizeInWords(from->max_capacity_in_words()));
+ }
UpdateMaxHeapCapacity();
return from;
@@ -1740,9 +1743,12 @@
// Swap from-space and to-space. The abandoned to-space will be deleted in
// the epilogue.
- SemiSpace* temp = to_;
- to_ = *from;
- *from = temp;
+ {
+ MutexLocker ml(&space_lock_);
+ SemiSpace* temp = to_;
+ to_ = *from;
+ *from = temp;
+ }
// Release any remaining part of the promotion worklist that wasn't completed.
promotion_stack_.Reset();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 47d868c..422d7b4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -18151,7 +18151,7 @@
} else {
ASSERT(instance_class_id_or_signature.IsFunctionType());
buffer->Printf(
- "%sfunction: %s", separator,
+ "%ssignature: %s", separator,
FunctionType::Cast(instance_class_id_or_signature).ToCString());
}
if (!destination_type.IsNull()) {
@@ -19237,6 +19237,7 @@
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
if (instantiated_other.IsTopTypeForSubtyping() ||
+ instantiated_other.IsObjectType() ||
instantiated_other.IsDartFunctionType()) {
return true;
}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index e1c900d..41d3e40 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -139,6 +139,10 @@
"../utils/dds:dds",
],
[
+ "frontend_server",
+ "../utils/kernel-service:frontend_server",
+ ],
+ [
"pub",
"../utils/pub",
],
@@ -169,10 +173,6 @@
"kernel_worker",
"../utils/bazel:kernel_worker",
],
- [
- "frontend_server",
- "../utils/kernel-service:frontend_server",
- ],
]
# Libraries that go under lib/
diff --git a/tests/language/constructor/reference_test.dart b/tests/language/constructor/reference_test.dart
index f57a26f..d781ab1 100644
--- a/tests/language/constructor/reference_test.dart
+++ b/tests/language/constructor/reference_test.dart
@@ -92,8 +92,6 @@
Foo<int>();
Foo<int>.bar();
Foo<int>.bar.baz();
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^^^^^
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.
diff --git a/tests/language/regress/regress46165_test.dart b/tests/language/regress/regress46165_test.dart
new file mode 100644
index 0000000..2aed9e0
--- /dev/null
+++ b/tests/language/regress/regress46165_test.dart
@@ -0,0 +1,10 @@
+// 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.
+
+void main() {
+ final l = <Object>[];
+ l.add((String x, StringBuffer y) {
+ print(x);
+ });
+}
diff --git a/tests/language_2/constructor/reference_test.dart b/tests/language_2/constructor/reference_test.dart
index 73abdb9..ee1aa67 100644
--- a/tests/language_2/constructor/reference_test.dart
+++ b/tests/language_2/constructor/reference_test.dart
@@ -94,8 +94,6 @@
Foo<int>();
Foo<int>.bar();
Foo<int>.bar.baz();
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^^^^^
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.
diff --git a/tests/language_2/regress/regress46165_test.dart b/tests/language_2/regress/regress46165_test.dart
new file mode 100644
index 0000000..2aed9e0
--- /dev/null
+++ b/tests/language_2/regress/regress46165_test.dart
@@ -0,0 +1,10 @@
+// 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.
+
+void main() {
+ final l = <Object>[];
+ l.add((String x, StringBuffer y) {
+ print(x);
+ });
+}
diff --git a/tools/VERSION b/tools/VERSION
index dcce38e..432be1f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 171
+PRERELEASE 172
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/flutter/analyze_flutter_plugins.sh b/tools/bots/flutter/analyze_flutter_plugins.sh
new file mode 100755
index 0000000..9696c74
--- /dev/null
+++ b/tools/bots/flutter/analyze_flutter_plugins.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# Analyze Dart code in the flutter/plugins repo.
+
+set -e
+
+checkout=$(pwd)
+export PATH=$checkout/out/ReleaseX64/dart-sdk/bin:$PATH
+dart=$checkout/out/ReleaseX64/dart-sdk/bin/dart
+pub=$checkout/out/ReleaseX64/dart-sdk/bin/pub
+sdk=$checkout/out/ReleaseX64/dart-sdk
+tmpdir=$(mktemp -d)
+
+cleanup() {
+ rm -rf "$tmpdir"
+}
+
+trap cleanup EXIT HUP INT QUIT TERM PIPE
+cd "$tmpdir"
+
+# install flutter
+git clone --single-branch -vv https://github.com/flutter/flutter
+export PATH="$PATH":"$tmpdir/flutter/bin"
+flutter --version
+
+# get the flutter/plugins repo
+git clone --single-branch -vv https://github.com/flutter/plugins
+cd plugins
+
+# validate the tool's source
+(cd script/tool; dart pub get)
+(cd script/tool; dart analyze --fatal-infos)
+
+# Invoke the repo's analysis script.
+./script/tool_runner.sh analyze --analysis-sdk $sdk
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 67fb0a0..1d078c0 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -3624,7 +3624,11 @@
{
"name": "analyze flutter/flutter",
"script": "tools/bots/flutter/analyze_flutter_flutter.sh"
- }
+ },
+ {
+ "name": "analyze flutter/plugins",
+ "script": "tools/bots/flutter/analyze_flutter_plugins.sh"
+ }
]
},
{