Version 2.18.0-127.0.dev
Merge commit 'a5e40e49169723c5e08fa696c4d83db6a20fcb70' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 8426836..0bd5019 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -372,9 +372,6 @@
_newRefactoringManager();
}
- /// The analytics instance; note, this object can be `null`.
- telemetry.Analytics? get analytics => options.analytics;
-
/// The [Future] that completes when analysis is complete.
Future<void> get onAnalysisComplete {
if (isAnalysisComplete()) {
@@ -668,6 +665,8 @@
pubApi.close();
+ // TODO(brianwilkerson) Remove the following 6 lines when the
+ // analyticsManager is being correctly initialized.
var analytics = options.analytics;
if (analytics != null) {
analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index 1669d7b..45f1ca8 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -6,6 +6,8 @@
import 'dart:io';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/analytics/analytics_manager.dart';
+import 'package:analysis_server/src/analytics/noop_analytics_manager.dart';
import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/domains/completion/available_suggestions.dart';
@@ -63,6 +65,9 @@
/// The options of this server instance.
AnalysisServerOptions options;
+ /// The object through which analytics are to be sent.
+ final AnalyticsManager analyticsManager;
+
/// The builder for attachments that should be included into crash reports.
final CrashReportingAttachmentsBuilder crashReportingAttachmentsBuilder;
@@ -159,7 +164,8 @@
this.notificationManager, {
this.requestStatistics,
bool enableBazelWatcher = false,
- }) : resourceProvider = OverlayResourceProvider(baseResourceProvider),
+ }) : analyticsManager = NoopAnalyticsManager(),
+ resourceProvider = OverlayResourceProvider(baseResourceProvider),
pubApi = PubApi(instrumentationService, httpClient,
Platform.environment['PUB_HOSTED_URL']) {
// We can only spawn processes (eg. to run pub commands) when backed by
@@ -530,6 +536,7 @@
@mustCallSuper
void shutdown() {
pubPackageService.shutdown();
+ analyticsManager.shutdown();
}
/// Return the path to the location of the byte store on disk, or `null` if
diff --git a/pkg/analysis_server/lib/src/analytics/analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/analytics_manager.dart
new file mode 100644
index 0000000..125c1c2
--- /dev/null
+++ b/pkg/analysis_server/lib/src/analytics/analytics_manager.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/src/analytics/google_analytics_manager.dart';
+import 'package:telemetry/telemetry.dart';
+
+/// An interface for managing and reporting analytics.
+///
+/// Individual methods can either send an analytics event immediately or can
+/// collect and even consolidate information to be reported later. Clients are
+/// required to invoke the [shutdown] method before the server shuts down in
+/// order to send any cached data.
+abstract class AnalyticsManager {
+ /// Return an analytics manager that will report results using the given
+ /// [analytics].
+ factory AnalyticsManager.forAnalytics(Analytics analytics) =
+ GoogleAnalyticsManager;
+
+ /// Record that the given [response] was sent to the client.
+ void sentResponse({required Response response});
+
+ /// Record that the given [response] was sent to the client.
+ void sentResponseMessage({required ResponseMessage response});
+
+ /// The server is shutting down. Report any accumulated analytics data.
+ void shutdown();
+
+ /// Record that the server started working on the give [request] at the given
+ /// [startTime].
+ void startedRequest({required Request request, required DateTime startTime});
+
+ /// Record that the server started working on the give [request] at the given
+ /// [startTime].
+ void startedRequestMessage(
+ {required RequestMessage request, required DateTime startTime});
+
+ /// Record that the server was started at the given [time], that it was passed
+ /// the given command-line [arguments], that it was started by the client with
+ /// the given [clientId] and [clientVersion], and that it was invoked from an
+ /// SDK with the given [sdkVersion].
+ void startUp(
+ {required DateTime time,
+ required List<String> arguments,
+ required String clientId,
+ required String? clientVersion,
+ required String sdkVersion});
+}
diff --git a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
new file mode 100644
index 0000000..63ca84b
--- /dev/null
+++ b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
@@ -0,0 +1,202 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/src/analytics/analytics_manager.dart';
+import 'package:analysis_server/src/analytics/percentile_calculator.dart';
+import 'package:telemetry/telemetry.dart';
+
+/// An implementation of [AnalyticsManager] that's appropriate to use when
+/// analytics have been enabled.
+class GoogleAnalyticsManager implements AnalyticsManager {
+ /// The object used to send analytics.
+ final Analytics analytics;
+
+ /// Data about the current session, or `null` if the [startUp] method has not
+ /// been invoked.
+ _SessionData? sessionData;
+
+ /// A map from the id of a request to data about the request.
+ Map<String, _ActiveRequestData> activeRequests = {};
+
+ /// A map from the name of a request to data about all such requests that have
+ /// been responded to.
+ Map<String, _RequestData> completedRequests = {};
+
+ /// Initialize a newly created analytics manager to report to the [analytics]
+ /// service.
+ GoogleAnalyticsManager(this.analytics);
+
+ @override
+ void sentResponse({required Response response}) {
+ var sendTime = DateTime.now();
+ _recordResponseData(response.id, sendTime);
+ }
+
+ @override
+ void sentResponseMessage({required ResponseMessage response}) {
+ var sendTime = DateTime.now();
+ var id = response.id?.asString;
+ if (id == null) {
+ return;
+ }
+ _recordResponseData(id, sendTime);
+ }
+
+ @override
+ void shutdown() {
+ final sessionData = this.sessionData;
+ if (sessionData == null) {
+ return;
+ }
+ // Send session data.
+ var endTime = DateTime.now().millisecondsSinceEpoch;
+ var duration = endTime - sessionData.startTime.millisecondsSinceEpoch;
+ analytics.sendEvent('language_server', 'session', parameters: {
+ 'flags': sessionData.commandLineArguments,
+ 'clientId': sessionData.clientId,
+ 'sdkVersion': sessionData.sdkVersion,
+ 'duration': duration.toString(),
+ // TODO(brianwilkerson) Report a list of the names of the plugins that
+ // were loaded, or possibly a map from plugin names to the number of
+ // analysis roots in which the plugins were loaded.
+ 'plugins': '',
+ });
+ // Send response data.
+ for (var data in completedRequests.values) {
+ analytics.sendEvent('language_server', 'request', parameters: {
+ 'latency': data.latencyTimes.toAnalyticsString(),
+ 'name': data.method,
+ 'duration': data.responseTimes.toAnalyticsString(),
+ // TODO(brianwilkerson) Report the latencies for each of the plugins,
+ // probably as a map from plugin name to latency information.
+ 'plugins': '',
+ });
+ }
+ analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
+ analytics.close();
+ });
+ }
+
+ @override
+ void startedRequest({required Request request, required DateTime startTime}) {
+ activeRequests[request.id] = _ActiveRequestData(
+ request.method, request.clientRequestTime, startTime);
+ }
+
+ @override
+ void startedRequestMessage(
+ {required RequestMessage request, required DateTime startTime}) {
+ activeRequests[request.id.asString] = _ActiveRequestData(
+ request.method.toString(), request.clientRequestTime, startTime);
+ }
+
+ @override
+ void startUp(
+ {required DateTime time,
+ required List<String> arguments,
+ required String clientId,
+ required String? clientVersion,
+ required String sdkVersion}) {
+ sessionData = _SessionData(
+ startTime: time,
+ commandLineArguments: arguments.join(' '),
+ clientId: clientId,
+ clientVersion: clientVersion ?? '',
+ sdkVersion: sdkVersion);
+ }
+
+ /// Record that the request with the given [id] was responded to at the given
+ /// [sendTime].
+ void _recordResponseData(String id, DateTime sendTime) {
+ var data = activeRequests.remove(id);
+ if (data == null) {
+ return;
+ }
+
+ var requestName = data.requestName;
+ var clientRequestTime = data.clientRequestTime;
+ var startTime = data.startTime.millisecondsSinceEpoch;
+
+ var requestData = completedRequests.putIfAbsent(
+ requestName, () => _RequestData(requestName));
+
+ if (clientRequestTime != null) {
+ var latencyTime = startTime - clientRequestTime;
+ requestData.latencyTimes.addValue(latencyTime);
+ }
+
+ var responseTime = sendTime.millisecondsSinceEpoch - startTime;
+ requestData.responseTimes.addValue(responseTime);
+ }
+}
+
+/// Data about a request that was received and is being handled.
+class _ActiveRequestData {
+ /// The name of the request that was received.
+ final String requestName;
+
+ /// The time at which the client sent the request.
+ final int? clientRequestTime;
+
+ /// The time at which the request was received.
+ final DateTime startTime;
+
+ /// Initialize a newly created data holder.
+ _ActiveRequestData(this.requestName, this.clientRequestTime, this.startTime);
+}
+
+/// Data about the requests that have been responded to that have the same name.
+class _RequestData {
+ /// The name of the requests.
+ final String method;
+
+ /// The percentile calculator for latency times. The _latency time_ is the
+ /// time from when the client sent the request until the time the server
+ /// started processing the request.
+ final PercentileCalculator latencyTimes = PercentileCalculator();
+
+ /// The percentile calculator for response times. The _response time_ is the
+ /// time from when the server started processing the request until the time
+ /// the response was sent.
+ final PercentileCalculator responseTimes = PercentileCalculator();
+
+ /// Initialize a newly create data holder for requests with the given
+ /// [method].
+ _RequestData(this.method);
+}
+
+/// Data about the current session.
+class _SessionData {
+ /// The time at which the current session started.
+ final DateTime startTime;
+
+ /// The command-line arguments passed to the server on startup.
+ final String commandLineArguments;
+
+ /// The name of the client that started the server.
+ final String clientId;
+
+ /// The version of the client that started the server, or an empty string if
+ /// no version information was provided.
+ final String clientVersion;
+
+ /// The version of the SDK from which the server was started.
+ final String sdkVersion;
+
+ /// Initialize a newly created data holder.
+ _SessionData(
+ {required this.startTime,
+ required this.commandLineArguments,
+ required this.clientId,
+ required this.clientVersion,
+ required this.sdkVersion});
+}
+
+extension on Either2<int, String> {
+ String get asString {
+ return map((value) => value.toString(), (value) => value);
+ }
+}
diff --git a/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart
new file mode 100644
index 0000000..36f46a5
--- /dev/null
+++ b/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/src/analytics/analytics_manager.dart';
+
+/// An implementation of [AnalyticsManager] that's appropriate to use when
+/// analytics have not been enabled.
+class NoopAnalyticsManager implements AnalyticsManager {
+ @override
+ void sentResponse({required Response response}) {}
+
+ @override
+ void sentResponseMessage({required ResponseMessage response}) {}
+
+ @override
+ void shutdown() {}
+
+ @override
+ void startedRequest(
+ {required Request request, required DateTime startTime}) {}
+
+ @override
+ void startedRequestMessage(
+ {required RequestMessage request, required DateTime startTime}) {}
+
+ @override
+ void startUp(
+ {required DateTime time,
+ required List<String> arguments,
+ required String clientId,
+ required String? clientVersion,
+ required String sdkVersion}) {}
+}
diff --git a/pkg/analysis_server/lib/src/analytics/percentile_calculator.dart b/pkg/analysis_server/lib/src/analytics/percentile_calculator.dart
new file mode 100644
index 0000000..b1a313c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/analytics/percentile_calculator.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, 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.
+
+/// An object used to calculate percentile-based analytics.
+///
+/// See https://en.wikipedia.org/wiki/Percentile.
+class PercentileCalculator {
+ /// A map from values to the number of times the value has been recorded.
+ final Map<int, int> _counts = {};
+
+ /// The number of values in [_counts].
+ int _valueCount = 0;
+
+ /// Initialize a newly created percentile calculator.
+ PercentileCalculator();
+
+ /// Record that the given [value] has been seen.
+ void addValue(int value) {
+ _counts[value] = (_counts[value] ?? 0) + 1;
+ _valueCount++;
+ }
+
+ /// Remove all of the previously seen values.
+ void clear() {
+ _counts.clear();
+ _valueCount = 0;
+ }
+
+ /// Calculates the value at the given [percentile], which must be in the range
+ /// [0..100].
+ int percentile(int percentile) {
+ assert(percentile >= 0 && percentile <= 100);
+ if (_valueCount == 0) {
+ return 0;
+ }
+ var targetIndex = _valueCount * percentile / 100;
+ var values = _counts.keys.toList()..sort();
+ // The number of values represented by walking the counts.
+ var accumulation = 0;
+ for (var i = 0; i < values.length; i++) {
+ var value = values[i];
+ accumulation += _counts[value]!;
+ if (accumulation >= targetIndex) {
+ // We've now accounted for [targetIndex] values, which includes the
+ // median value.
+ return value;
+ }
+ }
+ throw StateError('');
+ }
+
+ /// Return a string that is suitable for sending to the analytics service.
+ String toAnalyticsString() {
+ var buffer = StringBuffer();
+ buffer.write('[');
+ for (var p = 5; p <= 100; p += 5) {
+ if (p > 5) {
+ buffer.write(', ');
+ }
+ buffer.write(percentile(p));
+ }
+ buffer.write(']');
+ return buffer.toString();
+ }
+
+ @override
+ String toString() => toAnalyticsString();
+}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/analytics_enable.dart b/pkg/analysis_server/lib/src/handler/legacy/analytics_enable.dart
index 823b275..0c6b8b4 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/analytics_enable.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/analytics_enable.dart
@@ -16,7 +16,7 @@
@override
Future<void> handle() async {
var params = AnalyticsEnableParams.fromRequest(request);
- final analytics = server.analytics;
+ final analytics = server.options.analytics;
if (analytics != null) {
analytics.enabled = params.value;
}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/analytics_is_enabled.dart b/pkg/analysis_server/lib/src/handler/legacy/analytics_is_enabled.dart
index 529d1d1..7410e2a 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/analytics_is_enabled.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/analytics_is_enabled.dart
@@ -16,6 +16,7 @@
@override
Future<void> handle() async {
- sendResult(AnalyticsIsEnabledResult(server.analytics?.enabled ?? false));
+ sendResult(
+ AnalyticsIsEnabledResult(server.options.analytics?.enabled ?? false));
}
}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/analytics_send_event.dart b/pkg/analysis_server/lib/src/handler/legacy/analytics_send_event.dart
index fdb8f12..afb36ff 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/analytics_send_event.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/analytics_send_event.dart
@@ -18,7 +18,7 @@
@override
Future<void> handle() async {
- final analytics = server.analytics;
+ final analytics = server.options.analytics;
if (analytics == null) {
sendResult(AnalyticsSendEventResult());
return;
diff --git a/pkg/analysis_server/lib/src/handler/legacy/analytics_send_timing.dart b/pkg/analysis_server/lib/src/handler/legacy/analytics_send_timing.dart
index a3266a0..bddc7d0 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/analytics_send_timing.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/analytics_send_timing.dart
@@ -18,7 +18,7 @@
@override
Future<void> handle() async {
- final analytics = server.analytics;
+ final analytics = server.options.analytics;
if (analytics == null) {
sendResult(AnalyticsSendTimingResult());
return;
diff --git a/pkg/analysis_server/test/src/analytics/percentile_calculator_test.dart b/pkg/analysis_server/test/src/analytics/percentile_calculator_test.dart
new file mode 100644
index 0000000..a6a1047
--- /dev/null
+++ b/pkg/analysis_server/test/src/analytics/percentile_calculator_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/analytics/percentile_calculator.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PercentileTest);
+ });
+}
+
+@reflectiveTest
+class PercentileTest {
+ var calculator = PercentileCalculator();
+
+ void test_clear() {
+ for (int i = 1; i <= 100; i++) {
+ calculator.addValue(i);
+ }
+ calculator.clear();
+ expect(calculator.toAnalyticsString(),
+ '[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]');
+ }
+
+ void test_toAnalyticsString_empty() {
+ expect(calculator.toAnalyticsString(),
+ '[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]');
+ }
+
+ void test_toAnalyticsString_evenDistribution() {
+ for (int i = 1; i <= 100; i++) {
+ calculator.addValue(i);
+ }
+ expect(calculator.toAnalyticsString(),
+ '[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]');
+ }
+}
diff --git a/pkg/analysis_server/test/src/analytics/test_all.dart b/pkg/analysis_server/test/src/analytics/test_all.dart
new file mode 100644
index 0000000..b969877
--- /dev/null
+++ b/pkg/analysis_server/test/src/analytics/test_all.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'percentile_calculator_test.dart' as percentile_calculator;
+
+void main() {
+ defineReflectiveSuite(() {
+ percentile_calculator.main();
+ });
+}
diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart
index feab036..1b3b4b1 100644
--- a/pkg/analysis_server/test/src/test_all.dart
+++ b/pkg/analysis_server/test/src/test_all.dart
@@ -4,6 +4,7 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'analytics/test_all.dart' as analytics;
import 'cider/test_all.dart' as cider;
import 'computer/test_all.dart' as computer;
import 'domains/test_all.dart' as domains;
@@ -17,6 +18,7 @@
void main() {
defineReflectiveSuite(() {
+ analytics.main();
cider.main();
computer.main();
domains.main();
diff --git a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
index f2812d0..43f0251 100644
--- a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
@@ -388,7 +388,8 @@
AsyncMarker.Sync,
procedureNameScheme,
isExtensionMember: false,
- isInstanceMember: true);
+ isInstanceMember: true,
+ isSynthetic: true);
members["toString"] = toStringBuilder;
}
String className = name;
diff --git a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
index 1a7fe1f..2c412dd 100644
--- a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
@@ -76,7 +76,8 @@
NameScheme nameScheme,
{required bool isExtensionMember,
required bool isInstanceMember,
- String? nativeMethodName})
+ String? nativeMethodName,
+ bool isSynthetic: false})
// ignore: unnecessary_null_comparison
: assert(isExtensionMember != null),
// ignore: unnecessary_null_comparison
@@ -90,7 +91,8 @@
isExtensionInstanceMember ? ProcedureKind.Method : kind,
new FunctionNode(null),
fileUri: libraryBuilder.fileUri,
- reference: procedureReference)
+ reference: procedureReference,
+ isSynthetic: isSynthetic)
..startFileOffset = startCharOffset
..fileOffset = charOffset
..fileEndOffset = charEndOffset
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 4499a08..63f765a 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -437,7 +437,7 @@
Byte stubKind; // Index into the ProcedureStubKind enum above.
UInt flags (isStatic, isAbstract, isExternal, isConst,
isRedirectingFactory, isExtensionMember,
- isNonNullableByDefault);
+ isNonNullableByDefault, isSynthetic);
Name name;
List<Expression> annotations;
MemberReference stubTarget; // May be NullReference.
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 046f874..65690a1 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -608,6 +608,7 @@
bool IsAbstract() const { return (flags_ & kAbstract) != 0; }
bool IsExternal() const { return (flags_ & kExternal) != 0; }
bool IsConst() const { return (flags_ & kConst) != 0; }
+ bool IsSynthetic() const { return (flags_ & kSyntheticProcedure) != 0; }
bool IsForwardingStub() const {
return stub_kind_ == kAbstractForwardingStubKind ||
stub_kind_ == kConcreteForwardingStubKind;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 2ccf215..65aea3a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -154,6 +154,7 @@
};
static DartInitializationState init_state_;
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
static void CheckOffsets() {
#if !defined(IS_SIMARM_HOST64)
// These offsets are embedded in precompiled instructions. We need the
@@ -243,9 +244,16 @@
#undef CHECK_PAYLOAD_SIZEOF
#endif // !defined(IS_SIMARM_HOST64)
}
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
char* Dart::DartInit(const Dart_InitializeParams* params) {
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
CheckOffsets();
+#elif defined(ARCH_IS_64_BIT) != defined(TARGET_ARCH_IS_64_BIT)
+ return Utils::StrDup(
+ "JIT cannot simulate target architecture with different word size than "
+ "host");
+#endif
if (!Flags::Initialized()) {
return Utils::StrDup("VM initialization failed-VM Flags not initialized.");
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index a9835fa..5cb7d4f 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1977,6 +1977,7 @@
bool is_abstract = procedure_helper.IsAbstract();
bool is_external = procedure_helper.IsExternal();
bool is_extension_member = procedure_helper.IsExtensionMember();
+ bool is_synthetic = procedure_helper.IsSynthetic();
String& native_name = String::Handle(Z);
bool scan_annotations_lazy;
bool has_pragma_annotation;
@@ -2009,7 +2010,8 @@
function.set_has_pragma(has_pragma_annotation);
function.set_end_token_pos(procedure_helper.end_position_);
function.set_is_synthetic(procedure_helper.IsNoSuchMethodForwarder() ||
- procedure_helper.IsMemberSignature());
+ procedure_helper.IsMemberSignature() ||
+ is_synthetic);
function.set_is_visible(!is_invisible_function);
if (register_function) {
functions_.Add(&function);
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
index f749b28..f445ff1 100644
--- a/runtime/vm/source_report_test.cc
+++ b/runtime/vm/source_report_test.cc
@@ -1073,6 +1073,56 @@
buffer);
}
+ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_IssueCov386_EnhancedEnums) {
+ // https://github.com/dart-lang/coverage/issues/386
+ // WARNING: This MUST be big enough for the serialised JSON string.
+ const int kBufferSize = 1024;
+ char buffer[kBufferSize];
+ const char* kScript =
+ "enum FoodType {\n"
+ " candy();\n"
+ " const FoodType();\n"
+ "}\n"
+ "void main() {\n"
+ " final food = FoodType.candy;\n"
+ "}\n";
+
+ Library& lib = Library::Handle();
+ lib ^= ExecuteScript(kScript);
+ ASSERT(!lib.IsNull());
+ const Script& script =
+ Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
+
+ SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
+ JSONStream js;
+ report.PrintJSON(&js, script);
+ const char* json_str = js.ToCString();
+ ASSERT(strlen(json_str) < kBufferSize);
+ ElideJSONSubstring("classes", json_str, buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // There are two ranges at the FoodType constructor. This one is missed,
+ // but the one below is hit, so it's ok. The point is that the synthetic
+ // toString method doesn't appear in this hitmap.
+ "{\"scriptIndex\":0,\"startPos\":29,\"endPos\":45,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[29]}},"
+
+ // Main is hit.
+ "{\"scriptIndex\":0,\"startPos\":49,\"endPos\":94,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[49],\"misses\":[]}},"
+
+ // FoodType constructor is hit.
+ "{\"scriptIndex\":0,\"compiled\":true,\"startPos\":29,\"endPos\":45,"
+ "\"coverage\":{\"hits\":[29],\"misses\":[]}}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
+ buffer);
+}
+
ISOLATE_UNIT_TEST_CASE(SourceReport_Regress95008_RedirectingFactory) {
// WARNING: This MUST be big enough for the serialised JSON string.
const int kBufferSize = 1024;
diff --git a/tools/VERSION b/tools/VERSION
index 0b55526..c582ef0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 126
+PRERELEASE 127
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/utils/application_snapshot.gni b/utils/application_snapshot.gni
index 19cbb45..5679682 100644
--- a/utils/application_snapshot.gni
+++ b/utils/application_snapshot.gni
@@ -135,44 +135,51 @@
}
# Create a snapshot from kernel built above.
- dart_action(target_name) {
- if (defined(invoker.pool)) {
- pool = invoker.pool
- }
- deps = extra_deps + [ ":${target_name}_dill" ]
- depfile = "$output.d"
+ if (dart_snapshot_kind == "kernel") {
+ copy(target_name) {
+ deps = extra_deps + [ ":${target_name}_dill" ]
+ sources = [ "$target_gen_dir/$name.dart.dill" ]
+ outputs = [ output ]
- script = "$target_gen_dir/$name.dart.dill"
-
- inputs = extra_inputs
-
- outputs = [ output ]
-
- # Explicitly set DFE so Dart doesn't implicitly depend on the kernel service
- # snapshot (creating a circular dep. for kernel-service_snapshot).
- dfe = "NEVER_LOADED"
-
- abs_depfile = rebase_path(depfile)
- abs_output = rebase_path(output)
- rel_output = rebase_path(output, root_build_dir)
-
- vm_args = [
- "--deterministic",
- "--packages=$dot_packages",
- "--snapshot=$abs_output",
- "--snapshot-depfile=$abs_depfile",
- "--depfile-output-filename=$rel_output",
- ] + snapshot_vm_args
-
- if (dart_snapshot_kind == "kernel") {
- vm_args += [ "--snapshot-kind=kernel" ]
+ assert(snapshot_vm_args != "", "Ignoring unused argument")
assert(training_args != "", "Ignoring unused argument")
- args = []
- } else if (dart_snapshot_kind == "app-jit") {
- vm_args += [ "--snapshot-kind=app-jit" ]
- args = training_args
- } else {
- assert(false, "Bad dart_snapshot_kind: $dart_snapshot_kind")
+ }
+ } else {
+ dart_action(target_name) {
+ if (defined(invoker.pool)) {
+ pool = invoker.pool
+ }
+ deps = extra_deps + [ ":${target_name}_dill" ]
+ depfile = "$output.d"
+
+ script = "$target_gen_dir/$name.dart.dill"
+
+ inputs = extra_inputs
+
+ outputs = [ output ]
+
+ # Explicitly set DFE so Dart doesn't implicitly depend on the kernel service
+ # snapshot (creating a circular dep. for kernel-service_snapshot).
+ dfe = "NEVER_LOADED"
+
+ abs_depfile = rebase_path(depfile)
+ abs_output = rebase_path(output)
+ rel_output = rebase_path(output, root_build_dir)
+
+ vm_args = [
+ "--deterministic",
+ "--packages=$dot_packages",
+ "--snapshot=$abs_output",
+ "--snapshot-depfile=$abs_depfile",
+ "--depfile-output-filename=$rel_output",
+ ] + snapshot_vm_args
+
+ if (dart_snapshot_kind == "app-jit") {
+ vm_args += [ "--snapshot-kind=app-jit" ]
+ args = training_args
+ } else {
+ assert(false, "Bad dart_snapshot_kind: $dart_snapshot_kind")
+ }
}
}
}