Version 2.15.0-268.0.dev
Merge commit 'cd59d39fe3006cd0bf1a30699554e89071282783' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 4a18e4b..78fef2f 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -285,10 +285,6 @@
final DocumentationCache? documentationCache;
- /// Return the expression to the right of the "dot" or "dot dot",
- /// or `null` if this is not a "dot" completion (e.g. `foo.b`).
- final Expression? dotTarget;
-
/// Return the object used to compute the values of the features used to
/// compute relevance scores for suggestions.
final FeatureComputer featureComputer;
@@ -328,7 +324,6 @@
DocumentationCache? documentationCache,
}) {
var target = CompletionTarget.forOffset(resolvedUnit.unit, offset);
- var dotTarget = _dotTarget(target);
var featureComputer = FeatureComputer(
resolvedUnit.typeSystem,
@@ -350,7 +345,6 @@
contextType: contextType,
dartdocDirectiveInfo: dartdocDirectiveInfo ?? DartdocDirectiveInfo(),
documentationCache: documentationCache,
- dotTarget: dotTarget,
featureComputer: featureComputer,
offset: offset,
opType: opType,
@@ -366,7 +360,6 @@
required this.contextType,
required this.dartdocDirectiveInfo,
required this.documentationCache,
- required this.dotTarget,
required this.featureComputer,
required this.offset,
required this.opType,
@@ -464,29 +457,4 @@
throw AbortCompletion();
}
}
-
- /// TODO(scheglov) Should this be a property of [CompletionTarget]?
- static Expression? _dotTarget(CompletionTarget target) {
- var node = target.containingNode;
- var offset = target.offset;
- if (node is MethodInvocation) {
- if (identical(node.methodName, target.entity)) {
- return node.realTarget;
- } else if (node.isCascaded && node.operator!.offset + 1 == offset) {
- return node.realTarget;
- }
- }
- if (node is PropertyAccess) {
- if (identical(node.propertyName, target.entity)) {
- return node.realTarget;
- } else if (node.isCascaded && node.operator.offset + 1 == offset) {
- return node.realTarget;
- }
- }
- if (node is PrefixedIdentifier) {
- if (identical(node.identifier, target.entity)) {
- return node.prefix;
- }
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index 9b6634c..aa75988 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -15,24 +15,22 @@
/// A contributor that produces suggestions based on the members of an
/// extension.
class ExtensionMemberContributor extends DartCompletionContributor {
- late MemberSuggestionBuilder memberBuilder;
+ late final memberBuilder = MemberSuggestionBuilder(request, builder);
ExtensionMemberContributor(
DartCompletionRequest request,
SuggestionBuilder builder,
) : super(request, builder);
- @override
- Future<void> computeSuggestions() async {
+ void addExtensions(List<ExtensionElement> extensions) {
var containingLibrary = request.libraryElement;
- memberBuilder = MemberSuggestionBuilder(request, builder);
var defaultKind = request.target.isFunctionalArgument()
? CompletionSuggestionKind.IDENTIFIER
: request.opType.suggestKind;
// Recompute the target because resolution might have changed it.
- var expression = request.dotTarget;
+ var expression = request.target.dotTarget;
if (expression == null) {
if (!request.includeIdentifiers) {
@@ -44,7 +42,7 @@
if (classOrMixin != null) {
var type = classOrMixin.declaredElement?.thisType;
if (type != null) {
- _addExtensionMembers(containingLibrary, defaultKind, type);
+ _addExtensionMembers(extensions, defaultKind, type);
}
} else {
var extension = request.target.containingNode
@@ -59,7 +57,7 @@
extendedType.element, type.element);
_addTypeMembers(type, defaultKind, inheritanceDistance);
}
- _addExtensionMembers(containingLibrary, defaultKind, extendedType);
+ _addExtensionMembers(extensions, defaultKind, extendedType);
}
}
}
@@ -103,15 +101,23 @@
// invoked on a non-null value.
type = containingLibrary.typeSystem.promoteToNonNull(type);
}
- _addExtensionMembers(containingLibrary, defaultKind, type);
+ _addExtensionMembers(extensions, defaultKind, type);
expression.staticType;
}
}
- void _addExtensionMembers(LibraryElement containingLibrary,
+ @override
+ Future<void> computeSuggestions() async {
+ addExtensions(
+ request.libraryElement.accessibleExtensions,
+ );
+ }
+
+ void _addExtensionMembers(List<ExtensionElement> extensions,
CompletionSuggestionKind? kind, DartType type) {
+ var containingLibrary = request.libraryElement;
var typeSystem = containingLibrary.typeSystem;
- for (var extension in containingLibrary.accessibleExtensions) {
+ for (var extension in extensions) {
var extendedType =
extension.resolvedExtendedType(containingLibrary, type);
if (extendedType != null && typeSystem.isSubtypeOf(type, extendedType)) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index 5654e30..d9675cb 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -23,7 +23,7 @@
@override
Future<void> computeSuggestions() async {
// Determine if the target looks like a library prefix.
- var targetId = request.dotTarget;
+ var targetId = request.target.dotTarget;
if (targetId is SimpleIdentifier && !request.target.isCascade) {
var elem = targetId.staticElement;
if (elem is PrefixElement && !elem.isSynthetic) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
index 938228c..629fe475 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
@@ -6,13 +6,13 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_member_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
-import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
- show SuggestionBuilder;
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
-import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/lint/pub.dart';
import 'package:analyzer/src/workspace/pub.dart';
import 'package:collection/collection.dart';
@@ -36,10 +36,6 @@
@override
Future<void> computeSuggestions() async {
- if (!request.includeIdentifiers) {
- return;
- }
-
var session = request.result.session as AnalysisSessionImpl;
var analysisDriver = session.getDriver(); // ignore: deprecated_member_use
@@ -52,6 +48,9 @@
return;
}
+ // Use single instance to track getter / setter pairs.
+ var extensionContributor = ExtensionMemberContributor(request, builder);
+
var knownFiles = fsState.knownFiles.toList();
for (var file in knownFiles) {
onFile?.call(file);
@@ -70,10 +69,17 @@
continue;
}
+ var exportNamespace = elementResult.element.exportNamespace;
+ var exportElements = exportNamespace.definedNames.values.toList();
+
var newSuggestions = builder.markSuggestions();
- _buildSuggestions(
- elementResult.element.exportNamespace,
+ if (request.includeIdentifiers) {
+ _buildSuggestions(exportElements);
+ }
+
+ extensionContributor.addExtensions(
+ exportElements.whereType<ExtensionElement>().toList(),
);
newSuggestions.setLibraryUriToImportIndex(() {
@@ -93,9 +99,9 @@
}
}
- void _buildSuggestions(Namespace namespace) {
+ void _buildSuggestions(List<Element> elements) {
var visitor = LibraryElementSuggestionBuilder(request, builder);
- for (var element in namespace.definedNames.values) {
+ for (var element in elements) {
element.accept(visitor);
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index ec104fa..62adabb 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -23,7 +23,7 @@
Future<void> computeSuggestions() async {
var library = request.libraryElement;
bool isVisible(Element element) => element.isAccessibleIn(library);
- var targetId = request.dotTarget;
+ var targetId = request.target.dotTarget;
if (targetId is Identifier && !request.target.isCascade) {
var element = targetId.staticElement;
if (element is TypeAliasElement) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 06ce9e7..7de9949 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -250,7 +250,7 @@
String? get _containingMemberName {
if (!_hasContainingMemberName) {
_hasContainingMemberName = true;
- if (request.dotTarget is SuperExpression) {
+ if (request.target.dotTarget is SuperExpression) {
var containingMethod = request.target.containingNode
.thisOrAncestorOfType<MethodDeclaration>();
if (containingMethod != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index 66b7f47..589c793 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -26,7 +26,7 @@
@override
Future<void> computeSuggestions() async {
// Recompute the target because resolution might have changed it.
- var expression = request.dotTarget;
+ var expression = request.target.dotTarget;
if (expression == null ||
expression.isSynthetic ||
expression is ExtensionOverride) {
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 586a217..c2e4e39 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -4,7 +4,6 @@
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
-import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/base_processor.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
@@ -171,46 +170,6 @@
return assists;
}
- Future<List<Assist>> computeAssist(AssistKind assistKind) async {
- var context = CorrectionProducerContext.create(
- selectionOffset: selectionOffset,
- selectionLength: selectionLength,
- resolvedResult: resolvedResult,
- workspace: workspace,
- );
- if (context == null) {
- return assists;
- }
-
- Future<void> compute(CorrectionProducer producer) async {
- producer.configure(context);
-
- var builder = ChangeBuilder(
- workspace: context.workspace, eol: context.utils.endOfLine);
- await producer.compute(builder);
-
- var assistKind = producer.assistKind;
- if (assistKind != null) {
- _addAssistFromBuilder(builder, assistKind,
- args: producer.assistArguments);
- }
- }
-
- // Calculate only specific assists for edit.dartFix
- if (assistKind == DartAssistKind.CONVERT_CLASS_TO_MIXIN) {
- await compute(ConvertClassToMixin());
- } else if (assistKind == DartAssistKind.CONVERT_TO_INT_LITERAL) {
- await compute(ConvertToIntLiteral());
- } else if (assistKind == DartAssistKind.CONVERT_TO_SPREAD) {
- await compute(ConvertAddAllToSpread());
- } else if (assistKind == DartAssistKind.CONVERT_TO_FOR_ELEMENT) {
- await compute(ConvertMapFromIterableToForLiteral());
- } else if (assistKind == DartAssistKind.CONVERT_TO_IF_ELEMENT) {
- await compute(ConvertConditionalExpressionToIfElement());
- }
- return assists;
- }
-
void _addAssistFromBuilder(ChangeBuilder builder, AssistKind kind,
{List<Object>? args}) {
var change = builder.sourceChange;
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 67f769b..26bcfbd 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -229,15 +229,15 @@
dartFixContext: context,
diagnostic: error,
resolvedResult: resolveResult,
- selectionOffset: context.error.offset,
- selectionLength: context.error.length,
+ selectionOffset: error.offset,
+ selectionLength: error.length,
workspace: workspace,
);
if (correctionContext == null) {
return const <Fix>[];
}
- var generators = _getGenerators(error.errorCode, correctionContext);
+ var generators = _getGenerators(error.errorCode);
var fixes = <Fix>[];
for (var generator in generators) {
@@ -309,8 +309,7 @@
}
}
- List<ProducerGenerator> _getGenerators(
- ErrorCode errorCode, CorrectionProducerContext context) {
+ List<ProducerGenerator> _getGenerators(ErrorCode errorCode) {
if (errorCode is LintCode) {
return FixProcessor.lintProducerMap[errorCode.name] ?? [];
} else {
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 615fc09..2a46330 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -892,7 +892,7 @@
suggestions.withCompletion('foo02').assertSingle().assertMethod();
}
- Future<void> test_prefixed_extensionGetters() async {
+ Future<void> test_prefixed_expression_extensionGetters() async {
await _configureWithWorkspaceRoot();
var responseValidator = await _getTestCodeSuggestions(r'''
@@ -922,7 +922,255 @@
suggestionsValidator.withCompletion('foo02').assertSingle().assertGetter();
}
- /// TODO(scheglov) Also not imported, with type checks.
+ Future<void> test_prefixed_expression_extensionGetters_notImported() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ int get foo01 => 0;
+ int get bar => 0;
+}
+
+extension E2 on int {
+ int get foo02 => 0;
+}
+
+extension E3 on double {
+ int get foo03 => 0;
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle()
+ ..assertGetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ suggestionsValidator.withCompletion('foo02').assertSingle()
+ ..assertGetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
+ Future<void>
+ test_prefixed_expression_extensionGetters_notImported_private() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ int get foo01 => 0;
+}
+
+extension _E2 on int {
+ int get foo02 => 0;
+}
+
+extension on int {
+ int get foo03 => 0;
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle()
+ ..assertGetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
+ Future<void> test_prefixed_expression_extensionMethods() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+extension E1 on int {
+ void foo01() {}
+ void foo02() {}
+ void bar() {}
+}
+
+extension E2 on double {
+ void foo03() {}
+}
+
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertMethod();
+ suggestionsValidator.withCompletion('foo02').assertSingle().assertMethod();
+ }
+
+ Future<void> test_prefixed_expression_extensionMethods_notImported() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ void foo01() {}
+ void bar() {}
+}
+
+extension E2 on int {
+ void foo02() {}
+}
+
+extension E3 on double {
+ void foo03() {}
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle()
+ ..assertMethod()
+ ..assertLibraryToImport('package:test/a.dart');
+ suggestionsValidator.withCompletion('foo02').assertSingle()
+ ..assertMethod()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
+ Future<void> test_prefixed_expression_extensionSetters() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+extension E1 on int {
+ set foo01(int _) {}
+ set foo02(int _) {}
+ set bar(int _) {}
+}
+
+extension E2 on double {
+ set foo03(int _) {}
+}
+
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertSetter();
+ suggestionsValidator.withCompletion('foo02').assertSingle().assertSetter();
+ }
+
+ Future<void> test_prefixed_expression_extensionSetters_notImported() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ set foo01(int _) {}
+ set bar(int _) {}
+}
+
+extension E2 on int {
+ set foo02(int _) {}
+}
+
+extension E3 on double {
+ set foo03(int _) {}
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01', 'foo02']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle()
+ ..assertSetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ suggestionsValidator.withCompletion('foo02').assertSingle()
+ ..assertSetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
+ Future<void>
+ test_prefixed_expression_extensionSetters_notImported_private() async {
+ await _configureWithWorkspaceRoot();
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+extension E1 on int {
+ set foo01(int _) {}
+}
+
+extension _E2 on int {
+ set foo02(int _) {}
+}
+
+extension on int {
+ set foo03(int _) {}
+}
+''');
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+void f() {
+ 0.foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01']);
+
+ suggestionsValidator.withCompletion('foo01').assertSingle()
+ ..assertSetter()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
Future<void> test_prefixed_extensionGetters_imported() async {
await _configureWithWorkspaceRoot();
@@ -957,6 +1205,58 @@
suggestionsValidator.withCompletion('foo02').assertSingle().assertGetter();
}
+ Future<void> test_prefixed_extensionOverride_extensionGetters() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+extension E1 on int {
+ int get foo01 => 0;
+}
+
+extension E2 on int {
+ int get foo02 => 0;
+}
+
+void f() {
+ E1(0).foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01']);
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertGetter();
+ }
+
+ Future<void> test_prefixed_extensionOverride_extensionMethods() async {
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions(r'''
+extension E1 on int {
+ void foo01() {}
+}
+
+extension E2 on int {
+ void foo01() {}
+}
+
+void f() {
+ E1(0).foo0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4);
+
+ var suggestionsValidator = responseValidator.suggestions;
+ suggestionsValidator.assertCompletions(['foo01']);
+ suggestionsValidator.withCompletion('foo01').assertSingle().assertMethod();
+ }
+
Future<void> test_unprefixed_filters() async {
await _configureWithWorkspaceRoot();
@@ -2248,6 +2548,11 @@
expect(suggestion.element?.kind, ElementKind.METHOD);
}
+ void assertSetter() {
+ expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
+ expect(suggestion.element?.kind, ElementKind.SETTER);
+ }
+
void assertTopLevelVariable() {
expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
expect(suggestion.element?.kind, ElementKind.TOP_LEVEL_VARIABLE);
@@ -2333,6 +2638,10 @@
return withElementKind(ElementKind.CONSTRUCTOR);
}
+ SuggestionsValidator withElementGetter() {
+ return withElementKind(ElementKind.GETTER);
+ }
+
SuggestionsValidator withElementKind(ElementKind kind) {
return SuggestionsValidator(
suggestions.where((suggestion) {
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index 03f2c16..f83771a 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -42,7 +42,7 @@
expect(context.name, convertPath('/project'));
expect(context.explicitFileCount, 1); /* test.dart */
- expect(context.implicitFileCount, 4);
+ expect(context.implicitFileCount, 5);
expect(context.workItemQueueLength, isNotNull);
}
diff --git a/pkg/analyzer/lib/src/error/use_result_verifier.dart b/pkg/analyzer/lib/src/error/use_result_verifier.dart
index c6939dec..521d5b6 100644
--- a/pkg/analyzer/lib/src/error/use_result_verifier.dart
+++ b/pkg/analyzer/lib/src/error/use_result_verifier.dart
@@ -149,7 +149,9 @@
return parent.target == node;
}
- if (parent is ParenthesizedExpression || parent is ConditionalExpression) {
+ if (parent is ParenthesizedExpression ||
+ parent is ConditionalExpression ||
+ parent is AwaitExpression) {
return _isUsed(parent);
}
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 198b6a8..a7ecd5a 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -256,7 +256,7 @@
'''
library dart.core;
-import 'dart:async'; // ignore: unused_import
+import "dart:_internal" hide Symbol;
export 'dart:async' show Future, Stream;
@@ -409,7 +409,7 @@
const Iterable();
- const factory Iterable.empty() => EmptyIterable<E>();
+ const factory Iterable.empty() = EmptyIterable<E>;
bool contains(Object? element);
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 83bc4af..7a04577 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -202,6 +202,7 @@
if (withSdk) {
expectedPlusSdk
+ ..add(convertPath('/sdk/lib/_internal/internal.dart'))
..add(convertPath('/sdk/lib/async/async.dart'))
..add(convertPath('/sdk/lib/async/stream.dart'))
..add(convertPath('/sdk/lib/core/core.dart'))
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index fe578e8..148433e 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -255,6 +255,7 @@
List<String> get experiments => [
EnableString.constructor_tearoffs,
+ EnableString.named_arguments_anywhere,
];
/// The path that is not in [workspaceRootPath], contains external packages.
diff --git a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart b/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
index 63888b5..feac804 100644
--- a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
@@ -303,6 +303,46 @@
);
}
+ test_namedArgument_anywhere() async {
+ await assertNoErrorsInCode('''
+class A {
+ A(int a, double b, {bool? c, bool? d});
+}
+
+void f() {
+ A(0, c: true, 1.2, d: true);
+}
+''');
+
+ assertInstanceCreation(
+ findNode.instanceCreation('A(0'),
+ findElement.class_('A'),
+ 'A',
+ );
+
+ assertParameterElement(
+ findNode.integerLiteral('0'),
+ findElement.parameter('a'),
+ );
+
+ assertParameterElement(
+ findNode.doubleLiteral('1.2'),
+ findElement.parameter('b'),
+ );
+
+ assertParameterElement(
+ findNode.namedExpression('c: true'),
+ findElement.parameter('c'),
+ );
+ assertNamedParameterRef('c: true', 'c');
+
+ assertParameterElement(
+ findNode.namedExpression('d: true'),
+ findElement.parameter('d'),
+ );
+ assertNamedParameterRef('d: true', 'd');
+ }
+
test_typeAlias_generic_class_generic_named_infer_all() async {
await assertNoErrorsInCode(r'''
class A<T> {
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 17bac73..32d8c5d 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -2863,6 +2863,44 @@
);
}
+ test_namedArgument_anywhere() async {
+ await assertNoErrorsInCode('''
+void foo(int a, double b, {bool? c, bool? d}) {}
+
+void f() {
+ foo(0, c: true, 1.2, d: true);
+}
+''');
+
+ assertMethodInvocation(
+ findNode.methodInvocation('foo(0'),
+ findElement.topFunction('foo'),
+ 'void Function(int, double, {bool? c, bool? d})',
+ );
+
+ assertParameterElement(
+ findNode.integerLiteral('0'),
+ findElement.parameter('a'),
+ );
+
+ assertParameterElement(
+ findNode.doubleLiteral('1.2'),
+ findElement.parameter('b'),
+ );
+
+ assertParameterElement(
+ findNode.namedExpression('c: true'),
+ findElement.parameter('c'),
+ );
+ assertNamedParameterRef('c: true', 'c');
+
+ assertParameterElement(
+ findNode.namedExpression('d: true'),
+ findElement.parameter('d'),
+ );
+ assertNamedParameterRef('d: true', 'd');
+ }
+
test_nullShorting_cascade_firstMethodInvocation() async {
await assertNoErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
index 0181e0d..a1caf5d 100644
--- a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -94,7 +93,6 @@
''', [
error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 71,
1),
- error(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, 71, 1),
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 71, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
index 4e18f96..cce3dca 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
@@ -627,6 +627,20 @@
''');
}
+ test_topLevelFunction_result_awaited_future_passed() async {
+ await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+@useResult
+Future<List<String>> load() async => [];
+
+void f() async {
+ var l = [];
+ l.add(await load());
+}
+''');
+ }
+
test_topLevelFunction_result_optionNamedParam_unassigned_parameterDefined() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index f4e26a0..2fe6603 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -251,6 +251,31 @@
argIndex = _computeArgIndex(containingNode, entity),
droppedToken = _computeDroppedToken(containingNode, entity, offset);
+ /// Return the expression to the left of the "dot" or "dot dot",
+ /// or `null` if this is not a "dot" completion (e.g. `{ foo^; }`).
+ Expression? get dotTarget {
+ var node = containingNode;
+ if (node is MethodInvocation) {
+ if (identical(node.methodName, entity)) {
+ return node.realTarget;
+ } else if (node.isCascaded && node.operator!.offset + 1 == offset) {
+ return node.realTarget;
+ }
+ }
+ if (node is PropertyAccess) {
+ if (identical(node.propertyName, entity)) {
+ return node.realTarget;
+ } else if (node.isCascaded && node.operator.offset + 1 == offset) {
+ return node.realTarget;
+ }
+ }
+ if (node is PrefixedIdentifier) {
+ if (identical(node.identifier, entity)) {
+ return node.prefix;
+ }
+ }
+ }
+
/// If the target is an argument in an argument list, and the invocation is
/// resolved, return the invoked [ExecutableElement].
ExecutableElement? get executableElement {
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index 95d5833..dea31e3 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -246,6 +246,7 @@
@override
void visitArgumentList(ArgumentList node) {
+ final entity = this.entity;
var parent = node.parent;
List<ParameterElement>? parameters;
if (parent is InstanceCreationExpression) {
@@ -303,8 +304,10 @@
} else {
index = node.arguments.length - 1;
}
+ } else if (entity is Expression) {
+ index = node.arguments.indexOf(entity);
} else {
- index = node.arguments.indexOf(entity as Expression);
+ return;
}
if (0 <= index && index < parameters.length) {
var param = parameters[index];
diff --git a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
index 185d382..a27010c 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
@@ -54,30 +54,7 @@
DartCompletionRequest request, AstNode? entryPoint) {
var target = CompletionTarget.forOffset(request.result.unit, request.offset,
entryPoint: entryPoint);
- var node = target.containingNode;
- if (node is MethodInvocation) {
- if (identical(node.methodName, target.entity)) {
- return node.realTarget;
- } else if (node.isCascaded) {
- var operator = node.operator;
- if (operator != null && operator.offset + 1 == target.offset) {
- return node.realTarget;
- }
- }
- }
- if (node is PropertyAccess) {
- if (identical(node.propertyName, target.entity)) {
- return node.realTarget;
- } else if (node.isCascaded && node.operator.offset + 1 == target.offset) {
- return node.realTarget;
- }
- }
- if (node is PrefixedIdentifier) {
- if (identical(node.identifier, target.entity)) {
- return node.prefix;
- }
- }
- return null;
+ return target.dotTarget;
}
void _computeSuggestions(
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
index ba7d92f..0f66c92 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
@@ -240,6 +240,27 @@
completionLocation: 'ArgumentList_constructor_named', namedArgs: true);
}
+ Future<void> test_argumentList_inLineComment() async {
+ addTestSource('''
+void f() {
+ g(0, // ^
+ );
+}
+void g() {}
+''');
+ await assertOpType(/* No valid completions */);
+ }
+
+ Future<void> test_argumentList_inStarComment() async {
+ addTestSource('''
+void f() {
+ g(0, /*^*/);
+}
+void g() {}
+''');
+ await assertOpType(/* No valid completions */);
+ }
+
Future<void> test_argumentList_method_resolved_1_0() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('main() { foo(^);} foo({one, two}) {}');
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index b7f5dbe..bb24d00 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -935,18 +935,29 @@
bool File::SetLastAccessed(Namespace* namespc,
const char* name,
int64_t millis) {
- // First get the current times.
struct __stat64 st;
Utf8ToWideScope system_name(PrefixLongFilePath(name));
- if (!StatHelper(system_name.wide(), &st)) {
+ if (!StatHelper(system_name.wide(), &st)) { // Checks that it is a file.
return false;
}
- // Set the new time:
- struct __utimbuf64 times;
- times.actime = millis / kMillisecondsPerSecond;
- times.modtime = st.st_mtime;
- return _wutime64(system_name.wide(), ×) == 0;
+ // _utime and related functions set the access and modification times of the
+ // affected file. Even if the specified modification time is not changed
+ // from the current value, _utime will trigger a file modification event
+ // (e.g. ReadDirectoryChangesW will report the file as modified).
+ //
+ // So set the file access time directly using SetFileTime.
+ FILETIME at = GetFiletimeFromMillis(millis);
+ HANDLE file_handle =
+ CreateFileW(system_name.wide(), FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+ bool result = SetFileTime(file_handle, nullptr, &at, nullptr);
+ CloseHandle(file_handle);
+ return result;
}
bool File::SetLastModified(Namespace* namespc,
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index fcbbcbb..174ed7f 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -16,6 +16,23 @@
namespace dart {
namespace bin {
+// The offset between a `FILETIME` epoch (January 1, 1601 UTC) and a Unix
+// epoch (January 1, 1970 UTC) measured in 100ns intervals.
+//
+// See https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+static const int64_t kFileTimeEpoch = 116444736000000000LL;
+
+// Although win32 uses 64-bit integers for representing timestamps,
+// these are packed into a FILETIME structure. The FILETIME
+// structure is just a struct representing a 64-bit integer. The
+// TimeStamp union allows access to both a FILETIME and an integer
+// representation of the timestamp. The Windows timestamp is in
+// 100-nanosecond intervals since January 1, 1601.
+union TimeStamp {
+ FILETIME ft_;
+ int64_t t_;
+};
+
void FormatMessageIntoBuffer(DWORD code, wchar_t* buffer, int buffer_length) {
DWORD message_size = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code,
@@ -31,6 +48,12 @@
buffer[buffer_length - 1] = 0;
}
+FILETIME GetFiletimeFromMillis(int64_t millis) {
+ static const int64_t kTimeScaler = 10000; // 100 ns to ms.
+ TimeStamp t = {.t_ = millis * kTimeScaler + kFileTimeEpoch};
+ return t.ft_;
+}
+
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
Reload();
}
@@ -165,24 +188,12 @@
return true;
}
-// Although win32 uses 64-bit integers for representing timestamps,
-// these are packed into a FILETIME structure. The FILETIME
-// structure is just a struct representing a 64-bit integer. The
-// TimeStamp union allows access to both a FILETIME and an integer
-// representation of the timestamp. The Windows timestamp is in
-// 100-nanosecond intervals since January 1, 1601.
-union TimeStamp {
- FILETIME ft_;
- int64_t t_;
-};
-
static int64_t GetCurrentTimeMicros() {
- static const int64_t kTimeEpoc = 116444736000000000LL;
static const int64_t kTimeScaler = 10; // 100 ns to us.
TimeStamp time;
GetSystemTimeAsFileTime(&time.ft_);
- return (time.t_ - kTimeEpoc) / kTimeScaler;
+ return (time.t_ - kFileTimeEpoch) / kTimeScaler;
}
static int64_t qpc_ticks_per_second = 0;
diff --git a/runtime/bin/utils_win.h b/runtime/bin/utils_win.h
index 3d4cfe3..facee43 100644
--- a/runtime/bin/utils_win.h
+++ b/runtime/bin/utils_win.h
@@ -18,6 +18,9 @@
void FormatMessageIntoBuffer(DWORD code, wchar_t* buffer, int buffer_length);
+// Convert from milliseconds since the Unix epoch to a FILETIME.
+FILETIME GetFiletimeFromMillis(int64_t millis);
+
// These string utility functions return strings that have been allocated with
// Dart_ScopeAllocate(). They should be used only when we are inside an API
// scope. If a string returned by one of these functions must persist beyond
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index a211039..745412a 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -6692,6 +6692,9 @@
return calls_initializer() && !throw_exception_on_initialization();
}
+ virtual bool CanCallDart() const {
+ return calls_initializer() && !throw_exception_on_initialization();
+ }
virtual bool CanTriggerGC() const { return calls_initializer(); }
virtual bool MayThrow() const { return calls_initializer(); }
diff --git a/runtime/vm/compiler/write_barrier_elimination_test.cc b/runtime/vm/compiler/write_barrier_elimination_test.cc
index f483b05..936d432 100644
--- a/runtime/vm/compiler/write_barrier_elimination_test.cc
+++ b/runtime/vm/compiler/write_barrier_elimination_test.cc
@@ -252,4 +252,54 @@
EXPECT(store_into_phi->ShouldEmitStoreBarrier());
}
+ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_LoadLateField) {
+ DEBUG_ONLY(
+ SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
+ const char* kScript = R"(
+ class A {
+ late var x = new B();
+ }
+
+ class B {
+ }
+
+ class C {
+ C(this.a, this.b);
+ A a;
+ B b;
+ }
+
+ foo(A a) => C(a, a.x);
+
+ main() { foo(A()); }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+ Invoke(root_library, "main");
+
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ EXPECT(entry != nullptr);
+
+ StoreInstanceFieldInstr* store1 = nullptr;
+ StoreInstanceFieldInstr* store2 = nullptr;
+
+ ILMatcher cursor(flow_graph, entry);
+ RELEASE_ASSERT(cursor.TryMatch(
+ {
+ kMatchAndMoveAllocateObject,
+ kMatchAndMoveLoadField,
+ {kMatchAndMoveStoreInstanceField, &store1},
+ {kMatchAndMoveStoreInstanceField, &store2},
+ },
+ kMoveGlob));
+
+ EXPECT(store1->ShouldEmitStoreBarrier());
+ EXPECT(store2->ShouldEmitStoreBarrier());
+}
+
} // namespace dart
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 84cfbdf..b63102a 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -1199,7 +1199,7 @@
/// If a body is present, it must be read. Otherwise, it leads to resource
/// leaks. Consider using [HttpClientResponse.drain] if the body is unused.
///
-/// ```dart
+/// ```dart import:convert
/// var client = HttpClient();
/// try {
/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
@@ -1673,7 +1673,8 @@
/// encoding used is determined from the "charset" parameter of
/// the "Content-Type" header.
///
-/// ```dart
+/// ```dart import:convert
+/// var client = HttpClient();
/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
/// request.headers.contentType =
/// ContentType('application', 'json', charset: 'utf-8');
@@ -1683,6 +1684,7 @@
/// If no charset is provided the default of ISO-8859-1 (Latin 1) is used.
///
/// ```dart
+/// var client = HttpClient();
/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
/// request.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
/// request.write('blåbærgrød'); // Strings written will be ISO-8859-1 encoded
@@ -1783,8 +1785,9 @@
/// the request has been aborted
///
/// ```dart import:async
- /// HttpClientRequest request = ...
- /// request.write();
+ /// var client = HttpClient();
+ /// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
+ /// request.write('request content');
/// Timer(Duration(seconds: 1), () {
/// request.abort();
/// });
@@ -1804,7 +1807,7 @@
/// server. Use [Stream] methods like [`transform`][Stream.transform] and
/// [`join`][Stream.join] to access the data.
///
-/// ```dart
+/// ```dart import:convert
/// var client = HttpClient();
/// try {
/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
diff --git a/sdk/lib/_http/overrides.dart b/sdk/lib/_http/overrides.dart
index db464f8..021a978 100644
--- a/sdk/lib/_http/overrides.dart
+++ b/sdk/lib/_http/overrides.dart
@@ -13,20 +13,22 @@
/// that construct a mock implementation. The implementation in this base class
/// defaults to the actual [HttpClient] implementation. For example:
///
-/// ```dart
+/// ```dart import:io
+/// // An implementation of the HttpClient interface
/// class MyHttpClient implements HttpClient {
-/// ...
-/// // An implementation of the HttpClient interface
-/// ...
+/// MyHttpClient(SecurityContext? c);
+///
+/// @override
+/// noSuchMethod(Invocation invocation) {
+/// // your implementation here
+/// }
/// }
///
-/// main() {
+/// void main() {
/// HttpOverrides.runZoned(() {
-/// ...
/// // Operations will use MyHttpClient instead of the real HttpClient
/// // implementation whenever HttpClient is used.
-/// ...
-/// }, createHttpClient: (SecurityContext c) => MyHttpClient(c));
+/// }, createHttpClient: (SecurityContext? c) => MyHttpClient(c));
/// }
/// ```
abstract class HttpOverrides {
diff --git a/tests/standalone/io/issue_35112_test.dart b/tests/standalone/io/issue_35112_test.dart
new file mode 100644
index 0000000..1d53f1e
--- /dev/null
+++ b/tests/standalone/io/issue_35112_test.dart
@@ -0,0 +1,37 @@
+// 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:async';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+import 'test_utils.dart' show withTempDir;
+
+main() async {
+ // Verify that File.setLastAccessed does *not* trigger a FileSystemModifyEvent
+ // with FileSystemModifyEvent.contentChanged == true.
+ await withTempDir('issue_35112', (Directory tempDir) async {
+ File file = new File("${tempDir.path}/file.tmp");
+ file.createSync();
+
+ final eventCompleter = new Completer<FileSystemEvent?>();
+ StreamSubscription? subscription;
+ subscription = tempDir.watch().listen((FileSystemEvent event) {
+ if (event is FileSystemModifyEvent && event.contentChanged) {
+ eventCompleter.complete(event);
+ }
+ subscription?.cancel();
+ });
+
+ file.setLastAccessedSync(DateTime.now().add(Duration(days: 3)));
+ Timer(Duration(seconds: 1), () {
+ eventCompleter.complete(null);
+ subscription?.cancel();
+ });
+ ;
+ FileSystemEvent? event = await eventCompleter.future;
+ Expect.isNull(event,
+ "No event should be triggered or .contentChanged should equal false");
+ });
+}
diff --git a/tests/standalone_2/io/issue_35112_test.dart b/tests/standalone_2/io/issue_35112_test.dart
new file mode 100644
index 0000000..1c3cfd3
--- /dev/null
+++ b/tests/standalone_2/io/issue_35112_test.dart
@@ -0,0 +1,39 @@
+// 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.9
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+import 'test_utils.dart' show withTempDir;
+
+main() async {
+ // Verify that File.setLastAccessed does *not* trigger a FileSystemModifyEvent
+ // with FileSystemModifyEvent.contentChanged == true.
+ await withTempDir('issue_35112', (Directory tempDir) async {
+ File file = new File("${tempDir.path}/file.tmp");
+ file.createSync();
+
+ final eventCompleter = new Completer<FileSystemEvent>();
+ StreamSubscription subscription;
+ subscription = tempDir.watch().listen((FileSystemEvent event) {
+ if (event is FileSystemModifyEvent && event.contentChanged) {
+ eventCompleter.complete(event);
+ }
+ subscription?.cancel();
+ });
+
+ file.setLastAccessedSync(DateTime.now().add(Duration(days: 3)));
+ Timer(Duration(seconds: 1), () {
+ eventCompleter.complete(null);
+ subscription?.cancel();
+ });
+ ;
+ FileSystemEvent event = await eventCompleter.future;
+ Expect.isNull(event,
+ "No event should be triggered or .contentChanged should equal false");
+ });
+}
diff --git a/tools/VERSION b/tools/VERSION
index e5439cc..7f905bf 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 267
+PRERELEASE 268
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 448629c..2facefd5 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -2467,7 +2467,7 @@
"pkg//compiler/"
],
"shards": 3,
- "fileset": "web_platform"
+ "fileset": "web_platform_nnbd"
}
]
},
@@ -3474,6 +3474,7 @@
"script": "out/ReleaseX64/dart-sdk/bin/dart",
"arguments": [
"tools/verify_docs/bin/verify_docs.dart",
+ "sdk/lib/_http",
"sdk/lib/_internal",
"sdk/lib/cli",
"sdk/lib/convert",
diff --git a/tools/verify_docs/.gitignore b/tools/verify_docs/.gitignore
new file mode 100644
index 0000000..ed08bfe
--- /dev/null
+++ b/tools/verify_docs/.gitignore
@@ -0,0 +1,2 @@
+/.dart_tool/
+/.packages
diff --git a/tools/verify_docs/bin/verify_docs.dart b/tools/verify_docs/bin/verify_docs.dart
index c23b102..085223f 100644
--- a/tools/verify_docs/bin/verify_docs.dart
+++ b/tools/verify_docs/bin/verify_docs.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 'dart:collection';
import 'dart:io';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
@@ -15,7 +16,7 @@
import 'package:analyzer/file_system/overlay_file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/line_info.dart';
-import 'package:analyzer/src/dart/error/hint_codes.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/util/comment.dart';
import 'package:path/path.dart' as path;
@@ -253,38 +254,53 @@
final result = await analysisHelper.resolveFile(text);
if (result is ResolvedUnitResult) {
+ var errors = SplayTreeSet<AnalysisError>.from(
+ result.errors,
+ (a, b) {
+ var value = a.offset.compareTo(b.offset);
+ if (value == 0) {
+ value = a.message.compareTo(b.message);
+ }
+ return value;
+ },
+ );
+
// Filter out unused imports, since we speculatively add imports to some
// samples.
- var errors = result.errors.where(
- (e) => e.errorCode != HintCode.UNUSED_IMPORT,
+ errors.removeWhere(
+ (e) => e.errorCode == HintCode.UNUSED_IMPORT,
);
// Also, don't worry about 'unused_local_variable' and related; this may
// be intentional in samples.
- errors = errors.where(
+ errors.removeWhere(
(e) =>
- e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
- e.errorCode != HintCode.UNUSED_ELEMENT,
+ e.errorCode == HintCode.UNUSED_LOCAL_VARIABLE ||
+ e.errorCode == HintCode.UNUSED_ELEMENT,
);
// Remove warnings about deprecated member use from the same library.
- errors = errors.where(
+ errors.removeWhere(
(e) =>
- e.errorCode != HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE &&
- e.errorCode !=
+ e.errorCode == HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE ||
+ e.errorCode ==
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
);
+ // Handle edge case around dart:_http
+ errors.removeWhere((e) {
+ if (e.message.contains("'dart:_http'")) {
+ return e.errorCode == HintCode.UNNECESSARY_IMPORT ||
+ e.errorCode == CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY;
+ }
+ return false;
+ });
+
if (errors.isNotEmpty) {
print('$filePath:${sample.lineStartOffset}: ${errors.length} errors');
hadErrors = true;
- errors = errors.toList()
- ..sort(
- (a, b) => a.offset - b.offset,
- );
-
for (final error in errors) {
final location = result.lineInfo.getLocation(error.offset);
print(