Version 3.7.0-22.0.dev
Merge f77b5c19a37c1dcd52a6d09515022551d2a4c743 into dev
diff --git a/DEPS b/DEPS
index d500eb4..6040b9a 100644
--- a/DEPS
+++ b/DEPS
@@ -146,7 +146,6 @@
"dart_style_rev": "5d35f4d829ffb8532d345d95d3e9504ae6cd839e", # disable tools/rev_sdk_deps.dart
"dartdoc_rev": "80c6f18f34b387d4b9ce89ddd2e3049093335f9d",
"ecosystem_rev": "2d58550f9e3fd8ecbc3b2e4444095fcb204a66c6",
- "file_rev": "6842feaef1c4e06239bd30f8d3ef722838b1c97e",
"fixnum_rev": "83293b8ed86ccd574a94fcf4a2da43f31c1b43e0",
"flute_rev": "a531c96a8b43d015c6bfbbfe3ab54867b0763b8b",
"glob_rev": "00a9c82d31c01ae88ec9ae4021d842e9b832aa52",
@@ -422,9 +421,6 @@
"url": Var("dart_git") + "flute.git" + "@" + Var("flute_rev"),
"condition": "checkout_flute",
},
- Var("dart_root") + "/third_party/pkg/file":
- Var("dart_git") + "external/github.com/google/file.dart"
- + "@" + Var("file_rev"),
Var("dart_root") + "/third_party/pkg/glob":
Var("dart_git") + "glob.git" + "@" + Var("glob_rev"),
Var("dart_root") + "/third_party/pkg/html":
diff --git a/pkg/analysis_server/analyzer_use_new_elements.txt b/pkg/analysis_server/analyzer_use_new_elements.txt
index 5c59218..c32a8bd 100644
--- a/pkg/analysis_server/analyzer_use_new_elements.txt
+++ b/pkg/analysis_server/analyzer_use_new_elements.txt
@@ -533,6 +533,9 @@
lib/src/services/refactoring/move_selected_formal_parameters_left.dart
lib/src/services/snippets/dart/class_declaration.dart
lib/src/services/snippets/dart/do_statement.dart
+lib/src/services/snippets/dart/flutter_stateful_widget.dart
+lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
+lib/src/services/snippets/dart/flutter_stateless_widget.dart
lib/src/services/snippets/dart/for_in_statement.dart
lib/src/services/snippets/dart/for_statement.dart
lib/src/services/snippets/dart/function_declaration.dart
@@ -548,6 +551,8 @@
lib/src/services/snippets/dart_snippet_request.dart
lib/src/services/snippets/snippet.dart
lib/src/services/snippets/snippet_context.dart
+lib/src/services/snippets/snippet_manager.dart
+lib/src/services/snippets/snippet_producer.dart
lib/src/services/user_prompts/dart_fix_prompt_manager.dart
lib/src/services/user_prompts/survey_manager.dart
lib/src/services/user_prompts/user_prompts.dart
@@ -962,6 +967,7 @@
test/services/snippets/dart/test_group_definition_test.dart
test/services/snippets/dart/try_catch_statement_test.dart
test/services/snippets/dart/while_statement_test.dart
+test/services/snippets/snippet_manager_test.dart
test/services/snippets/snippet_request_test.dart
test/services/snippets/test_all.dart
test/services/test_all.dart
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart
index bbe99ec..08ddb34 100644
--- a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart
@@ -4,7 +4,7 @@
import 'package:analysis_server/src/services/snippets/snippet.dart';
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
/// Produces a [Snippet] that creates a Flutter StatefulWidget and related State
@@ -14,12 +14,12 @@
static const prefix = 'stful';
static const label = 'Flutter Stateful Widget';
- late ClassElement? classStatefulWidget;
- late ClassElement? classState;
+ late ClassElement2? classStatefulWidget;
+ late ClassElement2? classState;
@override
- late ClassElement? classBuildContext;
+ late ClassElement2? classBuildContext;
@override
- late ClassElement? classKey;
+ late ClassElement2? classKey;
FlutterStatefulWidget(super.request, {required super.elementImportCache});
@@ -58,7 +58,7 @@
builder.write('class _');
builder.addSimpleLinkedEdit('name', widgetClassName);
builder.write('State extends ');
- builder.writeReference(classState);
+ builder.writeReference2(classState);
builder.write('<');
builder.addSimpleLinkedEdit('name', widgetClassName);
builder.writeln('> {');
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
index f489b8b..b84ba10 100644
--- a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
@@ -4,7 +4,7 @@
import 'package:analysis_server/src/services/snippets/snippet.dart';
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -15,14 +15,14 @@
static const prefix = 'stanim';
static const label = 'Flutter Widget with AnimationController';
- late ClassElement? classStatefulWidget;
- late ClassElement? classState;
+ late ClassElement2? classStatefulWidget;
+ late ClassElement2? classState;
@override
- late ClassElement? classBuildContext;
+ late ClassElement2? classBuildContext;
@override
- late ClassElement? classKey;
- late ClassElement? classAnimationController;
- late MixinElement? classSingleTickerProviderStateMixin;
+ late ClassElement2? classKey;
+ late ClassElement2? classAnimationController;
+ late MixinElement2? classSingleTickerProviderStateMixin;
FlutterStatefulWidgetWithAnimationController(super.request,
{required super.elementImportCache});
@@ -65,15 +65,15 @@
builder.write('class _');
builder.addSimpleLinkedEdit('name', widgetClassName);
builder.write('State extends ');
- builder.writeReference(classState);
+ builder.writeReference2(classState);
builder.write('<');
builder.addSimpleLinkedEdit('name', widgetClassName);
builder.writeln('>');
builder.write(' with ');
- builder.writeReference(classSingleTickerProviderStateMixin);
+ builder.writeReference2(classSingleTickerProviderStateMixin);
builder.writeln(' {');
builder.write(' late ');
- builder.writeReference(classAnimationController);
+ builder.writeReference2(classAnimationController);
builder.writeln(' _controller;');
builder.writeln();
{
@@ -87,7 +87,7 @@
builder.writeln('{');
builder.writeln(' super.initState();');
builder.write(' _controller = ');
- builder.writeReference(classAnimationController);
+ builder.writeReference2(classAnimationController);
builder.writeln('(vsync: this);');
builder.writeln(' }');
},
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart
index ae94199..7bcb3cd 100644
--- a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart
@@ -4,7 +4,7 @@
import 'package:analysis_server/src/services/snippets/snippet.dart';
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
/// Produces a [Snippet] that creates a Flutter StatelessWidget.
@@ -13,11 +13,13 @@
static const prefix = 'stless';
static const label = 'Flutter Stateless Widget';
- late ClassElement? classStatelessWidget;
+ late ClassElement2? classStatelessWidget;
+
@override
- late ClassElement? classBuildContext;
+ late ClassElement2? classBuildContext;
+
@override
- late ClassElement? classKey;
+ late ClassElement2? classKey;
FlutterStatelessWidget(super.request, {required super.elementImportCache});
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart b/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart
index 0a82a85..85218ed 100644
--- a/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart
@@ -25,11 +25,11 @@
import 'package:analysis_server/src/services/snippets/snippet_context.dart';
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
typedef SnippetProducerGenerator = SnippetProducer Function(DartSnippetRequest,
- {required Map<Element, LibraryElement?> elementImportCache});
+ {required Map<Element2, LibraryElement2?> elementImportCache});
/// [DartSnippetManager] determines if a snippet request is Dart specific
/// and forwards those requests to all Snippet Producers that return `true` from
@@ -81,7 +81,7 @@
if (generators == null) {
return snippets;
}
- var elementImportCache = <Element, LibraryElement?>{};
+ var elementImportCache = <Element2, LibraryElement2?>{};
for (var generator in generators) {
var producer =
generator(request, elementImportCache: elementImportCache);
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart b/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart
index ce8cafd..4d74bb4 100644
--- a/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart
@@ -8,7 +8,7 @@
import 'package:analysis_server_plugin/edit/correction_utils.dart';
import 'package:analyzer/dart/analysis/code_style_options.dart';
import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/session_helper.dart';
@@ -21,27 +21,27 @@
abstract class DartSnippetProducer extends SnippetProducer {
final AnalysisSessionHelper sessionHelper;
final CorrectionUtils utils;
- final LibraryElement libraryElement;
+ final LibraryElement2 libraryElement;
final bool useSuperParams;
/// Elements that need to be imported for generated code to be valid.
///
/// Calling [addImports] will add any required imports to the supplied
/// builder.
- final Set<Element> requiredElementImports = {};
+ final Set<Element2> requiredElementImports = {};
/// A cache of mappings from Elements to their public Library Elements.
///
/// Callers can share this cache across multiple snippet producers to avoid
/// repeated searches where they may add imports for the same elements.
- final Map<Element, LibraryElement?> _elementImportCache;
+ final Map<Element2, LibraryElement2?> _elementImportCache;
DartSnippetProducer(super.request,
- {required Map<Element, LibraryElement?> elementImportCache})
+ {required Map<Element2, LibraryElement2?> elementImportCache})
: sessionHelper = AnalysisSessionHelper(request.analysisSession),
utils = CorrectionUtils(request.unit),
- libraryElement = request.unit.libraryElement,
- useSuperParams = request.unit.libraryElement.featureSet
+ libraryElement = request.unit.libraryElement2,
+ useSuperParams = request.unit.libraryElement2.featureSet
.isEnabled(Feature.super_parameters),
_elementImportCache = elementImportCache;
@@ -56,26 +56,26 @@
Future<void> addImports(DartFileEditBuilder builder) async {
var dartBuilder = builder as DartFileEditBuilderImpl;
await Future.wait(requiredElementImports.map((element) => dartBuilder
- .importElementLibrary(element, resultCache: _elementImportCache)));
+ .importElementLibrary2(element, resultCache: _elementImportCache)));
}
}
abstract class FlutterSnippetProducer extends DartSnippetProducer {
- late ClassElement? classWidget;
- late ClassElement? classPlaceholder;
+ late ClassElement2? classWidget;
+ late ClassElement2? classPlaceholder;
FlutterSnippetProducer(super.request, {required super.elementImportCache});
- Future<ClassElement?> getClass(String name) async {
- var class_ = await sessionHelper.getFlutterClass(name);
+ Future<ClassElement2?> getClass(String name) async {
+ var class_ = await sessionHelper.getFlutterClass2(name);
if (class_ != null) {
requiredElementImports.add(class_);
}
return class_;
}
- Future<MixinElement?> getMixin(String name) async {
- var mixin = await sessionHelper.getMixin(widgetsUri, name);
+ Future<MixinElement2?> getMixin(String name) async {
+ var mixin = await sessionHelper.getMixin2(widgetsUri, name);
if (mixin != null) {
requiredElementImports.add(mixin);
}
@@ -83,7 +83,7 @@
}
DartType getType(
- InterfaceElement classElement, [
+ InterfaceElement2 classElement, [
NullabilitySuffix nullabilitySuffix = NullabilitySuffix.none,
]) =>
classElement.instantiate(
@@ -109,8 +109,8 @@
/// A mixin that provides some common methods for producers that build snippets
/// for Flutter widget classes.
mixin FlutterWidgetSnippetProducerMixin on FlutterSnippetProducer {
- ClassElement? get classBuildContext;
- ClassElement? get classKey;
+ ClassElement2? get classBuildContext;
+ ClassElement2? get classKey;
String get widgetClassName => 'MyWidget';
void writeBuildMethod(DartEditBuilder builder) {
diff --git a/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart b/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
index 042d05f..6de4da6 100644
--- a/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
+++ b/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
@@ -7,7 +7,7 @@
import 'package:analysis_server/src/services/snippets/snippet_context.dart';
import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -78,7 +78,7 @@
SnippetContext.inClass: [
(
context, {
- required Map<Element, LibraryElement?> elementImportCache,
+ required Map<Element2, LibraryElement2?> elementImportCache,
}) =>
throw 'Tried to create producer for wrong context',
]
@@ -125,7 +125,7 @@
Future<bool> isValid() async => false;
static _NotValidSnippetProducer newInstance(DartSnippetRequest request,
- {required Map<Element, LibraryElement?> elementImportCache}) =>
+ {required Map<Element2, LibraryElement2?> elementImportCache}) =>
_NotValidSnippetProducer._(request);
}
@@ -158,6 +158,6 @@
Future<bool> isValid() async => true;
static _ValidSnippetProducer newInstance(DartSnippetRequest request,
- {required Map<Element, LibraryElement?> elementImportCache}) =>
+ {required Map<Element2, LibraryElement2?> elementImportCache}) =>
_ValidSnippetProducer._(request);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/session_helper.dart b/pkg/analyzer/lib/src/dart/analysis/session_helper.dart
index c71c4aa..d724c12 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session_helper.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session_helper.dart
@@ -107,6 +107,20 @@
return null;
}
+ /// Return the [MixinElement] with the given [name] that is exported
+ /// from the library with the given [libraryUri], or `null` if the library
+ /// does not export a class with such name.
+ Future<MixinElement2?> getMixin2(String libraryUri, String name) async {
+ var libraryResult = await session.getLibraryByUri(libraryUri);
+ if (libraryResult is LibraryElementResult) {
+ var element = libraryResult.element2.exportNamespace.get2(name);
+ if (element is MixinElement2) {
+ return element;
+ }
+ }
+ return null;
+ }
+
/// Return the resolved unit that declares the given [element].
Future<ResolvedUnitResult?> getResolvedUnitByElement(Element element) async {
var libraryPath = element.library!.source.fullName;
diff --git a/pkg/analyzer/lib/src/services/top_level_declarations.dart b/pkg/analyzer/lib/src/services/top_level_declarations.dart
index 0d00ab1..8228058 100644
--- a/pkg/analyzer/lib/src/services/top_level_declarations.dart
+++ b/pkg/analyzer/lib/src/services/top_level_declarations.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
import 'package:analyzer/src/dart/analysis/file_state_filter.dart';
@@ -63,6 +64,50 @@
return null;
}
+ /// Return the first public library that exports (but does not necessary
+ /// declare) [element].
+ Future<LibraryElement2?> publiclyExporting2(Element2 element,
+ {Map<Element2, LibraryElement2?>? resultCache}) async {
+ if (resultCache?.containsKey(element) ?? false) {
+ return resultCache![element];
+ }
+
+ var declarationFilePath = element.library2?.firstFragment.source.fullName;
+ if (declarationFilePath == null) {
+ return null;
+ }
+
+ var analysisDriver = _analysisContext.driver;
+ var fsState = analysisDriver.fsState;
+ await analysisDriver.discoverAvailableFiles();
+
+ var declarationFile = fsState.getFileForPath(declarationFilePath);
+ var declarationPackage = declarationFile.uriProperties.packageName;
+
+ for (var file in fsState.knownFiles.toList()) {
+ var uri = file.uriProperties;
+ // Only search the package that contains the declaration and its public
+ // libraries.
+ if (uri.packageName != declarationPackage || uri.isSrc) {
+ continue;
+ }
+
+ var elementResult = await analysisDriver.getLibraryByUri(file.uriStr);
+ if (elementResult is! LibraryElementResult) {
+ continue;
+ }
+
+ var elementLibrary = elementResult.element2;
+ if (_findElement2(elementLibrary, element.displayName)?.nonSynthetic2 ==
+ element.nonSynthetic2) {
+ resultCache?[element] = elementLibrary;
+ return elementLibrary;
+ }
+ }
+
+ return null;
+ }
+
/// Return the mapping from a library (that is available to this context) to
/// a top-level declaration that is exported (not necessary declared) by this
/// library, and has the requested base name. For getters and setters the
@@ -116,4 +161,21 @@
}
return element;
}
+
+ static Element2? _findElement2(LibraryElement2 libraryElement, String name) {
+ var element = libraryElement.exportNamespace.get2(name) ??
+ libraryElement.exportNamespace.get2('$name=');
+ if (element is GetterElement) {
+ var variable = element.variable3;
+ if (variable != null) {
+ return variable;
+ }
+ } else if (element is SetterElement) {
+ var variable = element.variable3;
+ if (variable != null) {
+ return variable;
+ }
+ }
+ return element;
+ }
}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 08ab499..3c48600 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -17,6 +17,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/services/top_level_declarations.dart';
+import 'package:analyzer/src/utilities/extensions/element.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide Element, ElementKind;
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
@@ -1961,13 +1962,9 @@
/// the names used in generated code, to information about these imports.
Map<Uri, _LibraryImport> librariesToImport = {};
- /// A mapping of [Element]s to pending imports that will be added to make
- /// them visible in the generated code.
- final Map<Element, _LibraryImport> _elementLibrariesToImport = {};
-
- /// A mapping of [Element2]s to pending imports that will be added to make
- /// them visible in the generated code.
- final Map<Element2, _LibraryImport> _elementLibrariesToImport2 = {};
+ /// A mapping of elements to pending imports that will be added to make them
+ /// visible in the generated code.
+ final Map<Element2, _LibraryImport> _elementLibrariesToImport = {};
/// Initializes a newly created builder to build a source file edit within the
/// change being built by the given [changeBuilder].
@@ -2049,9 +2046,6 @@
for (var entry in _elementLibrariesToImport.entries) {
copy._elementLibrariesToImport[entry.key] = entry.value;
}
- for (var entry in _elementLibrariesToImport2.entries) {
- copy._elementLibrariesToImport2[entry.key] = entry.value;
- }
return copy;
}
@@ -2145,7 +2139,8 @@
var uriToImport = libraryToImport?.source.uri;
if (uriToImport != null) {
- var newImport = elementLibrariesToImport[element] = _importLibrary(
+ var newImport =
+ elementLibrariesToImport[element.asElement2!] = _importLibrary(
uriToImport,
isExplicitImport: false,
shownName: element.name,
@@ -2159,6 +2154,55 @@
}
}
+ /// Arranges to have an import added that makes [element] available.
+ ///
+ /// If [element] is already available in the current library, does nothing.
+ ///
+ /// If the library [element] is declared in is inside the `src` folder, will
+ /// try to locate a public URI to import instead.
+ ///
+ /// If [useShow] is `true`, new imports will be added that `show` only the
+ /// requested element (or if there is a pending import for the library, added
+ /// to its `show` combinator).
+ Future<void> importElementLibrary2(Element2 element,
+ {Map<Element2, LibraryElement2?>? resultCache,
+ bool useShow = false}) async {
+ if (_isDefinedLocally2(element)) {
+ return;
+ }
+
+ var existingImport = _getImportElement2(element);
+ var name = element.name;
+ if (existingImport != null && name != null) {
+ existingImport.ensureShown(name, useShow: useShow);
+ return;
+ }
+
+ var elementLibrariesToImport =
+ (libraryChangeBuilder ?? this)._elementLibrariesToImport;
+ var libraryToImport = resultCache?[element] ??
+ await TopLevelDeclarations(resolvedUnit)
+ .publiclyExporting2(element, resultCache: resultCache) ??
+ // Fall back to the element's library if we didn't find a better one.
+ element.library2;
+
+ var uriToImport = libraryToImport?.firstFragment.source.uri;
+ if (uriToImport != null) {
+ var newImport = elementLibrariesToImport[element] = _importLibrary(
+ uriToImport,
+ isExplicitImport: false,
+ shownName: element.name,
+ useShow: useShow,
+ );
+
+ // It's possible this new import can satisfy other pending element's
+ // imports in which case we could remove them to avoid adding unnecessary
+ // imports.
+ _removeUnnecessaryPendingElementImports(
+ newImport, libraryToImport as LibraryElement);
+ }
+ }
+
@override
String importLibrary(Uri uri,
{String? prefix, String? showName, bool useShow = false}) {
@@ -2744,7 +2788,8 @@
}
}
- return (libraryChangeBuilder ?? this)._elementLibrariesToImport[element];
+ return (libraryChangeBuilder ?? this)
+ ._elementLibrariesToImport[element.asElement2];
}
/// Returns information about the library used to import the given [element]
@@ -2778,7 +2823,7 @@
}
}
- return (libraryChangeBuilder ?? this)._elementLibrariesToImport2[element];
+ return (libraryChangeBuilder ?? this)._elementLibrariesToImport[element];
}
List<LibraryImportElement> _getImportsForUri(Uri uri) {
@@ -2942,7 +2987,7 @@
// If this new import exports the other element, change it to this import
// and record it as a removal candidate.
- if (newLibrary?.exportNamespace.get(otherElement.displayName) ==
+ if (newLibrary?.exportNamespace.get2(otherElement.displayName) ==
otherElement) {
candidatesToRemove.add(otherImport);
elementLibrariesToImport[otherElement] = newImport;
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 23ad8d6..c8cc3f2 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -4,6 +4,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:isolate';
import 'package:args/args.dart';
import 'package:dart2native/generate.dart';
@@ -87,41 +88,48 @@
@override
FutureOr<int> run() async {
- if (!Sdk.checkArtifactExists(sdk.librariesJson)) {
- return genericErrorExitCode;
+ if (!Sdk.checkArtifactExists(sdk.dart2jsSnapshot) ||
+ !Sdk.checkArtifactExists(sdk.librariesJson)) {
+ return 255;
}
+
final args = argResults!;
- var snapshot = sdk.dart2jsAotSnapshot;
- var runtime = sdk.dartAotRuntime;
- if (!Sdk.checkArtifactExists(snapshot, logError: false)) {
- // AOT snapshots cannot be generated on IA32, so we need this fallback
- // branch until support for IA32 is dropped (https://dartbug.com/49969).
- snapshot = sdk.dart2jsSnapshot;
- runtime = sdk.dart;
- if (!Sdk.checkArtifactExists(snapshot)) {
- return genericErrorExitCode;
- }
- }
- final dart2jsCommand = [
- runtime,
- snapshot,
+
+ // Build arguments.
+ final buildArgs = <String>[
'--libraries-spec=${sdk.librariesJson}',
'--cfe-invocation-modes=compile',
'--invoker=dart_cli',
// Add the remaining arguments.
if (args.rest.isNotEmpty) ...args.rest.sublist(0),
];
+
+ var retval = 0;
+ final result = Completer<int>();
+ final exitPort = ReceivePort()
+ ..listen((msg) {
+ result.complete(0);
+ });
+ final errorPort = ReceivePort()
+ ..listen((error) {
+ log.stderr(error.toString());
+ result.complete(255);
+ });
try {
- final exitCode = await runProcessInheritStdio(dart2jsCommand);
- return exitCode;
+ await Isolate.spawnUri(Uri.file(sdk.dart2jsSnapshot), buildArgs, null,
+ onExit: exitPort.sendPort, onError: errorPort.sendPort);
+ retval = await result.future;
} catch (e, st) {
log.stderr('Error: JS compilation failed');
log.stderr(e.toString());
if (verbose) {
log.stderr(st.toString());
}
- return compileErrorExitCode;
+ retval = compileErrorExitCode;
}
+ errorPort.close();
+ exitPort.close();
+ return retval;
}
}
diff --git a/pkg/dartdev/lib/src/core.dart b/pkg/dartdev/lib/src/core.dart
index 8e89b55..c6a8c79 100644
--- a/pkg/dartdev/lib/src/core.dart
+++ b/pkg/dartdev/lib/src/core.dart
@@ -119,11 +119,8 @@
}
log.trace(command.join(' '));
- final process = await Process.start(
- command.first,
- command.skip(1).toList(),
- workingDirectory: cwd,
- );
+ final process = await Process.start(command.first, command.skip(1).toList(),
+ workingDirectory: cwd);
final (_, _, exitCode) = await (
forward(process.stdout, false),
forward(process.stderr, true),
@@ -132,22 +129,6 @@
return exitCode;
}
-Future<int> runProcessInheritStdio(
- List<String> command, {
- bool logToTrace = false,
- void Function(String str)? listener,
- String? cwd,
-}) async {
- log.trace(command.join(' '));
- final process = await Process.start(
- command.first,
- command.skip(1).toList(),
- workingDirectory: cwd,
- mode: ProcessStartMode.inheritStdio,
- );
- return await process.exitCode;
-}
-
Future _streamLineTransform(
Stream<List<int>> stream,
Function(String line) handler,
diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart
index 5ef7626..168294b 100644
--- a/pkg/dartdev/lib/src/sdk.dart
+++ b/pkg/dartdev/lib/src/sdk.dart
@@ -71,10 +71,6 @@
'dart2js.dart.snapshot',
);
- String get dart2jsAotSnapshot => _snapshotPathFor(
- 'dart2js_aot.dart.snapshot',
- );
-
String get dart2wasmSnapshot => _snapshotPathFor(
'dart2wasm_product.snapshot',
);
diff --git a/pkg/dartdev/test/sdk_test.dart b/pkg/dartdev/test/sdk_test.dart
index 9ef7801..de39966 100644
--- a/pkg/dartdev/test/sdk_test.dart
+++ b/pkg/dartdev/test/sdk_test.dart
@@ -30,7 +30,7 @@
});
test('dart2js snapshot', () {
- expectSnapshotExists(Sdk().dart2jsAotSnapshot, Sdk().dart2jsSnapshot);
+ expectFileExists(Sdk().dart2jsSnapshot);
});
}
diff --git a/pkg/linter/lib/src/rules/avoid_void_async.dart b/pkg/linter/lib/src/rules/avoid_void_async.dart
index fd56110..543fc69 100644
--- a/pkg/linter/lib/src/rules/avoid_void_async.dart
+++ b/pkg/linter/lib/src/rules/avoid_void_async.dart
@@ -38,7 +38,7 @@
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
- if (node.name.lexeme == 'main') return;
+ if (node.name.lexeme == 'main' && node.parent is CompilationUnit) return;
_check(
declaredElement: node.declaredElement,
returnType: node.returnType,
diff --git a/pkg/linter/lib/src/rules/unnecessary_parenthesis.dart b/pkg/linter/lib/src/rules/unnecessary_parenthesis.dart
index dd9b49a..15c1ff8 100644
--- a/pkg/linter/lib/src/rules/unnecessary_parenthesis.dart
+++ b/pkg/linter/lib/src/rules/unnecessary_parenthesis.dart
@@ -70,6 +70,7 @@
parent.declaredElement2?.type is RecordType) {
if (expression is! RecordLiteral) return;
}
+
// `g((3)); => g((int,) i) { }` is OK.
if (parent is ArgumentList) {
var element = node.correspondingParameter;
@@ -77,6 +78,7 @@
return;
}
}
+
// `g(i: (3)); => g({required (int,) i}) { }` is OK.
if (parent is NamedExpression &&
parent.correspondingParameter?.type is RecordType) {
@@ -158,16 +160,6 @@
return;
}
- // https://github.com/dart-lang/linter/issues/2944
- if (expression is FunctionExpression) {
- if (parent is MethodInvocation ||
- parent is PropertyAccess ||
- parent is BinaryExpression ||
- parent is IndexExpression) {
- return;
- }
- }
-
if (expression is ConstructorReference) {
if (parent is! FunctionExpressionInvocation ||
parent.typeArguments == null) {
@@ -230,6 +222,7 @@
// An expression with internal whitespace can be made more readable when
// wrapped in parentheses in many cases. But when the parentheses are
// inside one of the following nodes, the readability is not affected.
+ // See https://github.com/dart-lang/linter/issues/2944.
if (parent is! AssignmentExpression &&
parent is! ConstructorFieldInitializer &&
parent is! ExpressionFunctionBody &&
@@ -327,7 +320,9 @@
self is AssignmentExpression ||
self is AwaitExpression ||
self is BinaryExpression ||
+ self is FunctionExpression ||
self is IsExpression ||
+ self is SwitchExpression ||
// As in, `!(new Foo())`.
(self is InstanceCreationExpression && self.keyword != null) ||
// No TypedLiteral (ListLiteral, MapLiteral, SetLiteral) accepts `-`
diff --git a/pkg/linter/test/rules/all.dart b/pkg/linter/test/rules/all.dart
index 656be45..5bda8b6 100644
--- a/pkg/linter/test/rules/all.dart
+++ b/pkg/linter/test/rules/all.dart
@@ -210,6 +210,8 @@
import 'prefer_interpolation_to_compose_strings_test.dart'
as prefer_interpolation_to_compose_strings;
import 'prefer_is_empty_test.dart' as prefer_is_empty;
+import 'prefer_is_not_empty_test.dart' as prefer_is_not_empty;
+import 'prefer_is_not_operator_test.dart' as prefer_is_not_operator;
import 'prefer_iterable_whereType_test.dart' as prefer_iterable_whereType;
import 'prefer_mixin_test.dart' as prefer_mixin;
import 'prefer_null_aware_method_calls_test.dart'
@@ -464,6 +466,8 @@
prefer_int_literals.main();
prefer_interpolation_to_compose_strings.main();
prefer_is_empty.main();
+ prefer_is_not_empty.main();
+ prefer_is_not_operator.main();
prefer_iterable_whereType.main();
prefer_mixin.main();
prefer_null_aware_method_calls.main();
diff --git a/pkg/linter/test/rules/avoid_void_async_test.dart b/pkg/linter/test/rules/avoid_void_async_test.dart
index 94da5e4..5d66b29 100644
--- a/pkg/linter/test/rules/avoid_void_async_test.dart
+++ b/pkg/linter/test/rules/avoid_void_async_test.dart
@@ -112,7 +112,6 @@
]);
}
- @FailingTest(issue: 'https://github.com/dart-lang/linter/issues/4941')
test_functionLocal_main_async_arrow() async {
await assertDiagnostics(r'''
void f() {
diff --git a/pkg/linter/test/rules/prefer_final_fields_test.dart b/pkg/linter/test/rules/prefer_final_fields_test.dart
index 4d03fff..89cca98 100644
--- a/pkg/linter/test/rules/prefer_final_fields_test.dart
+++ b/pkg/linter/test/rules/prefer_final_fields_test.dart
@@ -2,14 +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 'package:analyzer/src/error/analyzer_error_code.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../rule_test_support.dart';
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(PreferFinalFieldsTest);
defineReflectiveTests(PreferFinalFieldsExtensionTypesTest);
+ defineReflectiveTests(PreferFinalFieldsTest);
});
}
@@ -59,8 +60,35 @@
@reflectiveTest
class PreferFinalFieldsTest extends LintRuleTest {
@override
+ List<AnalyzerErrorCode> get ignoredErrorCodes => [
+ WarningCode.UNUSED_FIELD,
+ WarningCode.UNUSED_LOCAL_VARIABLE,
+ ];
+
+ @override
String get lintRule => LintNames.prefer_final_fields;
+ test_assignedInConstructorInitializer() async {
+ await assertDiagnostics(r'''
+class C {
+ int _x;
+ C() : _x = 7;
+}
+''', [
+ lint(16, 2),
+ ]);
+ }
+
+ test_assignedInConstructorInitializer_butNotAll() async {
+ await assertNoDiagnostics(r'''
+class C {
+ var _x;
+ C(this._x);
+ C.named();
+}
+''');
+ }
+
test_assignedInPart() async {
newFile('$testPackageLibPath/part.dart', r'''
part of 'test.dart';
@@ -77,6 +105,30 @@
''');
}
+ test_assignedInTopLevelFunction() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int _x = 0;
+}
+
+void f() {
+ var c = C();
+ c._x = 42;
+}
+''');
+ }
+
+ test_assignment_plusEquals() async {
+ await assertNoDiagnostics(r'''
+class C {
+ var _x = 1;
+ void f() {
+ _x += 2;
+ }
+}
+''');
+ }
+
test_declaredInPart() async {
newFile('$testPackageLibPath/part.dart', r'''
part of 'test.dart';
@@ -106,6 +158,36 @@
]);
}
+ test_final_multiple() async {
+ await assertNoDiagnostics(r'''
+class C {
+ final _x = 1, _y = 2;
+}
+''');
+ }
+
+ test_final_public_multiple() async {
+ await assertNoDiagnostics(r'''
+class C {
+ final x = 1, y = 2;
+}
+''');
+ }
+
+ test_indexAssignment() async {
+ await assertDiagnostics(r'''
+class C {
+ var _x = [];
+
+ void f() {
+ _x[0] = 3;
+ }
+}
+''', [
+ lint(16, 7),
+ ]);
+ }
+
test_overrideField_extends() async {
await assertNoDiagnostics(r'''
class A {
@@ -192,4 +274,177 @@
}
''');
}
+
+ test_postfixExpression_decrement() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int _x = 1;
+ void f() {
+ _x--;
+ }
+}
+''');
+ }
+
+ test_postfixExpression_increment() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int _x = 1;
+ void f() {
+ _x++;
+ }
+}
+''');
+ }
+
+ test_prefixExpression_decrement() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int _x = 1;
+ void f() {
+ --_x;
+ }
+}
+''');
+ }
+
+ test_prefixExpression_increment() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int _x = 1;
+ void f() {
+ ++_x;
+ }
+}
+''');
+ }
+
+ test_prefixExpression_not() async {
+ await assertDiagnostics(r'''
+class C {
+ bool _x = false;
+ void f() {
+ !_x;
+ }
+}
+''', [
+ lint(17, 10),
+ ]);
+ }
+
+ test_prefixExpression_tilde() async {
+ await assertDiagnostics(r'''
+class C {
+ int _x = 0xffff;
+ void f() {
+ ~_x;
+ }
+}
+''', [
+ lint(16, 11),
+ ]);
+ }
+
+ test_propertyAccess() async {
+ await assertDiagnostics(r'''
+class C {
+ int _x = 1;
+ void f() {
+ _x.isEven;
+ }
+}
+''', [
+ lint(16, 6),
+ ]);
+ }
+
+ test_readInInstanceMethod() async {
+ await assertDiagnostics(r'''
+class C {
+ int _x = 0;
+
+ void f() {
+ var a = _x;
+ }
+}
+''', [
+ lint(16, 6),
+ ]);
+ }
+
+ test_reassigned() async {
+ await assertNoDiagnostics(r'''
+class C {
+ var _x = 1;
+ void f() {
+ _x = 2;
+ }
+}
+''');
+ }
+
+ test_referencedInFieldFormalParameters() async {
+ await assertDiagnostics(r'''
+class C {
+ int _x;
+ C(this._x);
+ C.named(this._x);
+}
+''', [
+ lint(16, 2),
+ ]);
+ }
+
+ test_subclassOnGenericClass() async {
+ await assertNoDiagnostics(r'''
+abstract class C<T> {
+ int _x = 0;
+}
+
+class D extends C<int> {
+ void f() {
+ _x = 1;
+ }
+}
+''');
+ }
+
+ test_unused() async {
+ await assertDiagnostics(r'''
+class C {
+ var _x = 1;
+}
+''', [
+ lint(16, 6),
+ ]);
+ }
+
+ test_unused_multiple() async {
+ await assertDiagnostics(r'''
+class C {
+ var _x = 1, _y = 2;
+ void f() {
+ _x = 2;
+ }
+}
+''', [
+ lint(24, 6),
+ ]);
+ }
+
+ test_unused_public() async {
+ await assertNoDiagnostics(r'''
+class C {
+ var x = 1;
+}
+''');
+ }
+
+ test_unused_uninitialized() async {
+ await assertNoDiagnostics(r'''
+class C {
+ int? _x;
+}
+''');
+ }
}
diff --git a/pkg/linter/test/rules/prefer_is_not_empty_test.dart b/pkg/linter/test/rules/prefer_is_not_empty_test.dart
new file mode 100644
index 0000000..615fc3c
--- /dev/null
+++ b/pkg/linter/test/rules/prefer_is_not_empty_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../rule_test_support.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PreferIsNotEmptyTest);
+ });
+}
+
+@reflectiveTest
+class PreferIsNotEmptyTest extends LintRuleTest {
+ @override
+ String get lintRule => 'prefer_is_not_empty';
+
+ test_iterable_isEmpty() async {
+ await assertNoDiagnostics(r'''
+void f(Iterable<int> p) {
+ p.isEmpty;
+}
+''');
+ }
+
+ test_iterable_isEmpty_not() async {
+ await assertDiagnostics(r'''
+void f(Iterable<int> p) {
+ !p.isEmpty;
+}
+''', [
+ lint(28, 10),
+ ]);
+ }
+
+ test_list_isEmpty() async {
+ await assertNoDiagnostics(r'''
+var x = [].isEmpty;
+''');
+ }
+
+ test_list_isEmpty_doubleParens_not() async {
+ await assertDiagnostics(r'''
+var x = !(([4].isEmpty));
+''', [
+ lint(8, 16),
+ ]);
+ }
+
+ test_list_isEmpty_not() async {
+ await assertDiagnostics(r'''
+var x = ![1].isEmpty;
+''', [
+ lint(8, 12),
+ ]);
+ }
+
+ test_list_isEmpty_parens_not() async {
+ await assertDiagnostics(r'''
+var x = !([3].isEmpty);
+''', [
+ lint(8, 14),
+ ]);
+ }
+
+ test_map_isEmpty() async {
+ await assertNoDiagnostics(r'''
+var x = {}.isEmpty;
+''');
+ }
+
+ test_map_isEmpty_not() async {
+ await assertDiagnostics(r'''
+var x = !{2: 'a'}.isEmpty;
+''', [
+ lint(8, 17),
+ ]);
+ }
+}
diff --git a/pkg/linter/test/rules/prefer_is_not_operator_test.dart b/pkg/linter/test/rules/prefer_is_not_operator_test.dart
new file mode 100644
index 0000000..2144d51
--- /dev/null
+++ b/pkg/linter/test/rules/prefer_is_not_operator_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../rule_test_support.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PreferIsNotOperatorTest);
+ });
+}
+
+@reflectiveTest
+class PreferIsNotOperatorTest extends LintRuleTest {
+ @override
+ String get lintRule => 'prefer_is_not_operator';
+
+ test_is_wrappedInNot() async {
+ await assertDiagnostics(r'''
+void f(Object p) {
+ !(p is int);
+}
+''', [
+ lint(21, 11),
+ ]);
+ }
+
+ test_isNot() async {
+ await assertNoDiagnostics(r'''
+void f(Object p) {
+ p is! int;
+}
+''');
+ }
+}
diff --git a/pkg/linter/test/rules/unnecessary_parenthesis_test.dart b/pkg/linter/test/rules/unnecessary_parenthesis_test.dart
index 831ef49..2f74ae0 100644
--- a/pkg/linter/test/rules/unnecessary_parenthesis_test.dart
+++ b/pkg/linter/test/rules/unnecessary_parenthesis_test.dart
@@ -566,6 +566,15 @@
''');
}
+ test_switchExpressionInside_methodInvocation() async {
+ await assertNoDiagnostics(r'''
+void f(Object v) {
+ const v = 0;
+ (switch (v) { _ => Future.value() }).then((_) {});
+}
+''');
+ }
+
test_switchExpressionInside_variableDeclaration() async {
await assertDiagnostics(r'''
void f(Object? x) {
diff --git a/pkg/linter/test_data/rules/prefer_final_fields.dart b/pkg/linter/test_data/rules/prefer_final_fields.dart
deleted file mode 100644
index 0abde54..0000000
--- a/pkg/linter/test_data/rules/prefer_final_fields.dart
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright (c) 2016, 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.
-
-//ignore_for_file: unused_field, unused_local_variable, prefer_expression_function_bodies
-
-class PrefixOps {
- bool _initialized = false; // LINT
- int _num = 1; // LINT
- int _num2 = 1; // OK
- int _bits = 0xffff; // LINT
- int getValue() {
- if (!_initialized) {
- return 0;
- }
- if (-_num == -1) {
- return 0;
- }
- if (~_bits == 0) {
- return 0;
- }
- if (--_num2 == 0) {
- return 0;
- }
- return 1;
- }
-}
-
-typedef bool Predicate();
-
-class PostfixOps {
- int _num = 1; // OK
- int _num2 = 1; // OK
- String _string = ''; // LINT
-
- Predicate _predicate = () => false; // LINT
-
- int getValue() {
- if (_num-- == -1) {
- return 0;
- }
- if (_num2++ == 1) {
- return 0;
- }
- if (_predicate()) {
- return 1;
- }
- if (_string.length == 1) {
- return 0;
- }
- return 1;
- }
-}
-
-class FalsePositiveWhenReturn {
- int _value = 0;
- int getValue() {
- return ++_value; // OK
- }
-}
-
-class BadImmutable {
- var _label = 'hola mundo! BadImmutable'; // LINT
- var label = 'hola mundo! BadImmutable'; // OK
-}
-
-class GoodImmutable {
- final label = 'hola mundo! BadImmutable', bla = 5; // OK
- final _label = 'hola mundo! BadImmutable', _bla = 5; // OK
-}
-
-class GoodMutable {
- var _label = 'hola mundo! GoodMutable';
- var _someInt = 0;
- var _otherInt = 1;
-
- void changeLabel() {
- _label = 'hello world! GoodMutable';
- _someInt++;
- _otherInt += 2;
- }
-}
-
-class MultipleMutable {
- final int _someOther;
- var _label = 'hola mundo! GoodMutable', _offender = 'mumble mumble!'; // LINT
- var _never_initialized_field; // OK
-
- MultipleMutable.foo() : _someOther = 5;
-
- MultipleMutable(this._someOther);
-
- void changeLabel() {
- _label = 'hello world! GoodMutable';
- }
-}
-
-class BadMultipleFormals {
- var _label; // LINT
- BadMultipleFormals(this._label);
- BadMultipleFormals.withDefault(this._label);
-}
-
-class BadInitializer {
- var _label; // LINT
- BadInitializer() : _label = 'Hello';
-}
-
-class BadMultipleInitializer {
- var _label; // LINT
- BadMultipleInitializer() : _label = 'Hello';
- BadMultipleInitializer.withDefault() : _label = 'Default';
-}
-
-class BadMultipleMixConstructors {
- var _label; // LINT
- BadMultipleMixConstructors(this._label);
- BadMultipleMixConstructors.withDefault() : _label = 'Hello';
-}
-
-class GoodFormals {
- var _label; // OK
- GoodFormals(this._label);
- GoodFormals.empty();
-}
-
-class GoodInitializer {
- var _label; // OK
- GoodInitializer() : _label = 'Hello';
- GoodInitializer.empty();
-}
-
-class C {
- int _f = 0; // LINT
- void m() {
- String _f;
- _f = '';
- }
-}
-
-class D {
- int _f = 0; // OK
-}
-
-void accessD_f() {
- D d = new D();
- d._f = 42;
-}
-
-class E {
- int _f = 0; // LINT
-
- void useItInRightHandSide() {
- // ignore: unused_local_variable
- int a = _f;
- }
-}
-
-class F {
- var _array = []; // LINT
-
- void foo() {
- _array[0] = 3;
- }
-}
-
-// https://github.com/dart-lang/linter/issues/686
-class IdBug686 {
- static int _id = 0;
- static String generateId({prefix: String}) {
- return (prefix ?? "id") + "-" + (_id++).toString() + "-" + _foo();
- }
-
- static String _foo() => '';
-}
-
-// analyzer's `FieldMember` vs `FieldElement` caused
-// https://github.com/dart-lang/sdk/issues/34417
-abstract class GenericBase<T> {
- int _current = 0; // OK
-}
-
-class GenericSub extends GenericBase<int> {
- void test() {
- _current = 1;
- }
-}
-
-class Z {
- /// Set in the top level [z] function below.
- int _z = 1; //OK
-}
-
-void z(Z z) {
- z._z = 0;
-}
diff --git a/pkg/linter/test_data/rules/prefer_is_not_empty.dart b/pkg/linter/test_data/rules/prefer_is_not_empty.dart
deleted file mode 100644
index febc139..0000000
--- a/pkg/linter/test_data/rules/prefer_is_not_empty.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2015, 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.
-
-bool lne = ![1].isEmpty; // LINT [12:12]
-bool mne = !{2: 'a'}.isEmpty; // LINT
-bool ine = !iterable.isEmpty; // LINT
-bool parens = !([3].isEmpty); // LINT
-bool parens2 = !(([4].isEmpty)); // LINT
-
-bool le = [].isEmpty;
-bool me = {}.isEmpty;
-bool ie = iterable.isEmpty;
-
-Iterable get iterable => [];
diff --git a/pkg/linter/test_data/rules/prefer_is_not_operator.dart b/pkg/linter/test_data/rules/prefer_is_not_operator.dart
deleted file mode 100644
index 2a57295..0000000
--- a/pkg/linter/test_data/rules/prefer_is_not_operator.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2019, 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.
-
-class Foo {}
-var _a;
-
-foo() {
- if (!(_a is Foo)) {} // LINT
- var _exp = !(_a is Foo); // LINT
-
- if (_a is! Foo) {} // OK
- var _exp1 = _a is! Foo; // OK
-}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 93cf022..e03cf3e 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -43,8 +43,7 @@
# ......snapshots/
# ........analysis_server.dart.snapshot
# ........dart2bytecode.snapshot (if dart_dynamic_modules)
-# ........dart2js_aot.dart.snapshot (AOT snapshot, if not on ia32)
-# ........dart2js.dart.snapshot (JIT snapshot only on ia32)
+# ........dart2js.dart.snapshot
# ........dart2wasm_product.snapshot (if not on ia32)
# ........dartdev.dart.snapshot (app-jit snapshot or kernel dill file)
# ........dartdevc.dart.snapshot
@@ -154,6 +153,10 @@
_full_sdk_snapshots = _platform_sdk_snapshots + [
[
+ "dart2js",
+ "../utils/compiler:dart2js",
+ ],
+ [
"dartdevc",
"../utils/ddc:dartdevc",
],
@@ -162,17 +165,6 @@
"../utils/bazel:kernel_worker",
],
]
-if (dart_target_arch != "ia32" && dart_target_arch != "x86") {
- _full_sdk_snapshots += [ [
- "dart2js_aot",
- "../utils/compiler:dart2js_sdk_aot",
- ] ]
-} else {
- _full_sdk_snapshots += [ [
- "dart2js",
- "../utils/compiler:dart2js",
- ] ]
-}
# Libraries that go under lib/
_full_sdk_libraries = [
diff --git a/tests/dartdevc/debugger/debugger_test.dart b/tests/dartdevc/debugger/debugger_test.dart
index 59a74ca..7af8f64 100644
--- a/tests/dartdevc/debugger/debugger_test.dart
+++ b/tests/dartdevc/debugger/debugger_test.dart
@@ -1,7 +1,6 @@
/// Debugger custom formatter tests.
-/// If the tests fail, paste the expected output into the [expectedGolden]
-/// string literal in this file and audit the diff to ensure changes are
-/// expected.
+/// If the tests fail, paste the expected output into the golden file and audit
+/// the diff to ensure changes are expected.
///
/// Currently only DDC supports debugging objects with custom formatters
/// but it is reasonable to add support to Dart2JS in the future.
@@ -9,10 +8,12 @@
library debugger_test;
import 'dart:html';
+import 'dart:js_interop';
+import 'dart:js_interop_unsafe';
+
import 'package:expect/async_helper.dart';
import 'package:expect/legacy/minitest.dart'; // ignore: deprecated_member_use_from_same_package
-import 'package:js/js.dart';
-import 'package:js/js_util.dart' as js_util;
+import 'package:js/js.dart' as pkgJs;
import 'dart:_debugger' as _debugger;
@@ -47,78 +48,103 @@
X x;
}
-@JS('Object.getOwnPropertyNames')
-external List getOwnPropertyNames(obj);
-
-@JS('devtoolsFormatters')
-external List get _devtoolsFormatters;
-List get devtoolsFormatters => _devtoolsFormatters;
-
-@JS('JSON.stringify')
-external stringify(value, [Function replacer, int space]);
-
-// TODO(jacobr): this is only valid if the DDC library loader is used.
-// We need a solution that works with all library loaders.
-@JS('dart_library.import')
-external importDartLibrary(String path);
-
-@JS('ExampleJSClass')
-class ExampleJSClass<T> {
- external factory ExampleJSClass(T x);
- external T get x;
-}
-
-// Replacer normalizes file names that could vary depending on the test runner.
-// styles.
-replacer(String key, value) {
- // The values for keys with name 'object' may be arbitrary Dart nested
- // Objects so are not safe to stringify.
- if (key == 'object') return '<OBJECT>';
- if (value is String) {
- if (value.contains('dart_sdk.js')) return '<DART_SDK>';
- if (new RegExp(r'[.](js|dart|html)').hasMatch(value)) return '<FILE>';
- // Normalize the name of the `Event` type as it appears in this test.
- // The new type system preserves the original name from the Dart source.
- // TODO(48585): Remove when no longer running with the old type system.
- value = value.replaceAll(r'Event$', 'Event');
- }
- return value;
-}
-
-String? format(value) {
- // Avoid double-escaping strings.
- if (value is String) return value;
- if (value is Function) value = allowInterop(value);
- return stringify(value, allowInterop(replacer), 4);
-}
-
class FormattedObject {
FormattedObject(this.object, this.config);
- Object? object;
- Object? config;
+ JSAny? object;
+ JSAny? config;
+}
+
+@JS('JSON.stringify')
+external String? stringify(JSAny? value, [JSFunction replacer, int space]);
+
+@JS('Object.getOwnPropertyNames')
+external JSArray<JSString> getOwnPropertyNames(JSObject obj);
+
+@JS()
+external JSArray? get devtoolsFormatters;
+
+@JS('Object.getPrototypeOf')
+external Prototype getPrototypeOf(JSAny obj);
+
+extension type FormattedJSObject._(JSObject _) implements JSObject {
+ external JSAny? get object;
+ external JSAny? get config;
+}
+
+// We use `JSAny` here since we're using this to interop with the prototype of a
+// Dart class, which isn't a `JSObject`.
+extension type Prototype._(JSAny _) implements JSAny {
+ external JSAny get constructor;
+}
+
+extension type FooBar._(JSObject _) implements JSObject {
+ external FooBar({String foo});
+}
+
+@pkgJs.JS()
+class PackageJSClass<T> {
+ external factory PackageJSClass(T x);
+}
+
+T unsafeCast<T extends JSAny?>(Object? object) {
+ // This is improper interop code. However, this test mixes Dart and JS values.
+ // Since this is only ever run on DDC, this is okay, but we should be
+ // deliberate about where we're mixing Dart and JS values.
+ return object as T;
+}
+
+// Replacer normalizes file names that could vary depending on the test runner
+// styles.
+JSAny? replacer(String key, JSAny? externalValue) {
+ // The values for keys with name 'object' may be arbitrary Dart nested
+ // Objects so are not safe to stringify.
+ if (key == 'object') return '<OBJECT>'.toJS;
+ if (externalValue.isA<JSString>()) {
+ final value = (externalValue as JSString).toDart;
+ if (value.contains('dart_sdk.js')) return '<DART_SDK>'.toJS;
+ if (new RegExp(r'[.](js|dart|html)').hasMatch(value)) {
+ return '<FILE>'.toJS;
+ }
+ // Normalize the name of the `Event` type as it appears in this test.
+ // The new type system preserves the original name from the Dart source.
+ // TODO(48585): Remove when no longer running with the old type system.
+ return value.replaceAll(r'Event$', 'Event').toJS;
+ }
+ return externalValue;
+}
+
+String? format(JSAny? value) {
+ // Avoid double-escaping strings.
+ if (value.isA<JSString>()) return (value as JSString).toDart;
+ return stringify(value, replacer.toJS, 4);
}
/// Extract all object tags from a json ml expression to enable
/// calling the custom formatter on the extracted object tag.
-List<FormattedObject> extractNestedFormattedObjects(json) {
+List<FormattedObject> extractNestedFormattedObjects(JSAny json) {
var ret = <FormattedObject>[];
- if (json is String || json is bool || json is num) return ret;
- if (json is List) {
- for (var e in json) {
- ret.addAll(extractNestedFormattedObjects(e));
+ if (json.isA<JSString>() || json.isA<JSBoolean>() || json.isA<JSNumber>()) {
+ return ret;
+ }
+ if (json.isA<JSArray>()) {
+ for (var i = 0; i < (json as JSArray<JSAny>).length; i++) {
+ ret.addAll(extractNestedFormattedObjects(json[i]));
}
return ret;
}
- for (var name in getOwnPropertyNames(json)) {
+ // Must be a JS object. See JsonMLElement in dart:_debugger.
+ final jsObject = json as FormattedJSObject;
+ final propertyNames = getOwnPropertyNames(jsObject);
+ for (var i = 0; i < propertyNames.length; i++) {
+ final name = propertyNames[i].toDart;
if (name == 'object') {
// Found a nested formatted object.
- ret.add(new FormattedObject(js_util.getProperty(json, 'object'),
- js_util.getProperty(json, 'config')));
+ ret.add(new FormattedObject(jsObject.object, jsObject.config));
return ret;
}
- ret.addAll(extractNestedFormattedObjects(js_util.getProperty(json, name)));
+ ret.addAll(extractNestedFormattedObjects(jsObject[name]!));
}
return ret;
}
@@ -146,12 +172,14 @@
document.body!.append(new ScriptElement()
..type = 'text/javascript'
..innerHtml = r"""
-window.ExampleJSClass = function ExampleJSClass(x) {
+window.PackageJSClass = function PackageJSClass(x) {
this.x = x;
};
""");
- var _devtoolsFormatter = devtoolsFormatters.first;
+ var _devtoolsFormatter = (devtoolsFormatters![0]
+ as ExternalDartReference<_debugger.JsonMLFormatter>)
+ .toDartObject;
var actual = new StringBuffer();
@@ -162,7 +190,7 @@
// of expectations.
// The verify golden match test cases does the final comparison of golden
// to expected output.
- addGolden(String name, value) {
+ void addGolden(String name, JSAny value) {
var text = format(value);
actual.write('Test: $name\n'
'Value:\n'
@@ -170,14 +198,14 @@
'-----------------------------------\n');
}
- addFormatterGoldens(String name, object, [config]) {
+ void addFormatterGoldens(String name, Object? object, [Object? config]) {
addGolden(
'$name formatting header', _devtoolsFormatter.header(object, config));
addGolden('$name formatting body', _devtoolsFormatter.body(object, config));
}
// Include goldens for the nested [[class]] definition field.
- addNestedFormatterGoldens(String name, obj) {
+ void addNestedFormatterGoldens(String name, Object obj) {
addGolden('$name instance header', _devtoolsFormatter.header(obj, null));
var body = _devtoolsFormatter.body(obj, null);
addGolden('$name instance body', body);
@@ -190,9 +218,11 @@
}
// Include goldens for the nested [[class]] definition field.
- addAllNestedFormatterGoldens(String name, obj) {
+ void addAllNestedFormatterGoldens(String name, Object obj) {
addGolden('$name header', _devtoolsFormatter.header(obj, null));
- var body = _devtoolsFormatter.body(obj, null);
+ // The cast to `JSAny` is safe as `header` and `body` should always return
+ // JS values.
+ var body = _devtoolsFormatter.body(obj, null) as JSAny;
addGolden('$name body', body);
var nestedObjects = extractNestedFormattedObjects(body);
@@ -256,14 +286,13 @@
addFormatterGoldens('Function with function arguments', addEventListener);
// Closure
- addGolden('dart:html method', window.addEventListener);
+ addGolden('dart:html method', unsafeCast(window.addEventListener));
// Get a reference to the JS constructor for a Dart class.
// This tracks a regression bug where overly verbose and confusing output
// was shown for this case.
var testClass = new TestClass(17);
- var dartConstructor = js_util.getProperty(
- js_util.objectGetPrototypeOf(testClass)!, 'constructor');
+ var dartConstructor = getPrototypeOf(unsafeCast(testClass)).constructor;
addFormatterGoldens('Raw reference to dart constructor', dartConstructor);
});
@@ -281,8 +310,7 @@
});
group('JS interop object formatting', () {
- var object = js_util.newObject();
- js_util.setProperty(object, 'foo', 'bar');
+ var object = FooBar(foo: 'bar');
// Make sure we don't apply the Dart custom formatter to JS interop objects.
expect(_devtoolsFormatter.header(object, null), isNull);
});
@@ -322,8 +350,8 @@
'TestGenericClass', new TestGenericClass<int, List>(42));
addNestedFormatterGoldens(
'TestGenericClassJSInterop',
- new TestGenericClass<ExampleJSClass<String>, int>(
- new ExampleJSClass("Hello")));
+ new TestGenericClass<PackageJSClass<JSString>, int>(
+ new PackageJSClass("Hello".toJS)));
});
test('verify golden match', () {
diff --git a/tests/dartdevc/debugger/debugger_test_golden.txt b/tests/dartdevc/debugger/debugger_test_golden.txt
index 59970a2..1e46818 100644
--- a/tests/dartdevc/debugger/debugger_test_golden.txt
+++ b/tests/dartdevc/debugger/debugger_test_golden.txt
@@ -5253,7 +5253,7 @@
{
"style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
},
- "ExampleJSClass: "
+ "FormattedObject: "
],
[
"span",
@@ -5279,7 +5279,189 @@
{
"style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
},
- "FormattedObject: "
+ "PackageJSClass: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "FormattedJSObject|constructor#_: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "FormattedJSObject|constructor#_#_#tearOff: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "Prototype|constructor#_: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "Prototype|constructor#_#_#tearOff: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "FooBar|constructor#_: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "FooBar|constructor#_#_#tearOff: "
+ ],
+ [
+ "span",
+ {
+ "style": "margin-left: 13px"
+ },
+ [
+ "object",
+ {
+ "object": "<OBJECT>",
+ "config": {}
+ }
+ ]
+ ]
+ ],
+ [
+ "li",
+ {
+ "style": "padding-left: 13px;"
+ },
+ [
+ "span",
+ {
+ "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
+ },
+ "unsafeCast: "
],
[
"span",
@@ -5398,32 +5580,6 @@
}
]
]
- ],
- [
- "li",
- {
- "style": "padding-left: 13px;"
- },
- [
- "span",
- {
- "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
- },
- "devtoolsFormatters: "
- ],
- [
- "span",
- {
- "style": "margin-left: 13px"
- },
- [
- "object",
- {
- "object": "<OBJECT>",
- "config": {}
- }
- ]
- ]
]
]
-----------------------------------
@@ -7203,7 +7359,7 @@
{
"style": "background-color: #d9edf7;color: black"
},
- "Instance of 'TestGenericClass<ExampleJSClass<String>, int>'"
+ "Instance of 'TestGenericClass<PackageJSClass<String>, int>'"
]
-----------------------------------
Test: TestGenericClassJSInterop instance body
diff --git a/tools/VERSION b/tools/VERSION
index 81ab9fd..de9a871 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 3
MINOR 7
PATCH 0
-PRERELEASE 21
+PRERELEASE 22
PRERELEASE_PATCH 0
diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
index 4e2cd4a..67a6268 100644
--- a/tools/generate_package_config.dart
+++ b/tools/generate_package_config.dart
@@ -9,7 +9,9 @@
import 'dart:io';
// Important! Do not add package: imports to this file.
+//
// Do not add relative deps for libraries that themselves use package deps.
+//
// This tool runs before the .dart_tool/package_config.json file is created, so
// can not itself use package references.
@@ -88,14 +90,6 @@
];
packages.sort((a, b) => a.name.compareTo(b.name));
- // TODO(devoncarew): Temporarily ignore the second package:file and
- // package:file_testing locations.
- packages.removeWhere((p) {
- final path = posix(p.rootUri);
- return path == 'third_party/pkg/file/packages/file' ||
- path == 'third_party/pkg/file/packages/file_testing';
- });
-
// Remove any packages with identical names.
final uniqueNames = packages.map((p) => p.name).toSet();
diff --git a/tools/package_deps/bin/package_deps.dart b/tools/package_deps/bin/package_deps.dart
index a2815be..ba3099c 100644
--- a/tools/package_deps/bin/package_deps.dart
+++ b/tools/package_deps/bin/package_deps.dart
@@ -453,8 +453,6 @@
_findPackages(Directory('pkg'));
_findPackages(Directory(path.join('third_party', 'devtools')));
_findPackages(Directory(path.join('third_party', 'pkg')));
- _findPackages(
- Directory(path.join('third_party', 'pkg', 'file', 'packages')));
if (verbose) {
print('Package versions in the SDK:');
diff --git a/utils/compiler/BUILD.gn b/utils/compiler/BUILD.gn
index f76196a..7a3093b 100644
--- a/utils/compiler/BUILD.gn
+++ b/utils/compiler/BUILD.gn
@@ -87,22 +87,6 @@
name = "dart2js_aot"
}
-aot_snapshot("dart2js_sdk_aot") {
- deps = [ ":dart2js_create_snapshot_entry" ]
-
- main_dart = "$target_gen_dir/dart2js.dart"
- name = "dart2js_aot.dart"
- output = "$root_gen_dir/dart2js_aot.dart.snapshot"
-
- # dartaotruntime has dart_product_config applied to it,
- # so it is built in # product mode in both release and
- # product builds, and is only built in debug mode in debug
- # builds. The following line ensures that the dartaotruntime
- # and dartdevc_aot snapshot in an SDK build are
- # always compatible with each other.
- force_product_mode = !dart_debug
-}
-
compile_platform("compile_dart2js_platform_unsound") {
single_root_scheme = "org-dartlang-sdk"
single_root_base = rebase_path("$sdk_root/")