Version 2.15.0-258.0.dev
Merge commit 'c46baff9c9a7d10b55d9039f0c75c11ecc41c32a' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 9c19e78..981de4b 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-10-15T13:46:59.969883",
+ "generated": "2021-10-26T10:20:01.277340",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -515,7 +515,7 @@
{
"name": "package_deps",
"rootUri": "../tools/package_deps",
- "languageVersion": "2.8"
+ "languageVersion": "2.12"
},
{
"name": "path",
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index e798ddb..cfb6da5 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -15,6 +15,7 @@
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/fuzzy_filter_sort.dart';
import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
@@ -64,13 +65,13 @@
/// automatically called when a client listens to the stream returned by
/// [results]. Subclasses should override this method, append at least one
/// result to the [controller], and close the controller stream once complete.
- Future<List<CompletionSuggestion>> computeSuggestions(
- OperationPerformanceImpl performance,
- DartCompletionRequest request,
+ Future<List<CompletionSuggestion>> computeSuggestions({
+ required OperationPerformanceImpl performance,
+ required DartCompletionRequest request,
Set<ElementKind>? includedElementKinds,
Set<String>? includedElementNames,
List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags,
- ) async {
+ }) async {
//
// Allow plugins to start computing fixes.
//
@@ -204,6 +205,84 @@
);
}
+ /// Implement the 'completion.getSuggestions2' request.
+ void getSuggestions2(Request request) async {
+ var params = CompletionGetSuggestions2Params.fromRequest(request);
+ var file = params.file;
+ var offset = params.offset;
+
+ var provider = server.resourceProvider;
+ var pathContext = provider.pathContext;
+
+ // TODO(scheglov) Support non-Dart files.
+ if (!file_paths.isDart(pathContext, file)) {
+ server.sendResponse(
+ CompletionGetSuggestions2Result(offset, 0, [], [], false)
+ .toResponse(request.id),
+ );
+ return;
+ }
+
+ var resolvedUnit = await server.getResolvedUnit(file);
+ if (resolvedUnit == null) {
+ server.sendResponse(Response.fileNotAnalyzed(request, file));
+ return;
+ }
+
+ server.requestStatistics?.addItemTimeNow(request, 'resolvedUnit');
+
+ if (offset < 0 || offset > resolvedUnit.content.length) {
+ server.sendResponse(Response.invalidParameter(
+ request,
+ 'params.offset',
+ 'Expected offset between 0 and source length inclusive,'
+ ' but found $offset'));
+ return;
+ }
+
+ final completionPerformance = CompletionPerformance();
+ recordRequest(completionPerformance, file, resolvedUnit.content, offset);
+
+ await completionPerformance.runRequestOperation((performance) async {
+ var completionRequest = DartCompletionRequest.from(
+ resolvedUnit: resolvedUnit,
+ offset: offset,
+ dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(
+ resolvedUnit,
+ ),
+ documentationCache: server.getDocumentationCacheFor(resolvedUnit),
+ );
+
+ var suggestions = await computeSuggestions(
+ performance: performance,
+ request: completionRequest,
+ );
+
+ performance.run('filter', (performance) {
+ performance.getDataInt('count').add(suggestions.length);
+ suggestions = fuzzyFilterSort(
+ pattern: completionRequest.targetPrefix,
+ suggestions: suggestions,
+ );
+ performance.getDataInt('matchCount').add(suggestions.length);
+ });
+
+ var lengthRestricted = suggestions.take(params.maxResults).toList();
+ var isIncomplete = lengthRestricted.length < suggestions.length;
+ completionPerformance.suggestionCount = lengthRestricted.length;
+
+ server.sendResponse(
+ CompletionGetSuggestions2Result(
+ completionRequest.replacementOffset,
+ completionRequest.replacementLength,
+ lengthRestricted,
+ [], // TODO(scheglov)
+ isIncomplete,
+ ).toResponse(request.id),
+ );
+ });
+ }
+
@override
Response? handleRequest(Request request) {
if (!server.options.featureSet.completion) {
@@ -223,6 +302,9 @@
} else if (requestName == COMPLETION_REQUEST_GET_SUGGESTIONS) {
processRequest(request);
return Response.DELAYED_RESPONSE;
+ } else if (requestName == COMPLETION_REQUEST_GET_SUGGESTIONS2) {
+ getSuggestions2(request);
+ return Response.DELAYED_RESPONSE;
} else if (requestName == COMPLETION_REQUEST_SET_SUBSCRIPTIONS) {
return setSubscriptions(request);
}
@@ -341,11 +423,11 @@
// Compute suggestions in the background
try {
var suggestions = await computeSuggestions(
- perf,
- completionRequest,
- includedElementKinds,
- includedElementNames,
- includedSuggestionRelevanceTags,
+ performance: perf,
+ request: completionRequest,
+ includedElementKinds: includedElementKinds,
+ includedElementNames: includedElementNames,
+ includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
);
String? libraryFile;
var includedSuggestionSets = <IncludedSuggestionSet>[];
diff --git a/pkg/analysis_server/lib/src/lsp/source_edits.dart b/pkg/analysis_server/lib/src/lsp/source_edits.dart
index e8b0baf..2a5834e 100644
--- a/pkg/analysis_server/lib/src/lsp/source_edits.dart
+++ b/pkg/analysis_server/lib/src/lsp/source_edits.dart
@@ -167,7 +167,48 @@
int formattedStart,
int formattedEnd,
) {
+ final unformattedWhitespace =
+ unformatted.substring(unformattedStart, unformattedEnd);
+ final formattedWhitespace =
+ formatted.substring(formattedStart, formattedEnd);
+
if (rangeStart != null && rangeEnd != null) {
+ // If this change crosses over the start of the requested range, discarding
+ // the change may result in leading whitespace of the next line not being
+ // formatted correctly.
+ //
+ // To handle this, if both unformatted/formatted contain at least one
+ // newline, split this change into two around the last newline so that the
+ // final part (likely leading whitespace) can be included without
+ // including the whole change.
+ //
+ // Without this, functionality like VS Code's "format modified lines"
+ // (which uses Git status to know which lines are edited) may appear to
+ // fail to format the first newly added line in a range.
+ if (unformattedStart < rangeStart.result &&
+ unformattedEnd > rangeStart.result &&
+ unformattedWhitespace.contains('\n') &&
+ formattedWhitespace.contains('\n')) {
+ // Find the offsets of the character after the last newlines.
+ final unformattedOffset = unformattedWhitespace.lastIndexOf('\n') + 1;
+ final formattedOffset = formattedWhitespace.lastIndexOf('\n') + 1;
+ // Call us again for the leading part
+ addEditFor(
+ unformattedStart,
+ unformattedStart + unformattedOffset,
+ formattedStart,
+ formattedStart + formattedOffset,
+ );
+ // Call us again for the trailing part
+ addEditFor(
+ unformattedStart + unformattedOffset,
+ unformattedEnd,
+ formattedStart + formattedOffset,
+ formattedEnd,
+ );
+ return;
+ }
+
// If we're formatting only a range, skip over any segments that don't fall
// entirely within that range.
if (unformattedStart < rangeStart.result ||
@@ -176,11 +217,6 @@
}
}
- final unformattedWhitespace =
- unformatted.substring(unformattedStart, unformattedEnd);
- final formattedWhitespace =
- formatted.substring(formattedStart, formattedEnd);
-
if (unformattedWhitespace == formattedWhitespace) {
return;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
index ef03f62..c66c747 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
@@ -16,6 +16,12 @@
AssistKind get assistKind => DartAssistKind.CONVERT_INTO_EXPRESSION_BODY;
@override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
FixKind get fixKind => DartFixKind.CONVERT_INTO_EXPRESSION_BODY;
@override
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_deprecated_new_in_comment_reference.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_deprecated_new_in_comment_reference.dart
new file mode 100644
index 0000000..9c902e7
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_deprecated_new_in_comment_reference.dart
@@ -0,0 +1,63 @@
+// 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:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class RemoveDeprecatedNewInCommentReference extends CorrectionProducer {
+ @override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
+ FixKind get fixKind => DartFixKind.REMOVE_DEPRECATED_NEW_IN_COMMENT_REFERENCE;
+
+ @override
+ FixKind get multiFixKind =>
+ DartFixKind.REMOVE_DEPRECATED_NEW_IN_COMMENT_REFERENCE_MULTI;
+
+ @override
+ Future<void> compute(ChangeBuilder builder) async {
+ final comment = node;
+ if (comment is! CommentReference) {
+ return;
+ }
+
+ final newToken = comment.newKeyword;
+ if (newToken == null) {
+ return;
+ }
+
+ await builder.addDartFileEdit(file, (builder) {
+ builder.addDeletion(range.startStart(newToken, newToken.next!));
+ });
+
+ final identifier = comment.identifier;
+ final classElement = identifier.staticElement;
+ if (identifier is SimpleIdentifier && classElement is ConstructorElement) {
+ await builder.addDartFileEdit(file, (builder) {
+ builder.addSimpleInsertion(identifier.end, '.new');
+ });
+ } else {
+ if (classElement is ClassElement) {
+ if (classElement.unnamedConstructor != null) {
+ await builder.addDartFileEdit(file, (builder) {
+ builder.addSimpleInsertion(identifier.end, '.new');
+ });
+ }
+ }
+ }
+ }
+
+ /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+ static RemoveDeprecatedNewInCommentReference newInstance() =>
+ RemoveDeprecatedNewInCommentReference();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/replace_new_with_const.dart b/pkg/analysis_server/lib/src/services/correction/dart/replace_new_with_const.dart
index 2828c1c..5e4b9b6 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/replace_new_with_const.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/replace_new_with_const.dart
@@ -11,13 +11,10 @@
class ReplaceNewWithConst extends CorrectionProducer {
@override
- // TODO(brianwilkerson) This fix can produce changes that are inconsistent
- // with the `unnecessary_const` lint. Fix it and then enable it for both
- // uses.
- bool get canBeAppliedInBulk => false;
+ bool get canBeAppliedInBulk => true;
@override
- bool get canBeAppliedToFile => false;
+ bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.REPLACE_NEW_WITH_CONST;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_interpolation.dart b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_interpolation.dart
index 48ddf53..71adedb 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_interpolation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_interpolation.dart
@@ -13,9 +13,18 @@
class ReplaceWithInterpolation extends CorrectionProducer {
@override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
FixKind get fixKind => DartFixKind.REPLACE_WITH_INTERPOLATION;
@override
+ FixKind? get multiFixKind => DartFixKind.REPLACE_WITH_INTERPOLATION_MULTI;
+
+ @override
Future<void> compute(ChangeBuilder builder) async {
//
// Validate the fix.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e344b12..84a648c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -825,6 +825,16 @@
DartFixKindPriority.DEFAULT,
'Remove dead code',
);
+ static const REMOVE_DEPRECATED_NEW_IN_COMMENT_REFERENCE = FixKind(
+ 'dart.fix.remove.deprecatedNewInCommentReference',
+ DartFixKindPriority.DEFAULT,
+ 'Remove deprecated new keyword',
+ );
+ static const REMOVE_DEPRECATED_NEW_IN_COMMENT_REFERENCE_MULTI = FixKind(
+ 'dart.fix.remove.deprecatedNewInCommentReference.multi',
+ DartFixKindPriority.IN_FILE,
+ 'Remove deprecated new keyword in file',
+ );
static const REMOVE_DUPLICATE_CASE = FixKind(
'dart.fix.remove.duplicateCase',
DartFixKindPriority.DEFAULT,
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 04f4725..67f769b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -105,6 +105,7 @@
import 'package:analysis_server/src/services/correction/dart/remove_constructor_name.dart';
import 'package:analysis_server/src/services/correction/dart/remove_dead_code.dart';
import 'package:analysis_server/src/services/correction/dart/remove_dead_if_null.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_deprecated_new_in_comment_reference.dart';
import 'package:analysis_server/src/services/correction/dart/remove_duplicate_case.dart';
import 'package:analysis_server/src/services/correction/dart/remove_empty_catch.dart';
import 'package:analysis_server/src/services/correction/dart/remove_empty_constructor_body.dart';
@@ -474,7 +475,6 @@
ReplaceColonWithEquals.newInstance,
],
LintNames.prefer_expression_function_bodies: [
- // TODO(brianwilkerson) Consider applying in bulk.
ConvertToExpressionFunctionBody.newInstance,
],
LintNames.prefer_final_fields: [
@@ -518,7 +518,6 @@
ConvertToIntLiteral.newInstance,
],
LintNames.prefer_interpolation_to_compose_strings: [
- // TODO(brianwilkerson) Consider applying in bulk.
ReplaceWithInterpolation.newInstance,
],
LintNames.prefer_is_not_operator: [
@@ -1097,6 +1096,9 @@
// a place where it can be reached (when possible).
RemoveDeadCode.newInstance,
],
+ HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE: [
+ RemoveDeprecatedNewInCommentReference.newInstance,
+ ],
HintCode.DIVISION_OPTIMIZATION: [
UseEffectiveIntegerDivision.newInstance,
],
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index d9c733a..b0adedf 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -2,12 +2,19 @@
// 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:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/domain_completion.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/instrumentation/service.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
-import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -18,11 +25,496 @@
void main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(CompletionDomainHandlerGetSuggestions2Test);
defineReflectiveTests(CompletionDomainHandlerGetSuggestionsTest);
});
}
@reflectiveTest
+class CompletionDomainHandlerGetSuggestions2Test with ResourceProviderMixin {
+ late final MockServerChannel serverChannel;
+ late final AnalysisServer server;
+
+ AnalysisDomainHandler get analysisDomain {
+ return server.handlers.whereType<AnalysisDomainHandler>().single;
+ }
+
+ CompletionDomainHandler get completionDomain {
+ return server.handlers.whereType<CompletionDomainHandler>().single;
+ }
+
+ String get testFilePath => '$testPackageLibPath/test.dart';
+
+ String get testPackageLibPath => '$testPackageRootPath/lib';
+
+ String get testPackageRootPath => '$workspaceRootPath/test';
+
+ String get workspaceRootPath => '/home';
+
+ Future<void> setRoots({
+ required List<String> included,
+ required List<String> excluded,
+ }) async {
+ var includedConverted = included.map(convertPath).toList();
+ var excludedConverted = excluded.map(convertPath).toList();
+ await _handleSuccessfulRequest(
+ AnalysisSetAnalysisRootsParams(
+ includedConverted,
+ excludedConverted,
+ packageRoots: {},
+ ).toRequest('0'),
+ );
+ }
+
+ void setUp() {
+ serverChannel = MockServerChannel();
+
+ var sdkRoot = newFolder('/sdk');
+ createMockSdk(
+ resourceProvider: resourceProvider,
+ root: sdkRoot,
+ );
+
+ server = AnalysisServer(
+ serverChannel,
+ resourceProvider,
+ AnalysisServerOptions(),
+ DartSdkManager(sdkRoot.path),
+ CrashReportingAttachmentsBuilder.empty,
+ InstrumentationService.NULL_SERVICE,
+ );
+ }
+
+ Future<void> test_numResults_class_methods() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+class A {
+ void foo01() {}
+ void foo02() {}
+ void foo03() {}
+}
+
+void f(A a) {
+ a.foo0^
+}
+''', maxResults: 2);
+
+ responseValidator
+ ..assertIncomplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+ }
+
+ Future<void> test_numResults_topLevelVariables() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+var foo01 = 0;
+var foo02 = 0;
+var foo03 = 0;
+
+void f() {
+ foo0^
+}
+''', maxResults: 2);
+
+ responseValidator
+ ..assertIncomplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+ suggestionsValidator
+ .withCompletion('foo01')
+ .assertSingle()
+ .assertTopLevelVariable();
+ suggestionsValidator
+ .withCompletion('foo02')
+ .assertSingle()
+ .assertTopLevelVariable();
+ }
+
+ Future<void> test_numResults_topLevelVariables_imported_withPrefix() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+var foo01 = 0;
+var foo02 = 0;
+var foo03 = 0;
+''');
+
+ var responseValidator = await _getTestCodeSuggestions('''
+import 'a.dart' as prefix;
+
+void f() {
+ prefix.^
+}
+''', maxResults: 2);
+
+ responseValidator
+ ..assertIncomplete()
+ ..assertEmptyReplacement();
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+ }
+
+ Future<void> test_prefixed_class_constructors() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+class A {
+ A.foo01();
+ A.foo02();
+}
+
+void f() {
+ A.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestions = responseValidator.suggestions;
+ suggestions.assertCompletions(['foo01', 'foo02']);
+ suggestions.withCompletion('foo01').assertSingle().assertConstructor();
+ suggestions.withCompletion('foo02').assertSingle().assertConstructor();
+ }
+
+ Future<void> test_prefixed_class_getters() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+class A {
+ int get foo01 => 0;
+ int get foo02 => 0;
+}
+
+void f(A a) {
+ a.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestions = responseValidator.suggestions;
+ suggestions.assertCompletions(['foo01', 'foo02']);
+ suggestions.withCompletion('foo01').assertSingle().assertGetter();
+ suggestions.withCompletion('foo02').assertSingle().assertGetter();
+ }
+
+ Future<void> test_prefixed_class_methods_instance() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+class A {
+ void foo01() {}
+ void foo02() {}
+}
+
+void f(A a) {
+ a.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestions = responseValidator.suggestions;
+ suggestions.assertCompletions(['foo01', 'foo02']);
+ suggestions.withCompletion('foo01').assertSingle().assertMethod();
+ suggestions.withCompletion('foo02').assertSingle().assertMethod();
+ }
+
+ Future<void> test_prefixed_class_methods_static() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+class A {
+ static void foo01() {}
+ static void foo02() {}
+}
+
+void f() {
+ A.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestions = responseValidator.suggestions;
+ suggestions.assertCompletions(['foo01', 'foo02']);
+ suggestions.withCompletion('foo01').assertSingle().assertMethod();
+ suggestions.withCompletion('foo02').assertSingle().assertMethod();
+ }
+
+ Future<void> test_prefixed_extensionGetters() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+extension E1 on int {
+ int get foo01 => 0;
+ int get foo02 => 0;
+ int get bar => 0;
+}
+
+extension E2 on double {
+ int get foo03 => 0;
+}
+
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertGetter();
+ suggestionsValidator.withCompletion('foo02').assertSingle().assertGetter();
+ }
+
+ /// TODO(scheglov) Also not imported, with type checks.
+ Future<void> test_prefixed_extensionGetters_imported() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ int get foo01 => 0;
+ int get foo02 => 0;
+ int get bar => 0;
+}
+
+extension E2 on double {
+ int get foo03 => 0;
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+import 'a.dart';
+
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertGetter();
+ suggestionsValidator.withCompletion('foo02').assertSingle().assertGetter();
+ }
+
+ Future<void> test_unprefixed_filters() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+var foo01 = 0;
+var foo02 = 0;
+var bar01 = 0;
+var bar02 = 0;
+
+void f() {
+ foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator
+ .withCompletion('foo01')
+ .assertSingle()
+ .assertTopLevelVariable();
+ suggestionsValidator
+ .withCompletion('foo02')
+ .assertSingle()
+ .assertTopLevelVariable();
+ suggestionsValidator.withCompletion('bar01').assertEmpty();
+ suggestionsValidator.withCompletion('bar02').assertEmpty();
+ }
+
+ Future<void> test_unprefixed_imported_class() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+''');
+
+ newFile('$testPackageLibPath/b.dart', content: '''
+class A02 {}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions('''
+import 'a.dart';
+import 'b.dart';
+
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02']);
+ classes.withCompletion('A01').assertSingle().assertClass();
+ classes.withCompletion('A02').assertSingle().assertClass();
+ }
+
+ Future<void> test_unprefixed_imported_topLevelVariable() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+var foo01 = 0;
+''');
+
+ newFile('$testPackageLibPath/b.dart', content: '''
+var foo02 = 0;
+''');
+
+ var responseValidator = await _getTestCodeSuggestions('''
+import 'a.dart';
+import 'b.dart';
+
+void f() {
+ foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+ suggestionsValidator
+ .withCompletion('foo01')
+ .assertSingle()
+ .assertTopLevelVariable();
+ suggestionsValidator
+ .withCompletion('foo02')
+ .assertSingle()
+ .assertTopLevelVariable();
+ }
+
+ Future<void> test_unprefixed_sorts_byScore() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+var fooAB = 0;
+var fooBB = 0;
+
+void f() {
+ fooB^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ // `fooBB` has better score than `fooAB` - prefix match
+ suggestionsValidator.assertCompletions(['fooBB', 'fooAB']);
+ }
+
+ Future<void> test_unprefixed_sorts_byType() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+var foo01 = 0.0;
+var foo02 = 0;
+
+void f() {
+ int v = foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ // `foo02` has better relevance, its type matches the context type
+ suggestionsValidator.assertCompletions(['foo02', 'foo01']);
+ }
+
+ Future<void> _configureWithWorkspaceRoot() async {
+ await setRoots(included: [workspaceRootPath], excluded: []);
+ await server.onAnalysisComplete;
+ }
+
+ Future<CompletionGetSuggestions2ResponseValidator> _getSuggestions({
+ required String path,
+ required int completionOffset,
+ required int maxResults,
+ }) async {
+ var request = CompletionGetSuggestions2Params(
+ path,
+ completionOffset,
+ maxResults,
+ ).toRequest('0');
+
+ var response = await _handleSuccessfulRequest(request);
+ var result = CompletionGetSuggestions2Result.fromResponse(response);
+ return CompletionGetSuggestions2ResponseValidator(completionOffset, result);
+ }
+
+ Future<CompletionGetSuggestions2ResponseValidator> _getTestCodeSuggestions(
+ String content, {
+ int maxResults = 1 << 10,
+ }) async {
+ var completionOffset = content.indexOf('^');
+ expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+
+ var nextOffset = content.indexOf('^', completionOffset + 1);
+ expect(nextOffset, equals(-1), reason: 'too many ^');
+
+ var testFile = newFile(testFilePath,
+ content: content.substring(0, completionOffset) +
+ content.substring(completionOffset + 1));
+
+ return await _getSuggestions(
+ path: testFile.path,
+ completionOffset: completionOffset,
+ maxResults: maxResults,
+ );
+ }
+
+ /// Validates that the given [request] is handled successfully.
+ Future<Response> _handleSuccessfulRequest(Request request) async {
+ var response = await serverChannel.sendRequest(request);
+ expect(response, isResponseSuccess(request.id));
+ return response;
+ }
+}
+
+@reflectiveTest
class CompletionDomainHandlerGetSuggestionsTest
extends AbstractCompletionDomainTest {
Future<void> test_ArgumentList_constructor_named_fieldFormalParam() async {
@@ -910,3 +1402,123 @@
});
}
}
+
+class CompletionGetSuggestions2ResponseValidator {
+ final int completionOffset;
+ final CompletionGetSuggestions2Result result;
+
+ CompletionGetSuggestions2ResponseValidator(
+ this.completionOffset,
+ this.result,
+ );
+
+ SuggestionsValidator get suggestions {
+ return SuggestionsValidator(result.suggestions);
+ }
+
+ void assertComplete() {
+ expect(result.isIncomplete, isFalse);
+ }
+
+ void assertEmptyReplacement() {
+ assertReplacement(completionOffset, 0);
+ }
+
+ void assertIncomplete() {
+ expect(result.isIncomplete, isTrue);
+ }
+
+ void assertReplacement(int offset, int length) {
+ expect(result.replacementOffset, offset);
+ expect(result.replacementLength, length);
+ }
+
+ void assertReplacementBack(int length) {
+ assertReplacement(completionOffset - length, length);
+ }
+}
+
+class SingleSuggestionValidator {
+ final CompletionSuggestion suggestion;
+
+ SingleSuggestionValidator(this.suggestion);
+
+ void assertClass() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.CLASS);
+ }
+
+ void assertConstructor() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.CONSTRUCTOR);
+ }
+
+ void assertGetter() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.GETTER);
+ }
+
+ void assertMethod() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.METHOD);
+ }
+
+ void assertTopLevelVariable() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ }
+}
+
+class SuggestionsValidator {
+ final List<CompletionSuggestion> suggestions;
+
+ SuggestionsValidator(this.suggestions);
+
+ int get length => suggestions.length;
+
+ /// Assert that this has suggestions with exactly the given completions,
+ /// with the exact order.
+ ///
+ /// Does not check suggestion kinds, elements, etc.
+ void assertCompletions(Iterable<String> completions) {
+ var actual = suggestions.map((e) => e.completion).toList();
+ expect(actual, completions);
+ }
+
+ void assertEmpty() {
+ expect(suggestions, isEmpty);
+ }
+
+ void assertLength(Object matcher) {
+ expect(suggestions, hasLength(matcher));
+ }
+
+ SingleSuggestionValidator assertSingle() {
+ assertLength(1);
+ return SingleSuggestionValidator(suggestions.single);
+ }
+
+ SuggestionsValidator withCompletion(String completion) {
+ return SuggestionsValidator(
+ suggestions.where((suggestion) {
+ return suggestion.completion == completion;
+ }).toList(),
+ );
+ }
+
+ SuggestionsValidator withElementClass() {
+ return withElementKind(ElementKind.CLASS);
+ }
+
+ SuggestionsValidator withElementConstructor() {
+ return withElementKind(ElementKind.CONSTRUCTOR);
+ }
+
+ SuggestionsValidator withElementKind(ElementKind kind) {
+ return SuggestionsValidator(
+ suggestions.where((suggestion) {
+ return suggestion.element?.kind == kind;
+ }).toList(),
+ );
+ }
+}
diff --git a/pkg/analysis_server/test/lsp/format_test.dart b/pkg/analysis_server/test/lsp/format_test.dart
index 5ba380f..61bac2e 100644
--- a/pkg/analysis_server/test/lsp/format_test.dart
+++ b/pkg/analysis_server/test/lsp/format_test.dart
@@ -210,6 +210,30 @@
await expectRangeFormattedContents(mainFileUri, contents, expected);
}
+ Future<void> test_formatRange_expandsLeadingWhitespaceToNearestLine() async {
+ const contents = '''
+void main()
+{
+
+[[ print('test'); // line 2
+ print('test'); // line 3
+ print('test'); // line 4]]
+}
+''';
+ const expected = '''
+void main()
+{
+
+ print('test'); // line 2
+ print('test'); // line 3
+ print('test'); // line 4
+}
+''';
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(contents));
+ await expectRangeFormattedContents(mainFileUri, contents, expected);
+ }
+
Future<void> test_formatRange_invalidRange() async {
const contents = '''
void f()
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index c688ac2..79d6fe7 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -91,7 +91,8 @@
Future<void> test_createChange_add() async {
await indexTestUnit('''
-/// Documentation for [new A]
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A] and [A.new]
class A {
A() {} // marker
factory A._() = A;
@@ -112,7 +113,8 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
-/// Documentation for [new A.newName]
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A.newName] and [A.newName]
class A {
A.newName() {} // marker
factory A._() = A.newName;
@@ -129,7 +131,8 @@
Future<void> test_createChange_add_toSynthetic() async {
await indexTestUnit('''
-/// Documentation for [new A]
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A] and [A.new]
class A {
int field = 0;
}
@@ -149,7 +152,8 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
-/// Documentation for [new A.newName]
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A.newName] and [A.newName]
class A {
int field = 0;
@@ -167,6 +171,7 @@
Future<void> test_createChange_change() async {
await indexTestUnit('''
+// ignore: deprecated_new_in_comment_reference
/// Documentation for [A.test] and [new A.test]
class A {
A.test() {} // marker
@@ -188,6 +193,7 @@
// validate change
refactoring.newName = 'newName';
return assertSuccessfulRefactoring('''
+// ignore: deprecated_new_in_comment_reference
/// Documentation for [A.newName] and [new A.newName]
class A {
A.newName() {} // marker
@@ -234,6 +240,7 @@
Future<void> test_createChange_remove() async {
await indexTestUnit('''
+// ignore: deprecated_new_in_comment_reference
/// Documentation for [A.test] and [new A.test]
class A {
A.test() {} // marker
@@ -255,6 +262,7 @@
// validate change
refactoring.newName = '';
return assertSuccessfulRefactoring('''
+// ignore: deprecated_new_in_comment_reference
/// Documentation for [A] and [new A]
class A {
A() {} // marker
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
index 33d2b33..638ecab 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
@@ -12,10 +12,49 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ConvertIntoExpressionBodyTest);
+ defineReflectiveTests(ConvertIntoExpressionBodyBulkTest);
});
}
@reflectiveTest
+class ConvertIntoExpressionBodyBulkTest extends BulkFixProcessorTest {
+ @override
+ String get lintCode => LintNames.prefer_expression_function_bodies;
+
+ Future<void> test_singleFile() async {
+ // See the discussion in https://dart-review.googlesource.com/c/sdk/+/217521
+ // for the nested closure case (var f = () ...).
+ // Note this is another place where multiple passes will improve results.
+ await resolveTestCode('''
+class A {
+ mmm() async {
+ return 42;
+ }
+ int nnn() {
+ return mmm() + 1;
+ }
+}
+
+var f = () {
+ return () {
+ return 3;
+ };
+};
+''');
+ await assertHasFix('''
+class A {
+ mmm() async => 42;
+ int nnn() => mmm() + 1;
+}
+
+var f = () => () {
+ return 3;
+ };
+''');
+ }
+}
+
+@reflectiveTest
class ConvertIntoExpressionBodyTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.CONVERT_INTO_EXPRESSION_BODY;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
index 83e66a2b..763bc38 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
@@ -19,6 +19,7 @@
'avoid_types_on_closure_parameters',
'empty_statements',
'prefer_collection_literals',
+ 'prefer_const_constructors',
'prefer_inlined_adds',
];
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_deprecated_new_in_comment_reference_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_deprecated_new_in_comment_reference_test.dart
new file mode 100644
index 0000000..58cc478
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_deprecated_new_in_comment_reference_test.dart
@@ -0,0 +1,80 @@
+// 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:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(RemoveDeprecatedNewInCommentReferenceBulkTest);
+ defineReflectiveTests(RemoveDeprecatedNewInCommentReferenceTest);
+ });
+}
+
+@reflectiveTest
+class RemoveDeprecatedNewInCommentReferenceBulkTest
+ extends BulkFixProcessorTest {
+ Future<void> test_named() async {
+ await resolveTestCode('''
+/// See [new A.named].
+class A {
+ A.named();
+}
+''');
+ await assertHasFix('''
+/// See [A.named].
+class A {
+ A.named();
+}
+''');
+ }
+}
+
+@reflectiveTest
+class RemoveDeprecatedNewInCommentReferenceTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.REMOVE_DEPRECATED_NEW_IN_COMMENT_REFERENCE;
+
+ Future<void> test_named() async {
+ await resolveTestCode('''
+/// See [new A.named].
+class A {
+ A.named();
+}
+''');
+ await assertHasFix('''
+/// See [A.named].
+class A {
+ A.named();
+}
+''');
+ }
+
+ Future<void> test_prefixedUnnamed() async {
+ await resolveTestCode('''
+/// See [new self.A].
+import '' as self;
+class A {}
+''');
+ await assertHasFix('''
+/// See [self.A.new].
+import '' as self;
+class A {}
+''');
+ }
+
+ Future<void> test_unnamed() async {
+ await resolveTestCode('''
+/// See [new A].
+class A {}
+''');
+ await assertHasFix('''
+/// See [A.new].
+class A {}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
index 6960bb5..4fca1eb 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
@@ -21,23 +21,75 @@
@override
String get lintCode => LintNames.prefer_const_constructors;
- /// Disabled in BulkFixProcessor.
- @failingTest
Future<void> test_singleFile() async {
await resolveTestCode(r'''
-class C {
- const C();
+class A {
+ const A();
}
main() {
- print('${new C()} ${new C()}');
+ var a = new A();
+ var b = new A();
}
''');
await assertHasFix(r'''
-class C {
- const C();
+class A {
+ const A();
}
main() {
- print('${const C()} ${const C()}');
+ var a = const A();
+ var b = const A();
+}
+''');
+ }
+
+ Future<void> test_singleFile_incomplete_promotableNew() async {
+ await resolveTestCode(r'''
+class A {
+ const A({A? parent});
+ const A.a();
+}
+main() {
+ var a = new A(
+ parent: new A(),
+ );
+}
+''');
+ // The outer new should get promoted to const on a future fix pass.
+ await assertHasFix(r'''
+class A {
+ const A({A? parent});
+ const A.a();
+}
+main() {
+ var a = new A(
+ parent: const A(),
+ );
+}
+''');
+ }
+
+ Future<void> test_singleFile_incomplete_unnecessaryConst() async {
+ await resolveTestCode(r'''
+class A {
+ const A({A? parent});
+ const A.a();
+}
+main() {
+ var b = new A(
+ parent: const A.a(),
+ );
+}
+''');
+ // The inner const is unnecessary and should get removed on a future fix pass.
+ await assertHasFix(r'''
+class A {
+ const A({A? parent});
+ const A.a();
+}
+main() {
+ var b = const A(
+ parent: const A.a(),
+ );
}
''');
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
index 5dc54a1..64726ee 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
@@ -12,10 +12,34 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ReplaceWithInterpolationTest);
+ defineReflectiveTests(ReplaceWithInterpolationBulkTest);
});
}
@reflectiveTest
+class ReplaceWithInterpolationBulkTest extends BulkFixProcessorTest {
+ @override
+ String get lintCode => LintNames.prefer_interpolation_to_compose_strings;
+
+ Future<void> test_singleFile() async {
+ await resolveTestCode(r'''
+String f() {
+ var a = 'a';
+ var c = a + 'b';
+ return c + 'and $s';
+}
+''');
+ await assertHasFix(r'''
+String f() {
+ var a = 'a';
+ var c = '${a}b';
+ return '${c}and $s';
+}
+''');
+ }
+}
+
+@reflectiveTest
class ReplaceWithInterpolationTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.REPLACE_WITH_INTERPOLATION;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index ac07949..3753bfb 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -128,6 +128,8 @@
import 'remove_const_test.dart' as remove_const;
import 'remove_constructor_name_test.dart' as remove_constructor_name;
import 'remove_dead_code_test.dart' as remove_dead_code;
+import 'remove_deprecated_new_in_comment_reference_test.dart'
+ as remove_deprecated_new_in_comment_reference;
import 'remove_duplicate_case_test.dart' as remove_duplicate_case;
import 'remove_empty_catch_test.dart' as remove_empty_catch;
import 'remove_empty_constructor_body_test.dart'
@@ -321,6 +323,7 @@
remove_const.main();
remove_constructor_name.main();
remove_dead_code.main();
+ remove_deprecated_new_in_comment_reference.main();
remove_duplicate_case.main();
remove_empty_catch.main();
remove_empty_constructor_body.main();
diff --git a/pkg/analysis_server/tool/bulk_fix/supported_nonlints.dart b/pkg/analysis_server/tool/bulk_fix/supported_diagnostics.dart
similarity index 80%
rename from pkg/analysis_server/tool/bulk_fix/supported_nonlints.dart
rename to pkg/analysis_server/tool/bulk_fix/supported_diagnostics.dart
index e9dcbbc..2603f84 100644
--- a/pkg/analysis_server/tool/bulk_fix/supported_nonlints.dart
+++ b/pkg/analysis_server/tool/bulk_fix/supported_diagnostics.dart
@@ -7,19 +7,22 @@
import 'parse_utils.dart';
-/// Print hint bulk-fix info.
+/// Print diagnostic bulk-fix info.
Future<void> main() async {
var overrideDetails = await BulkFixDetails().collectOverrides();
- print('hints w/ correction producers:\n');
+ print('diagnostics w/ correction producers:\n');
var hintEntries = FixProcessor.nonLintProducerMap.entries.where((e) =>
e.key.type == ErrorType.HINT || e.key.type == ErrorType.STATIC_WARNING);
- for (var hint in hintEntries) {
+
+ var diagnostics = List.from(hintEntries)
+ ..addAll(FixProcessor.lintProducerMap.entries);
+ for (var diagnostic in diagnostics) {
var canBeAppliedInBulk = false;
var missingExplanations = <String>[];
var hasOverride = false;
- for (var generator in hint.value) {
+ for (var generator in diagnostic.value) {
var producer = generator();
if (!producer.canBeAppliedInBulk) {
var producerName = producer.runtimeType.toString();
@@ -36,7 +39,7 @@
}
}
- print('${hint.key} bulk fixable: $canBeAppliedInBulk');
+ print('${diagnostic.key} bulk fixable: $canBeAppliedInBulk');
if (!canBeAppliedInBulk && !hasOverride) {
print(' => override missing');
}
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 6e1954d..1c98a3a 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -530,6 +530,7 @@
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE,
HintCode.DEPRECATED_MIXIN_FUNCTION,
+ HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE,
HintCode.DIVISION_OPTIMIZATION,
HintCode.DUPLICATE_HIDDEN_NAME,
HintCode.DUPLICATE_IGNORE,
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 9e95612..227abea 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -487,15 +487,7 @@
_assertType(testedType);
var typeType = (testedType._state as TypeState)._type;
BoolState state;
- if (isNull) {
- if (typeType == typeSystem.typeProvider.objectType ||
- typeType == typeSystem.typeProvider.dynamicType ||
- typeType == typeSystem.typeProvider.nullType) {
- state = BoolState.TRUE_STATE;
- } else {
- state = BoolState.FALSE_STATE;
- }
- } else if (typeType == null) {
+ if (typeType == null) {
state = BoolState.TRUE_STATE;
} else {
state = BoolState.from(typeSystem.isSubtypeOf(type, typeType));
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index e0f5728..8dc8f2a 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -439,6 +439,15 @@
);
/**
+ * No parameters.
+ */
+ static const HintCode DEPRECATED_NEW_IN_COMMENT_REFERENCE = HintCode(
+ 'DEPRECATED_NEW_IN_COMMENT_REFERENCE',
+ "Using the 'new' keyword in a comment reference is deprecated.",
+ correctionMessage: "Try referring to a constructor by its name.",
+ );
+
+ /**
* Hint to use the ~/ operator.
*/
static const HintCode DIVISION_OPTIMIZATION = HintCode(
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index cdd12a2..85441dc 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -4,6 +4,7 @@
import 'dart:collection';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/token.dart';
@@ -393,6 +394,17 @@
}
@override
+ void visitCommentReference(CommentReference node) {
+ var newKeyword = node.newKeyword;
+ if (newKeyword != null &&
+ _currentLibrary.featureSet.isEnabled(Feature.constructor_tearoffs)) {
+ _errorReporter.reportErrorForToken(
+ HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, newKeyword, []);
+ }
+ super.visitCommentReference(node);
+ }
+
+ @override
void visitConstructorDeclaration(ConstructorDeclaration node) {
var element = node.declaredElement as ConstructorElementImpl;
if (!_isNonNullableByDefault && node.declaredElement!.isFactory) {
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 24287cf..3637c8d 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -14293,6 +14293,10 @@
Parameters:
0: the name of the member
1: message details
+ DEPRECATED_NEW_IN_COMMENT_REFERENCE:
+ problemMessage: "Using the 'new' keyword in a comment reference is deprecated."
+ correctionMessage: Try referring to a constructor by its name.
+ comment: No parameters.
DEPRECATED_MIXIN_FUNCTION:
sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
problemMessage: "Mixing in 'Function' is deprecated."
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 24b6f96..dddec74 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -557,6 +557,49 @@
_assertTypeArguments(result, null);
}
+ test_visitIsExpression_is_null() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is A;
+class A {}
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), false);
+ }
+
+ test_visitIsExpression_is_null_nullable() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is A?;
+class A {}
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), true);
+ }
+
+ test_visitIsExpression_is_null_object() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is Object;
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), false);
+ }
+
+ test_visitIsExpression_isNot_null() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is! A;
+class A {}
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), true);
+ }
+
test_visitPrefixedIdentifier_genericFunction_instantiated() async {
await resolveTestCode('''
import '' as self;
@@ -1520,17 +1563,6 @@
expect(result.toBoolValue(), false);
}
- test_visitIsExpression_is_null() async {
- await resolveTestCode('''
-const a = null;
-const b = a is A;
-class A {}
-''');
- DartObjectImpl result = _evaluateConstant('b');
- expect(result.type, typeProvider.boolType);
- expect(result.toBoolValue(), false);
- }
-
test_visitIsExpression_is_null_dynamic() async {
await resolveTestCode('''
const a = null;
@@ -1553,17 +1585,6 @@
expect(result.toBoolValue(), true);
}
- test_visitIsExpression_is_null_object() async {
- await resolveTestCode('''
-const a = null;
-const b = a is Object;
-class A {}
-''');
- DartObjectImpl result = _evaluateConstant('b');
- expect(result.type, typeProvider.boolType);
- expect(result.toBoolValue(), true);
- }
-
test_visitIsExpression_isNot_instanceOfSameClass() async {
await resolveTestCode('''
const a = const A();
@@ -1625,17 +1646,6 @@
expect(result.toBoolValue(), true);
}
- test_visitIsExpression_isNot_null() async {
- await resolveTestCode('''
-const a = null;
-const b = a is! A;
-class A {}
-''');
- DartObjectImpl result = _evaluateConstant('b');
- expect(result.type, typeProvider.boolType);
- expect(result.toBoolValue(), true);
- }
-
test_visitPrefixedIdentifier_function() async {
await resolveTestCode('''
import '' as self;
@@ -1892,11 +1902,58 @@
DartObjectImpl result = _evaluateConstant('b');
expect(result.type, typeProvider.nullType);
}
+
+ test_visitIsExpression_is_null() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is A;
+class A {}
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), true);
+ }
+
+ test_visitIsExpression_is_null_object() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is Object;
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), true);
+ }
+
+ test_visitIsExpression_isNot_null() async {
+ await resolveTestCode('''
+const a = null;
+const b = a is! A;
+class A {}
+''');
+ DartObjectImpl result = _evaluateConstant('b');
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), false);
+ }
}
@reflectiveTest
class InstanceCreationEvaluatorTest extends ConstantVisitorTestSupport
with InstanceCreationEvaluatorTestCases {
+ test_assertInitializer_assertIsNot_null_nullableType() async {
+ await resolveTestCode('''
+class A<T> {
+ const A() : assert(null is! T);
+}
+
+const a = const A<int?>();
+''');
+
+ _evaluateConstantOrNull(
+ 'a',
+ errorCodes: [CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION],
+ );
+ }
+
test_fieldInitializer_typeParameter() async {
await resolveTestCode('''
class A<T> {
@@ -2031,6 +2088,31 @@
@reflectiveTest
mixin InstanceCreationEvaluatorTestCases on ConstantVisitorTestSupport {
+ test_assertInitializer_assertIsNot_false() async {
+ await resolveTestCode('''
+class A {
+ const A() : assert(0 is! int);
+}
+
+const a = const A(null);
+''');
+ _evaluateConstantOrNull(
+ 'a',
+ errorCodes: [CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION],
+ );
+ }
+
+ test_assertInitializer_assertIsNot_true() async {
+ await resolveTestCode('''
+class A {
+ const A() : assert(0 is! String);
+}
+
+const a = const A(null);
+''');
+ _assertValidConstant('a');
+ }
+
test_assertInitializer_intInDoubleContext_assertIsDouble_true() async {
await resolveTestCode('''
class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/comment_test.dart b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
index d5d1255..3d386b9 100644
--- a/pkg/analyzer/test/src/dart/resolution/comment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/src/dart/error/hint_codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'context_collection_resolution.dart';
@@ -367,7 +368,7 @@
}
test_new() async {
- await assertNoErrorsInCode(r'''
+ await assertErrorsInCode('''
class A {
A();
A.named();
@@ -375,7 +376,10 @@
/// [new A] or [new A.named]
main() {}
-''');
+''', [
+ error(HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, 38, 3),
+ error(HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, 49, 3),
+ ]);
assertElement(
findNode.simple('A]'),
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 5a67b84..b899fbe 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -44,6 +44,7 @@
import 'js_model/js_strategy.dart';
import 'js_model/js_world.dart';
import 'js_model/locals.dart';
+import 'kernel/front_end_adapter.dart' show CompilerFileSystem;
import 'kernel/kernel_strategy.dart';
import 'kernel/loader.dart' show KernelLoaderTask, KernelResult;
import 'null_compiler_output.dart' show NullCompilerOutput;
@@ -90,6 +91,7 @@
final List<CodeLocation> _userCodeLocations = <CodeLocation>[];
+ ir.Component componentForTesting;
JClosedWorld backendClosedWorldForTesting;
DataSourceIndices closedWorldIndicesForTesting;
@@ -252,9 +254,12 @@
reporter.log('Compiling $compilationTarget (${options.buildId})');
if (options.readProgramSplit != null) {
+ var constraintUri = options.readProgramSplit;
var constraintParser = psc.Parser();
- programSplitConstraintsData =
- await constraintParser.read(provider, options.readProgramSplit);
+ var programSplitJson = await CompilerFileSystem(provider)
+ .entityForUri(constraintUri)
+ .readAsString();
+ programSplitConstraintsData = constraintParser.read(programSplitJson);
}
if (onlyPerformGlobalTypeInference) {
@@ -309,6 +314,9 @@
if (compilationFailed) {
return;
}
+ if (retainDataForTesting) {
+ componentForTesting = result.component;
+ }
if (options.cfeOnly) return;
frontendStrategy.registerLoadedLibraries(result);
diff --git a/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart b/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
index 33f7b58..9f10c18 100644
--- a/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
+++ b/pkg/compiler/lib/src/deferred_load/program_split_constraints/nodes.dart
@@ -4,7 +4,9 @@
/// A [Node] is an abstract base class for all [Node]s parsed from json
/// constraints.
-abstract class Node {}
+abstract class Node {
+ Map<String, dynamic> toJson();
+}
/// A [NamedNode] is an abstract base class for all [Node]s that have a name.
abstract class NamedNode extends Node {
@@ -13,12 +15,54 @@
NamedNode(this.name);
}
-/// A [ReferenceNode] is a [NamedNode] with a uri and prefix.
-class ReferenceNode extends NamedNode {
+/// A [UriAndPrefix] is a simple POD data type wrapping a uri and prefix.
+class UriAndPrefix {
final Uri uri;
final String prefix;
- ReferenceNode(name, this.uri, this.prefix) : super(name);
+ UriAndPrefix(this.uri, this.prefix);
+
+ @override
+ String toString() {
+ return '$uri#$prefix';
+ }
+
+ static UriAndPrefix fromJson(String json) {
+ var uriAndPrefix = json.split('#');
+ if (uriAndPrefix.length != 2) {
+ throw 'Invalid "import" "uri#prefix" value in $json';
+ }
+ var uri = Uri.parse(uriAndPrefix[0]);
+ var prefix = uriAndPrefix[1];
+ return UriAndPrefix(uri, prefix);
+ }
+}
+
+/// A [ReferenceNode] is a [NamedNode] with a uri and prefix.
+class ReferenceNode extends NamedNode {
+ final UriAndPrefix _uriAndPrefix;
+ Uri get uri => _uriAndPrefix.uri;
+ String get prefix => _uriAndPrefix.prefix;
+
+ ReferenceNode(this._uriAndPrefix, {name})
+ : super(name ?? _uriAndPrefix.prefix);
+
+ @override
+ Map<String, dynamic> toJson() {
+ return {
+ 'type': 'reference',
+ 'name': name,
+ 'import': _uriAndPrefix.toString()
+ };
+ }
+
+ static ReferenceNode fromJson(Map<String, dynamic> nodeJson) {
+ if (nodeJson['type'] != 'reference') {
+ throw 'Unrecognized type for reference node: ${nodeJson['type']}.';
+ }
+ return ReferenceNode(UriAndPrefix.fromJson(nodeJson['import']),
+ name: nodeJson['name']);
+ }
@override
String toString() {
@@ -30,13 +74,76 @@
/// single step.
enum CombinerType { fuse, and, or }
+CombinerType parseCombinerType(Map<String, dynamic> nodeJson) {
+ String type = nodeJson['type'];
+ switch (type) {
+ case 'fuse':
+ return CombinerType.fuse;
+ case 'and':
+ return CombinerType.and;
+ case 'or':
+ return CombinerType.or;
+ default:
+ throw 'Unrecognized Combiner $nodeJson';
+ }
+}
+
+String combinerTypeToString(CombinerType type) {
+ switch (type) {
+ case CombinerType.fuse:
+ return 'fuse';
+ case CombinerType.and:
+ return 'and';
+ case CombinerType.or:
+ return 'or';
+ }
+ throw 'Unreachable';
+}
+
+T _jsonLookup<T>(Map<String, dynamic> nodeJson, String key) {
+ var value = nodeJson[key];
+ if (value == null) {
+ throw 'Missing "$key" key in $nodeJson';
+ }
+ return value;
+}
+
+NamedNode _jsonLookupNode(
+ Map<String, dynamic> nodeJson, String key, Map<String, NamedNode> nameMap) {
+ var node = nameMap[_jsonLookup(nodeJson, key)];
+ if (node == null) {
+ throw 'Invalid "$key" name in $nodeJson';
+ }
+ return node;
+}
+
/// A [CombinerNode] is a [NamedNode] with a list of [ReferenceNode] children
/// and a [CombinerType] for combining them.
class CombinerNode extends NamedNode {
final CombinerType type;
final Set<ReferenceNode> nodes;
- CombinerNode(name, this.type, this.nodes) : super(name);
+ CombinerNode(String name, this.type, this.nodes) : super(name);
+
+ @override
+ Map<String, dynamic> toJson() {
+ return {
+ 'type': combinerTypeToString(type),
+ 'name': name,
+ 'nodes': nodes.map((node) => node.name).toList()
+ };
+ }
+
+ static CombinerNode fromJson(
+ Map<String, dynamic> nodeJson, Map<String, NamedNode> nameMap) {
+ String name = _jsonLookup(nodeJson, 'name');
+ List<dynamic> referencesJson = _jsonLookup(nodeJson, 'nodes');
+ Set<ReferenceNode> references = {};
+ for (String reference in referencesJson) {
+ references.add(nameMap[reference]);
+ }
+ return CombinerNode(name, parseCombinerType(nodeJson), references);
+ }
@override
String toString() {
@@ -57,12 +164,95 @@
}
@override
+ Map<String, dynamic> toJson() {
+ return {
+ 'type': 'order',
+ 'predecessor': predecessor.name,
+ 'successor': successor.name
+ };
+ }
+
+ static RelativeOrderNode fromJson(
+ Map<String, dynamic> nodeJson, Map<String, NamedNode> nameMap) {
+ var predecessor = _jsonLookupNode(nodeJson, 'predecessor', nameMap);
+ var successor = _jsonLookupNode(nodeJson, 'successor', nameMap);
+ return RelativeOrderNode(predecessor: predecessor, successor: successor);
+ }
+
+ @override
String toString() {
return 'RelativeOrderNode(predecessor=${predecessor.name}, '
'successor=${successor.name})';
}
}
+/// A builder class for constructing constraint nodes.
+typedef ReferenceNodeNamer = String Function(UriAndPrefix);
+
+class ProgramSplitBuilder {
+ final Map<String, NamedNode> namedNodes = {};
+ ReferenceNodeNamer _referenceNodeNamer;
+
+ /// The prefix in the 'uri#prefix' string will become a key to reference this
+ /// node in other builder calls.
+ String _prefixNamer(UriAndPrefix uriAndPrefix) => uriAndPrefix.prefix;
+
+ /// Override the default reference node namer.
+ set referenceNodeNamer(ReferenceNodeNamer namer) =>
+ _referenceNodeNamer = namer;
+
+ /// Returns the [ReferenceNodeNamer] to use for naming.
+ ReferenceNodeNamer get referenceNodeNamer =>
+ _referenceNodeNamer ?? _prefixNamer;
+
+ /// Returns a [ReferenceNode] referencing [importUriAndPrefix].
+ /// [ReferenceNode]s are typically created in bulk, by mapping over a list of
+ /// strings of imports in the form 'uri#prefix'. In further builder calls,
+ /// created nodes can be referenced by their namers, derived from calling
+ /// [referenceNodeNamer] per [ReferenceNode].
+ ReferenceNode referenceNode(String importUriAndPrefix) {
+ var uriAndPrefix = UriAndPrefix.fromJson(importUriAndPrefix);
+ var referenceNode = ReferenceNode(uriAndPrefix);
+ var name = referenceNodeNamer(uriAndPrefix);
+ namedNodes[name] = referenceNode;
+ return referenceNode;
+ }
+
+ /// Creates an unnamed [RelativeOrderNode] referencing two [NamedNode]s.
+ RelativeOrderNode orderNode(String predecessor, String successor) {
+ return RelativeOrderNode(
+ predecessor: namedNodes[predecessor], successor: namedNodes[successor]);
+ }
+
+ /// Creates a [CombinerNode] which can be referenced by [name] in further
+ /// calls to the builder.
+ CombinerNode combinerNode(
+ String name, List<String> nodes, CombinerType type) {
+ var combinerNode = CombinerNode(name, type,
+ nodes.map((name) => namedNodes[name] as ReferenceNode).toSet());
+ namedNodes[name] = combinerNode;
+ return combinerNode;
+ }
+
+ /// Creates an 'and' [CombinerNode] which can be referenced by [name] in
+ /// further calls to the builder.
+ CombinerNode andNode(String name, List<String> nodes) {
+ return combinerNode(name, nodes, CombinerType.and);
+ }
+
+ /// Creates a 'fuse' [CombinerNode] which can be referenced by [name] in
+ /// further calls to the builder.
+ CombinerNode fuseNode(String name, List<String> nodes) {
+ return combinerNode(name, nodes, CombinerType.fuse);
+ }
+
+ /// Creates an 'or' [CombinerNode] which can be referenced by [name] in
+ /// further calls to the builder.
+ CombinerNode orNode(String name, List<String> nodes) {
+ return combinerNode(name, nodes, CombinerType.or);
+ }
+}
+
/// [ConstraintData] is a data object which contains the results of parsing json
/// program split constraints.
class ConstraintData {
diff --git a/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart b/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
index a758569..968b07b 100644
--- a/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
+++ b/pkg/compiler/lib/src/deferred_load/program_split_constraints/parser.dart
@@ -6,83 +6,29 @@
import 'nodes.dart';
-import '../../../compiler_new.dart' as api;
-import '../../kernel/front_end_adapter.dart' show CompilerFileSystem;
-
/// [Parser] parsers a program split constraints json file and returns a
/// [ConstraintData] object.
class Parser {
final Map<String, NamedNode> nameMap = {};
final List<RelativeOrderNode> orderedNodes = [];
- T _lookup<T>(Map<String, dynamic> nodeJson, String key) {
- var value = nodeJson[key];
- if (value == null) {
- throw 'Missing "$key" key in $nodeJson';
- }
- return value;
- }
-
void parseReference(Map<String, dynamic> nodeJson) {
- String name = _lookup(nodeJson, 'name');
- String uriAndPrefixString = _lookup(nodeJson, 'import');
- var uriAndPrefix = uriAndPrefixString.split('#');
- if (uriAndPrefix.length != 2) {
- throw 'Invalid "import" "uri#prefix" value in $nodeJson';
- }
- var uri = Uri.parse(uriAndPrefix[0]);
- var prefix = uriAndPrefix[1];
- var referenceNode = ReferenceNode(name, uri, prefix);
- nameMap[name] = referenceNode;
- }
-
- CombinerType parseCombinerType(Map<String, dynamic> nodeJson) {
- String type = nodeJson['type'];
- switch (type) {
- case 'fuse':
- return CombinerType.fuse;
- case 'and':
- return CombinerType.and;
- case 'or':
- return CombinerType.or;
- default:
- throw 'Unrecognized Combiner $nodeJson';
- }
+ var reference = ReferenceNode.fromJson(nodeJson);
+ nameMap[reference.name] = reference;
}
void parseCombiner(Map<String, dynamic> nodeJson) {
- String name = _lookup(nodeJson, 'name');
- List<dynamic> referencesJson = _lookup(nodeJson, 'nodes');
- Set<ReferenceNode> references = {};
- for (String reference in referencesJson) {
- references.add(nameMap[reference]);
- }
- var combinerNode =
- CombinerNode(name, parseCombinerType(nodeJson), references);
- nameMap[name] = combinerNode;
- }
-
- NamedNode _lookupNode(Map<String, dynamic> nodeJson, String key) {
- var node = nameMap[_lookup(nodeJson, key)];
- if (node == null) {
- throw 'Invalid "$key" name in $nodeJson';
- }
- return node;
+ var combinerNode = CombinerNode.fromJson(nodeJson, nameMap);
+ nameMap[combinerNode.name] = combinerNode;
}
void parseOrder(Map<String, dynamic> nodeJson) {
- var predecessor = _lookupNode(nodeJson, 'predecessor');
- var successor = _lookupNode(nodeJson, 'successor');
- var orderNode =
- RelativeOrderNode(predecessor: predecessor, successor: successor);
- orderedNodes.add(orderNode);
+ orderedNodes.add(RelativeOrderNode.fromJson(nodeJson, nameMap));
}
- /// Reads a program split constraints json file and returns a [Nodes] object
- /// reflecting the parsed constraints.
- Future<ConstraintData> read(api.CompilerInput provider, Uri path) async {
- String programSplitJson =
- await CompilerFileSystem(provider).entityForUri(path).readAsString();
+ /// Reads a program split constraints json file string and returns a [Nodes]
+ /// object reflecting the parsed constraints.
+ ConstraintData read(String programSplitJson) {
List<dynamic> doc = json.decode(programSplitJson);
List<Map<String, dynamic>> referenceConstraints = [];
List<Map<String, dynamic>> combinerConstraints = [];
diff --git a/pkg/compiler/test/custom_split/constraint_harness.dart b/pkg/compiler/test/custom_split/constraint_harness.dart
new file mode 100644
index 0000000..24c890e
--- /dev/null
+++ b/pkg/compiler/test/custom_split/constraint_harness.dart
@@ -0,0 +1,28 @@
+// 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.
+
+// @dart = 2.7
+
+import 'dart:convert';
+import 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+
+typedef ImportsProcessor = List<Node> Function(List<String>);
+
+/// A helper function which waits for a list of deferred imports, and then
+/// invokes the supplied [processFunc]. The list of nodes returned from
+/// [processFunc] will then be serialized as json and sent back over the
+/// supplied [sendPort].
+void waitForImportsAndInvoke(
+ SendPort sendPort, ImportsProcessor importsProcessor) async {
+ ReceivePort receivePort = ReceivePort();
+ sendPort.send(receivePort.sendPort);
+
+ var msg = await receivePort.first;
+ assert(msg is List<String>);
+ var constraints = importsProcessor(msg);
+ sendPort.send(JsonEncoder.withIndent(' ').convert(constraints));
+ receivePort.close();
+}
diff --git a/pkg/compiler/test/custom_split/custom_split_test.dart b/pkg/compiler/test/custom_split/custom_split_test.dart
index 5203eb3..fb0968a 100644
--- a/pkg/compiler/test/custom_split/custom_split_test.dart
+++ b/pkg/compiler/test/custom_split/custom_split_test.dart
@@ -5,7 +5,13 @@
// @dart = 2.7
import 'dart:io' hide Link;
+import 'dart:isolate';
+
import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:expect/expect.dart';
+import 'package:kernel/ast.dart' as ir;
+
import '../equivalence/id_equivalence_helper.dart';
import '../deferred_loading/deferred_loading_test_helper.dart';
@@ -25,12 +31,71 @@
Map<String, List<String>> createPerTestOptions() {
Map<String, List<String>> perTestOptions = {};
for (var test in tests) {
- Uri dir = Platform.script.resolve('data/$test/constraints.json');
- perTestOptions['$test'] = ['--read-program-split=$dir'];
+ Uri constraints = Platform.script.resolve('data/$test/constraints.json');
+ perTestOptions['$test'] = ['--read-program-split=$constraints'];
}
return perTestOptions;
}
+/// Returns a list of the deferred imports in a component where each import
+/// becomes a string of 'uri#prefix'.
+List<String> getDeferredImports(ir.Component component) {
+ List<String> imports = [];
+ for (var library in component.libraries) {
+ for (var import in library.dependencies) {
+ if (import.isDeferred) {
+ imports.add('${library.importUri}#${import.name}');
+ }
+ }
+ }
+ imports.sort();
+ return imports;
+}
+
+/// A helper function which performs the following steps:
+/// 1) Get deferred imports from a given [component]
+/// 2) Spawns the supplied [constraintsUri] in its own isolate
+/// 3) Passes deferred imports via a port to the spawned isolate
+/// 4) Listens for a json string from the spawned isolated and returns the
+/// results as a a [Future<String>].
+Future<String> constraintsToJson(
+ ir.Component component, Uri constraintsUri) async {
+ var imports = getDeferredImports(component);
+ SendPort sendPort;
+ var receivePort = ReceivePort();
+ var isolate = await Isolate.spawnUri(constraintsUri, [], receivePort.sendPort,
+ paused: true);
+ isolate.addOnExitListener(receivePort.sendPort);
+ isolate.resume(isolate.pauseCapability);
+ String json;
+ await for (var msg in receivePort) {
+ if (msg == null) {
+ receivePort.close();
+ } else if (sendPort == null) {
+ sendPort = msg;
+ sendPort.send(imports);
+ } else if (json == null) {
+ json = msg;
+ } else {
+ throw 'Unexpected message $msg';
+ }
+ }
+ return json;
+}
+
+/// Verifies the programmatic API produces the expected JSON.
+Future<void> verifyCompiler(String test, Compiler compiler) async {
+ var constraints = Platform.script.resolve('data/$test/constraints.dart');
+ var constraintsJsonUri =
+ Platform.script.resolve('data/$test/constraints.json');
+ var component = compiler.componentForTesting;
+ var json = await constraintsToJson(component, constraints);
+ var constraintsJson =
+ File(constraintsJsonUri.toFilePath()).readAsStringSync();
+ constraintsJson = constraintsJson.substring(0, constraintsJson.length - 1);
+ Expect.equals(json, constraintsJson);
+}
+
/// Compute the [OutputUnit]s for all source files involved in the test, and
/// ensure that the compiler is correctly calculating what is used and what is
/// not. We expect all test entry points to be in the `data` directory and any
@@ -44,6 +109,6 @@
perTestOptions: createPerTestOptions(),
args: args, setUpFunction: () {
importPrefixes.clear();
- }, testedConfigs: allSpecConfigs);
+ }, testedConfigs: allSpecConfigs, verifyCompiler: verifyCompiler);
});
}
diff --git a/pkg/compiler/test/custom_split/data/diamond/constraints.dart b/pkg/compiler/test/custom_split/data/diamond/constraints.dart
new file mode 100644
index 0000000..92a7665
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond/constraints.dart
@@ -0,0 +1,23 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.orderNode('step1', 'step2a'),
+ builder.orderNode('step1', 'step2b'),
+ builder.orderNode('step2a', 'step3'),
+ builder.orderNode('step2b', 'step3'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/diamond/constraints.json b/pkg/compiler/test/custom_split/data/diamond/constraints.json
index 19bc46e..83dfe0a 100644
--- a/pkg/compiler/test/custom_split/data/diamond/constraints.json
+++ b/pkg/compiler/test/custom_split/data/diamond/constraints.json
@@ -1,42 +1,42 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2a",
+ "name": "step2a",
"import": "memory:sdk/tests/web/native/main.dart#step2a"
},
{
"type": "reference",
- "name": "s2b",
+ "name": "step2b",
"import": "memory:sdk/tests/web/native/main.dart#step2b"
},
{
"type": "reference",
- "name": "s3",
+ "name": "step3",
"import": "memory:sdk/tests/web/native/main.dart#step3"
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2a"
+ "predecessor": "step1",
+ "successor": "step2a"
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2b"
+ "predecessor": "step1",
+ "successor": "step2b"
},
{
"type": "order",
- "predecessor": "s2a",
- "successor": "s3"
+ "predecessor": "step2a",
+ "successor": "step3"
},
{
"type": "order",
- "predecessor": "s2b",
- "successor": "s3"
+ "predecessor": "step2b",
+ "successor": "step3"
}
]
diff --git a/pkg/compiler/test/custom_split/data/diamond_and/constraints.dart b/pkg/compiler/test/custom_split/data/diamond_and/constraints.dart
new file mode 100644
index 0000000..b3a40ca
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_and/constraints.dart
@@ -0,0 +1,22 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.andNode('step2', ['step2a', 'step2b']),
+ builder.orderNode('step1', 'step2'),
+ builder.orderNode('step2', 'step3'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/diamond_and/constraints.json b/pkg/compiler/test/custom_split/data/diamond_and/constraints.json
index 72d7e25..931a910 100644
--- a/pkg/compiler/test/custom_split/data/diamond_and/constraints.json
+++ b/pkg/compiler/test/custom_split/data/diamond_and/constraints.json
@@ -1,40 +1,40 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2a",
+ "name": "step2a",
"import": "memory:sdk/tests/web/native/main.dart#step2a"
},
{
"type": "reference",
- "name": "s2b",
+ "name": "step2b",
"import": "memory:sdk/tests/web/native/main.dart#step2b"
},
{
"type": "reference",
- "name": "s3",
+ "name": "step3",
"import": "memory:sdk/tests/web/native/main.dart#step3"
},
{
"type": "and",
- "name": "s2",
+ "name": "step2",
"nodes": [
- "s2a",
- "s2b"
+ "step2a",
+ "step2b"
]
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2"
+ "predecessor": "step1",
+ "successor": "step2"
},
{
"type": "order",
- "predecessor": "s2",
- "successor": "s3"
+ "predecessor": "step2",
+ "successor": "step3"
}
]
diff --git a/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.dart b/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.dart
new file mode 100644
index 0000000..6fdf62e
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.dart
@@ -0,0 +1,22 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.fuseNode('step2', ['step2a', 'step2b']),
+ builder.orderNode('step1', 'step2'),
+ builder.orderNode('step2', 'step3'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.json b/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.json
index 9fbb3cd..f170d18 100644
--- a/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.json
+++ b/pkg/compiler/test/custom_split/data/diamond_fuse/constraints.json
@@ -1,40 +1,40 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2a",
+ "name": "step2a",
"import": "memory:sdk/tests/web/native/main.dart#step2a"
},
{
"type": "reference",
- "name": "s2b",
+ "name": "step2b",
"import": "memory:sdk/tests/web/native/main.dart#step2b"
},
{
"type": "reference",
- "name": "s3",
+ "name": "step3",
"import": "memory:sdk/tests/web/native/main.dart#step3"
},
{
"type": "fuse",
- "name": "s2",
+ "name": "step2",
"nodes": [
- "s2a",
- "s2b"
+ "step2a",
+ "step2b"
]
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2"
+ "predecessor": "step1",
+ "successor": "step2"
},
{
"type": "order",
- "predecessor": "s2",
- "successor": "s3"
+ "predecessor": "step2",
+ "successor": "step3"
}
]
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/constraints.dart b/pkg/compiler/test/custom_split/data/diamond_or/constraints.dart
new file mode 100644
index 0000000..659bf73
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/diamond_or/constraints.dart
@@ -0,0 +1,22 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.orNode('step2', ['step2a', 'step2b']),
+ builder.orderNode('step1', 'step2'),
+ builder.orderNode('step2', 'step3'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/diamond_or/constraints.json b/pkg/compiler/test/custom_split/data/diamond_or/constraints.json
index 310309a..5fcc300 100644
--- a/pkg/compiler/test/custom_split/data/diamond_or/constraints.json
+++ b/pkg/compiler/test/custom_split/data/diamond_or/constraints.json
@@ -1,40 +1,40 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2a",
+ "name": "step2a",
"import": "memory:sdk/tests/web/native/main.dart#step2a"
},
{
"type": "reference",
- "name": "s2b",
+ "name": "step2b",
"import": "memory:sdk/tests/web/native/main.dart#step2b"
},
{
"type": "reference",
- "name": "s3",
+ "name": "step3",
"import": "memory:sdk/tests/web/native/main.dart#step3"
},
{
"type": "or",
- "name": "s2",
+ "name": "step2",
"nodes": [
- "s2a",
- "s2b"
+ "step2a",
+ "step2b"
]
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2"
+ "predecessor": "step1",
+ "successor": "step2"
},
{
"type": "order",
- "predecessor": "s2",
- "successor": "s3"
+ "predecessor": "step2",
+ "successor": "step3"
}
]
diff --git a/pkg/compiler/test/custom_split/data/two_branch/constraints.dart b/pkg/compiler/test/custom_split/data/two_branch/constraints.dart
new file mode 100644
index 0000000..1e6ad05
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/two_branch/constraints.dart
@@ -0,0 +1,21 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.orderNode('step1', 'step2a'),
+ builder.orderNode('step1', 'step2b'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/two_branch/constraints.json b/pkg/compiler/test/custom_split/data/two_branch/constraints.json
index 542cf85..8b86071 100644
--- a/pkg/compiler/test/custom_split/data/two_branch/constraints.json
+++ b/pkg/compiler/test/custom_split/data/two_branch/constraints.json
@@ -1,27 +1,27 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2a",
+ "name": "step2a",
"import": "memory:sdk/tests/web/native/main.dart#step2a"
},
{
"type": "reference",
- "name": "s2b",
+ "name": "step2b",
"import": "memory:sdk/tests/web/native/main.dart#step2b"
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2a"
+ "predecessor": "step1",
+ "successor": "step2a"
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2b"
+ "predecessor": "step1",
+ "successor": "step2b"
}
]
diff --git a/pkg/compiler/test/custom_split/data/two_step/constraints.dart b/pkg/compiler/test/custom_split/data/two_step/constraints.dart
new file mode 100644
index 0000000..9089c5c
--- /dev/null
+++ b/pkg/compiler/test/custom_split/data/two_step/constraints.dart
@@ -0,0 +1,21 @@
+// 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 'dart:isolate';
+
+import 'package:compiler/src/deferred_load/program_split_constraints/nodes.dart';
+import '../../constraint_harness.dart';
+
+void main(List<String> args, SendPort sendPort) {
+ waitForImportsAndInvoke(sendPort, processDeferredImports);
+}
+
+List<Node> processDeferredImports(List<String> imports) {
+ var builder = ProgramSplitBuilder();
+ return [
+ ...imports.map(builder.referenceNode),
+ builder.orderNode('step1', 'step2'),
+ builder.orderNode('step2', 'step3'),
+ ];
+}
diff --git a/pkg/compiler/test/custom_split/data/two_step/constraints.json b/pkg/compiler/test/custom_split/data/two_step/constraints.json
index 31c29a1..b72db44 100644
--- a/pkg/compiler/test/custom_split/data/two_step/constraints.json
+++ b/pkg/compiler/test/custom_split/data/two_step/constraints.json
@@ -1,27 +1,27 @@
[
{
"type": "reference",
- "name": "s1",
+ "name": "step1",
"import": "memory:sdk/tests/web/native/main.dart#step1"
},
{
"type": "reference",
- "name": "s2",
+ "name": "step2",
"import": "memory:sdk/tests/web/native/main.dart#step2"
},
{
"type": "reference",
- "name": "s3",
+ "name": "step3",
"import": "memory:sdk/tests/web/native/main.dart#step3"
},
{
"type": "order",
- "predecessor": "s1",
- "successor": "s2"
+ "predecessor": "step1",
+ "successor": "step2"
},
{
"type": "order",
- "predecessor": "s2",
- "successor": "s3"
+ "predecessor": "step2",
+ "successor": "step3"
}
]
diff --git a/pkg/compiler/test/equivalence/id_equivalence_helper.dart b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
index 20993eb..d0288ee 100644
--- a/pkg/compiler/test/equivalence/id_equivalence_helper.dart
+++ b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
@@ -121,7 +121,7 @@
/// [entryPoint] and [memorySourceFiles].
///
/// Actual data is computed using [computeMemberData].
-Future<CompiledData<T>> computeData<T>(Uri entryPoint,
+Future<CompiledData<T>> computeData<T>(String name, Uri entryPoint,
Map<String, String> memorySourceFiles, DataComputer<T> dataComputer,
{List<String> options: const <String>[],
bool verbose: false,
@@ -130,7 +130,8 @@
bool forUserLibrariesOnly: true,
bool skipUnprocessedMembers: false,
bool skipFailedCompilations: false,
- Iterable<Id> globalIds: const <Id>[]}) async {
+ Iterable<Id> globalIds: const <Id>[],
+ Future<void> verifyCompiler(String test, Compiler compiler)}) async {
OutputCollector outputCollector = new OutputCollector();
DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
Uri packageConfig;
@@ -166,6 +167,9 @@
print('------------------------------------------------------------------');
}
Compiler compiler = result.compiler;
+ if (verifyCompiler != null) {
+ await verifyCompiler(name, compiler);
+ }
Map<Uri, Map<Id, ActualData<T>>> actualMaps = <Uri, Map<Id, ActualData<T>>>{};
Map<Id, ActualData<T>> globalData = <Id, ActualData<T>>{};
@@ -403,7 +407,8 @@
int shardIndex: 0,
void onTest(Uri uri),
List<TestConfig> testedConfigs = const [],
- Map<String, List<String>> perTestOptions = const {}}) async {
+ Map<String, List<String>> perTestOptions = const {},
+ Future<void> verifyCompiler(String test, Compiler compiler)}) async {
if (testedConfigs.isEmpty) testedConfigs = defaultInternalConfigs;
Set<String> testedMarkers =
testedConfigs.map((config) => config.marker).toSet();
@@ -455,7 +460,8 @@
succinct: succinct,
testAfterFailures: testAfterFailures,
forUserLibrariesOnly: forUserLibrariesOnly,
- printCode: printCode);
+ printCode: printCode,
+ verifyCompiler: verifyCompiler);
}
}
return results;
@@ -484,17 +490,19 @@
bool succinct: false,
bool printCode: false,
bool forUserLibrariesOnly: true,
- bool testAfterFailures: false}) async {
+ bool testAfterFailures: false,
+ Future<void> verifyCompiler(String test, Compiler compiler)}) async {
MemberAnnotations<IdValue> annotations =
testData.expectedMaps[testConfiguration.marker];
- CompiledData<T> compiledData = await computeData(
+ CompiledData<T> compiledData = await computeData(testData.name,
testData.entryPoint, testData.memorySourceFiles, dataComputer,
options: [...options, ...testConfiguration.options],
verbose: verbose,
printCode: printCode,
testFrontend: dataComputer.testFrontend,
forUserLibrariesOnly: forUserLibrariesOnly,
- globalIds: annotations.globalData.keys);
+ globalIds: annotations.globalData.keys,
+ verifyCompiler: verifyCompiler);
return await checkCode(testConfiguration.name, testData.testFileUri,
testData.code, annotations, compiledData, dataComputer.dataValidator,
filterActualData: filterActualData,
diff --git a/pkg/compiler/test/equivalence/show_helper.dart b/pkg/compiler/test/equivalence/show_helper.dart
index 754f2e2..ecc6257 100644
--- a/pkg/compiler/test/equivalence/show_helper.dart
+++ b/pkg/compiler/test/equivalence/show_helper.dart
@@ -52,7 +52,7 @@
options.add(Flags.omitImplicitChecks);
}
Dart2jsCompiledData<T> data = await computeData<T>(
- entryPoint, const {}, dataComputer,
+ file, entryPoint, const {}, dataComputer,
options: options,
testFrontend: dataComputer.testFrontend,
forUserLibrariesOnly: false,
diff --git a/pkg/nnbd_migration/pubspec.yaml b/pkg/nnbd_migration/pubspec.yaml
index 6d8ac9d..19a70c2 100644
--- a/pkg/nnbd_migration/pubspec.yaml
+++ b/pkg/nnbd_migration/pubspec.yaml
@@ -7,28 +7,34 @@
sdk: '>=2.14.0 <3.0.0'
dependencies:
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
- analyzer:
- path: ../analyzer
- analyzer_plugin:
- path: ../analyzer_plugin
- args: ^1.4.4
+ _fe_analyzer_shared: any
+ analyzer: any
+ analyzer_plugin: any
+ args: ^2.3.0
charcode: ^1.1.0
- cli_util: ^0.2.0
- collection: ^1.15.0-nullsafety.4
- crypto: ^2.0.6
- meta:
- path: ../meta
+ cli_util: ^0.3.5
+ collection: ^1.15.0
+ crypto: ^3.0.1
+ meta: any
path: ^1.6.2
- pub_semver: ^1.4.2
+ pub_semver: ^2.1.0
source_span: ^1.4.1
yaml: any
dev_dependencies:
analyzer_utilities:
path: ../analyzer_utilities
- http: '>=0.11.3+17 <0.13.0'
+ http: ^0.13.4
pedantic: ^1.9.0
test: ^1.6.4
- test_reflective_loader: ^0.1.8
+ test_reflective_loader: ^0.2.0
+
+dependency_overrides:
+ _fe_analyzer_shared:
+ path: ../_fe_analyzer_shared
+ analyzer:
+ path: ../analyzer
+ analyzer_plugin:
+ path: ../analyzer_plugin
+ meta:
+ path: ../meta
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 089a4c9..61870d6 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -104,6 +104,9 @@
_Invocation(this.selector, this.args);
+ /// Initialize invocation before it is cached and processed.
+ void init() {}
+
Type process(TypeFlowAnalysis typeFlowAnalysis);
/// Returns result of this invocation if its available without
@@ -186,21 +189,29 @@
class _DirectInvocation extends _Invocation {
_DirectInvocation(DirectSelector selector, Args<Type> args)
- : super(selector, args) {
+ : super(selector, args);
+
+ @override
+ void init() {
// We don't emit [TypeCheck] statements for bounds checks of type
// parameters, so if there are any type parameters, we must assume
// they could fail bounds checks.
//
// TODO(sjindel): Use [TypeCheck] to avoid bounds checks.
- final function = selector.member.function;
+ final function = selector.member!.function;
if (function != null) {
- typeChecksNeeded =
- function.typeParameters.any((t) => t.isCovariantByClass);
+ for (TypeParameter tp in function.typeParameters) {
+ if (tp.isCovariantByClass) {
+ typeChecksNeeded = true;
+ }
+ }
} else {
Field field = selector.member as Field;
if (selector.callKind == CallKind.PropertySet) {
// TODO(dartbug.com/40615): Use TFA results to improve this criterion.
- typeChecksNeeded = field.isCovariantByClass;
+ if (field.isCovariantByClass) {
+ typeChecksNeeded = true;
+ }
}
}
}
@@ -791,6 +802,7 @@
_typeFlowAnalysis.summaryCollector.rawArguments(selector);
sa.approximation =
approximation = _DispatchableInvocation(selector, rawArgs);
+ approximation.init();
Statistics.approximateInvocationsCreated++;
}
Statistics.approximateInvocationsUsed++;
@@ -802,6 +814,7 @@
max(Statistics.maxInvocationsCachedPerSelector, sa.count);
}
+ invocation.init();
bool added = _invocations.add(invocation);
assert(added);
++Statistics.invocationsAddedToCache;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 952eefe..a72ad85 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -1669,23 +1669,35 @@
@override
TypeExpr visitEqualsCall(EqualsCall node) {
- final left = _visit(node.left);
- final right = _visit(node.right);
+ _addUse(_visit(node.left));
+ _addUse(_visit(node.right));
final target = node.interfaceTarget;
+ // 'operator==' is a very popular method which can be called
+ // with a huge number of combinations of argument types.
+ // These invocations can be sensitive to changes in the set of allocated
+ // classes, causing a large number of invalidated invocations.
+ // In order to speed up the analysis, arguments of 'operator=='
+ // are approximated eagerly to static types during summary construction.
return _makeCall(
node,
(node.left is ThisExpression)
? new VirtualSelector(target)
: new InterfaceSelector(target),
- Args<TypeExpr>([left, right]));
+ Args<TypeExpr>([_staticType(node.left), _staticType(node.right)]));
}
@override
TypeExpr visitEqualsNull(EqualsNull node) {
final arg = _visit(node.expression);
_makeNarrowNotNull(node, arg);
+ // 'operator==' is a very popular method which can be called
+ // with a huge number of combinations of argument types.
+ // These invocations can be sensitive to changes in the set of allocated
+ // classes, causing a large number of invalidated invocations.
+ // In order to speed up the analysis, arguments of 'operator=='
+ // are approximated eagerly to static types during summary construction.
_makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
- Args<TypeExpr>([arg, _nullType]));
+ Args<TypeExpr>([_staticType(node.expression), _nullType]));
return _boolType;
}
@@ -1838,6 +1850,18 @@
passTypeArguments: node.target.isFactory);
final target = node.target;
assert((target is! Field) && !target.isGetter && !target.isSetter);
+ if (target == _environment.coreTypes.identicalProcedure) {
+ assert(args.values.length == 2 && args.names.isEmpty);
+ // 'identical' is a very popular method which can be called
+ // with a huge number of combinations of argument types.
+ // Those invocations can be sensitive to changes in the set of allocated
+ // classes, causing a large number of invalidated invocations.
+ // In order to speed up the analysis, invocations of 'identical'
+ // are approximated eagerly during summary construction.
+ _makeCall(node, new DirectSelector(target),
+ Args<TypeExpr>([Type.nullableAny(), Type.nullableAny()]));
+ return _boolType;
+ }
TypeExpr result = _makeCall(node, new DirectSelector(target), args);
if (target == unsafeCast) {
// Async transformation inserts unsafeCasts to make sure
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 3ed7b9b..6db75a7 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -166,7 +166,7 @@
factory Type.nullable(Type t) => new NullableType(t);
/// Create a type representing arbitrary nullable object (`dynamic`).
- factory Type.nullableAny() => new NullableType(const AnyType());
+ factory Type.nullableAny() => const NullableType(const AnyType());
Class? getConcreteClass(TypeHierarchy typeHierarchy) => null;
@@ -253,9 +253,7 @@
class NullableType extends Type {
final Type baseType;
- NullableType(this.baseType) {
- assert(baseType is! NullableType);
- }
+ const NullableType(this.baseType) : assert(baseType is! NullableType);
@override
int get hashCode => (baseType.hashCode + 31) & kHashMask;
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
index 23f3ef4..4f6ab2a 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
@@ -112,8 +112,8 @@
%x = _Parameter #0 [_T (dart.core::int)+?]
%y = _Parameter #1 [_T (dart.core::String)+?]
%z = _Parameter #2 [_T ANY?]
-t3* = _Call [dart.core::num.==] (%x, _T (dart.core::_Smi, 5))
-t4* = _Call [dart.core::String.==] (%y, _T (dart.core::_OneByteString, "hi"))
+t3* = _Call [dart.core::num.==] (_T (dart.core::int)+?, _T (dart.core::int)+?)
+t4* = _Call [dart.core::String.==] (_T (dart.core::String)+?, _T (dart.core::String)+?)
t5 = _Call direct [dart.core::Object.==] (%z, _T {}?)
t6 = _Narrow (%z to _T ANY)
t7 = _Call direct [#lib::foo] (_T (dart.core::_Smi, 5))
@@ -127,7 +127,7 @@
RESULT: _T {}?
------------ if9 ------------
%x = _Parameter #0 [_T (#lib::TestEnum)+?]
-t1* = _Call [dart.core::Object.==] (%x, _T (#lib::TestEnum, const #lib::TestEnum{dart.core::_Enum.index: 0, dart.core::_Enum._name: "v1"}))
+t1* = _Call [dart.core::Object.==] (_T (#lib::TestEnum)+?, _T (#lib::TestEnum)+?)
t2 = _Call direct [#lib::foo] (_T (#lib::TestEnum, const #lib::TestEnum{dart.core::_Enum.index: 0, dart.core::_Enum._name: "v1"}))
RESULT: _T {}?
------------ conditional1 ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
index b559883..e5f2883 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
@@ -14,7 +14,7 @@
a1_0 = _Join [dart.core::Object] (t3, %a1)
t5 = _Call direct [#lib::bar] (a1_0, _T (dart.core::_Smi, 42))
t6* = _Call direct [#lib::B.] (_T (#lib::B))
-t7* = _Call [dart.core::Object.==] (t6, %a2)
+t7* = _Call [dart.core::Object.==] (_T (dart.core::Object)+?, _T (dart.core::Object)+?)
t8 = _Join [dart.core::Object?] (t6, %a2)
t9 = _Narrow (t8 to _T (dart.core::Object)+?)
RESULT: t9
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
index 9ff69a2..1878d03 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
@@ -7,7 +7,7 @@
if(_in::unsafeCast<core::bool>([@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool] n{dynamic}.<(2)))
return false;
for (core::int i = 2; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<=] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::*}(i){(core::num) → core::int}.{core::num::<=}(_in::unsafeCast<core::num>(n)){(core::num) → core::bool}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}) {
- if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::_IntegerImplementation.%] [@vm.inferred-type.metadata=int] n{dynamic}.%(i) =={core::Object::==}{(core::Object) → core::bool} 0)
+ if([@vm.inferred-type.metadata=dart.core::bool?] [@vm.direct-call.metadata=dart.core::_IntegerImplementation.%] [@vm.inferred-type.metadata=int] n{dynamic}.%(i) =={core::Object::==}{(core::Object) → core::bool} 0)
return false;
}
return true;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
index 4771de1..b822802 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
@@ -100,7 +100,7 @@
self::ByteStream x = new self::ByteStream::•(new self::_ControllerStream::•());
self::Stream y = [@vm.direct-call.metadata=#lib::ByteStream.super_stream] [@vm.inferred-type.metadata=!] x.{self::ByteStream::super_stream}{self::Stream};
self::Stream z = [@vm.direct-call.metadata=#lib::StreamView._stream] [@vm.inferred-type.metadata=!] x.{self::StreamView::_stream}{self::Stream};
- if([@vm.direct-call.metadata=dart.core::Object.==] [@vm.inferred-type.metadata=dart.core::bool (skip check) (receiver not int)] y =={core::Object::==}{(core::Object) → core::bool} z) {
+ if([@vm.inferred-type.metadata=dart.core::bool (skip check) (receiver not int)] y =={core::Object::==}{(core::Object) → core::bool} z) {
[@vm.direct-call.metadata=#lib::ByteStream.super_foobar2] [@vm.inferred-type.metadata=!? (skip check)] x.{self::ByteStream::super_foobar2}(){((dynamic) →? void) → dynamic};
}
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
index 73b0430..423420c 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
@@ -29,7 +29,7 @@
core::print("List<int> buffer = <int>[");
for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int}){(core::num) → core::bool}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num) → core::int}) {
final core::String numbers = [@vm.direct-call.metadata=dart.typed_data::_TypedListBase.join] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=dart.typed_data::__Uint8List&_TypedList&_IntListMixin&_TypedIntListMixin.sublist] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] buffer.{typ::Uint8List::sublist}(i, [@vm.inferred-type.metadata=int] math::min<core::int>([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num) → core::int})){(core::int, [core::int?]) → typ::Uint8List}.{core::Iterable::join}(", "){([core::String]) → core::String};
- core::print(" ${numbers},${[@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i =={core::num::==}{(core::Object) → core::bool} 0 ?{core::String} " //" : ""}");
+ core::print(" ${numbers},${[@vm.inferred-type.metadata=dart.core::bool] i =={core::num::==}{(core::Object) → core::bool} 0 ?{core::String} " //" : ""}");
}
core::print("];");
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
index 3310998..4203e7a 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
@@ -61,7 +61,7 @@
});
self::E e = new self::F::•();
let final core::int #t3 = [@vm.direct-call.metadata=#lib::F.bar] [@vm.inferred-type.metadata=dart.core::_Smi (value: 42)] e.{self::E::bar}{core::int} in exp::Expect::equals();
- exp::Expect::isTrue(![@vm.inferred-type.metadata=dart.core::bool] core::identical(#C2, #C4));
+ exp::Expect::isTrue(!core::identical(#C2, #C4));
[@vm.direct-call.metadata=#lib::I.foo] [@vm.inferred-type.metadata=!? (skip check)] new self::I::•().{self::I::foo}(){() → dynamic};
5;
}
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index de4433c..4b8f59d 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -756,12 +756,13 @@
actions[fixed_actions_cnt + i] = {
.action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY,
.ns = {
- .prefix = flat_ns->path[i],
+ .prefix = DartUtils::ScopedCopyCString(flat_ns->path[i]),
.handle = flat_ns->handle[i],
},
};
+ flat_ns->handle[i] = ZX_HANDLE_INVALID;
}
- free(flat_ns);
+ fdio_ns_free_flat_ns(flat_ns);
flat_ns = nullptr;
}
diff --git a/tools/VERSION b/tools/VERSION
index 772fd4d..dd9fa8f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 257
+PRERELEASE 258
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/package_deps/bin/package_deps.dart b/tools/package_deps/bin/package_deps.dart
index eab4201..d0a8abc 100644
--- a/tools/package_deps/bin/package_deps.dart
+++ b/tools/package_deps/bin/package_deps.dart
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:cli_util/cli_logging.dart';
+import 'package:collection/collection.dart';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart' as yaml;
@@ -85,34 +86,59 @@
}
if (validateFailure) {
- exit(1);
+ exitCode = 1;
}
}
class Package implements Comparable<Package> {
final String dir;
+ final _regularDependencies = <String>{};
+ final _devDependencies = <String>{};
+ final _declaredPubDeps = <PubDep>[];
+ final _declaredDevPubDeps = <PubDep>[];
+ final _declaredOverridePubDeps = <PubDep>[];
+
+ late final String _packageName;
+ late final Set<String> _declaredDependencies;
+ late final Set<String> _declaredDevDependencies;
+ late final Set<String> _declaredOverrideDependencies;
+ late final bool _publishToNone;
Package(this.dir) {
- _parsePubspec();
+ var pubspec = File(path.join(dir, 'pubspec.yaml'));
+ var doc = yaml.loadYamlDocument(pubspec.readAsStringSync());
+ dynamic docContents = doc.contents.value;
+ _packageName = docContents['name'];
+ _publishToNone = docContents['publish_to'] == 'none';
+
+ Set<String> process(String section, List<PubDep> target) {
+ if (docContents[section] != null) {
+ final value = Set<String>.from(docContents[section].keys);
+
+ var deps = docContents[section];
+ for (var package in deps.keys) {
+ target.add(PubDep.parse(package, deps[package]));
+ }
+
+ return value;
+ } else {
+ return {};
+ }
+ }
+
+ _declaredDependencies = process('dependencies', _declaredPubDeps);
+ _declaredDevDependencies = process('dev_dependencies', _declaredDevPubDeps);
+ _declaredOverrideDependencies =
+ process('dependency_overrides', _declaredOverridePubDeps);
}
String get dirName => path.basename(dir);
- final Set<String> _regularDependencies = {};
- final Set<String> _devDependencies = {};
- String _packageName;
-
String get packageName => _packageName;
- Set<String> _declaredDependencies;
- List<PubDep> _declaredPubDeps;
- Set<String> _declaredDevDependencies;
- List<PubDep> _declaredDevPubDeps;
List<String> get regularDependencies => _regularDependencies.toList()..sort();
List<String> get devDependencies => _devDependencies.toList()..sort();
- bool _publishToNone;
-
bool get publishable => !_publishToNone;
@override
@@ -161,40 +187,6 @@
}
}
- void _parsePubspec() {
- var pubspec = File(path.join(dir, 'pubspec.yaml'));
- var doc = yaml.loadYamlDocument(pubspec.readAsStringSync());
- dynamic docContents = doc.contents.value;
- _packageName = docContents['name'];
- _publishToNone = docContents['publish_to'] == 'none';
-
- _declaredPubDeps = [];
- if (docContents['dependencies'] != null) {
- _declaredDependencies =
- Set<String>.from(docContents['dependencies'].keys);
-
- var deps = docContents['dependencies'];
- for (var package in deps.keys) {
- _declaredPubDeps.add(PubDep.parse(package, deps[package]));
- }
- } else {
- _declaredDependencies = {};
- }
-
- _declaredDevPubDeps = [];
- if (docContents['dev_dependencies'] != null) {
- _declaredDevDependencies =
- Set<String>.from(docContents['dev_dependencies'].keys);
-
- var deps = docContents['dev_dependencies'];
- for (var package in deps.keys) {
- _declaredDevPubDeps.add(PubDep.parse(package, deps[package]));
- }
- } else {
- _declaredDevDependencies = {};
- }
- }
-
bool _validatePubspecDeps(Logger logger, List<String> pkgPackages) {
var fail = false;
@@ -300,6 +292,13 @@
if (!publishable) {
for (PubDep dep in [..._declaredPubDeps, ..._declaredDevPubDeps]) {
if (pkgPackages.contains(dep.name) && dep is! PathPubDep) {
+ // check to see if there is a dependency_override to a path dependency
+ final override = _declaredOverridePubDeps
+ .singleWhereOrNull((element) => element.name == dep.name);
+ if (override != null && override is PathPubDep) {
+ continue;
+ }
+
out(' Prefer a relative path dep for pkg/ packages:');
out(' $dep');
fail = true;
@@ -368,13 +367,13 @@
var match = importRegex1.firstMatch(line);
if (match != null) {
- results.add(match.group(2));
+ results.add(match.group(2)!);
continue;
}
match = importRegex2.firstMatch(line);
if (match != null) {
- results.add(match.group(2));
+ results.add(match.group(2)!);
continue;
}
}
@@ -418,9 +417,9 @@
var testedPkgDep = testedPkgRegExp.firstMatch(line);
if (pkgDep != null) {
- pkgs.add(pkgDep.group(1));
+ pkgs.add(pkgDep.group(1)!);
} else if (testedPkgDep != null) {
- testedPkgs.add(testedPkgDep.group(1));
+ testedPkgs.add(testedPkgDep.group(1)!);
}
}
diff --git a/tools/package_deps/pubspec.yaml b/tools/package_deps/pubspec.yaml
index ef104c9..184795e 100644
--- a/tools/package_deps/pubspec.yaml
+++ b/tools/package_deps/pubspec.yaml
@@ -5,12 +5,10 @@
publish_to: none
environment:
- sdk: '>=2.8.1 <3.0.0'
+ sdk: '>=2.12.0 <3.0.0'
dependencies:
cli_util: any
+ collection: any
path: any
yaml: any
-
-dev_dependencies:
- pedantic: ^1.9.0