Version 2.13.0-212.0.dev
Merge commit '0fa7878d561398d6d4df75c230deaec13a8f65a2' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 4064188..b5ad7d0 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-04-06T14:39:06.316531",
+ "generated": "2021-04-06T11:20:39.965073",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -728,6 +728,12 @@
"languageVersion": "2.12"
},
{
+ "name": "uuid",
+ "rootUri": "../third_party/pkg/uuid",
+ "packageUri": "lib/",
+ "languageVersion": "2.0"
+ },
+ {
"name": "vector_math",
"rootUri": "../third_party/pkg/vector_math",
"packageUri": "lib/",
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index c456641..f8bdd41 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -2,8 +2,6 @@
// 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
-
/// Utilities for converting Dart entities into analysis server's protocol
/// entities.
import 'package:analysis_server/src/protocol_server.dart';
@@ -130,7 +128,7 @@
}
}
-String _getParametersString(engine.Element element) {
+String? _getParametersString(engine.Element element) {
// TODO(scheglov) expose the corresponding feature from ExecutableElement
List<engine.ParameterElement> parameters;
if (element is engine.ExecutableElement) {
@@ -179,8 +177,8 @@
return '(' + sb.toString() + ')';
}
-String _getTypeParametersString(engine.Element element) {
- List<engine.TypeParameterElement> typeParameters;
+String? _getTypeParametersString(engine.Element element) {
+ List<engine.TypeParameterElement>? typeParameters;
if (element is engine.ClassElement) {
typeParameters = element.typeParameters;
} else if (element is engine.TypeAliasElement) {
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index f9abadf..bfbc6ba 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -2,8 +2,6 @@
// 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:convert';
import 'dart:io';
@@ -17,7 +15,6 @@
/// [ClientCommunicationChannel] that uses a stream and a sink (typically,
/// standard input and standard output) to communicate with servers.
class ByteStreamClientChannel implements ClientCommunicationChannel {
- final Stream input;
final IOSink output;
@override
@@ -26,23 +23,37 @@
@override
Stream<Notification> notificationStream;
- ByteStreamClientChannel(this.input, this.output) {
- Stream jsonStream = input
+ factory ByteStreamClientChannel(Stream<List<int>> input, IOSink output) {
+ var jsonStream = input
.transform(const Utf8Decoder())
.transform(LineSplitter())
.transform(JsonStreamDecoder())
- .where((json) => json is Map)
+ .where((json) => json is Map<String, Object?>)
+ .cast<Map<String, Object?>>()
.asBroadcastStream();
- responseStream = jsonStream
+ var responseStream = jsonStream
.where((json) => json[Notification.EVENT] == null)
.transform(ResponseConverter())
+ .where((response) => response != null)
+ .cast<Response>()
.asBroadcastStream();
- notificationStream = jsonStream
+ var notificationStream = jsonStream
.where((json) => json[Notification.EVENT] != null)
.transform(NotificationConverter())
.asBroadcastStream();
+ return ByteStreamClientChannel._(
+ output,
+ responseStream,
+ notificationStream,
+ );
}
+ ByteStreamClientChannel._(
+ this.output,
+ this.responseStream,
+ this.notificationStream,
+ );
+
@override
Future close() {
return output.close();
@@ -69,7 +80,7 @@
final InstrumentationService _instrumentationService;
/// The helper for recording request / response statistics.
- final RequestStatisticsHelper _requestStatistics;
+ final RequestStatisticsHelper? _requestStatistics;
/// Completer that will be signalled when the input stream is closed.
final Completer _closed = Completer();
@@ -79,7 +90,7 @@
ByteStreamServerChannel(
this._input, this._output, this._instrumentationService,
- {RequestStatisticsHelper requestStatistics})
+ {RequestStatisticsHelper? requestStatistics})
: _requestStatistics = requestStatistics {
_requestStatistics?.serverChannel = this;
}
@@ -100,12 +111,12 @@
@override
void listen(void Function(Request request) onRequest,
- {Function onError, void Function() onDone}) {
+ {Function? onError, void Function()? onDone}) {
_input.transform(const Utf8Decoder()).transform(LineSplitter()).listen(
(String data) => _readRequest(data, onRequest),
onError: onError, onDone: () {
close();
- onDone();
+ onDone?.call();
});
}
@@ -148,7 +159,7 @@
/// Read a request from the given [data] and use the given function to handle
/// the request.
- void _readRequest(Object data, void Function(Request request) onRequest) {
+ void _readRequest(String data, void Function(Request request) onRequest) {
// Ignore any further requests after the communication channel is closed.
if (_closed.isCompleted) {
return;
diff --git a/pkg/analysis_server/lib/src/channel/channel.dart b/pkg/analysis_server/lib/src/channel/channel.dart
index 627db8a..6b5e95f 100644
--- a/pkg/analysis_server/lib/src/channel/channel.dart
+++ b/pkg/analysis_server/lib/src/channel/channel.dart
@@ -2,8 +2,6 @@
// 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:convert';
import 'package:analysis_server/protocol/protocol.dart';
@@ -46,10 +44,10 @@
/// receive both [Response]s and [Notification]s.
abstract class ClientCommunicationChannel {
/// The stream of notifications from the server.
- Stream<Notification> notificationStream;
+ Stream<Notification> get notificationStream;
/// The stream of responses from the server.
- Stream<Response> responseStream;
+ Stream<Response> get responseStream;
/// Close the channel to the server. Once called, all future communication
/// with the server via [sendRequest] will silently be ignored.
@@ -60,36 +58,40 @@
Future<Response> sendRequest(Request request);
}
-/// Instances of the class [JsonStreamDecoder] convert JSON strings to JSON
-/// maps.
-class JsonStreamDecoder extends Converter<String, Map> {
+/// Instances of the class [JsonStreamDecoder] convert JSON strings to values.
+class JsonStreamDecoder extends Converter<String, Object?> {
@override
- Map convert(String text) => json.decode(text);
+ Object? convert(String text) => json.decode(text);
@override
- ChunkedConversionSink<String> startChunkedConversion(Sink<Map> sink) =>
- ChannelChunkSink<String, Map>(this, sink);
+ ChunkedConversionSink<String> startChunkedConversion(Sink<Object?> sink) =>
+ ChannelChunkSink<String, Object?>(this, sink);
}
/// Instances of the class [NotificationConverter] convert JSON maps to
/// [Notification]s.
-class NotificationConverter extends Converter<Map, Notification> {
+class NotificationConverter
+ extends Converter<Map<String, Object?>, Notification> {
@override
Notification convert(Map json) => Notification.fromJson(json);
@override
- ChunkedConversionSink<Map> startChunkedConversion(Sink<Notification> sink) =>
- ChannelChunkSink<Map, Notification>(this, sink);
+ ChunkedConversionSink<Map<String, Object?>> startChunkedConversion(
+ Sink<Notification> sink) =>
+ ChannelChunkSink<Map<String, Object?>, Notification>(this, sink);
}
/// Instances of the class [ResponseConverter] convert JSON maps to [Response]s.
-class ResponseConverter extends Converter<Map, Response> {
+class ResponseConverter extends Converter<Map<String, Object?>, Response?> {
@override
- Response convert(Map json) => Response.fromJson(json);
+ Response? convert(Map<String, Object?> json) => Response.fromJson(json);
@override
- ChunkedConversionSink<Map> startChunkedConversion(Sink<Response> sink) =>
- ChannelChunkSink<Map, Response>(this, sink);
+ ChunkedConversionSink<Map<String, Object?>> startChunkedConversion(
+ Sink<Response?> sink,
+ ) {
+ return ChannelChunkSink<Map<String, Object?>, Response?>(this, sink);
+ }
}
/// The abstract class [ServerCommunicationChannel] defines the behavior of
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index dda065c..d84f9cb 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -2,13 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analysis_server/plugin/protocol/protocol_dart.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/search/search_engine.dart'
as engine;
+import 'package:analysis_server/src/utilities/extensions/element.dart';
import 'package:analyzer/dart/analysis/results.dart' as engine;
import 'package:analyzer/dart/ast/ast.dart' as engine;
import 'package:analyzer/dart/element/element.dart' as engine;
@@ -35,7 +34,7 @@
/// Adds [edit] to the file containing the given [element].
void doSourceChange_addElementEdit(
SourceChange change, engine.Element element, SourceEdit edit) {
- var source = element.source;
+ var source = element.source!;
doSourceChange_addSourceEdit(change, source, edit);
}
@@ -47,7 +46,7 @@
change.addEdit(file, isNewFile ? -1 : 0, edit);
}
-String getAliasedTypeString(engine.Element element) {
+String? getAliasedTypeString(engine.Element element) {
if (element is engine.TypeAliasElement) {
var aliasedType = element.aliasedType;
return aliasedType.getDisplayString(withNullability: false);
@@ -55,18 +54,16 @@
return null;
}
-String getReturnTypeString(engine.Element element) {
+String? getReturnTypeString(engine.Element element) {
if (element is engine.ExecutableElement) {
if (element.kind == engine.ElementKind.SETTER) {
return null;
} else {
- return element.returnType?.getDisplayString(withNullability: false);
+ return element.returnType.getDisplayString(withNullability: false);
}
} else if (element is engine.VariableElement) {
var type = element.type;
- return type != null
- ? type.getDisplayString(withNullability: false)
- : 'dynamic';
+ return type.getDisplayString(withNullability: false);
} else if (element is engine.TypeAliasElement) {
var aliasedType = element.aliasedType;
if (aliasedType is FunctionType) {
@@ -107,7 +104,7 @@
/// If an [errorSeverity] is specified, it will override the one in [error].
AnalysisError newAnalysisError_fromEngine(
engine.ResolvedUnitResult result, engine.AnalysisError error,
- [engine.ErrorSeverity errorSeverity]) {
+ [engine.ErrorSeverity? errorSeverity]) {
var errorCode = error.errorCode;
// prepare location
Location location;
@@ -115,23 +112,16 @@
var file = error.source.fullName;
var offset = error.offset;
var length = error.length;
- var startLine = -1;
- var startColumn = -1;
- var endLine = -1;
- var endColumn = -1;
var lineInfo = result.lineInfo;
- if (lineInfo != null) {
- var startLocation = lineInfo.getLocation(offset);
- if (startLocation != null) {
- startLine = startLocation.lineNumber;
- startColumn = startLocation.columnNumber;
- }
- var endLocation = lineInfo.getLocation(offset + length);
- if (endLocation != null) {
- endLine = endLocation.lineNumber;
- endColumn = endLocation.columnNumber;
- }
- }
+
+ var startLocation = lineInfo.getLocation(offset);
+ var startLine = startLocation.lineNumber;
+ var startColumn = startLocation.columnNumber;
+
+ var endLocation = lineInfo.getLocation(offset + length);
+ var endLine = endLocation.lineNumber;
+ var endColumn = endLocation.columnNumber;
+
location = Location(
file, offset, length, startLine, startColumn, endLine, endColumn);
}
@@ -144,7 +134,7 @@
var type = AnalysisErrorType(errorCode.type.name);
var message = error.message;
var code = errorCode.name.toLowerCase();
- List<DiagnosticMessage> contextMessages;
+ List<DiagnosticMessage>? contextMessages;
if (error.contextMessages.isNotEmpty) {
contextMessages = error.contextMessages
.map((message) => newDiagnosticMessage(result, message))
@@ -182,7 +172,7 @@
}
/// Create a Location based on an [engine.Element].
-Location newLocation_fromElement(engine.Element element) {
+Location? newLocation_fromElement(engine.Element? element) {
if (element == null || element.source == null) {
return null;
}
@@ -206,8 +196,8 @@
/// Create a Location based on an [engine.AstNode].
Location newLocation_fromNode(engine.AstNode node) {
- var unit = node.thisOrAncestorOfType<engine.CompilationUnit>();
- var unitElement = unit.declaredElement;
+ var unit = node.thisOrAncestorOfType<engine.CompilationUnit>()!;
+ var unitElement = unit.declaredElement!;
var range = engine.SourceRange(node.offset, node.length);
return _locationForArgs(unitElement, range);
}
@@ -215,13 +205,13 @@
/// Create a Location based on an [engine.CompilationUnit].
Location newLocation_fromUnit(
engine.CompilationUnit unit, engine.SourceRange range) {
- return _locationForArgs(unit.declaredElement, range);
+ return _locationForArgs(unit.declaredElement!, range);
}
/// Construct based on an element from the analyzer engine.
OverriddenMember newOverriddenMember_fromEngine(engine.Element member) {
var element = convertElement(member);
- var className = member.enclosingElement.displayName;
+ var className = member.enclosingElement!.displayName;
return OverriddenMember(element, className);
}
@@ -258,22 +248,19 @@
/// Construct based on a SourceRange.
SourceEdit newSourceEdit_range(engine.SourceRange range, String replacement,
- {String id}) {
+ {String? id}) {
return SourceEdit(range.offset, range.length, replacement, id: id);
}
List<Element> _computePath(engine.Element element) {
var path = <Element>[];
- while (element != null) {
- path.add(convertElement(element));
- // go up
- if (element is engine.PrefixElement) {
- // imports are library children, but they are physically in the unit
- engine.LibraryElement library = element.enclosingElement;
- element = library.definingCompilationUnit;
- } else {
- element = element.enclosingElement;
- }
+
+ if (element is engine.PrefixElement) {
+ element = element.enclosingElement.definingCompilationUnit;
+ }
+
+ for (var e in element.withAncestors) {
+ path.add(convertElement(e));
}
return path;
}
@@ -282,18 +269,23 @@
if (element is engine.CompilationUnitElement) {
return element;
}
- if (element?.enclosingElement is engine.LibraryElement) {
- element = element.enclosingElement;
+
+ var enclosingElement = element.enclosingElement;
+ if (enclosingElement is engine.LibraryElement) {
+ element = enclosingElement;
}
+
if (element is engine.LibraryElement) {
return element.definingCompilationUnit;
}
- for (; element != null; element = element.enclosingElement) {
- if (element is engine.CompilationUnitElement) {
- return element;
+
+ for (var e in element.withAncestors) {
+ if (e is engine.CompilationUnitElement) {
+ return e;
}
}
- return null;
+
+ throw StateError('No unit: $element');
}
/// Creates a new [Location].
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 9cee80a..e2bf228 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -28,7 +28,6 @@
if (withPotential && _isMemberElement(element)) {
var name = element.displayName;
var matches = await searchEngine.searchMemberReferences(name);
- matches = SearchMatch.withNotNullElement(matches);
results.addAll(matches.where((match) => !match.isResolved).map(toResult));
}
@@ -51,7 +50,6 @@
Future<List<SearchResult>> _findSingleElementReferences(
Element element) async {
var matches = await searchEngine.searchReferences(element);
- matches = SearchMatch.withNotNullElement(matches);
return matches.map(toResult).toList();
}
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 80b84ce..1317e40 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -70,7 +70,6 @@
request, protocol.SearchFindMemberDeclarationsResult(searchId));
// search
var matches = await searchEngine.searchMemberDeclarations(params.name);
- matches = SearchMatch.withNotNullElement(matches);
_sendSearchNotification(searchId, true, matches.map(toResult));
}
@@ -83,7 +82,6 @@
request, protocol.SearchFindMemberReferencesResult(searchId));
// search
var matches = await searchEngine.searchMemberReferences(params.name);
- matches = SearchMatch.withNotNullElement(matches);
_sendSearchNotification(searchId, true, matches.map(toResult));
}
@@ -106,7 +104,6 @@
request, protocol.SearchFindTopLevelDeclarationsResult(searchId));
// search
var matches = await searchEngine.searchTopLevelDeclarations(params.pattern);
- matches = SearchMatch.withNotNullElement(matches);
_sendSearchNotification(searchId, true, matches.map(toResult));
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index a2190f6..98dfce5 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart
index bbfdd2a..bd0dde1 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -11,7 +9,7 @@
abstract class Accessor {
/// Return the result of using this accessor to access a value from the
/// [target].
- AccessorResult getValue(Object target);
+ AccessorResult getValue(Object? target);
}
/// The result of using an accessor to get a result.
@@ -35,10 +33,10 @@
/// Initialize a newly created accessor to access the argument that
/// corresponds to the given [parameter].
- ArgumentAccessor(this.parameter) : assert(parameter != null);
+ ArgumentAccessor(this.parameter);
@override
- AccessorResult getValue(Object target) {
+ AccessorResult getValue(Object? target) {
if (target is AstNode) {
var argumentList = _getArgumentList(target);
if (argumentList != null) {
@@ -55,7 +53,7 @@
String toString() => 'arguments[$parameter]';
/// Return the argument list associated with the [node].
- ArgumentList _getArgumentList(AstNode node) {
+ ArgumentList? _getArgumentList(AstNode node) {
if (node is Annotation) {
return node.arguments;
} else if (node is ExtensionOverride) {
@@ -92,19 +90,16 @@
/// Initialize a newly created accessor to access the type argument at the
/// given [index].
- TypeArgumentAccessor(this.index) : assert(index != null);
+ TypeArgumentAccessor(this.index);
@override
- AccessorResult getValue(Object target) {
+ AccessorResult getValue(Object? target) {
if (target is AstNode) {
var typeArgumentList = _getTypeArgumentList(target);
if (typeArgumentList != null) {
var arguments = typeArgumentList.arguments;
if (arguments.length > index) {
- var argument = arguments[index];
- if (argument != null) {
- return ValidResult(argument);
- }
+ return ValidResult(arguments[index]);
}
}
}
@@ -115,7 +110,7 @@
String toString() => 'typeArguments[$index]';
/// Return the type argument list associated with the [node].
- TypeArgumentList _getTypeArgumentList(AstNode node) {
+ TypeArgumentList? _getTypeArgumentList(AstNode node) {
if (node is ExtensionOverride) {
return node.typeArguments;
} else if (node is InstanceCreationExpression) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
index 9eeedf3..1c24767 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
@@ -2,13 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart' show ClassElement;
import 'package:analyzer/dart/element/type.dart';
-import 'package:meta/meta.dart';
/// The path to an element.
class ElementDescriptor {
@@ -27,9 +24,9 @@
/// within the library is given by the list of [components]. The [kind] of the
/// element is represented by the key used in the data file.
ElementDescriptor(
- {@required this.libraryUris,
- @required this.kind,
- @required this.components});
+ {required this.libraryUris,
+ required this.kind,
+ required this.components});
/// Return `true` if the described element is a constructor.
bool get isConstructor => kind == ElementKind.constructorKind;
@@ -118,7 +115,7 @@
// that the method might have been in the element's class.
return true;
}
- if (components[1] == type.element.name) {
+ if (components[1] == type.element?.name) {
return true;
}
if (type is InterfaceType) {
@@ -145,7 +142,6 @@
// TODO: Handle this case.
return false;
}
- return false;
}
String _nameFromIdentifier(Identifier identifier) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_kind.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_kind.dart
index be3d61e..a3fb8b1 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_kind.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_kind.dart
@@ -2,8 +2,6 @@
// 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
-
/// An indication of the kind of an element.
enum ElementKind {
classKind,
@@ -23,7 +21,7 @@
extension ElementKindUtilities on ElementKind {
/// Return the element kind corresponding to the given [name].
- static ElementKind fromName(String name) {
+ static ElementKind? fromName(String name) {
for (var kind in ElementKind.values) {
if (kind.toString() == 'ElementKind.${name}Kind') {
return kind;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
index fe8ba62..51b100f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
@@ -2,15 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart'
show ClassElement, ExtensionElement;
import 'package:analyzer/dart/element/type.dart';
-import 'package:meta/meta.dart';
/// An object that can be used to determine whether an element is appropriate
/// for a given reference.
@@ -31,10 +28,10 @@
/// Initialize a newly created matcher representing a reference to an element
/// with the given [name] in a library that imports the [importedUris].
ElementMatcher(
- {@required this.importedUris,
- @required this.components,
- List<ElementKind> kinds})
- : assert(components != null && components.isNotEmpty),
+ {required this.importedUris,
+ required this.components,
+ List<ElementKind>? kinds})
+ : assert(components.isNotEmpty),
validKinds = kinds ?? const [];
/// Return `true` if this matcher matches the given [element].
@@ -99,7 +96,7 @@
/// Return an element matcher that will match the element that is, or should
/// be, associated with the given [node], or `null` if there is no appropriate
/// matcher for the node.
- static ElementMatcher forNode(AstNode node) {
+ static ElementMatcher? forNode(AstNode? node) {
if (node == null) {
return null;
}
@@ -122,14 +119,14 @@
/// For example, for a constructor this would be the name of the constructor
/// followed by the name of the class in which the constructor is declared
/// (with an empty string for the unnamed constructor).
- static List<String> _componentsForNode(AstNode node) {
+ static List<String>? _componentsForNode(AstNode? node) {
if (node is SimpleIdentifier) {
var parent = node.parent;
if (parent is Label && parent.parent is NamedExpression) {
// The parent of the named expression is an argument list. Because we
// don't represent parameters as elements, the element we need to match
// against is the invocation containing those arguments.
- return _componentsFromParent(parent.parent.parent);
+ return _componentsFromParent(parent.parent!.parent!);
} else if (parent is TypeName && parent.parent is ConstructorName) {
return ['', node.name];
} else if (parent is MethodDeclaration && node == parent.name) {
@@ -147,15 +144,20 @@
}
return [node.identifier.name];
} else if (node is ConstructorName) {
- return [node.name.name];
+ var constructorName = node.name;
+ if (constructorName != null) {
+ return [constructorName.name];
+ }
} else if (node is NamedType) {
return [node.name.name];
} else if (node is TypeArgumentList) {
return _componentsFromParent(node);
} else if (node is ArgumentList) {
return _componentsFromParent(node);
- } else if (node?.parent is ArgumentList) {
- return _componentsFromParent(node.parent);
+ }
+ var parent = node?.parent;
+ if (parent is ArgumentList) {
+ return _componentsFromParent(parent);
}
return null;
}
@@ -172,9 +174,13 @@
}
if (element != null) {
var enclosingElement = element.enclosingElement;
- if (enclosingElement is ClassElement ||
- enclosingElement is ExtensionElement) {
+ if (enclosingElement is ClassElement) {
return [identifier.name, enclosingElement.name];
+ } else if (enclosingElement is ExtensionElement) {
+ var name = enclosingElement.name;
+ if (name != null) {
+ return [identifier.name, name];
+ }
}
}
return [identifier.name];
@@ -182,7 +188,7 @@
/// Return the components for the element associated with the given [node] by
/// looking at the parent of the [node].
- static List<String> _componentsFromParent(AstNode node) {
+ static List<String>? _componentsFromParent(AstNode node) {
var parent = node.parent;
if (parent is ArgumentList) {
parent = parent.parent;
@@ -231,17 +237,20 @@
/// Return the URIs of the imports in the library containing the [node], or
/// `null` if the imports can't be determined.
- static List<Uri> _importElementsForNode(AstNode node) {
+ static List<Uri>? _importElementsForNode(AstNode node) {
var root = node.root;
if (root is! CompilationUnit) {
return null;
}
var importedUris = <Uri>[];
- var library = (root as CompilationUnit).declaredElement.library;
+ var library = root.declaredElement?.library;
+ if (library == null) {
+ return null;
+ }
for (var importElement in library.imports) {
// TODO(brianwilkerson) Filter based on combinators to help avoid making
// invalid suggestions.
- var uri = importElement.importedLibrary?.source?.uri;
+ var uri = importElement.importedLibrary?.source.uri;
if (uri != null) {
// The [uri] is `null` if the literal string is not a valid URI.
importedUris.add(uri);
@@ -251,9 +260,9 @@
}
/// Return the kinds of elements that could reasonably be referenced at the
- /// location of the [node]. If [child] is no `null` then the [node] is a
- /// parent of the original node.
- static List<ElementKind> _kindsForNode(AstNode node, {AstNode child}) {
+ /// location of the [node]. If [child] is not `null` then the [node] is a
+ /// parent of the [child].
+ static List<ElementKind>? _kindsForNode(AstNode? node, {AstNode? child}) {
if (node is ConstructorName) {
return const [ElementKind.constructorKind];
} else if (node is ExtensionOverride) {
@@ -261,8 +270,8 @@
} else if (node is InstanceCreationExpression) {
return const [ElementKind.constructorKind];
} else if (node is Label) {
- var argumentList = node.parent.parent;
- return _kindsForNode(argumentList.parent, child: argumentList);
+ var argumentList = node.parent?.parent;
+ return _kindsForNode(argumentList?.parent, child: argumentList);
} else if (node is MethodInvocation) {
assert(child != null);
if (node.target == child) {
@@ -315,7 +324,7 @@
}
/// Return the name of the class associated with the given [target].
- static String _nameOfTarget(Expression target) {
+ static String? _nameOfTarget(Expression? target) {
if (target is SimpleIdentifier) {
var type = target.staticType;
if (type != null) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/parameter_reference.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/parameter_reference.dart
index 662a953..ffd9683 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/parameter_reference.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/parameter_reference.dart
@@ -2,8 +2,6 @@
// 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 'package:analyzer/dart/ast/ast.dart';
/// A reference to a named parameter.
@@ -16,7 +14,7 @@
NamedParameterReference(this.name) : assert(name.isNotEmpty);
@override
- Expression argumentFrom(ArgumentList argumentList) {
+ Expression? argumentFrom(ArgumentList argumentList) {
for (var argument in argumentList.arguments) {
if (argument is NamedExpression && argument.name.label.name == name) {
return argument.expression;
@@ -35,7 +33,7 @@
/// parameter, or `null` if there is no argument corresponding to the
/// parameter. Note that for named parameters this will be an expression whose
/// parent is a named expression.
- Expression argumentFrom(ArgumentList argumentList);
+ Expression? argumentFrom(ArgumentList argumentList);
}
/// A reference to a positional parameter.
@@ -48,7 +46,7 @@
PositionalParameterReference(this.index) : assert(index >= 0);
@override
- Expression argumentFrom(ArgumentList argumentList) {
+ Expression? argumentFrom(ArgumentList argumentList) {
var arguments = argumentList.arguments;
if (index >= arguments.length) {
return null;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override.dart
index b873aba..857336c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override.dart
@@ -2,10 +2,6 @@
// 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 'package:meta/meta.dart';
-
/// A description of a set of changes to a single transform.
class TransformOverride {
/// The title of the transform being overridden.
@@ -13,12 +9,12 @@
/// The overridden value of the `bulkApply` property of the transform, or
/// `null` if the property should not be overridden.
- final bool bulkApply;
+ final bool? bulkApply;
/// Initialize a newly created transform override to override the transform
/// with the given [title]. The remaining parameters correspond to properties
/// of the transform. They should have non-null values when the property is to
/// be overridden, and a value of `null` when the property should be
/// unchanged.
- TransformOverride({@required this.title, this.bulkApply});
+ TransformOverride({required this.title, this.bulkApply});
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override_set.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override_set.dart
index 9b18a0f..14d186a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override_set.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_override_set.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/correction/fix/data_driven/transform_override.dart';
/// A description of a set of transform overrides.
@@ -24,5 +22,5 @@
/// Return the override for the transform with the given [title] or `null` if
/// there is no such override in this set.
- TransformOverride overrideForTransform(String title) => overrideMap[title];
+ TransformOverride? overrideForTransform(String title) => overrideMap[title];
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 10a8af9..1f68a5c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -2,8 +2,6 @@
// 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
-
// ignore_for_file: prefer_single_quotes, slash_for_doc_comments
import 'package:analyzer/error/error.dart';
@@ -160,7 +158,7 @@
const TransformSetErrorCode(
String name,
String message, {
- String correction,
+ String? correction,
bool hasPublishedDocs = false,
}) : super(
correction: correction,
diff --git a/pkg/analysis_server/lib/src/services/correction/status.dart b/pkg/analysis_server/lib/src/services/correction/status.dart
index d552874..d148d34 100644
--- a/pkg/analysis_server/lib/src/services/correction/status.dart
+++ b/pkg/analysis_server/lib/src/services/correction/status.dart
@@ -2,15 +2,13 @@
// 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 'package:analyzer_plugin/protocol/protocol_common.dart';
/// An outcome of a condition checking operation.
class RefactoringStatus {
/// The current severity of this [RefactoringStatus] - the maximum of the
/// severities of its [entries].
- RefactoringProblemSeverity _severity;
+ RefactoringProblemSeverity? _severity;
/// A list of [RefactoringProblem]s.
final List<RefactoringProblem> problems = [];
@@ -19,21 +17,21 @@
RefactoringStatus();
/// Creates a new [RefactoringStatus] with the ERROR severity.
- factory RefactoringStatus.error(String msg, [Location location]) {
+ factory RefactoringStatus.error(String msg, [Location? location]) {
var status = RefactoringStatus();
status.addError(msg, location);
return status;
}
/// Creates a new [RefactoringStatus] with the FATAL severity.
- factory RefactoringStatus.fatal(String msg, [Location location]) {
+ factory RefactoringStatus.fatal(String msg, [Location? location]) {
var status = RefactoringStatus();
status.addFatalError(msg, location);
return status;
}
/// Creates a new [RefactoringStatus] with the WARNING severity.
- factory RefactoringStatus.warning(String msg, [Location location]) {
+ factory RefactoringStatus.warning(String msg, [Location? location]) {
var status = RefactoringStatus();
status.addWarning(msg, location);
return status;
@@ -56,7 +54,7 @@
/// Returns the message of the [RefactoringProblem] with highest severity;
/// may be `null` if no problems.
- String get message {
+ String? get message {
var problem = this.problem;
if (problem == null) {
return null;
@@ -67,7 +65,7 @@
/// Returns the first [RefactoringProblem] with the highest severity.
///
/// Returns `null` if no entries.
- RefactoringProblem get problem {
+ RefactoringProblem? get problem {
for (var problem in problems) {
if (problem.severity == _severity) {
return problem;
@@ -77,16 +75,16 @@
}
/// Returns the current severity of this [RefactoringStatus].
- RefactoringProblemSeverity get severity => _severity;
+ RefactoringProblemSeverity? get severity => _severity;
/// Adds an ERROR problem with the given message and location.
- void addError(String msg, [Location location]) {
+ void addError(String msg, [Location? location]) {
_addProblem(RefactoringProblem(RefactoringProblemSeverity.ERROR, msg,
location: location));
}
/// Adds a FATAL problem with the given message and location.
- void addFatalError(String msg, [Location location]) {
+ void addFatalError(String msg, [Location? location]) {
_addProblem(RefactoringProblem(RefactoringProblemSeverity.FATAL, msg,
location: location));
}
@@ -98,7 +96,7 @@
/// The resulting severity is the more severe of this and [other] severities.
///
/// Merging with `null` is allowed - it has no effect.
- void addStatus(RefactoringStatus other) {
+ void addStatus(RefactoringStatus? other) {
if (other == null) {
return;
}
@@ -107,7 +105,7 @@
}
/// Adds a WARNING problem with the given message and location.
- void addWarning(String msg, [Location location]) {
+ void addWarning(String msg, [Location? location]) {
_addProblem(RefactoringProblem(RefactoringProblemSeverity.WARNING, msg,
location: location));
}
@@ -116,10 +114,11 @@
String toString() {
var sb = StringBuffer();
sb.write('<');
- if (_severity == null) {
+ var severity = _severity;
+ if (severity == null) {
sb.write('OK');
} else {
- sb.write(_severity.name);
+ sb.write(severity.name);
}
if (!isOK) {
sb.write('\n');
diff --git a/pkg/analysis_server/lib/src/services/pub/pub_api.dart b/pkg/analysis_server/lib/src/services/pub/pub_api.dart
index a9e504a..2ba45d0 100644
--- a/pkg/analysis_server/lib/src/services/pub/pub_api.dart
+++ b/pkg/analysis_server/lib/src/services/pub/pub_api.dart
@@ -2,8 +2,6 @@
// 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:convert';
import 'dart:io';
@@ -42,7 +40,7 @@
' (+https://github.com/dart-lang/sdk)',
};
- PubApi(this.instrumentationService, http.Client httpClient,
+ PubApi(this.instrumentationService, http.Client? httpClient,
String envPubHostedUrl)
: httpClient =
httpClient != null ? _NoCloseHttpClient(httpClient) : http.Client(),
@@ -52,7 +50,7 @@
///
/// Failed requests will be retried a number of times. If no successful response
/// is received, will return null.
- Future<List<PubApiPackage>> allPackages() async {
+ Future<List<PubApiPackage>?> allPackages() async {
final json = await _getJson('$_pubHostedUrl$packageNameListPath');
if (json == null) {
return null;
@@ -73,7 +71,7 @@
/// Automatically retries the request for specific types of failures after
/// [_failedRetryInitialDelaySeconds] doubling each time. After [maxFailedRequests]
/// requests or upon a 4XX response, will return `null` and not retry.
- Future<Map<String, dynamic>> _getJson(String url) async {
+ Future<Map<String, Object?>?> _getJson(String url) async {
var requestCount = 0;
var retryAfterSeconds = _failedRetryInitialDelaySeconds;
while (requestCount++ < maxFailedRequests) {
@@ -115,7 +113,7 @@
/// Returns a valid Pub base URL from [envPubHostedUrl] if valid, otherwise using
/// the default 'https://pub.dartlang.org'.
- static String _validPubHostedUrl(String envPubHostedUrl) {
+ static String _validPubHostedUrl(String? envPubHostedUrl) {
final validUrl = envPubHostedUrl != null &&
(Uri.tryParse(envPubHostedUrl)?.isAbsolute ?? false)
? envPubHostedUrl
diff --git a/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart b/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
index 09d0c80..e958542 100644
--- a/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
+++ b/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
@@ -2,8 +2,6 @@
// 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:convert';
@@ -51,20 +49,47 @@
return PackageDetailsCache._(packages, DateTime.now().toUtc());
}
- /// Deserialises cached package data from JSON.
+ /// Deserializes cached package data from JSON.
///
/// If the JSON version does not match the current version, will return null.
- static PackageDetailsCache fromJson(Map<String, Object> json) {
+ static PackageDetailsCache? fromJson(Map<String, Object?> json) {
if (json['version'] != cacheVersion) {
return null;
}
- final packagesJson = json['packages'] as List<Object>;
- final packages = packagesJson.map((json) => PubPackage.fromJson(json));
+ final packagesJson = json['packages'];
+ if (packagesJson is! List<Object>) {
+ return null;
+ }
+
+ final packages = <PubPackage>[];
+ for (final packageJson in packagesJson) {
+ if (packageJson is! Map<String, Object?>) {
+ return null;
+ }
+ final nameJson = packageJson['packageName'];
+ if (nameJson is! String) {
+ return null;
+ }
+ packages.add(PubPackage.fromJson(nameJson));
+ }
+
final packageMap = Map.fromEntries(
- packages.map((package) => MapEntry(package.packageName, package)));
- return PackageDetailsCache._(
- packageMap, DateTime.parse(json['lastUpdated']));
+ packages.map(
+ (package) => MapEntry(package.packageName, package),
+ ),
+ );
+
+ final lastUpdatedJson = json['lastUpdated'];
+ if (lastUpdatedJson is! String) {
+ return null;
+ }
+ final lastUpdated = DateTime.tryParse(lastUpdatedJson);
+ if (lastUpdated == null) {
+ return null;
+ }
+
+ return PackageDetailsCache._(packageMap, lastUpdated);
}
}
@@ -72,15 +97,14 @@
class PubPackage {
String packageName;
- PubPackage.fromJson(Map<String, Object> json)
- : packageName = json['packageName'];
+ PubPackage.fromJson(this.packageName);
PubPackage.fromName(PubApiPackage package)
: packageName = package.packageName;
Map<String, Object> toJson() {
return {
- if (packageName != null) 'packageName': packageName,
+ 'packageName': packageName,
};
}
}
@@ -91,57 +115,60 @@
class PubPackageService {
final InstrumentationService _instrumentationService;
final PubApi _api;
- Timer _nextRequestTimer;
+ Timer? _nextRequestTimer;
/// [ResourceProvider] used for caching. This should generally be a
/// [PhysicalResourceProvider] outside of tests.
final ResourceProvider cacheResourceProvider;
- /// The current cache of package information. Initiailly null, but overwritten
- /// after first read of cache from disk or fetch from the API.
+ /// The current cache of package information. Initially `null`, but
+ /// overwritten after first read of cache from disk or fetch from the API.
@visibleForTesting
- PackageDetailsCache packageCache;
+ PackageDetailsCache? packageCache;
PubPackageService(
this._instrumentationService, this.cacheResourceProvider, this._api);
/// Gets the last set of package results or an empty List if no results.
List<PubPackage> get cachedPackages =>
- packageCache?.packages?.values?.toList() ?? [];
+ packageCache?.packages.values.toList() ?? [];
bool get isRunning => _nextRequestTimer != null;
@visibleForTesting
File get packageCacheFile {
final cacheFolder = cacheResourceProvider
- .getStateLocation('.pub-package-details-cache')
- ..create();
+ .getStateLocation('.pub-package-details-cache')!
+ ..create();
return cacheFolder.getChildAssumingFile('packages.json');
}
/// Begin a request to pre-load the package name list.
void beginPackageNamePreload() {
// If first time, try to read from disk.
- packageCache ??= readDiskCache() ?? PackageDetailsCache.empty();
+ var packageCache = this.packageCache;
+ if (packageCache == null) {
+ packageCache ??= readDiskCache() ?? PackageDetailsCache.empty();
+ this.packageCache = packageCache;
+ }
// If there is no queued request, initialize one when the current cache expires.
_nextRequestTimer ??=
Timer(packageCache.cacheTimeRemaining, _fetchFromServer);
}
- PubPackage cachedPackageDetails(String packageName) =>
- packageCache.packages[packageName];
-
@visibleForTesting
- PackageDetailsCache readDiskCache() {
+ PackageDetailsCache? readDiskCache() {
final file = packageCacheFile;
if (!file.exists) {
return null;
}
try {
final contents = file.readAsStringSync();
- final json = jsonDecode(contents) as Map<String, Object>;
- return PackageDetailsCache.fromJson(json);
+ final json = jsonDecode(contents);
+ if (json is Map<String, Object?>) {
+ return PackageDetailsCache.fromJson(json);
+ }
} catch (e) {
_instrumentationService.logError('Error reading pub cache file: $e');
return null;
@@ -159,11 +186,14 @@
Future<void> _fetchFromServer() async {
try {
final packages = await _api.allPackages();
+
+ // If we never got a valid response, just skip until the next refresh.
if (packages == null) {
- // If we never got a valid response, just skip until the next refresh.
return;
}
- packageCache = PackageDetailsCache.fromApiResults(packages);
+
+ final packageCache = PackageDetailsCache.fromApiResults(packages);
+ this.packageCache = packageCache;
writeDiskCache(packageCache);
} catch (e) {
_instrumentationService.logError('Failed to fetch packages from Pub: $e');
diff --git a/pkg/analysis_server/lib/src/services/search/element_visitors.dart b/pkg/analysis_server/lib/src/services/search/element_visitors.dart
index de03c6f..06ec9b2 100644
--- a/pkg/analysis_server/lib/src/services/search/element_visitors.dart
+++ b/pkg/analysis_server/lib/src/services/search/element_visitors.dart
@@ -2,14 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.9
-
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/visitor.dart';
/// Return the [Element] that is either [root], or one of its direct or
/// indirect children, and has the given [nameOffset].
-Element findElementByNameOffset(Element root, int nameOffset) {
+Element? findElementByNameOffset(Element? root, int nameOffset) {
if (root == null) {
return null;
}
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index 6d30c6b..7189bd6 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -2,8 +2,6 @@
// 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:collection';
import 'package:analysis_server/src/services/search/element_visitors.dart';
@@ -11,7 +9,7 @@
import 'package:analyzer/dart/element/element.dart';
/// Returns direct children of [parent].
-List<Element> getChildren(Element parent, [String name]) {
+List<Element> getChildren(Element parent, [String? name]) {
var children = <Element>[];
visitChildren(parent, (Element element) {
if (name == null || element.displayName == name) {
@@ -26,7 +24,7 @@
///
/// Includes: fields, accessors and methods.
/// Excludes: constructors and synthetic elements.
-List<Element> getClassMembers(ClassElement clazz, [String name]) {
+List<Element> getClassMembers(ClassElement clazz, [String? name]) {
var members = <Element>[];
visitChildren(clazz, (Element element) {
if (element.isSynthetic) {
@@ -58,7 +56,7 @@
/// Return the non-synthetic children of the given [extension]. This includes
/// fields, accessors and methods, but excludes synthetic elements.
-List<Element> getExtensionMembers(ExtensionElement extension, [String name]) {
+List<Element> getExtensionMembers(ExtensionElement extension, [String? name]) {
var members = <Element>[];
visitChildren(extension, (Element element) {
if (element.isSynthetic) {
@@ -84,7 +82,8 @@
SearchEngine searchEngine, ClassMemberElement member) async {
Set<ClassMemberElement> result = HashSet<ClassMemberElement>();
// extension member
- if (member.enclosingElement is ExtensionElement) {
+ var enclosingElement = member.enclosingElement;
+ if (enclosingElement is ExtensionElement) {
result.add(member);
return Future.value(result);
}
@@ -94,27 +93,29 @@
return Future.value(result);
}
// method, field, etc
- var name = member.displayName;
- ClassElement memberClass = member.enclosingElement;
- var searchClasses = getSuperClasses(memberClass);
- searchClasses.add(memberClass);
- for (var superClass in searchClasses) {
- // ignore if super- class does not declare member
- if (getClassMembers(superClass, name).isEmpty) {
- continue;
- }
- // check all sub- classes
- var subClasses = await searchEngine.searchAllSubtypes(superClass);
- subClasses.add(superClass);
- for (var subClass in subClasses) {
- var subClassMembers = getChildren(subClass, name);
- for (var member in subClassMembers) {
- if (member is ClassMemberElement) {
- result.add(member);
+ if (enclosingElement is ClassElement) {
+ var name = member.displayName;
+ var searchClasses = getSuperClasses(enclosingElement);
+ searchClasses.add(enclosingElement);
+ for (var superClass in searchClasses) {
+ // ignore if super- class does not declare member
+ if (getClassMembers(superClass, name).isEmpty) {
+ continue;
+ }
+ // check all sub- classes
+ var subClasses = await searchEngine.searchAllSubtypes(superClass);
+ subClasses.add(superClass);
+ for (var subClass in subClasses) {
+ var subClassMembers = getChildren(subClass, name);
+ for (var member in subClassMembers) {
+ if (member is ClassMemberElement) {
+ result.add(member);
+ }
}
}
}
}
+
return result;
}
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart
index 8addf0a..4b61420 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart
@@ -2,8 +2,6 @@
// 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 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -42,7 +40,7 @@
/// If the [type] has subtypes, return the set of names of members which these
/// subtypes declare, possibly empty. If the [type] does not have subtypes,
/// return `null`.
- Future<Set<String>> membersOfSubtypes(ClassElement type);
+ Future<Set<String>?> membersOfSubtypes(ClassElement type);
/// Returns all subtypes of the given [type].
///
@@ -108,12 +106,4 @@
/// The unit [Source] of the reference.
Source get unitSource;
-
- /// Return elements of [matches] which has not-null elements.
- ///
- /// When [SearchMatch.element] is not `null` we cache its value, so it cannot
- /// become `null` later.
- static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) {
- return matches.where((match) => match.element != null).toList();
- }
}
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 3f5cd22..d4247e1 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
@@ -17,7 +15,7 @@
SearchEngineImpl(this._drivers);
@override
- Future<Set<String>> membersOfSubtypes(ClassElement type) async {
+ Future<Set<String>?> membersOfSubtypes(ClassElement type) async {
var drivers = _drivers.toList();
var searchedFiles = _createSearchedFiles(drivers);
@@ -26,7 +24,7 @@
var visitedIds = <String>{};
var members = <String>{};
- Future<void> addMembers(ClassElement type, SubtypeResult subtype) async {
+ Future<void> addMembers(ClassElement? type, SubtypeResult? subtype) async {
if (subtype != null && !visitedIds.add(subtype.id)) {
return;
}
@@ -206,10 +204,10 @@
static SearchMatchImpl forElement(Element element) {
return SearchMatchImpl(
- element.source.fullName,
- element.librarySource,
- element.source,
- element.library,
+ element.source!.fullName,
+ element.librarySource!,
+ element.source!,
+ element.library!,
element,
true,
true,
@@ -220,10 +218,10 @@
static SearchMatchImpl forSearchResult(SearchResult result) {
var enclosingElement = result.enclosingElement;
return SearchMatchImpl(
- enclosingElement.source.fullName,
- enclosingElement.librarySource,
- enclosingElement.source,
- enclosingElement.library,
+ enclosingElement.source!.fullName,
+ enclosingElement.librarySource!,
+ enclosingElement.source!,
+ enclosingElement.library!,
enclosingElement,
result.isResolved,
result.isQualified,
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/element.dart b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
index 440d3ef..73e8eb8 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/element.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
@@ -40,6 +40,19 @@
return ancestor is CompilationUnitElement &&
ancestor.enclosingElement.hasDeprecated;
}
+
+ /// Return this element and all its enclosing elements.
+ Iterable<Element> get withAncestors sync* {
+ var current = this;
+ while (true) {
+ yield current;
+ var enclosing = current.enclosingElement;
+ if (enclosing == null) {
+ break;
+ }
+ current = enclosing;
+ }
+ }
}
extension MethodElementExtensions on MethodElement {
diff --git a/pkg/analysis_server/lib/src/utilities/request_statistics.dart b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
index 044be84..3921409 100644
--- a/pkg/analysis_server/lib/src/utilities/request_statistics.dart
+++ b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
@@ -2,9 +2,6 @@
// 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:convert';
import 'dart:io';
import 'package:analysis_server/protocol/protocol.dart';
@@ -20,17 +17,16 @@
final Map<String, _RequestStatistics> _statisticsMap = {};
/// The [StringSink] to which performance logger should copy its output.
- _ServerLogStringSink _perfLoggerStringSink;
+ late final _ServerLogStringSink _perfLoggerStringSink =
+ _ServerLogStringSink(this);
/// The channel to send 'server.log' notifications to.
- ByteStreamServerChannel _serverChannel;
+ ByteStreamServerChannel? _serverChannel;
/// Is `true` if the client subscribed for "server.log" notification.
bool _isNotificationSubscribed = false;
- RequestStatisticsHelper() {
- _perfLoggerStringSink = _ServerLogStringSink(this);
- }
+ RequestStatisticsHelper();
/// Set whether the client subscribed for "server.log" notification.
set isNotificationSubscribed(bool value) {
@@ -93,8 +89,8 @@
var id = response.id;
var stat = _statisticsMap.remove(id);
if (stat != null) {
- stat.responseTime = DateTime.now();
- _sendLogEntry(ServerLogEntryKind.RESPONSE, stat.toJson());
+ var responseTime = DateTime.now();
+ _sendLogEntry(ServerLogEntryKind.RESPONSE, stat.toJson(responseTime));
}
}
@@ -110,6 +106,11 @@
return;
}
+ var params = notification.params;
+ if (params == null) {
+ return;
+ }
+
var map = <String, Object>{
'event': event,
};
@@ -119,13 +120,13 @@
event == 'analysis.navigation' ||
event == 'analysis.outline' ||
event == 'analysis.overrides') {
- map['file'] = notification.params['file'];
+ map['file'] = params['file'] as String;
}
if (event == 'server.status') {
- var analysis = notification.params['analysis'];
- if (analysis is Map<String, Object>) {
- map['isAnalyzing'] = analysis['isAnalyzing'];
+ var analysis = params['analysis'];
+ if (analysis is Map<String, Object?>) {
+ map['isAnalyzing'] = analysis['isAnalyzing'] as bool;
}
}
@@ -163,9 +164,11 @@
void _sendLogEntry(ServerLogEntryKind kind, Object data) {
if (!_isNotificationSubscribed) return;
- if (_serverChannel == null) return;
- _serverChannel.sendNotification(
+ var serverChannel = _serverChannel;
+ if (serverChannel == null) return;
+
+ serverChannel.sendNotification(
Notification(
'server.log',
<String, Object>{
@@ -185,7 +188,6 @@
final DateTime clientRequestTime;
final DateTime serverRequestTime;
final List<_RequestStatisticsItem> items = [];
- DateTime responseTime;
_RequestStatistics(
this.id,
@@ -194,7 +196,7 @@
this.serverRequestTime,
);
- Map<String, Object> toJson() {
+ Map<String, Object> toJson(DateTime responseTime) {
var map = {
'id': id,
'method': method,
@@ -207,21 +209,16 @@
}
return map;
}
-
- @override
- String toString() {
- var map = toJson();
- return json.encode(map);
- }
}
class _RequestStatisticsItem {
final String name;
- final DateTime timeValue;
+ final DateTime? timeValue;
_RequestStatisticsItem(this.name, {this.timeValue});
Map<String, Object> toJson() {
+ var timeValue = this.timeValue;
if (timeValue != null) {
return {
'name': name,
@@ -238,7 +235,7 @@
_ServerLogStringSink(this.helper);
@override
- void write(Object obj) {
+ void write(Object? obj) {
throw UnimplementedError();
}
@@ -253,7 +250,7 @@
}
@override
- void writeln([Object obj = '']) {
+ void writeln([Object? obj = '']) {
helper._sendLogEntry(ServerLogEntryKind.RAW, '$obj');
}
}
diff --git a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
index 5d80b9b..0724bfe 100644
--- a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
+++ b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
@@ -2,8 +2,6 @@
// 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:convert';
import 'dart:io';
@@ -23,17 +21,17 @@
@reflectiveTest
class ByteStreamClientChannelTest {
- ByteStreamClientChannel channel;
+ late ByteStreamClientChannel channel;
/// Sink that may be used to deliver data to the channel, as though it's
/// coming from the server.
- IOSink inputSink;
+ late IOSink inputSink;
/// Sink through which the channel delivers data to the server.
- IOSink outputSink;
+ late IOSink outputSink;
/// Stream of lines sent back to the client by the channel.
- Stream<String> outputLineStream;
+ late Stream<String> outputLineStream;
void setUp() {
var inputStream = StreamController<List<int>>();
@@ -103,23 +101,23 @@
@reflectiveTest
class ByteStreamServerChannelTest {
- ByteStreamServerChannel channel;
+ late ByteStreamServerChannel channel;
/// Sink that may be used to deliver data to the channel, as though it's
/// coming from the client.
- IOSink inputSink;
+ late IOSink inputSink;
/// Stream of lines sent back to the client by the channel.
- Stream<String> outputLineStream;
+ late Stream<String> outputLineStream;
/// Stream of requests received from the channel via [listen()].
- Stream<Request> requestStream;
+ late Stream<Request> requestStream;
/// Stream of errors received from the channel via [listen()].
- Stream errorStream;
+ late Stream errorStream;
/// Future which is completed when then [listen()] reports [onDone].
- Future doneFuture;
+ late Future doneFuture;
void setUp() {
var inputStream = StreamController<List<int>>();
@@ -220,10 +218,10 @@
Future<void> test_sendNotification_exceptionInSink() async {
// This IOSink asynchronously throws an exception on any writeln().
- var outputSink = _IOSinkMock();
+ var outputSink = _IOSinkThatAsyncThrowsOnWrite();
- var channel = ByteStreamServerChannel(
- null, outputSink, InstrumentationService.NULL_SERVICE);
+ var channel = ByteStreamServerChannel(StreamController<List<int>>().stream,
+ outputSink, InstrumentationService.NULL_SERVICE);
// Attempt to send a notification.
channel.sendNotification(Notification('foo'));
@@ -245,39 +243,14 @@
}
}
-class _IOSinkMock implements IOSink {
+class _IOSinkThatAsyncThrowsOnWrite implements IOSink {
@override
- Encoding encoding;
+ dynamic noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
@override
- Future done;
-
- @override
- void add(List<int> data) {}
-
- @override
- void addError(Object error, [StackTrace stackTrace]) {}
-
- @override
- Future addStream(Stream<List<int>> stream) => null;
-
- @override
- Future close() => null;
-
- @override
- Future flush() => null;
-
- @override
- void write(Object obj) {}
-
- @override
- void writeAll(Iterable objects, [String separator = '']) {}
-
- @override
- void writeCharCode(int charCode) {}
-
- @override
- void writeln([Object obj = '']) {
+ void writeln([Object? obj = '']) {
Timer(Duration(milliseconds: 10), () {
throw '42';
});
diff --git a/pkg/analysis_server/test/channel/test_all.dart b/pkg/analysis_server/test/channel/test_all.dart
index 689c931..b712e00 100644
--- a/pkg/analysis_server/test/channel/test_all.dart
+++ b/pkg/analysis_server/test/channel/test_all.dart
@@ -2,8 +2,6 @@
// 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 'package:test/test.dart';
import 'byte_stream_channel_test.dart' as byte_stream_channel_test;
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 663687b..1f18e72 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -32,6 +32,7 @@
import 'package:test/test.dart' as test show expect;
import '../mocks.dart';
+import '../mocks_lsp.dart';
import '../src/utilities/mock_packages.dart';
const dartLanguageId = 'dart';
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index f0ca226..d6cfa2c 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -2,27 +2,17 @@
// 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:convert';
-import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp;
-import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
-import 'package:analysis_server/lsp_protocol/protocol_special.dart' as lsp;
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/timestamped_data.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
-const _jsonEncoder = JsonEncoder.withIndent(' ');
-
/// A [Matcher] that check that the given [Response] has an expected identifier
/// and has an error. The error code may optionally be checked.
-Matcher isResponseFailure(String id, [RequestErrorCode code]) =>
+Matcher isResponseFailure(String id, [RequestErrorCode? code]) =>
_IsResponseFailure(id, code);
/// A [Matcher] that check that the given [Response] has an expected identifier
@@ -30,7 +20,7 @@
Matcher isResponseSuccess(String id) => _IsResponseSuccess(id);
class MockHttpClient extends http.BaseClient {
- Future<http.Response> Function(http.BaseRequest request) sendHandler;
+ late Future<http.Response> Function(http.BaseRequest request) sendHandler;
int sendHandlerCalls = 0;
bool wasClosed = false;
@@ -57,242 +47,36 @@
}
}
-/// A mock [LspServerCommunicationChannel] for testing [LspAnalysisServer].
-class MockLspServerChannel implements LspServerCommunicationChannel {
- final StreamController<lsp.Message> _clientToServer =
- StreamController<lsp.Message>.broadcast();
- final StreamController<lsp.Message> _serverToClient =
- StreamController<lsp.Message>.broadcast();
-
- String name;
-
- /// Completer that will be signalled when the input stream is closed.
- final Completer _closed = Completer();
-
- /// Errors popups sent to the user.
- final shownErrors = <lsp.ShowMessageParams>[];
-
- /// Warning popups sent to the user.
- final shownWarnings = <lsp.ShowMessageParams>[];
-
- MockLspServerChannel(bool _printMessages) {
- if (_printMessages) {
- _serverToClient.stream
- .listen((message) => print('<== ' + jsonEncode(message)));
- _clientToServer.stream
- .listen((message) => print('==> ' + jsonEncode(message)));
- }
-
- // Keep track of any errors/warnings that are sent to the user with
- // `window/showMessage`.
- _serverToClient.stream.listen((message) {
- if (message is lsp.NotificationMessage &&
- message.method == Method.window_showMessage &&
- message.params is lsp.ShowMessageParams) {
- if (message.params?.type == MessageType.Error) {
- shownErrors.add(message.params);
- } else if (message.params?.type == MessageType.Warning) {
- shownWarnings.add(message.params);
- }
- }
- });
- }
-
- /// Future that will be completed when the input stream is closed.
+class MockSource implements Source {
@override
- Future get closed {
- return _closed.future;
- }
+ final String fullName;
- Stream<lsp.Message> get serverToClient => _serverToClient.stream;
+ MockSource({
+ this.fullName = 'mocked.dart',
+ });
@override
- void close() {
- if (!_closed.isCompleted) {
- _closed.complete();
- }
- if (!_serverToClient.isClosed) {
- _serverToClient.close();
- }
- if (!_clientToServer.isClosed) {
- _clientToServer.close();
- }
- }
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
- void listen(void Function(lsp.Message message) onMessage,
- {Function onError, void Function() onDone}) {
- _clientToServer.stream.listen(onMessage, onError: onError, onDone: onDone);
- }
-
- @override
- void sendNotification(lsp.NotificationMessage notification) {
- // Don't deliver notifications after the connection is closed.
- if (_closed.isCompleted) {
- return;
- }
-
- notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
-
- _serverToClient.add(notification);
- }
-
- void sendNotificationToServer(lsp.NotificationMessage notification) {
- // Don't deliver notifications after the connection is closed.
- if (_closed.isCompleted) {
- return;
- }
-
- notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
-
- // Wrap send request in future to simulate WebSocket.
- Future(() => _clientToServer.add(notification));
- }
-
- @override
- void sendRequest(lsp.RequestMessage request) {
- // Don't deliver notifications after the connection is closed.
- if (_closed.isCompleted) {
- return;
- }
-
- request = _convertJson(request, lsp.RequestMessage.fromJson);
-
- _serverToClient.add(request);
- }
-
- /// Send the given [request] to the server and return a future that will
- /// complete when a response associated with the [request] has been received.
- /// The value of the future will be the received response.
- Future<lsp.ResponseMessage> sendRequestToServer(lsp.RequestMessage request) {
- // No further requests should be sent after the connection is closed.
- if (_closed.isCompleted) {
- throw Exception('sendLspRequest after connection closed');
- }
-
- request = _convertJson(request, lsp.RequestMessage.fromJson);
-
- // Wrap send request in future to simulate WebSocket.
- Future(() => _clientToServer.add(request));
- return waitForResponse(request);
- }
-
- @override
- void sendResponse(lsp.ResponseMessage response) {
- // Don't deliver responses after the connection is closed.
- if (_closed.isCompleted) {
- return;
- }
-
- response = _convertJson(response, lsp.ResponseMessage.fromJson);
-
- // Wrap send response in future to simulate WebSocket.
- Future(() => _serverToClient.add(response));
- }
-
- void sendResponseToServer(lsp.ResponseMessage response) {
- // Don't deliver notifications after the connection is closed.
- if (_closed.isCompleted) {
- return;
- }
-
- response = _convertJson(response, lsp.ResponseMessage.fromJson);
-
- _clientToServer.add(response);
- }
-
- /// Return a future that will complete when a response associated with the
- /// given [request] has been received. The value of the future will be the
- /// received response. The returned future will throw an exception if a server
- /// error is reported before the response has been received.
- ///
- /// Unlike [sendLspRequest], this method assumes that the [request] has
- /// already been sent to the server.
- Future<lsp.ResponseMessage> waitForResponse(
- lsp.RequestMessage request, {
- bool throwOnError = true,
- }) async {
- final response = await _serverToClient.stream.firstWhere((message) =>
- (message is lsp.ResponseMessage && message.id == request.id) ||
- (throwOnError &&
- message is lsp.NotificationMessage &&
- message.method == Method.window_showMessage &&
- lsp.ShowMessageParams.fromJson(message.params).type ==
- MessageType.Error));
-
- if (response is lsp.ResponseMessage) {
- return response;
- } else {
- throw 'An error occurred while waiting for a response to ${request.method}: '
- '${_jsonEncoder.convert(response.toJson())}';
- }
- }
-
- /// Round trips the object to JSON and back to ensure it behaves the same as
- /// when running over the real STDIO server. Without this, the object passed
- /// to the handlers will have concrete types as constructed in tests rather
- /// than the maps as they would be (the server expects to do the conversion).
- T _convertJson<T>(
- lsp.ToJsonable message, T Function(Map<String, dynamic>) constructor) {
- return constructor(jsonDecode(jsonEncode(message.toJson())));
- }
-}
-
-class MockSource extends StringTypedMock implements Source {
- @override
- TimestampedData<String> contents;
-
- @override
- String encoding;
-
- @override
- String fullName;
-
- @override
- bool isInSystemLibrary;
-
- @override
- Source librarySource;
-
- @override
- int modificationStamp;
-
- @override
- String shortName;
-
- @override
- Source source;
-
- @override
- Uri uri;
-
- @override
- UriKind uriKind;
-
- MockSource([String name = 'mocked.dart']) : super(name);
-
- @override
- bool exists() => null;
+ String toString() => fullName;
}
class StringTypedMock {
- final String _toString;
+ final String? _toString;
StringTypedMock(this._toString);
@override
String toString() {
- if (_toString != null) {
- return _toString;
- }
- return super.toString();
+ return _toString ?? super.toString();
}
}
/// A [Matcher] that check that there are no `error` in a given [Response].
class _IsResponseFailure extends Matcher {
final String _id;
- final RequestErrorCode _code;
+ final RequestErrorCode? _code;
_IsResponseFailure(this._id, this._code);
@@ -300,8 +84,9 @@
Description describe(Description description) {
description =
description.add('response with identifier "$_id" and an error');
- if (_code != null) {
- description = description.add(' with code ${_code.name}');
+ var code = _code;
+ if (code != null) {
+ description = description.add(' with code ${code.name}');
}
return description;
}
@@ -316,8 +101,7 @@
if (error == null) {
mismatchDescription.add(' and has no error');
} else {
- mismatchDescription
- .add(' and has error code ${response.error.code.name}');
+ mismatchDescription.add(' and has error code ${error.code.name}');
}
return mismatchDescription;
}
@@ -325,10 +109,11 @@
@override
bool matches(item, Map matchState) {
Response response = item;
- if (response.id != _id || response.error == null) {
+ var error = response.error;
+ if (response.id != _id || error == null) {
return false;
}
- if (_code != null && response.error.code != _code) {
+ if (_code != null && error.code != _code) {
return false;
}
return true;
@@ -350,7 +135,7 @@
@override
Description describeMismatch(
item, Description mismatchDescription, Map matchState, bool verbose) {
- Response response = item;
+ Response? response = item;
if (response == null) {
mismatchDescription.add('is null response');
} else {
@@ -366,7 +151,7 @@
@override
bool matches(item, Map matchState) {
- Response response = item;
+ Response? response = item;
return response != null && response.id == _id && response.error == null;
}
}
diff --git a/pkg/analysis_server/test/mocks_lsp.dart b/pkg/analysis_server/test/mocks_lsp.dart
new file mode 100644
index 0000000..868b648
--- /dev/null
+++ b/pkg/analysis_server/test/mocks_lsp.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2014, 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:convert';
+
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp;
+import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart' as lsp;
+import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
+
+const _jsonEncoder = JsonEncoder.withIndent(' ');
+
+/// A mock [LspServerCommunicationChannel] for testing [LspAnalysisServer].
+class MockLspServerChannel implements LspServerCommunicationChannel {
+ final StreamController<lsp.Message> _clientToServer =
+ StreamController<lsp.Message>.broadcast();
+ final StreamController<lsp.Message> _serverToClient =
+ StreamController<lsp.Message>.broadcast();
+
+ String name;
+
+ /// Completer that will be signalled when the input stream is closed.
+ final Completer _closed = Completer();
+
+ /// Errors popups sent to the user.
+ final shownErrors = <lsp.ShowMessageParams>[];
+
+ /// Warning popups sent to the user.
+ final shownWarnings = <lsp.ShowMessageParams>[];
+
+ MockLspServerChannel(bool _printMessages) {
+ if (_printMessages) {
+ _serverToClient.stream
+ .listen((message) => print('<== ' + jsonEncode(message)));
+ _clientToServer.stream
+ .listen((message) => print('==> ' + jsonEncode(message)));
+ }
+
+ // Keep track of any errors/warnings that are sent to the user with
+ // `window/showMessage`.
+ _serverToClient.stream.listen((message) {
+ if (message is lsp.NotificationMessage &&
+ message.method == Method.window_showMessage &&
+ message.params is lsp.ShowMessageParams) {
+ if (message.params?.type == MessageType.Error) {
+ shownErrors.add(message.params);
+ } else if (message.params?.type == MessageType.Warning) {
+ shownWarnings.add(message.params);
+ }
+ }
+ });
+ }
+
+ /// Future that will be completed when the input stream is closed.
+ @override
+ Future get closed {
+ return _closed.future;
+ }
+
+ Stream<lsp.Message> get serverToClient => _serverToClient.stream;
+
+ @override
+ void close() {
+ if (!_closed.isCompleted) {
+ _closed.complete();
+ }
+ if (!_serverToClient.isClosed) {
+ _serverToClient.close();
+ }
+ if (!_clientToServer.isClosed) {
+ _clientToServer.close();
+ }
+ }
+
+ @override
+ void listen(void Function(lsp.Message message) onMessage,
+ {Function onError, void Function() onDone}) {
+ _clientToServer.stream.listen(onMessage, onError: onError, onDone: onDone);
+ }
+
+ @override
+ void sendNotification(lsp.NotificationMessage notification) {
+ // Don't deliver notifications after the connection is closed.
+ if (_closed.isCompleted) {
+ return;
+ }
+
+ notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
+
+ _serverToClient.add(notification);
+ }
+
+ void sendNotificationToServer(lsp.NotificationMessage notification) {
+ // Don't deliver notifications after the connection is closed.
+ if (_closed.isCompleted) {
+ return;
+ }
+
+ notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
+
+ // Wrap send request in future to simulate WebSocket.
+ Future(() => _clientToServer.add(notification));
+ }
+
+ @override
+ void sendRequest(lsp.RequestMessage request) {
+ // Don't deliver notifications after the connection is closed.
+ if (_closed.isCompleted) {
+ return;
+ }
+
+ request = _convertJson(request, lsp.RequestMessage.fromJson);
+
+ _serverToClient.add(request);
+ }
+
+ /// Send the given [request] to the server and return a future that will
+ /// complete when a response associated with the [request] has been received.
+ /// The value of the future will be the received response.
+ Future<lsp.ResponseMessage> sendRequestToServer(lsp.RequestMessage request) {
+ // No further requests should be sent after the connection is closed.
+ if (_closed.isCompleted) {
+ throw Exception('sendLspRequest after connection closed');
+ }
+
+ request = _convertJson(request, lsp.RequestMessage.fromJson);
+
+ // Wrap send request in future to simulate WebSocket.
+ Future(() => _clientToServer.add(request));
+ return waitForResponse(request);
+ }
+
+ @override
+ void sendResponse(lsp.ResponseMessage response) {
+ // Don't deliver responses after the connection is closed.
+ if (_closed.isCompleted) {
+ return;
+ }
+
+ response = _convertJson(response, lsp.ResponseMessage.fromJson);
+
+ // Wrap send response in future to simulate WebSocket.
+ Future(() => _serverToClient.add(response));
+ }
+
+ void sendResponseToServer(lsp.ResponseMessage response) {
+ // Don't deliver notifications after the connection is closed.
+ if (_closed.isCompleted) {
+ return;
+ }
+
+ response = _convertJson(response, lsp.ResponseMessage.fromJson);
+
+ _clientToServer.add(response);
+ }
+
+ /// Return a future that will complete when a response associated with the
+ /// given [request] has been received. The value of the future will be the
+ /// received response. The returned future will throw an exception if a server
+ /// error is reported before the response has been received.
+ ///
+ /// Unlike [sendLspRequest], this method assumes that the [request] has
+ /// already been sent to the server.
+ Future<lsp.ResponseMessage> waitForResponse(
+ lsp.RequestMessage request, {
+ bool throwOnError = true,
+ }) async {
+ final response = await _serverToClient.stream.firstWhere((message) =>
+ (message is lsp.ResponseMessage && message.id == request.id) ||
+ (throwOnError &&
+ message is lsp.NotificationMessage &&
+ message.method == Method.window_showMessage &&
+ lsp.ShowMessageParams.fromJson(message.params).type ==
+ MessageType.Error));
+
+ if (response is lsp.ResponseMessage) {
+ return response;
+ } else {
+ throw 'An error occurred while waiting for a response to ${request.method}: '
+ '${_jsonEncoder.convert(response.toJson())}';
+ }
+ }
+
+ /// Round trips the object to JSON and back to ensure it behaves the same as
+ /// when running over the real STDIO server. Without this, the object passed
+ /// to the handlers will have concrete types as constructed in tests rather
+ /// than the maps as they would be (the server expects to do the conversion).
+ T _convertJson<T>(
+ lsp.ToJsonable message, T Function(Map<String, dynamic>) constructor) {
+ return constructor(jsonDecode(jsonEncode(message.toJson())));
+ }
+}
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 65df4b5..850b29a 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -2,8 +2,6 @@
// 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:mirrors';
import 'package:analysis_server/src/protocol_server.dart'
@@ -34,37 +32,45 @@
@reflectiveTest
class AnalysisErrorTest {
- MockSource source = MockSource();
- MockAnalysisError engineError;
- ResolvedUnitResult result;
+ late MockSource source;
+ late MockAnalysisError engineError;
+ late ResolvedUnitResult result;
void setUp() {
// prepare Source
- source.fullName = 'foo.dart';
+ source = MockSource(fullName: 'foo.dart');
// prepare AnalysisError
- engineError = MockAnalysisError(source,
- engine.CompileTimeErrorCode.AMBIGUOUS_EXPORT, 10, 20, 'my message');
+ engineError = MockAnalysisError(
+ source: source,
+ errorCode: engine.CompileTimeErrorCode.AMBIGUOUS_EXPORT,
+ offset: 10,
+ length: 20,
+ message: 'my message',
+ );
// prepare ResolvedUnitResult
var lineInfo = engine.LineInfo([0, 5, 9, 20]);
- result = engine.ResolvedUnitResultImpl(null, 'foo.dart', null, true, null,
- lineInfo, false, null, [engineError]);
- }
-
- void tearDown() {
- source = null;
- engineError = null;
+ result = _ResolvedUnitResultImplMock(
+ lineInfo: lineInfo,
+ errors: [engineError],
+ );
}
void test_fromEngine_hasContextMessage() {
- engineError.contextMessages.add(engine.DiagnosticMessageImpl(
- filePath: 'bar.dart', offset: 30, length: 5, message: 'context'));
- var session = MockAnalysisSession();
- session.addFileResult(engine.FileResultImpl(
- session, 'bar.dart', null, engine.LineInfo([0, 5, 9, 20]), false));
+ engineError.contextMessages.add(
+ engine.DiagnosticMessageImpl(
+ filePath: 'bar.dart',
+ offset: 30,
+ length: 5,
+ message: 'context',
+ ),
+ );
var error = newAnalysisError_fromEngine(
- engine.ResolvedUnitResultImpl(session, 'foo.dart', null, true, null,
- engine.LineInfo([0, 5, 9, 20]), false, null, [engineError]),
- engineError);
+ _ResolvedUnitResultImplMock(
+ lineInfo: engine.LineInfo([0, 5, 9, 20]),
+ errors: [engineError],
+ ),
+ engineError,
+ );
expect(error.toJson(), {
SEVERITY: 'ERROR',
TYPE: 'COMPILE_TIME_ERROR',
@@ -99,7 +105,14 @@
}
void test_fromEngine_hasCorrection() {
- engineError.correction = 'my correction';
+ engineError = MockAnalysisError(
+ source: source,
+ errorCode: engine.CompileTimeErrorCode.AMBIGUOUS_EXPORT,
+ offset: 10,
+ length: 20,
+ message: 'my message',
+ correction: 'my correction',
+ );
var error = newAnalysisError_fromEngine(result, engineError);
expect(error.toJson(), {
SEVERITY: 'ERROR',
@@ -123,11 +136,12 @@
void test_fromEngine_hasUrl() {
engineError = MockAnalysisError(
- source,
- MockErrorCode(url: 'http://codes.dartlang.org/TEST_ERROR'),
- 10,
- 20,
- 'my message');
+ source: source,
+ errorCode: MockErrorCode(url: 'http://codes.dartlang.org/TEST_ERROR'),
+ offset: 10,
+ length: 20,
+ message: 'my message',
+ );
var error = newAnalysisError_fromEngine(result, engineError);
expect(error.toJson(), {
SEVERITY: 'ERROR',
@@ -150,11 +164,12 @@
void test_fromEngine_lint() {
engineError = MockAnalysisError(
- source,
- LintCode('my_lint', 'my message', correction: 'correction'),
- 10,
- 20,
- 'my message');
+ source: source,
+ errorCode: LintCode('my_lint', 'my message', correction: 'correction'),
+ offset: 10,
+ length: 20,
+ message: 'my message',
+ );
var error = newAnalysisError_fromEngine(result, engineError);
expect(error.toJson(), {
SEVERITY: 'INFO',
@@ -176,7 +191,13 @@
}
void test_fromEngine_noCorrection() {
- engineError.correction = null;
+ engineError = MockAnalysisError(
+ source: source,
+ errorCode: engine.CompileTimeErrorCode.AMBIGUOUS_EXPORT,
+ offset: 10,
+ length: 20,
+ message: 'my message',
+ );
var error = newAnalysisError_fromEngine(result, engineError);
expect(error.toJson(), {
SEVERITY: 'ERROR',
@@ -196,31 +217,6 @@
HAS_FIX: false
});
}
-
- void test_fromEngine_noLineInfo() {
- engineError.correction = null;
- var error = newAnalysisError_fromEngine(
- engine.ResolvedUnitResultImpl(null, 'foo.dart', null, true, null, null,
- false, null, [engineError]),
- engineError);
- expect(error.toJson(), {
- SEVERITY: 'ERROR',
- TYPE: 'COMPILE_TIME_ERROR',
- LOCATION: {
- FILE: 'foo.dart',
- OFFSET: 10,
- LENGTH: 20,
- START_LINE: -1,
- START_COLUMN: -1,
- END_LINE: -1,
- END_COLUMN: -1,
- },
- MESSAGE: 'my message',
- CODE: 'ambiguous_export',
- URL: 'https://dart.dev/tools/diagnostic-messages#ambiguous_export',
- HAS_FIX: false
- });
- }
}
@reflectiveTest
@@ -271,7 +267,7 @@
/// If the corresponding value is an [ApiEnum], then we check that converting
/// the given key results in the given value.
void run(ApiEnum Function(EngineEnum) convert,
- {Map<EngineEnum, ApiEnum> exceptions = const {}}) {
+ {Map<EngineEnum, ApiEnum?> exceptions = const {}}) {
var engineClass = reflectClass(EngineEnum);
engineClass.staticMembers.forEach((Symbol symbol, MethodMirror method) {
if (symbol == #values) {
@@ -302,49 +298,73 @@
}
class MockAnalysisError implements engine.AnalysisError {
- @override
- MockSource source;
-
- @override
- engine.ErrorCode errorCode;
-
- @override
- int offset;
-
- @override
- String message;
-
- @override
- String correction;
-
- @override
- int length;
+ final MockSource? _source;
+ final engine.ErrorCode? _errorCode;
+ final int? _offset;
+ final int? _length;
+ final String? _message;
+ final String? _correction;
+ final DiagnosticMessage? _problemMessage;
+ final String? _correctionMessage;
@override
List<DiagnosticMessage> contextMessages = <DiagnosticMessage>[];
- MockAnalysisError(
- this.source, this.errorCode, this.offset, this.length, this.message);
+ MockAnalysisError({
+ MockSource? source,
+ engine.ErrorCode? errorCode,
+ int? offset,
+ int? length,
+ String? message,
+ String? correction,
+ DiagnosticMessage? problemMessage,
+ String? correctionMessage,
+ }) : _source = source,
+ _errorCode = errorCode,
+ _offset = offset,
+ _length = length,
+ _message = message,
+ _correction = correction,
+ _problemMessage = problemMessage,
+ _correctionMessage = correctionMessage;
@override
- String get correctionMessage => null;
+ String? get correction => _correction;
@override
- DiagnosticMessage get problemMessage => null;
+ String? get correctionMessage => _correctionMessage;
@override
- Severity get severity => null;
+ engine.ErrorCode get errorCode => _errorCode!;
+
+ @override
+ int get length => _length!;
+
+ @override
+ String get message => _message!;
+
+ @override
+ int get offset => _offset!;
+
+ @override
+ DiagnosticMessage get problemMessage => _problemMessage!;
+
+ @override
+ Severity get severity => throw UnimplementedError();
+
+ @override
+ engine.Source get source => _source!;
}
class MockAnalysisSession implements AnalysisSession {
Map<String, FileResult> fileResults = {};
void addFileResult(FileResult result) {
- fileResults[result.path] = result;
+ fileResults[result.path!] = result;
}
@override
- FileResult getFile(String path) => fileResults[path];
+ FileResult getFile(String path) => fileResults[path]!;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@@ -361,7 +381,7 @@
String name;
@override
- String url;
+ String? url;
MockErrorCode(
{this.type = engine.ErrorType.COMPILE_TIME_ERROR,
@@ -393,3 +413,19 @@
throw StateError('Unexpected invocation of uniqueName');
}
}
+
+class _ResolvedUnitResultImplMock implements engine.ResolvedUnitResultImpl {
+ @override
+ final engine.LineInfo lineInfo;
+
+ @override
+ final List<engine.AnalysisError> errors;
+
+ _ResolvedUnitResultImplMock({
+ required this.lineInfo,
+ required this.errors,
+ });
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analysis_server/test/services/search/element_visitors_test.dart b/pkg/analysis_server/test/services/search/element_visitors_test.dart
index 3f2b9e4..0de43dd0 100644
--- a/pkg/analysis_server/test/services/search/element_visitors_test.dart
+++ b/pkg/analysis_server/test/services/search/element_visitors_test.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/search/element_visitors.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:test/test.dart';
@@ -62,8 +60,7 @@
}
void _assertElement(int nameOffset, ElementKind kind, String name) {
- var element = findElementByNameOffset(testUnitElement, nameOffset);
- expect(element, isNotNull);
+ var element = findElementByNameOffset(testUnitElement, nameOffset)!;
expect(element.kind, kind);
expect(element.name, name);
}
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index fc72aa4..0280926 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/search/hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -20,7 +18,7 @@
@reflectiveTest
class HierarchyTest extends AbstractSingleUnitTest {
- SearchEngineImpl searchEngine;
+ late SearchEngineImpl searchEngine;
@override
void setUp() {
@@ -73,7 +71,7 @@
var futureB = getHierarchyMembers(searchEngine, memberB).then((members) {
expect(members, unorderedEquals([memberB]));
});
- return Future.wait([futureA, futureB]);
+ await Future.wait([futureA, futureB]);
}
Future<void> test_getHierarchyMembers_fields() async {
@@ -111,7 +109,7 @@
var futureD = getHierarchyMembers(searchEngine, memberD).then((members) {
expect(members, unorderedEquals([memberD]));
});
- return Future.wait([futureA, futureB, futureC, futureD]);
+ await Future.wait([futureA, futureB, futureC, futureD]);
}
Future<void> test_getHierarchyMembers_fields_static() async {
@@ -189,7 +187,7 @@
var futureE = getHierarchyMembers(searchEngine, memberE).then((members) {
expect(members, unorderedEquals([memberD, memberE]));
});
- return Future.wait([futureA, futureB, futureC, futureD, futureE]);
+ await Future.wait([futureA, futureB, futureC, futureD, futureE]);
}
Future<void> test_getHierarchyMembers_methods_static() async {
@@ -247,7 +245,7 @@
var futureD = getHierarchyMembers(searchEngine, memberD).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberD]));
});
- return Future.wait([futureA, futureB, futureD]);
+ await Future.wait([futureA, futureB, futureD]);
}
Future<void> test_getHierarchyNamedParameters() async {
@@ -403,7 +401,7 @@
var classD = findElement.class_('D');
var classE = findElement.class_('E');
var classF = findElement.class_('F');
- var objectElement = classA.supertype.element;
+ var objectElement = classA.supertype!.element;
// Object
{
var supers = getSuperClasses(objectElement);
@@ -461,7 +459,7 @@
var m3 = findElement.mixin('M3');
var m4 = findElement.mixin('M4');
var m5 = findElement.mixin('M5');
- var object = a.supertype.element;
+ var object = a.supertype!.element;
_assertSuperClasses(object, []);
_assertSuperClasses(a, [object]);
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 593f483..664c8fd 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/dart/analysis/results.dart';
@@ -26,9 +24,9 @@
/// TODO(scheglov) This class does not really belong here.
/// Consider merging it into [AbstractContextTest].
class PubPackageResolutionTest extends AbstractContextTest {
- ResolvedUnitResult result;
- FindNode findNode;
- FindElement findElement;
+ late ResolvedUnitResult result;
+ late FindNode findNode;
+ late FindElement findElement;
String get testFilePath => '$testPackageLibPath/test.dart';
@@ -43,8 +41,8 @@
result = await resolveFile(path);
expect(result.state, ResultState.VALID);
- findNode = FindNode(result.content, result.unit);
- findElement = FindElement(result.unit);
+ findNode = FindNode(result.content!, result.unit!);
+ findElement = FindElement(result.unit!);
}
/// Put the [code] into the test file, and resolve it.
@@ -331,14 +329,14 @@
''').path;
var coreLib = await driverFor(testFilePath).getLibraryByUri('dart:core');
- var intElement = coreLib.getType('int');
+ var intElement = coreLib.getType('int')!;
var matches = await searchEngine.searchReferences(intElement);
void assertHasOne(String path, String name) {
expect(matches.where((m) {
var element = m.element;
- return element.name == name && element.source.fullName == path;
+ return element.name == name && element.source!.fullName == path;
}), hasLength(1));
}
@@ -426,7 +424,7 @@
Future _ensureContainedFilesKnown() async {
for (var driver in allDrivers) {
- var contextRoot = driver.analysisContext.contextRoot;
+ var contextRoot = driver.analysisContext!.contextRoot;
for (var file in contextRoot.analyzedFiles()) {
if (file.endsWith('.dart')) {
await driver.getUnitElement(file);
diff --git a/pkg/analysis_server/test/services/search/test_all.dart b/pkg/analysis_server/test/services/search/test_all.dart
index 123f0cf..c3f8f91 100644
--- a/pkg/analysis_server/test/services/search/test_all.dart
+++ b/pkg/analysis_server/test/services/search/test_all.dart
@@ -2,8 +2,6 @@
// 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 'package:test_reflective_loader/test_reflective_loader.dart';
import 'element_visitors_test.dart' as element_visitors;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
index a219dbc..99e8f93 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
@@ -59,7 +59,8 @@
void parse(String content) {
errorListener = GatheringErrorListener();
- var errorReporter = ErrorReporter(errorListener, MockSource('data.yaml'));
+ var errorReporter =
+ ErrorReporter(errorListener, MockSource(fullName: 'data.yaml'));
var parser = TransformOverrideSetParser(errorReporter);
result = parser.parse(content);
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
index a18e9be..8a790402 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
@@ -42,7 +42,8 @@
void parse(String content) {
errorListener = GatheringErrorListener();
- var errorReporter = ErrorReporter(errorListener, MockSource('data.yaml'));
+ var errorReporter =
+ ErrorReporter(errorListener, MockSource(fullName: 'data.yaml'));
var parser = TransformSetParser(errorReporter, 'myPackage');
result = parser.parse(content);
}
diff --git a/pkg/analysis_server/test/tool/completion_metrics/metrics_util_test.dart b/pkg/analysis_server/test/tool/completion_metrics/metrics_util_test.dart
index 9b0865d..8c83b04 100644
--- a/pkg/analysis_server/test/tool/completion_metrics/metrics_util_test.dart
+++ b/pkg/analysis_server/test/tool/completion_metrics/metrics_util_test.dart
@@ -2,8 +2,6 @@
// 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 'package:test/test.dart';
import '../../../tool/code_completion/metrics_util.dart';
@@ -172,8 +170,6 @@
@override
bool matches(item, Map matchState) {
return item is num &&
- item != null &&
- _value != null &&
num.parse(item.toStringAsFixed(fractionDigits)) ==
num.parse(_value.toStringAsFixed(fractionDigits));
}
diff --git a/pkg/analysis_server/test/tool/completion_metrics/test_all.dart b/pkg/analysis_server/test/tool/completion_metrics/test_all.dart
index 2a7e8b3..8ca30d9 100644
--- a/pkg/analysis_server/test/tool/completion_metrics/test_all.dart
+++ b/pkg/analysis_server/test/tool/completion_metrics/test_all.dart
@@ -2,8 +2,6 @@
// 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 'package:test_reflective_loader/test_reflective_loader.dart';
import 'metrics_util_test.dart' as metrics_util_test;
diff --git a/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart b/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
index 3204eeb..baa7300 100644
--- a/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
+++ b/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
@@ -2,8 +2,6 @@
// 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:io' as io;
import 'package:analysis_server/src/status/pages.dart';
@@ -17,7 +15,6 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:args/args.dart';
-import 'package:meta/meta.dart';
/// Compute metrics to determine which untyped variable declarations can be used
/// to imply an expected context type, i.e. the RHS of 'var string = ^' could be
@@ -63,7 +60,7 @@
}
/// Print usage information for this tool.
-void printUsage(ArgParser parser, {String error}) {
+void printUsage(ArgParser parser, {String? error}) {
if (error != null) {
print(error);
print('');
@@ -104,7 +101,7 @@
/// [data].
ImpliedTypeCollector(this.data);
- void handleVariableDeclaration(VariableDeclaration node, DartType dartType) {
+ void handleVariableDeclaration(VariableDeclaration node, DartType? dartType) {
// If some untyped variable declaration
if (node.equals != null && dartType == null ||
(dartType != null && (dartType.isDynamic || dartType.isVoid))) {
@@ -141,7 +138,7 @@
/// Compute the metrics for the file(s) in the [rootPath].
/// If [corpus] is true, treat rootPath as a container of packages, creating
/// a new context collection for each subdirectory.
- Future<void> compute(String rootPath, {@required bool verbose}) async {
+ Future<void> compute(String rootPath, {required bool verbose}) async {
final collection = AnalysisContextCollection(
includedPaths: [rootPath],
resourceProvider: PhysicalResourceProvider.INSTANCE,
@@ -174,7 +171,7 @@
/// output if [verbose] is `true`.
Future<void> _computeInContext(
ContextRoot root, ImpliedTypeCollector collector,
- {@required bool verbose}) async {
+ {required bool verbose}) async {
// Create a new collection to avoid consuming large quantities of memory.
final collection = AnalysisContextCollection(
includedPaths: root.includedPaths.toList(),
@@ -191,13 +188,7 @@
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult == null) {
- print('File $filePath skipped because resolved unit was null.');
- if (verbose) {
- print('');
- }
- continue;
- } else if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult.state != ResultState.VALID) {
print('File $filePath skipped because it could not be analyzed.');
if (verbose) {
print('');
@@ -217,7 +208,7 @@
continue;
}
- resolvedUnitResult.unit.accept(collector);
+ resolvedUnitResult.unit!.accept(collector);
} catch (exception, stacktrace) {
print('Exception caught analyzing: "$filePath"');
print(exception);
@@ -243,8 +234,6 @@
/// Record the variable name with the type.
void recordImpliedType(String name, String displayString) {
- assert(name != null);
- assert(displayString != null);
var nameMap = impliedTypesMap.putIfAbsent(name, () => {});
nameMap[displayString] = (nameMap[displayString] ?? 0) + 1;
}
diff --git a/pkg/analysis_server/tool/code_completion/metrics_util.dart b/pkg/analysis_server/tool/code_completion/metrics_util.dart
index 47671f0..00364e9 100644
--- a/pkg/analysis_server/tool/code_completion/metrics_util.dart
+++ b/pkg/analysis_server/tool/code_completion/metrics_util.dart
@@ -2,8 +2,6 @@
// 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 'package:analysis_server/src/status/pages.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
@@ -96,12 +94,12 @@
}
void count(String id, [int countNumber = 1]) {
- assert(id != null && id.isNotEmpty && 1 <= countNumber);
- if (_buckets.containsKey(id)) {
- _buckets[id] += countNumber;
- } else {
- _buckets.putIfAbsent(id, () => countNumber);
- }
+ assert(id.isNotEmpty && 1 <= countNumber);
+ _buckets.update(
+ id,
+ (value) => value + countNumber,
+ ifAbsent: () => countNumber,
+ );
_totalCount += countNumber;
}
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 03b5275..e7dff9b 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -489,9 +489,6 @@
}
});
- results.forEach((key, value) {
- print('$key: $value');
- });
var resolvedUnits = results.values.map((fileResult) {
var file = fileResult.file;
return ResolvedUnitResultImpl(
diff --git a/pkg/dartdev/test/commands/format_test.dart b/pkg/dartdev/test/commands/format_test.dart
index 6f36795..82e68d2 100644
--- a/pkg/dartdev/test/commands/format_test.dart
+++ b/pkg/dartdev/test/commands/format_test.dart
@@ -62,6 +62,33 @@
'Formatted lib/main.dart\nFormatted 1 file (1 changed) in '));
});
+ test('formatted with exit code set', () {
+ p = project(mainSrc: 'int get foo => 1;\n');
+ ProcessResult result = p.runSync([
+ 'format',
+ '--set-exit-if-changed',
+ p.relativeFilePath,
+ ]);
+ expect(result.exitCode, isNot(0));
+ expect(result.stderr, isEmpty);
+ expect(
+ result.stdout,
+ startsWith(
+ 'Formatted lib/main.dart\nFormatted 1 file (1 changed) in '));
+ });
+
+ test('not formatted with exit code set', () {
+ p = project(mainSrc: 'int get foo => 1;\n');
+ ProcessResult result = p.runSync([
+ 'format',
+ '--set-exit-if-changed',
+ p.relativeFilePath,
+ ]);
+ expect(result.exitCode, 0);
+ expect(result.stderr, isEmpty);
+ expect(result.stdout, startsWith('Formatted 1 file (0 changed) in '));
+ });
+
test('unknown file', () {
p = project(mainSrc: 'int get foo => 1;\n');
var unknownFilePath = '${p.relativeFilePath}-unknown-file.dart';
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
index 9ae2415..6fd9bb0 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
@@ -963,4 +963,99 @@
breakpointId: 'bp', expression: 'e', expectedResult: '1');
});
});
+
+ group('Expression compiler tests in generic method:', () {
+ var source = '''
+ class C<T1> {
+ void generic<T2>(T1 a, T2 b) {
+ // Breakpoint: bp
+ print(a);
+ print(b);
+ }
+ }
+
+ void main() => C<int>().generic<String>(0, 'hi');
+ ''';
+
+ setUpAll(() async {
+ await driver.initSource(setup, source);
+ });
+
+ tearDownAll(() {
+ driver.cleanupTest();
+ });
+
+ test('evaluate formals', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: "'\${a} \$b'",
+ expectedResult: '0 hi');
+ });
+
+ test('evaluate class type parameters', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: "'\$T1'", expectedResult: 'int');
+ });
+
+ test('evaluate method type parameters', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: "'\$T2'", expectedResult: 'String');
+ });
+ });
+
+ group('Expression compiler tests for interactions with module containers:',
+ () {
+ var source = '''
+ class A {
+ const A();
+ }
+ class B {
+ const B();
+ }
+ void foo() {
+ const a = A();
+ var check = a is int;
+ // Breakpoint: bp
+ return;
+ }
+
+ void main() => foo();
+ ''';
+
+ setUpAll(() async {
+ await driver.initSource(setup, source);
+ });
+
+ tearDownAll(() {
+ driver.cleanupTest();
+ });
+
+ test('evaluation that non-destructively appends to the type container',
+ () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'a is String',
+ expectedResult: 'false');
+ });
+
+ test('evaluation that reuses the type container', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'a is int', expectedResult: 'false');
+ });
+
+ test('evaluation that non-destructively appends to the constant container',
+ () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'const B() == const B()',
+ expectedResult: 'true');
+ });
+
+ test('evaluation that properly canonicalizes constants', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'a == const A()',
+ expectedResult: 'true');
+ });
+ });
}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_sound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_sound_test.dart
index f67ae6a9..9db3279 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_sound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_sound_test.dart
@@ -6,19 +6,29 @@
library dev_compiler.test.expression_compiler;
+import 'package:dev_compiler/dev_compiler.dart' show ModuleFormat;
import 'package:test/test.dart';
import 'expression_compiler_e2e_shared.dart';
import 'expression_compiler_e2e_suite.dart';
void main() async {
var driver = await TestDriver.init();
- var setup = SetupCompilerOptions(soundNullSafety: true);
group('(Sound null safety)', () {
tearDownAll(() {
driver.finish();
});
- runSharedTests(setup, driver);
+ group('(AMD module system)', () {
+ var setup = SetupCompilerOptions(
+ soundNullSafety: true, moduleFormat: ModuleFormat.amd);
+ runSharedTests(setup, driver);
+ });
+
+ group('(DDC module system)', () {
+ var setup = SetupCompilerOptions(
+ soundNullSafety: true, moduleFormat: ModuleFormat.ddc);
+ runSharedTests(setup, driver);
+ });
});
}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
index 1dceafe..7f79898 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -314,7 +314,7 @@
'dart_sdk.js'));
var dartLibraryPath =
escaped(p.join(ddcPath, 'lib', 'js', 'legacy', 'dart_library.js'));
- var outputPath = escaped(output.toFilePath());
+ var outputPath = output.toFilePath();
bootstrapFile.writeAsStringSync('''
<script src='$dartLibraryPath'></script>
<script src='$dartSdkPath'></script>
@@ -542,7 +542,12 @@
for (var prop in response) {
var propKey = '${prop.name}';
var propValue = '${prop.value.value}';
- jsScope[propKey] = propValue == 'null' ? propKey : propValue;
+ if (prop.value.type == 'string') {
+ propValue = "'$propValue'";
+ } else if (propValue == 'null') {
+ propValue = propKey;
+ }
+ jsScope[propKey] = propValue;
}
}
return jsScope;
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_unsound_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_unsound_test.dart
index 7ac4ce7..72df6f5 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_unsound_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_unsound_test.dart
@@ -6,19 +6,29 @@
library dev_compiler.test.expression_compiler;
+import 'package:dev_compiler/dev_compiler.dart' show ModuleFormat;
import 'package:test/test.dart';
import 'expression_compiler_e2e_shared.dart';
import 'expression_compiler_e2e_suite.dart';
void main() async {
var driver = await TestDriver.init();
- var setup = SetupCompilerOptions(soundNullSafety: false);
group('(Unsound null safety)', () {
tearDownAll(() {
driver.finish();
});
- runSharedTests(setup, driver);
+ group('(AMD module system)', () {
+ var setup = SetupCompilerOptions(
+ soundNullSafety: false, moduleFormat: ModuleFormat.amd);
+ runSharedTests(setup, driver);
+ });
+
+ group('(DDC module system)', () {
+ var setup = SetupCompilerOptions(
+ soundNullSafety: false, moduleFormat: ModuleFormat.ddc);
+ runSharedTests(setup, driver);
+ });
});
}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 17e60eb..d5fbeea 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -405,149 +405,6 @@
});
});
- group('Expression compiler extension symbols tests', () {
- var source = '''
- ${options.dartLangComment}
-
- main() {
- List<int> list = {};
- list.add(0);
- /* evaluation placeholder */
- }
- ''';
-
- TestDriver driver;
-
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('extension symbol used in original compilation', () async {
- await driver.check(
- scope: <String, String>{'list': 'list'},
- expression: 'list.add(1)',
- expectedResult: '''
- (function(list) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dartx = dart_sdk.dartx;
- var \$add = dartx.add;
- var S = {\$add: dartx.add};
- return list[\$add](1);
- }(
- list
- ))
- ''');
- });
-
- test('extension symbol used only in expression compilation',
- () async {
- await driver.check(
- scope: <String, String>{'list': 'list'},
- expression: 'list.first',
- expectedResult: '''
- (function(list) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dartx = dart_sdk.dartx;
- var S = {\$first: dartx.first};
- return list[S.\$first];
- }(
- list
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in closures:', () {
- var source = '''
- ${options.dartLangComment}
- int globalFunction() {
- int x = 15;
- var c = C(1, 2);
-
- var outerClosure = (int y) {
- var closureCaptureInner = (int z) {
- /* evaluation placeholder */
- print('\$y+\$z');
- };
- closureCaptureInner(0);
- };
-
- outerClosure(3);
- return 0;
- }
-
- main() => 0;
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- }, expression: 'typo', expectedError: "Getter not found: 'typo'.");
- });
-
- test('expression using uncaptured variables', () async {
- await driver.check(
- scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- },
- expression: "'\$x+\$y+\$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.str(x) + "+" + dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
-
- test('expression using captured variables', () async {
- await driver.check(
- scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- },
- expression: "'\$y+\$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
- });
-
group(
'Expression compiler tests for interactions with module containers:',
() {
@@ -679,74 +536,6 @@
});
});
- group('Expression compiler tests in generic method:', () {
- var source = '''
- ${options.dartLangComment}
- class A {
- void generic<TType, KType>(TType a, KType b) {
- /* evaluation placeholder */
- print(a);
- print(b);
- }
- }
-
- void main() => generic<int, String>(0, 'hi');
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('evaluate formals', () async {
- await driver.check(
- scope: <String, String>{
- 'TType': 'TType',
- 'KType': 'KType',
- 'a': 'a',
- 'b': 'b'
- },
- expression: 'a',
- expectedResult: '''
- (function(TType, KType, a, b) {
- return a;
- }.bind(this)(
- TType,
- KType,
- a,
- b
- ))
- ''');
- });
-
- test('evaluate type parameters', () async {
- await driver.check(
- scope: <String, String>{
- 'TType': 'TType',
- 'KType': 'KType',
- 'a': 'a',
- 'b': 'b'
- },
- expression: 'TType',
- expectedResult: '''
- (function(TType, KType, a, b) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.wrapType(dart.legacy(TType));
- }.bind(this)(
- TType,
- KType,
- a,
- b
- ))
- ''');
- });
- });
-
group('Expression compiler tests using extension symbols', () {
var source = '''
${options.dartLangComment}
@@ -878,218 +667,8 @@
});
});
- group('Expression compiler extension symbols tests', () {
- var source = '''
- ${options.dartLangComment}
-
- main() {
- List<int> list = {};
- list.add(0);
- /* evaluation placeholder */
- }
- ''';
-
- TestDriver driver;
-
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('extension symbol used in original compilation', () async {
- await driver.check(
- scope: <String, String>{'list': 'list'},
- expression: 'list.add(1)',
- expectedResult: '''
- (function(list) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dartx = dart_sdk.dartx;
- var \$add = dartx.add;
- var S = {\$add: dartx.add};
- return list[\$add](1);
- }(
- list
- ))
- ''');
- });
-
- test('extension symbol used only in expression compilation',
- () async {
- await driver.check(
- scope: <String, String>{'list': 'list'},
- expression: 'list.first',
- expectedResult: '''
- (function(list) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dartx = dart_sdk.dartx;
- var S = {\$first: dartx.first};
- return list[S.\$first];
- }(
- list
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in closures:', () {
- var source = '''
- ${options.dartLangComment}
- int globalFunction() {
- int x = 15;
- var c = C(1, 2);
-
- var outerClosure = (int y) {
- var closureCaptureInner = (int z) {
- /* evaluation placeholder */
- print('\$y+\$z');
- };
- closureCaptureInner(0);
- };
-
- outerClosure(3);
- return 0;
- }
-
- main() => 0;
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- }, expression: 'typo', expectedError: "Getter not found: 'typo'.");
- });
-
- test('expression using uncaptured variables', () async {
- await driver.check(
- scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- },
- expression: "'\$x+\$y+\$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.str(x) + "+" + dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
-
- test('expression using captured variables', () async {
- await driver.check(
- scope: <String, String>{
- 'x': '1',
- 'c': 'null',
- 'y': '3',
- 'z': '0'
- },
- expression: "'\$y+\$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in generic method:', () {
- var source = '''
- ${options.dartLangComment}
- class A {
- void generic<TType, KType>(TType a, KType b) {
- /* evaluation placeholder */
- print(a);
- print(b);
- }
- }
-
- void main() => generic<int, String>(0, 'hi');
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('evaluate formals', () async {
- await driver.check(
- scope: <String, String>{
- 'TType': 'TType',
- 'KType': 'KType',
- 'a': 'a',
- 'b': 'b'
- },
- expression: 'a',
- expectedResult: '''
- (function(TType, KType, a, b) {
- return a;
- }.bind(this)(
- TType,
- KType,
- a,
- b
- ))
- ''');
- });
-
- test('evaluate type parameters', () async {
- await driver.check(
- scope: <String, String>{
- 'TType': 'TType',
- 'KType': 'KType',
- 'a': 'a',
- 'b': 'b'
- },
- expression: 'TType',
- expectedResult: '''
- (function(TType, KType, a, b) {
- const dart_sdk = ${options.loadModule}('dart_sdk');
- const dart = dart_sdk.dart;
- return dart.wrapType(TType);
- }.bind(this)(
- TType,
- KType,
- a,
- b
- ))
- ''');
- });
- });
-
- group('Expression compiler tests using extension symbols', () {
+ group('Expression compiler expressions that import extension symbols',
+ () {
var source = '''
${options.dartLangComment}
void bar() {
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 2492753..5f0da4d 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## 6.3.0-dev
+- Add support for `setBreakpointState` RPC and updated `Breakpoint` class to include
+ `enabled` property.
+
## 6.2.0
- Added support for `getHttpProfile` and `clearHttpProfile` `dart:io` service extensions.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 7122a12..c861f82 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -136,6 +136,7 @@
if (obj == "BreakpointAdded") return obj;
if (obj == "BreakpointRemoved") return obj;
if (obj == "BreakpointResolved") return obj;
+ if (obj == "BreakpointUpdated") return obj;
if (obj == "Extension") return obj;
if (obj == "GC") return obj;
if (obj == "Inspect") return obj;
@@ -293,6 +294,7 @@
assertNotNull(obj);
assertString(obj.id!);
assertInt(obj.breakpointNumber!);
+ assertBool(obj.enabled!);
assertBool(obj.resolved!);
if (obj.location is vms.SourceLocation) {
assertSourceLocation(obj.location!);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index 7e45717..cdc39af 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -4,6 +4,7 @@
src/org/dartlang/vm/service/consumer/AddBreakpointAtEntryConsumer.java
src/org/dartlang/vm/service/consumer/AddBreakpointConsumer.java
src/org/dartlang/vm/service/consumer/AddBreakpointWithScriptUriConsumer.java
+src/org/dartlang/vm/service/consumer/BreakpointConsumer.java
src/org/dartlang/vm/service/consumer/ClearCpuSamplesConsumer.java
src/org/dartlang/vm/service/consumer/CpuSamplesConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index 452573e..d934516 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.44
+version=3.45
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 8b869fb..50fe029 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -26,7 +26,7 @@
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
-const String vmServiceVersion = '3.44.0';
+const String vmServiceVersion = '3.45.0';
/// @optional
const String optional = 'optional';
@@ -229,6 +229,7 @@
'removeBreakpoint': const ['Success'],
'requestHeapSnapshot': const ['Success'],
'resume': const ['Success'],
+ 'setBreakpointState': const ['Breakpoint'],
'setExceptionPauseMode': const ['Success'],
'setFlag': const ['Success', 'Error'],
'setLibraryDebuggable': const ['Success'],
@@ -1008,6 +1009,18 @@
Future<Success> resume(String isolateId,
{/*StepOption*/ String? step, int? frameIndex});
+ /// The `setBreakpointState` RPC allows for breakpoints to be enabled or
+ /// disabled, without requiring for the breakpoint to be completely removed.
+ ///
+ /// If `isolateId` refers to an isolate which has exited, then the `Collected`
+ /// [Sentinel] is returned.
+ ///
+ /// The returned [Breakpoint] is the updated breakpoint with its new values.
+ ///
+ /// See [Breakpoint].
+ Future<Breakpoint> setBreakpointState(
+ String isolateId, String breakpointId, bool enable);
+
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
/// when an exception is thrown.
///
@@ -1136,7 +1149,7 @@
/// IsolateReload, ServiceExtensionAdded
/// Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted,
/// PauseException, PausePostRequest, Resume, BreakpointAdded,
- /// BreakpointResolved, BreakpointRemoved, Inspect, None
+ /// BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
/// GC | GC
/// Extension | Extension
/// Timeline | TimelineEvents, TimelineStreamsSubscriptionUpdate
@@ -1471,6 +1484,13 @@
frameIndex: params['frameIndex'],
);
break;
+ case 'setBreakpointState':
+ response = await _serviceImplementation.setBreakpointState(
+ params!['isolateId'],
+ params['breakpointId'],
+ params['enable'],
+ );
+ break;
case 'setExceptionPauseMode':
response = await _serviceImplementation.setExceptionPauseMode(
params!['isolateId'],
@@ -1667,7 +1687,7 @@
// IsolateStart, IsolateRunnable, IsolateExit, IsolateUpdate, IsolateReload, ServiceExtensionAdded
Stream<Event> get onIsolateEvent => _getEventController('Isolate').stream;
- // PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, Inspect, None
+ // PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
Stream<Event> get onDebugEvent => _getEventController('Debug').stream;
// GC
@@ -1982,6 +2002,15 @@
});
@override
+ Future<Breakpoint> setBreakpointState(
+ String isolateId, String breakpointId, bool enable) =>
+ _call('setBreakpointState', {
+ 'isolateId': isolateId,
+ 'breakpointId': breakpointId,
+ 'enable': enable
+ });
+
+ @override
Future<Success> setExceptionPauseMode(
String isolateId, /*ExceptionPauseMode*/ String mode) =>
_call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode});
@@ -2430,6 +2459,9 @@
/// A breakpoint has been removed.
static const String kBreakpointRemoved = 'BreakpointRemoved';
+ /// A breakpoint has been updated.
+ static const String kBreakpointUpdated = 'BreakpointUpdated';
+
/// A garbage collection event.
static const String kGC = 'GC';
@@ -2810,6 +2842,9 @@
/// A number identifying this breakpoint to the user.
int? breakpointNumber;
+ /// Is this breakpoint enabled?
+ bool? enabled;
+
/// Has this breakpoint been assigned to a specific program location?
bool? resolved;
@@ -2826,6 +2861,7 @@
Breakpoint({
required this.breakpointNumber,
+ required this.enabled,
required this.resolved,
required this.location,
required String id,
@@ -2836,6 +2872,7 @@
Breakpoint._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
breakpointNumber = json['breakpointNumber'] ?? -1;
+ enabled = json['enabled'] ?? false;
resolved = json['resolved'] ?? false;
isSyntheticAsyncContinuation = json['isSyntheticAsyncContinuation'];
location = createServiceObject(json['location']!,
@@ -2851,6 +2888,7 @@
json['type'] = type;
json.addAll({
'breakpointNumber': breakpointNumber,
+ 'enabled': enabled,
'resolved': resolved,
'location': location?.toJson(),
});
@@ -2864,8 +2902,8 @@
operator ==(other) => other is Breakpoint && id == other.id;
String toString() => '[Breakpoint ' //
- 'id: ${id}, breakpointNumber: ${breakpointNumber}, resolved: ${resolved}, ' //
- 'location: ${location}]';
+ 'id: ${id}, breakpointNumber: ${breakpointNumber}, enabled: ${enabled}, ' //
+ 'resolved: ${resolved}, location: ${location}]';
}
/// `ClassRef` is a reference to a `Class`.
@@ -3685,6 +3723,7 @@
/// - BreakpointAdded
/// - BreakpointRemoved
/// - BreakpointResolved
+ /// - BreakpointUpdated
@optional
Breakpoint? breakpoint;
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 5ba220b..dfe2e30 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -3,7 +3,7 @@
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 6.2.0
+version: 6.3.0-dev
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/set_breakpoint_state_test.dart b/pkg/vm_service/test/set_breakpoint_state_test.dart
new file mode 100644
index 0000000..7bc96ab
--- /dev/null
+++ b/pkg/vm_service/test/set_breakpoint_state_test.dart
@@ -0,0 +1,71 @@
+// 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.
+// VMOptions=--verbose_debug
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 17;
+const int LINE_B = LINE_A + 1;
+
+testMain() {
+ while (true) {
+ print('a'); // LINE_A
+ print('b'); // LINE_B
+ }
+}
+
+late Breakpoint bpt;
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ (VmService service, IsolateRef isolateRef) async {
+ bpt = await service.addBreakpointWithScriptUri(
+ isolateRef.id!,
+ 'set_breakpoint_state_test.dart',
+ LINE_A,
+ );
+ expect(bpt.enabled, true);
+ },
+ setBreakpointAtLine(LINE_B),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (VmService service, IsolateRef isolateRef) async {
+ bpt = await service.setBreakpointState(
+ isolateRef.id!,
+ bpt.id!,
+ false,
+ );
+ expect(bpt.enabled, false);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (VmService service, IsolateRef isolateRef) async {
+ bpt = await service.setBreakpointState(
+ isolateRef.id!,
+ bpt.id!,
+ true,
+ );
+ expect(bpt.enabled, true);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+];
+
+main([args = const <String>[]]) => runIsolateTests(
+ args,
+ tests,
+ 'set_breakpoint_state_test.dart',
+ pause_on_start: true,
+ testeeConcurrent: testMain,
+ );
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 1516d15..e32c00f 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -2407,6 +2407,9 @@
// Either SourceLocation or UnresolvedSourceLocation.
Location? location;
+ // Is the breakpoint enabled?
+ bool? enabled;
+
// The breakpoint is in a file which is not yet loaded.
bool? latent;
@@ -2425,6 +2428,7 @@
// number never changes.
assert((number == null) || (number == newNumber));
number = newNumber;
+ enabled = map['enabled'];
resolved = map['resolved'];
var oldLocation = location;
@@ -2448,6 +2452,15 @@
assert(resolved! || location is UnresolvedSourceLocation);
}
+ Future<void> setState(bool enable) {
+ return location!.script.isolate!.invokeRpcNoUpgrade('setBreakpointState', {
+ 'breakpointId': 'breakpoints/$number',
+ 'enable': enable,
+ }).then((Map result) {
+ _update(result, false);
+ });
+ }
+
void remove() {
location!.script._removeBreakpoint(this);
}
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index b63155d..1fe66c5 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], 'Version');
expect(result['major'], 3);
- expect(result['minor'], 44);
+ expect(result['minor'], 45);
expect(result['_privateMajor'], 0);
expect(result['_privateMinor'], 0);
},
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 3ddf48d..291688c 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -175,6 +175,7 @@
reload_sources_test: SkipByDesign # Hot reload is disabled in AOT mode.
rewind_optimized_out_test: SkipByDesign # Debugger is disabled in AOT mode.
rewind_test: SkipByDesign # Debugger is disabled in AOT mode.
+set_breakpoint_state_test: SkipByDesign # Debugger is disabled in AOT mode.
set_library_debuggable_test: SkipByDesign # Debugger is disabled in AOT mode.
sigquit_starts_service_test: SkipByDesign # Spawns a secondary process using Platform.executable.
simple_reload_test: SkipByDesign # Hot reload is disabled in AOT mode.
diff --git a/runtime/observatory/tests/service/set_breakpoint_state_test.dart b/runtime/observatory/tests/service/set_breakpoint_state_test.dart
new file mode 100644
index 0000000..fdcee6a
--- /dev/null
+++ b/runtime/observatory/tests/service/set_breakpoint_state_test.dart
@@ -0,0 +1,65 @@
+// 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.
+// VMOptions=--verbose_debug
+
+import 'package:observatory/service_io.dart';
+import 'package:test/test.dart';
+
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const int LINE_A = 17;
+const int LINE_B = LINE_A + 1;
+
+testMain() {
+ while (true) {
+ print('a'); // LINE_A
+ print('b'); // LINE_B
+ }
+}
+
+late Breakpoint bpt;
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ (Isolate isolate) async {
+ bpt = await isolate.addBreakpointByScriptUri(
+ 'set_breakpoint_state_test.dart',
+ LINE_A,
+ );
+ expect(bpt.enabled, true);
+ },
+ setBreakpointAtLine(LINE_B),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (Isolate isolate) async {
+ await bpt.setState(
+ false,
+ );
+ expect(bpt.enabled, false);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (Isolate isolate) async {
+ await bpt.setState(
+ true,
+ );
+ expect(bpt.enabled, true);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+];
+
+main([args = const <String>[]]) => runIsolateTests(
+ args,
+ tests,
+ pause_on_start: true,
+ testeeConcurrent: testMain,
+ );
diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart
index 1c5c9bc..743ab24 100644
--- a/runtime/observatory_2/lib/src/service/object.dart
+++ b/runtime/observatory_2/lib/src/service/object.dart
@@ -2418,6 +2418,9 @@
// Either SourceLocation or UnresolvedSourceLocation.
Location location;
+ // Is the breakpoint enabled?
+ bool enabled;
+
// The breakpoint is in a file which is not yet loaded.
bool latent;
@@ -2436,6 +2439,7 @@
// number never changes.
assert((number == null) || (number == newNumber));
number = newNumber;
+ enabled = map['enabled'];
resolved = map['resolved'];
var oldLocation = location;
@@ -2459,6 +2463,15 @@
assert(resolved || location is UnresolvedSourceLocation);
}
+ Future<void> setState(bool enable) {
+ return location.script.isolate.invokeRpcNoUpgrade('setBreakpointState', {
+ 'breakpointId': 'breakpoints/$number',
+ 'enable': enable,
+ }).then((Map result) {
+ _update(result, false);
+ });
+ }
+
void remove() {
location.script._removeBreakpoint(this);
}
diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
index e7a9528..bd9d9b1 100644
--- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(44));
+ expect(result['minor'], equals(45));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/observatory_2/tests/service_2/service_2_kernel.status b/runtime/observatory_2/tests/service_2/service_2_kernel.status
index 099e686..717b43e 100644
--- a/runtime/observatory_2/tests/service_2/service_2_kernel.status
+++ b/runtime/observatory_2/tests/service_2/service_2_kernel.status
@@ -174,6 +174,7 @@
reload_sources_test: SkipByDesign # Hot reload is disabled in AOT mode.
rewind_optimized_out_test: SkipByDesign # Debugger is disabled in AOT mode.
rewind_test: SkipByDesign # Debugger is disabled in AOT mode.
+set_breakpoint_state_test: SkipByDesign # Debugger is disabled in AOT mode.
set_library_debuggable_test: SkipByDesign # Debugger is disabled in AOT mode.
sigquit_starts_service_test: SkipByDesign # Spawns a secondary process using Platform.executable.
simple_reload_test: SkipByDesign # Hot reload is disabled in AOT mode.
diff --git a/runtime/observatory_2/tests/service_2/set_breakpoint_state_test.dart b/runtime/observatory_2/tests/service_2/set_breakpoint_state_test.dart
new file mode 100644
index 0000000..78e0fcb
--- /dev/null
+++ b/runtime/observatory_2/tests/service_2/set_breakpoint_state_test.dart
@@ -0,0 +1,65 @@
+// 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.
+// VMOptions=--verbose_debug
+
+import 'package:observatory_2/service_io.dart';
+import 'package:test/test.dart';
+
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+const int LINE_A = 17;
+const int LINE_B = LINE_A + 1;
+
+testMain() {
+ while (true) {
+ print('a'); // LINE_A
+ print('b'); // LINE_B
+ }
+}
+
+Breakpoint bpt;
+
+var tests = <IsolateTest>[
+ hasPausedAtStart,
+ (Isolate isolate) async {
+ bpt = await isolate.addBreakpointByScriptUri(
+ 'set_breakpoint_state_test.dart',
+ LINE_A,
+ );
+ expect(bpt.enabled, true);
+ },
+ setBreakpointAtLine(LINE_B),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (Isolate isolate) async {
+ await bpt.setState(
+ false,
+ );
+ expect(bpt.enabled, false);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ (Isolate isolate) async {
+ await bpt.setState(
+ true,
+ );
+ expect(bpt.enabled, true);
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+];
+
+main([args = const <String>[]]) => runIsolateTests(
+ args,
+ tests,
+ pause_on_start: true,
+ testeeConcurrent: testMain,
+ );
diff --git a/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_script.dart b/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_script.dart
new file mode 100644
index 0000000..630dd02
--- /dev/null
+++ b/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_script.dart
@@ -0,0 +1,49 @@
+// 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:developer';
+import 'dart:isolate' as I;
+
+import 'package:vm_service/vm_service.dart';
+import 'package:vm_service/vm_service_io.dart';
+
+int fib(int n) {
+ if (n <= 1) return n;
+ return fib(n - 1) + fib(n - 2);
+}
+
+Future<void> main() async {
+ // Do some work.
+ fib(20);
+
+ ServiceProtocolInfo serviceInfo = await Service.getInfo();
+ while (serviceInfo.serverUri == null) {
+ await Future.delayed(const Duration(milliseconds: 200));
+ serviceInfo = await Service.getInfo();
+ }
+ final isolateId = Service.getIsolateID(I.Isolate.current)!;
+ final uri = serviceInfo.serverUri!.replace(scheme: 'ws', pathSegments: [
+ ...serviceInfo.serverUri!.pathSegments.where((e) => e != ''),
+ 'ws'
+ ]);
+ final service = await vmServiceConnectUri(uri.toString());
+ final timeExtent = Duration(minutes: 5).inMicroseconds;
+ final samples = await service.getCpuSamples(isolateId, 0, timeExtent);
+
+ // Cleanup VM service connection as it's no longer needed.
+ await service.dispose();
+
+ final functions = samples.functions!.where((f) => f.kind! == 'Dart').toList();
+ if (functions.isEmpty) {
+ print('FAILED: could not find a profiled Dart function');
+ return;
+ }
+
+ functions.retainWhere((f) => f.resolvedUrl!.isNotEmpty);
+ if (functions.isNotEmpty) {
+ print('SUCCESS');
+ } else {
+ print('FAILED');
+ }
+}
diff --git a/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_test.dart b/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_test.dart
new file mode 100644
index 0000000..9b6d74d
--- /dev/null
+++ b/runtime/tests/vm/dart/gen_snapshot_include_resolved_urls_test.dart
@@ -0,0 +1,118 @@
+// 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 "dart:convert";
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+main(List<String> args) async {
+ if (!Platform.executable.endsWith("dart_precompiled_runtime")) {
+ return; // Running in JIT: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree and gen_snapshot not available on the test device.
+ }
+
+ final buildDir = path.dirname(Platform.executable);
+ final sdkDir = path.dirname(path.dirname(buildDir));
+ final scriptUrl = path.join(
+ sdkDir,
+ 'runtime',
+ 'tests',
+ 'vm',
+ 'dart',
+ 'gen_snapshot_include_resolved_urls_script.dart',
+ );
+
+ final platformDill = path.join(buildDir, 'vm_platform_strong.dill');
+ final genSnapshot = path.join(buildDir, 'gen_snapshot');
+ final aotRuntime = path.join(buildDir, 'dart_precompiled_runtime');
+
+ late Directory tempDir;
+ setUpAll(() async {
+ tempDir = Directory.systemTemp.createTempSync('aot-script-urls-test');
+ final scriptDill = path.join(tempDir.path, 'test.dill');
+
+ // Compile script to Kernel IR.
+ await run('pkg/vm/tool/gen_kernel', <String>[
+ '--aot',
+ '--packages=$sdkDir/.packages',
+ '--platform=$platformDill',
+ '-o',
+ scriptDill,
+ scriptUrl,
+ ]);
+ });
+
+ tearDownAll(() {
+ tempDir.deleteSync(recursive: true);
+ });
+
+ // Let the test runner handle timeouts.
+ test(
+ 'Include resolved urls',
+ () async {
+ final scriptDill = path.join(tempDir.path, 'test.dill');
+
+ // Compile script to Kernel IR.
+ await run('pkg/vm/tool/gen_kernel', <String>[
+ '--aot',
+ '--packages=$sdkDir/.packages',
+ '--platform=$platformDill',
+ '-o',
+ scriptDill,
+ scriptUrl,
+ ]);
+
+ final elfFile = path.join(tempDir.path, 'aot.snapshot');
+ await run(genSnapshot, <String>[
+ '--snapshot-kind=app-aot-elf',
+ '--elf=$elfFile',
+ scriptDill,
+ ]);
+
+ // Ensure we can actually run the code.
+ expect(
+ await run(aotRuntime, <String>[
+ '--enable-vm-service=0',
+ '--profiler',
+ elfFile,
+ ]),
+ true,
+ );
+ },
+ timeout: Timeout.none,
+ );
+}
+
+Future<String> readFile(String file) {
+ return File(file).readAsString();
+}
+
+Future<bool> run(String executable, List<String> args) async {
+ print('Running $executable ${args.join(' ')}');
+
+ final result = await Process.run(executable, args);
+ final String stdout = result.stdout;
+ final String stderr = result.stderr;
+ if (stdout.isNotEmpty) {
+ print('stdout:');
+ print(stdout);
+ }
+ if (stderr.isNotEmpty) {
+ print('stderr:');
+ print(stderr);
+ }
+
+ if (result.exitCode != 0) {
+ print('Command failed with non-zero exit code (was ${result.exitCode})');
+ return false;
+ }
+ return result.stdout.contains('SUCCESS') && stderr.isEmpty;
+}
diff --git a/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_script.dart b/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_script.dart
new file mode 100644
index 0000000..d36bd7f
--- /dev/null
+++ b/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_script.dart
@@ -0,0 +1,49 @@
+// 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:developer';
+import 'dart:isolate' as I;
+
+import 'package:vm_service/vm_service.dart';
+import 'package:vm_service/vm_service_io.dart';
+
+int fib(int n) {
+ if (n <= 1) return n;
+ return fib(n - 1) + fib(n - 2);
+}
+
+Future<void> main() async {
+ // Do some work.
+ fib(20);
+
+ ServiceProtocolInfo serviceInfo = await Service.getInfo();
+ while (serviceInfo.serverUri == null) {
+ await Future.delayed(const Duration(milliseconds: 200));
+ serviceInfo = await Service.getInfo();
+ }
+ final isolateId = Service.getIsolateID(I.Isolate.current);
+ final uri = serviceInfo.serverUri.replace(scheme: 'ws', pathSegments: [
+ ...serviceInfo.serverUri.pathSegments.where((e) => e != ''),
+ 'ws'
+ ]);
+ final service = await vmServiceConnectUri(uri.toString());
+ final timeExtent = Duration(minutes: 5).inMicroseconds;
+ final samples = await service.getCpuSamples(isolateId, 0, timeExtent);
+
+ // Cleanup VM service connection as it's no longer needed.
+ await service.dispose();
+
+ final functions = samples.functions.where((f) => f.kind == 'Dart').toList();
+ if (functions.isEmpty) {
+ print('FAILED: could not find a profiled Dart function');
+ return;
+ }
+
+ functions.retainWhere((f) => f.resolvedUrl.isNotEmpty);
+ if (functions.isNotEmpty) {
+ print('SUCCESS');
+ } else {
+ print('FAILED');
+ }
+}
diff --git a/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_test.dart b/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_test.dart
new file mode 100644
index 0000000..bea28ff
--- /dev/null
+++ b/runtime/tests/vm/dart_2/gen_snapshot_include_resolved_urls_test.dart
@@ -0,0 +1,118 @@
+// 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 "dart:convert";
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+main(List<String> args) async {
+ if (!Platform.executable.endsWith("dart_precompiled_runtime")) {
+ return; // Running in JIT: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree and gen_snapshot not available on the test device.
+ }
+
+ final buildDir = path.dirname(Platform.executable);
+ final sdkDir = path.dirname(path.dirname(buildDir));
+ final scriptUrl = path.join(
+ sdkDir,
+ 'runtime',
+ 'tests',
+ 'vm',
+ 'dart_2',
+ 'gen_snapshot_include_resolved_urls_script.dart',
+ );
+
+ final platformDill = path.join(buildDir, 'vm_platform_strong.dill');
+ final genSnapshot = path.join(buildDir, 'gen_snapshot');
+ final aotRuntime = path.join(buildDir, 'dart_precompiled_runtime');
+
+ Directory tempDir;
+ setUpAll(() async {
+ tempDir = Directory.systemTemp.createTempSync('aot-script-urls-test');
+ final scriptDill = path.join(tempDir.path, 'test.dill');
+
+ // Compile script to Kernel IR.
+ await run('pkg/vm/tool/gen_kernel', <String>[
+ '--aot',
+ '--packages=$sdkDir/.packages',
+ '--platform=$platformDill',
+ '-o',
+ scriptDill,
+ scriptUrl,
+ ]);
+ });
+
+ tearDownAll(() {
+ tempDir.deleteSync(recursive: true);
+ });
+
+ // Let the test runner handle timeouts.
+ test(
+ 'Include resolved urls',
+ () async {
+ final scriptDill = path.join(tempDir.path, 'test.dill');
+
+ // Compile script to Kernel IR.
+ await run('pkg/vm/tool/gen_kernel', <String>[
+ '--aot',
+ '--packages=$sdkDir/.packages',
+ '--platform=$platformDill',
+ '-o',
+ scriptDill,
+ scriptUrl,
+ ]);
+
+ final elfFile = path.join(tempDir.path, 'aot.snapshot');
+ await run(genSnapshot, <String>[
+ '--snapshot-kind=app-aot-elf',
+ '--elf=$elfFile',
+ scriptDill,
+ ]);
+
+ // Ensure we can actually run the code.
+ expect(
+ await run(aotRuntime, <String>[
+ '--enable-vm-service=0',
+ '--profiler',
+ elfFile,
+ ]),
+ true,
+ );
+ },
+ timeout: Timeout.none,
+ );
+}
+
+Future<String> readFile(String file) {
+ return File(file).readAsString();
+}
+
+Future<bool> run(String executable, List<String> args) async {
+ print('Running $executable ${args.join(' ')}');
+
+ final result = await Process.run(executable, args);
+ final String stdout = result.stdout;
+ final String stderr = result.stderr;
+ if (stdout.isNotEmpty) {
+ print('stdout:');
+ print(stdout);
+ }
+ if (stderr.isNotEmpty) {
+ print('stderr:');
+ print(stderr);
+ }
+
+ if (result.exitCode != 0) {
+ print('Command failed with non-zero exit code (was ${result.exitCode})');
+ return false;
+ }
+ return result.stdout.contains('SUCCESS') && stderr.isEmpty;
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index a95d016..d4bfbe0 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -128,7 +128,9 @@
cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors
cc/CreateMirrorSystem: SkipByDesign # Imports dart:mirrors
cc/StandaloneSnapshotSize: SkipByDesign # Imports dart:mirrors
+dart/gen_snapshot_include_resolved_urls_test: SkipByDesign # Script URLs not included in product gen_snapshot
dart/redirection_type_shuffling_test: SkipByDesign # Imports dart:mirrors
+dart_2/gen_snapshot_include_resolved_urls_test: SkipByDesign # Script URLs not included in product gen_snapshot
dart_2/redirection_type_shuffling_test: SkipByDesign # Imports dart:mirrors
[ $nnbd == legacy ]
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 4eddc2e..8946b68 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -2538,7 +2538,9 @@
program_info.set_libraries_cache(Array::null_array());
program_info.set_classes_cache(Array::null_array());
}
+#if defined(PRODUCT)
script.set_resolved_url(String::null_string());
+#endif // defined(PRODUCT)
script.set_compile_time_constants(Array::null_array());
script.set_line_starts(null_typed_data);
script.set_debug_positions(Array::null_array());
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 592a7e5..cfa5e5e 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -109,7 +109,14 @@
}
bool BreakpointLocation::AnyEnabled() const {
- return breakpoints() != NULL;
+ Breakpoint* bpt = breakpoints();
+ while (bpt != nullptr) {
+ if (bpt->is_enabled()) {
+ return true;
+ }
+ bpt = bpt->next();
+ }
+ return false;
}
void BreakpointLocation::SetResolved(const Function& func,
@@ -175,6 +182,7 @@
jsobj.AddProperty("type", "Breakpoint");
jsobj.AddFixedServiceId("breakpoints/%" Pd "", id());
+ jsobj.AddProperty("enabled", enabled_);
jsobj.AddProperty("breakpointNumber", id());
if (is_synthetic_async()) {
jsobj.AddProperty("isSyntheticAsyncContinuation", is_synthetic_async());
@@ -358,7 +366,7 @@
void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) {
bpt->set_next(breakpoints());
set_breakpoints(bpt);
-
+ bpt->Enable();
dbg->group_debugger()->SyncBreakpointLocation(this);
dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
}
@@ -2945,7 +2953,6 @@
// associated with the breakpoint location loc.
void GroupDebugger::SyncBreakpointLocation(BreakpointLocation* loc) {
bool any_enabled = loc->AnyEnabled();
-
SafepointWriteRwLocker sl(Thread::Current(), code_breakpoints_lock());
CodeBreakpoint* cbpt = code_breakpoints_;
while (cbpt != NULL) {
@@ -4283,6 +4290,21 @@
return Code::null();
}
+bool Debugger::SetBreakpointState(Breakpoint* bpt, bool enable) {
+ SafepointWriteRwLocker sl(Thread::Current(),
+ group_debugger()->breakpoint_locations_lock());
+ if (bpt->is_enabled() != enable) {
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("Setting breakpoint %" Pd " to state: %s\n", bpt->id(),
+ enable ? "enabled" : "disabled");
+ }
+ enable ? bpt->Enable() : bpt->Disable();
+ group_debugger()->SyncBreakpointLocation(bpt->bpt_location());
+ return true;
+ }
+ return false;
+}
+
// Remove and delete the source breakpoint bpt and its associated
// code breakpoints.
void Debugger::RemoveBreakpoint(intptr_t bp_id) {
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index bd2d0de..b9d99de 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -81,6 +81,18 @@
closure_ = closure.ptr();
}
+ void Enable() {
+ ASSERT(!enabled_);
+ enabled_ = true;
+ }
+
+ void Disable() {
+ ASSERT(enabled_);
+ enabled_ = false;
+ }
+
+ bool is_enabled() const { return enabled_; }
+
// Mark that this breakpoint is a result of a step OverAwait request.
void set_is_synthetic_async(bool is_synthetic_async) {
is_synthetic_async_ = is_synthetic_async;
@@ -105,6 +117,7 @@
InstancePtr closure_;
BreakpointLocation* bpt_location_;
bool is_synthetic_async_;
+ bool enabled_ = false;
friend class BreakpointLocation;
DISALLOW_COPY_AND_ASSIGN(Breakpoint);
@@ -713,6 +726,9 @@
intptr_t line_number,
intptr_t column_number);
+ // Returns true if the breakpoint's state changed.
+ bool SetBreakpointState(Breakpoint* bpt, bool enable);
+
void RemoveBreakpoint(intptr_t bp_id);
Breakpoint* GetBreakpointById(intptr_t id);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 965764b..51ba8bd 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -149,7 +149,7 @@
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
Debugger* debugger = I->debugger();
- bpt = debugger->SetBreakpointAtLine(script_url, line_number);
+ bpt = debugger->SetBreakpointAtLineCol(script_url, line_number, -1);
if (bpt == NULL) {
return Api::NewError("%s: could not set breakpoint at line %" Pd
" in '%s'",
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index 4b21ce5..27edd7a 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -398,12 +398,11 @@
// it is already converted to 32-bit float via DoubleToFloat
// instruction before it was stored.
// Reinterpret double value as float to get the value back.
- union {
- double d;
- float f;
- } v;
- v.d = Double::Cast(value).value();
- typed_data.SetFloat32(element_offset, v.f);
+ typed_data.SetFloat32(
+ element_offset,
+ bit_cast<float, uint32_t>(
+ static_cast<uint32_t>(bit_cast<uint64_t, double>(
+ Double::Cast(value).value()))));
break;
case kTypedDataFloat64ArrayCid:
typed_data.SetFloat64(element_offset,
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b24f93e..bbec4f1 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1439,7 +1439,11 @@
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kFullAOT:
+#if defined(PRODUCT)
return reinterpret_cast<CompressedObjectPtr*>(&url_);
+#else
+ return reinterpret_cast<CompressedObjectPtr*>(&resolved_url_);
+#endif
case Snapshot::kFull:
case Snapshot::kFullCore:
case Snapshot::kFullJIT:
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index ee7a7ec..4c5578f 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -4805,6 +4805,36 @@
return true;
}
+static const MethodParameter* set_breakpoint_state_params[] = {
+ ISOLATE_PARAMETER,
+ new IdParameter("breakpointId", true),
+ new BoolParameter("enable", true),
+ nullptr,
+};
+
+static bool SetBreakpointState(Thread* thread, JSONStream* js) {
+ Isolate* isolate = thread->isolate();
+ const char* bpt_id = js->LookupParam("breakpointId");
+ bool enable = BoolParameter::Parse(js->LookupParam("enable"), true);
+ ObjectIdRing::LookupResult lookup_result;
+ Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id, &lookup_result);
+ // TODO(bkonyi): Should we return a different error for bpts which
+ // have been already removed?
+ if (bpt == nullptr) {
+ PrintInvalidParamError(js, "breakpointId");
+ return true;
+ }
+ if (isolate->debugger()->SetBreakpointState(bpt, enable)) {
+ if (Service::debug_stream.enabled()) {
+ ServiceEvent event(isolate, ServiceEvent::kBreakpointUpdated);
+ event.set_breakpoint(bpt);
+ Service::HandleEvent(&event);
+ }
+ }
+ bpt->PrintJSON(js);
+ return true;
+}
+
static const MethodParameter* get_flag_list_params[] = {
NO_ISOLATE_PARAMETER,
NULL,
@@ -5188,6 +5218,8 @@
request_heap_snapshot_params },
{ "_evaluateCompiledExpression", EvaluateCompiledExpression,
evaluate_compiled_expression_params },
+ { "setBreakpointState", SetBreakpointState,
+ set_breakpoint_state_params },
{ "setExceptionPauseMode", SetExceptionPauseMode,
set_exception_pause_mode_params },
{ "setFlag", SetFlag,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 032fafd..0b94d3d 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 44
+#define SERVICE_PROTOCOL_MINOR_VERSION 45
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index e78af3e..99bdab7 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.44
+# Dart VM Service Protocol 3.45
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.44_ of the Dart VM Service Protocol. This
+This document describes of _version 3.45_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -67,6 +67,7 @@
- [reloadSources](#reloadsources)
- [removeBreakpoint](#removebreakpoint)
- [resume](#resume)
+ - [setBreakpointState](#setbreakpointstate)
- [setExceptionPauseMode](#setexceptionpausemode)
- [setFlag](#setflag)
- [setLibraryDebuggable](#setlibrarydebuggable)
@@ -1305,6 +1306,24 @@
See [Success](#success), [StepOption](#StepOption).
+### setBreakpointState
+
+```
+Breakpoint setBreakpointState(string isolateId,
+ string breakpointId,
+ bool enable)
+```
+
+The _setBreakpointState_ RPC allows for breakpoints to be enabled or disabled,
+without requiring for the breakpoint to be completely removed.
+
+If _isolateId_ refers to an isolate which has exited, then the
+_Collected_ [Sentinel](#sentinel) is returned.
+
+The returned [Breakpoint](#breakpoint) is the updated breakpoint with its new
+values.
+
+See [Breakpoint](#breakpoint).
### setExceptionPauseMode
```
@@ -1457,7 +1476,7 @@
-------- | -----------
VM | VMUpdate, VMFlagUpdate
Isolate | IsolateStart, IsolateRunnable, IsolateExit, IsolateUpdate, IsolateReload, ServiceExtensionAdded
-Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, Inspect, None
+Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
GC | GC
Extension | Extension
Timeline | TimelineEvents, TimelineStreamsSubscriptionUpdate
@@ -1639,6 +1658,9 @@
// A number identifying this breakpoint to the user.
int breakpointNumber;
+ // Is this breakpoint enabled?
+ bool enabled;
+
// Has this breakpoint been assigned to a specific program location?
bool resolved;
@@ -2002,6 +2024,7 @@
// BreakpointAdded
// BreakpointRemoved
// BreakpointResolved
+ // BreakpointUpdated
Breakpoint breakpoint [optional];
// The list of breakpoints at which we are currently paused
@@ -2199,6 +2222,9 @@
// A breakpoint has been removed.
BreakpointRemoved,
+ // A breakpoint has been updated.
+ BreakpointUpdated,
+
// A garbage collection event.
GC,
@@ -4011,5 +4037,6 @@
3.42 | Added `limit` optional parameter to `getStack` RPC.
3.43 | Updated heap snapshot format to include identity hash codes. Added `getAllocationTraces` and `setTraceClassAllocation` RPCs, updated `CpuSample` to include `identityHashCode` and `classId` properties, updated `Class` to include `traceAllocations` property.
3.44 | Added `identityHashCode` property to `@Instance` and `Instance`.
+3.45 | Added `setBreakpointState` RPC and `BreakpointUpdated` event kind.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index aed7093..6b97b6d 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -117,6 +117,8 @@
return "BreakpointResolved";
case kBreakpointRemoved:
return "BreakpointRemoved";
+ case kBreakpointUpdated:
+ return "BreakpointUpdated";
case kGC:
return "GC"; // TODO(koda): Change to GarbageCollected.
case kInspect:
@@ -166,6 +168,7 @@
case kBreakpointAdded:
case kBreakpointResolved:
case kBreakpointRemoved:
+ case kBreakpointUpdated:
case kInspect:
case kDebuggerSettingsUpdate:
return &Service::debug_stream;
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index 08979ac..80aaa8a 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -44,6 +44,7 @@
kBreakpointAdded,
kBreakpointResolved,
kBreakpointRemoved,
+ kBreakpointUpdated,
kInspect,
kDebuggerSettingsUpdate,
@@ -128,7 +129,8 @@
Breakpoint* breakpoint() const { return breakpoint_; }
void set_breakpoint(Breakpoint* bpt) {
ASSERT(kind() == kPauseBreakpoint || kind() == kBreakpointAdded ||
- kind() == kBreakpointResolved || kind() == kBreakpointRemoved);
+ kind() == kBreakpointResolved || kind() == kBreakpointRemoved ||
+ kind() == kBreakpointUpdated);
breakpoint_ = bpt;
}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_cast_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_cast_test.dart
new file mode 100644
index 0000000..414c5af
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_cast_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs can be used for casts
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+class Derived1 extends PublicClass {}
+
+class Derived2 implements PublicClass {
+ noSuchMethod(_) {}
+}
+
+void test1() {
+ // Test casts from a derived subclass.
+ var d1 = Derived1();
+ Expect.equals(d1, d1 as Derived1);
+ Expect.equals(d1, d1 as PublicClass);
+ Expect.equals(d1, d1 as AlsoPublicClass);
+ Expect.throws(() => d1 as Derived2);
+
+ // Test casts from a derived implementation
+ var d2 = Derived2();
+ Expect.throws(() => d2 as Derived1);
+ Expect.equals(d2, d2 as PublicClass);
+ Expect.equals(d2, d2 as AlsoPublicClass);
+ Expect.equals(d2, d2 as Derived2);
+
+ // Test casts from the exported private subclass.
+ var p = PublicClass();
+ Expect.throws(() => p as Derived1);
+ Expect.equals(p, p as PublicClass);
+ Expect.equals(p, p as AlsoPublicClass);
+ Expect.throws(() => p as Derived2);
+}
+
+void main() {
+ test1();
+}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_creation_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_creation_test.dart
new file mode 100644
index 0000000..b43d9b7
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_creation_test.dart
@@ -0,0 +1,43 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs allow creation.
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+void test1() {
+ // Test that a private class can be created via an exported public name using
+ // an unnamed constructor.
+ var p = PublicClass();
+ Expect.equals(privateLibrarySentinel, p.x);
+ Expect.equals(privateLibrarySentinel, p.instanceMethod());
+ Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
+}
+
+void test2() {
+ // Test that a private class can be created via an exported public name using
+ // a named constructor.
+ var p = AlsoPublicClass.named(1);
+ Expect.equals(1, p.x);
+ Expect.equals(privateLibrarySentinel, p.instanceMethod());
+ Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
+}
+
+void test3() {
+ // Test that a private class can be created as const via an exported public
+ // name.
+ const c1 = PublicClass();
+ const c2 = AlsoPublicClass();
+ Expect.identical(c1, c2);
+}
+
+void main() {
+ test1();
+ test2();
+ test3();
+}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_duplicate_interface_error_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_duplicate_interface_error_test.dart
new file mode 100644
index 0000000..7d482d0
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_duplicate_interface_error_test.dart
@@ -0,0 +1,66 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs may not appear multiple
+// times in a super-interface graph.
+
+import "private_name_library.dart";
+
+/// Test that having a private class in the implements and extends class via two
+/// different public names is an error.
+class A0 extends PublicClass implements AlsoPublicClass {
+// ^
+// [cfe] '_PrivateClass' can't be used in both 'extends' and 'implements' clauses.
+// ^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_SUPER_CLASS
+}
+
+/// Test that having a private class in the implements class twice via the same
+/// public name is an error.
+class A1 implements PublicClass, PublicClass {
+// ^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
+// [cfe] unspecified
+ noSuchMethod(_) => null;
+}
+
+/// Test that having a private class in the implements class twice via two
+/// different public names is an error.
+class A2 implements PublicClass, AlsoPublicClass {
+// ^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
+// [cfe] unspecified
+ noSuchMethod(_) => null;
+}
+
+/// Helper class for the following test
+class A3 extends PublicGenericClassOfInt {}
+
+/// Test that having a private generic class in the super-interface graph
+/// twice with two different generic instantiations is an error.
+class A4 extends A3 implements PublicGenericClass<String> {
+// [error line 42, column 1, length 411]
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
+// ^
+// [cfe] 'A4' can't implement both '_PrivateGenericClass<int>' and '_PrivateGenericClass<String>'
+}
+
+/// Test that having a private generic class in the super-interface graph
+/// twice at the same instantiation is not an error.
+class A5 extends A3 implements PublicGenericClass<int> {}
+
+/// Test that having a private generic class in the implements clause twice with
+/// two different generic instantiations is an error.
+class A6 implements PublicGenericClass<int>, PublicGenericClass<String> {
+// [error line 55, column 1, length 546]
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
+// ^
+// [cfe] 'A6' can't implement both '_PrivateGenericClass<int>' and '_PrivateGenericClass<String>'
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
+}
+
+void main() {}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_extension_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_extension_test.dart
index ece07c3..5c48f2a 100644
--- a/tests/language/nonfunction_type_aliases/private_names/private_name_extension_test.dart
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_extension_test.dart
@@ -10,36 +10,83 @@
import "private_name_library.dart";
+/// Extend a private class via a public typedef without overriding any methods.
class Derived extends PublicClass {
- Derived() : super(0);
+ // Check that super constructor calls work.
+ Derived() : super();
}
+/// Extend a private class via a public typedef overriding methods and
+/// properties. The final field `x` is overriden with a getter which returns
+/// different values every time it is called.
class AlsoDerived extends AlsoPublicClass {
- AlsoDerived() : super.named(0);
- int instanceMethod() => 0;
- int _privateInstanceMethod() => 0;
+ int backingStore = publicLibrarySentinel;
+ int get x => backingStore++;
+ int get y => super.x;
+ // Check that named super constructors work. Use the private sentinel value
+ // to allow us to distinguish reads of `x` from `super.x`.
+ AlsoDerived() : super.named(privateLibrarySentinel);
+ // Override the instanceMethod to return a distinguishing value.
+ int instanceMethod() => publicLibrarySentinel;
+ // Add a non-overriding private method with the same textual name as a private
+ // name in the super class which returns a distinguishing value.
+ int _privateInstanceMethod() => publicLibrarySentinel;
}
/// Test that inherited methods work correctly.
void test1() {
- {
- PublicClass p = Derived();
- Expect.equals(3, p.instanceMethod());
- Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateInstanceMethod());
- }
+ PublicClass p = Derived();
+ Expect.equals(privateLibrarySentinel, p.instanceMethod());
+ // Calling the inherited private method from the private library should work.
+ Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
+ Expect.equals(privateLibrarySentinel, callInstanceMethod(p));
+ // Calling the inherited private method from this library should throw.
+ Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateInstanceMethod());
}
-/// Test that inherited methods work correctly.
+/// Test that overriden methods work correctly.
void test2() {
- {
- var p = AlsoDerived();
- Expect.equals(0, p.instanceMethod());
- Expect.equals(0, p._privateInstanceMethod());
- Expect.equals(0, (p as dynamic)._privateInstanceMethod());
- }
+ var p = AlsoDerived();
+ Expect.equals(publicLibrarySentinel, p.instanceMethod());
+ // Calling the overriden private method from this library should work.
+ Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
+ // Calling the inherited private method from the private library should work.
+ Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
+ // Calling the overriden private method dynamically from this library should
+ // work.
+ Expect.equals(publicLibrarySentinel, (p as dynamic)._privateInstanceMethod());
+}
+
+/// Test that inherited properties work correctly
+void test3() {
+ var p = Derived();
+ // Reading the virtual field should give the private value
+ Expect.equals(privateLibrarySentinel, p.x);
+ // Reading the virtual field from the private library should give the private
+ // value
+ Expect.equals(privateLibrarySentinel, readInstanceField(p));
+}
+
+/// Test that overriden properties work correctly.
+void test4() {
+ var p = AlsoDerived();
+ // Reading the original virtual field should give the private value.
+ Expect.equals(privateLibrarySentinel, p.y);
+ // Reading the overriding getter from this library should give the public
+ // value and increment it each time it is called.
+ Expect.equals(publicLibrarySentinel, readInstanceField(p));
+ // Reading the overriding getter from the original library should give the
+ // public value and increment it each time it is called.
+ Expect.equals(publicLibrarySentinel + 1, p.x);
+
+ Expect.equals(privateLibrarySentinel, p.y);
+ Expect.equals(publicLibrarySentinel + 2, readInstanceField(p));
+ Expect.equals(publicLibrarySentinel + 3, p.x);
}
void main() {
test1();
test2();
+ test3();
+ test4();
}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_implementation_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_implementation_test.dart
new file mode 100644
index 0000000..eafc545
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_implementation_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs allow implementation
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+class Derived implements PublicClass {
+ int x;
+ Derived(this.x);
+ int instanceMethod() => publicLibrarySentinel;
+ int _privateInstanceMethod() => publicLibrarySentinel;
+}
+
+void test1() {
+ PublicClass _ = Derived(publicLibrarySentinel);
+ var p = Derived(publicLibrarySentinel);
+ Expect.equals(publicLibrarySentinel, p.instanceMethod());
+ // Calling the private instance method from this library should succeed.
+ Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
+ // Calling the private instance method from the other library should fail.
+ Expect.throwsNoSuchMethodError(() => callPrivateInstanceMethod(p));
+}
+
+void main() {
+ test1();
+}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_instance_checks_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_instance_checks_test.dart
new file mode 100644
index 0000000..4496a7a
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_instance_checks_test.dart
@@ -0,0 +1,43 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs can be used for instance
+// checks
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+class Derived1 extends PublicClass {}
+
+class Derived2 implements PublicClass {
+ // Dummy implementation for the class using noSuchMethod.
+ noSuchMethod(_) {}
+}
+
+void test1() {
+ var d1 = Derived1();
+ Expect.isTrue(d1 is Derived1);
+ Expect.isTrue(d1 is PublicClass);
+ Expect.isTrue(d1 is AlsoPublicClass);
+ Expect.isFalse(d1 is Derived2);
+
+ var d2 = Derived2();
+ Expect.isFalse(d2 is Derived1);
+ Expect.isTrue(d2 is PublicClass);
+ Expect.isTrue(d2 is AlsoPublicClass);
+ Expect.isTrue(d2 is Derived2);
+
+ var p = PublicClass();
+ Expect.isFalse(p is Derived1);
+ Expect.isTrue(p is PublicClass);
+ Expect.isTrue(p is AlsoPublicClass);
+ Expect.isFalse(p is Derived2);
+}
+
+void main() {
+ test1();
+}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_library.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_library.dart
index 07e441c..9f34b2f 100644
--- a/tests/language/nonfunction_type_aliases/private_names/private_name_library.dart
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_library.dart
@@ -7,26 +7,74 @@
library private;
+// Sentinel values for checking that the correct methods are called. Methods
+// defined in this library return the private sentinel, and (potentially
+// overriding) methods defined in other libraries return the public sentinel.
+// By checking the return value of methods against the respective sentinels,
+// test expectations can establish whether the correct method has been called.
+const int privateLibrarySentinel = -1;
+const int publicLibrarySentinel = privateLibrarySentinel + 1;
+
+// A private class that will be exported via a public typedef.
class _PrivateClass {
- int x;
- _PrivateClass(this.x);
+ final int x;
+ const _PrivateClass() : x = privateLibrarySentinel;
_PrivateClass.named(this.x);
- static int staticMethod() => 3;
- static int _privateStaticMethod() => 3;
- int instanceMethod() => 3;
- int _privateInstanceMethod() => 3;
+ static int staticMethod() => privateLibrarySentinel;
+ static int _privateStaticMethod() => privateLibrarySentinel;
+ int instanceMethod() => privateLibrarySentinel;
+ int _privateInstanceMethod() => privateLibrarySentinel;
}
+// Export the private class publicly, along with a factory.
typedef PublicClass = _PrivateClass;
-PublicClass mkPublicClass() => PublicClass(0);
+PublicClass mkPublicClass() => PublicClass();
+// Export the private class publicly via an indirection through another private
+// typedef, along with a factory.
typedef _PrivateTypeDef = _PrivateClass;
typedef AlsoPublicClass = _PrivateTypeDef;
-AlsoPublicClass mkAlsoPublicClass() => AlsoPublicClass(0);
+AlsoPublicClass mkAlsoPublicClass() => AlsoPublicClass();
+// A private generic class which will be exported through a public typedef.
class _PrivateGenericClass<T> {
- static int staticMethod() => 3;
+ static int staticMethod() => privateLibrarySentinel;
}
+
+// Export the private generic class publicly, along with a factory and a
+// specific instantiation.
typedef PublicGenericClass<T> = _PrivateGenericClass<T>;
PublicGenericClass<T> mkPublicGenericClass<T>() => PublicGenericClass();
typedef PublicGenericClassOfInt = _PrivateGenericClass<int>;
+
+// Helper methods to do virtual calls on instances of _PrivateClass in this
+// library context.
+int callPrivateInstanceMethod(_PrivateClass other) => other._privateInstanceMethod();
+int callInstanceMethod(_PrivateClass other) => other.instanceMethod();
+int readInstanceField(_PrivateClass other) => other.x;
+
+// A private mixin to be exported via a typedef.
+mixin _PrivateMixin {
+ int mixinMethod() => privateLibrarySentinel;
+ int _privateMixinMethod() => privateLibrarySentinel;
+}
+
+// Helper method to call a private method on the mixin in this library context.
+int callPrivateMixinMethod(_PrivateMixin other) => other._privateMixinMethod();
+
+// Export the private mixin
+typedef PublicMixin = _PrivateMixin;
+
+// A private super-mixin which is intended to be mixed onto PublicClass
+// and which makes super calls into it.
+mixin _PrivateSuperMixin on PublicClass {
+ int mixinMethod() => super.instanceMethod();
+ int _privateMixinMethod() => super._privateInstanceMethod();
+}
+
+// Call the private SuperMixinMethod
+int callPrivateSuperMixinMethod(_PrivateSuperMixin other) =>
+other._privateMixinMethod();
+
+// Export the private super-mixin.
+typedef PublicSuperMixin = _PrivateSuperMixin;
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_error_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_error_test.dart
new file mode 100644
index 0000000..87642bc
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_error_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that a private mixin exported via a typedef cannot be used as a class.
+
+import "private_name_library.dart";
+
+/// Class that attempts to use a private mixin as a class via a public typedef
+/// name.
+class A0 extends PublicMixin {}
+// ^
+// [cfe] The superclass, '_PrivateMixin', has no unnamed constructor that takes no arguments.
+// ^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.EXTENDS_NON_CLASS
+
+void main() {}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_test.dart
new file mode 100644
index 0000000..3ca5bc3
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_mixin_test.dart
@@ -0,0 +1,75 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs can be used as mixins.
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+// Class that mixes in a private mixin via a public name.
+class Derived0 with PublicMixin {}
+
+void test0() {
+ // Test that the Derived0 class receives the PublicMixin methods.
+ PublicMixin p = Derived0();
+ Expect.equals(privateLibrarySentinel, p.mixinMethod());
+ // The private mixin method is accessible in the original library.
+ Expect.equals(privateLibrarySentinel, callPrivateMixinMethod(p));
+ // The private mixin method is not accessible in this library.
+ Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateMixinMethod());
+}
+
+// Class that mixes in a private mixin via a public name and overrides the
+// PublicMixin methods.
+class Derived1 with PublicMixin {
+ int mixinMethod() => publicLibrarySentinel;
+ int _privateMixinMethod() => publicLibrarySentinel;
+}
+
+void test1() {
+ // Test that the mixed in methods have been overriden correctly, and that the
+ // private methods from the two libraries resolve correctly.
+ var p = Derived1();
+ Expect.equals(publicLibrarySentinel, p.mixinMethod());
+ // The overriding private mixin method is accessible in this library.
+ Expect.equals(publicLibrarySentinel, p._privateMixinMethod());
+ // The original private mixin method is accessible in the other library.
+ Expect.equals(privateLibrarySentinel, callPrivateMixinMethod(p));
+}
+
+class _Derived2 extends PublicClass {}
+
+// This class mixes a private super-mixin onto a subclass of a private class,
+// and also defines new library private members with the same textual name as
+// private members defined in the other library.
+class Derived2 extends _Derived2 with PublicSuperMixin {
+ int _privateMixinMethod() => publicLibrarySentinel;
+ int _privateInstanceMethod() => publicLibrarySentinel;
+}
+
+void test2() {
+ // Test that the super-mixin methods resolve correctly.
+ var p = Derived2();
+ PublicSuperMixin _ = p; // Check assignability
+ PublicClass __ = p; // Check assignability
+ // The mixin and instance methods are accessible.
+ Expect.equals(privateLibrarySentinel, p.mixinMethod());
+ Expect.equals(privateLibrarySentinel, p.instanceMethod());
+ // The original private mixin and instance methods are accessible in the
+ // original library.
+ Expect.equals(privateLibrarySentinel, callPrivateSuperMixinMethod(p));
+ Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
+ // The new private mixin and instance methods are acessible in this library.
+ Expect.equals(publicLibrarySentinel, p._privateMixinMethod());
+ Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
+}
+
+void main() {
+ test0();
+ test1();
+ test2();
+}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_static_methods_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_static_methods_test.dart
index 8ea31a4..639e6c9 100644
--- a/tests/language/nonfunction_type_aliases/private_names/private_name_static_methods_test.dart
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_static_methods_test.dart
@@ -15,13 +15,14 @@
/// Test that each public typedef can be used to access static methods.
void test1() {
{
- Expect.equals(3, PublicClass.staticMethod());
+ Expect.equals(privateLibrarySentinel, PublicClass.staticMethod());
PublicClass.staticMethod().expectStaticType<Exactly<int>>();
- Expect.equals(3, AlsoPublicClass.staticMethod());
+ Expect.equals(privateLibrarySentinel, AlsoPublicClass.staticMethod());
AlsoPublicClass.staticMethod().expectStaticType<Exactly<int>>();
- Expect.equals(3, PublicGenericClassOfInt.staticMethod());
+ Expect.equals(
+ privateLibrarySentinel, PublicGenericClassOfInt.staticMethod());
PublicGenericClassOfInt.staticMethod().expectStaticType<Exactly<int>>();
}
}
diff --git a/tests/language/nonfunction_type_aliases/private_names/private_name_try_catch_test.dart b/tests/language/nonfunction_type_aliases/private_names/private_name_try_catch_test.dart
new file mode 100644
index 0000000..e4b4947
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/private_names/private_name_try_catch_test.dart
@@ -0,0 +1,42 @@
+// 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+// Test that private names exported via public typedefs can be used in a try
+// catch.
+
+import "package:expect/expect.dart";
+
+import "private_name_library.dart";
+
+class Derived extends PublicClass {}
+
+void test1() {
+ try {
+ throw Derived();
+ } on PublicClass catch (e) {}
+
+ try {
+ throw Derived();
+ } on Derived catch (e) {}
+
+ try {
+ throw PublicClass();
+ } on PublicClass catch (e) {}
+
+ try {
+ throw PublicClass();
+ } on AlsoPublicClass catch (e) {}
+
+ Expect.throws(() {
+ try {
+ throw PublicClass();
+ } on Derived catch (e) {}
+ });
+}
+
+void main() {
+ test1();
+}
diff --git a/tools/VERSION b/tools/VERSION
index f65d244..0c0a1fb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 211
+PRERELEASE 212
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 9d6d61a..94d11a1 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -380,6 +380,7 @@
"pkg/status_file/",
"pkg/test_runner/",
"pkg/vm/",
+ "pkg/vm_service/",
"pkg/vm_snapshot_analysis/",
"runtime/",
"sdk/",