[analysis_server] Ensure plugin protocol classes only use types valid for Isolate.send()

Fixes https://github.com/dart-lang/sdk/issues/50594.

Change-Id: I5550239dbce4a1ed7fbd844dd53642989289c899
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273200
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2022-12-01 16:57:56 +00:00 committed by Commit Queue
parent 5fd3d4b810
commit a7baf9309f
4 changed files with 104 additions and 3 deletions

View file

@ -76,7 +76,7 @@ bool mapEqual<K, V>(
/// [valueCallback] to all its values.
Map<KR, VR> mapMap<KP, VP, KR, VR>(Map<KP, VP> map,
{KR Function(KP key)? keyCallback, VR Function(VP value)? valueCallback}) {
Map<KR, VR> result = HashMap<KR, VR>();
var result = <KR, VR>{};
map.forEach((key, value) {
KR resultKey;
VR resultValue;

View file

@ -142,7 +142,7 @@ bool mapEqual<K, V>(
/// [valueCallback] to all its values.
Map<KR, VR> mapMap<KP, VP, KR, VR>(Map<KP, VP> map,
{KR Function(KP key)? keyCallback, VR Function(VP value)? valueCallback}) {
Map<KR, VR> result = HashMap<KR, VR>();
var result = <KR, VR>{};
map.forEach((key, value) {
KR resultKey;
VR resultValue;

View file

@ -174,7 +174,7 @@ bool mapEqual<K, V>(
/// [valueCallback] to all its values.
Map<KR, VR> mapMap<KP, VP, KR, VR>(Map<KP, VP> map,
{KR Function(KP key)? keyCallback, VR Function(VP value)? valueCallback}) {
Map<KR, VR> result = HashMap<KR, VR>();
var result = <KR, VR>{};
map.forEach((key, value) {
KR resultKey;
VR resultValue;

View file

@ -2,6 +2,9 @@
// 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:convert';
import 'dart:isolate';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/file_system/file_system.dart';
@ -11,6 +14,7 @@ import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
import 'package:meta/meta.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
@ -64,6 +68,31 @@ class ServerPluginTest extends AbstractPluginTest {
late String filePath2;
late ContextRoot contextRoot2;
/// Asserts that [params] is valid to send to an [Isolate] started with
/// [Isolate.spawnUri].
Future<void> assertValidForIsolateSend(RequestParams params) async {
const isolateSource = r'''
import 'dart:isolate';
void main(List<String> args, SendPort sendPort) {
final receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((msg) => sendPort.send('ECHO: $msg'));
}
''';
final isolateUri = Uri.dataFromString(isolateSource, encoding: utf8);
final receivePort = ReceivePort();
final isolate =
await Isolate.spawnUri(isolateUri, [], receivePort.sendPort);
final sendPort = (await receivePort.first) as SendPort;
try {
sendPort.send(params.toJson());
} catch (e) {
fail('Failed to send ${params.runtimeType} across Isolate: $e');
}
isolate.kill();
}
@override
ServerPlugin createPlugin() {
return _TestServerPlugin(resourceProvider);
@ -229,6 +258,78 @@ class ServerPluginTest extends AbstractPluginTest {
fail('Not yet implemented.');
}
Future<void> test_isolateSend_analysisGetNavigation() async {
await assertValidForIsolateSend(AnalysisGetNavigationParams('', 1, 2));
}
Future<void> test_isolateSend_analysisHandleWatchEvents() async {
await assertValidForIsolateSend(AnalysisHandleWatchEventsParams([]));
}
Future<void> test_isolateSend_analysisSetPriorityFiles() async {
await assertValidForIsolateSend(
AnalysisSetPriorityFilesParams([filePath1]));
}
Future<void> test_isolateSend_analysisSetSubscriptions() async {
await assertValidForIsolateSend(AnalysisSetSubscriptionsParams({
AnalysisService.OUTLINE: [filePath1]
}));
}
Future<void> test_isolateSend_analysisUpdateContent_add() async {
await assertValidForIsolateSend(AnalysisUpdateContentParams(
{filePath1: AddContentOverlay('class C {}')}));
}
Future<void> test_isolateSend_analysisUpdateContent_change() async {
await assertValidForIsolateSend(AnalysisUpdateContentParams({
filePath1: ChangeContentOverlay([SourceEdit(7, 0, ' extends Object')])
}));
}
Future<void> test_isolateSend_analysisUpdateContent_remove() async {
await assertValidForIsolateSend(
AnalysisUpdateContentParams({filePath1: RemoveContentOverlay()}));
}
Future<void> test_isolateSend_completionGetSuggestions() async {
await assertValidForIsolateSend(
CompletionGetSuggestionsParams(filePath1, 12));
}
Future<void> test_isolateSend_editGetAssists() async {
await assertValidForIsolateSend(EditGetAssistsParams(filePath1, 10, 0));
}
Future<void> test_isolateSend_editGetAvailableRefactorings() async {
await assertValidForIsolateSend(
EditGetAvailableRefactoringsParams(filePath1, 10, 0));
}
Future<void> test_isolateSend_editGetFixes() async {
await assertValidForIsolateSend(EditGetFixesParams(filePath1, 13));
}
Future<void> test_isolateSend_editGetRefactoring() async {
await assertValidForIsolateSend(EditGetRefactoringParams(
RefactoringKind.RENAME, filePath1, 7, 0, false));
}
Future<void> test_isolateSend_pluginShutdown() async {
await assertValidForIsolateSend(PluginShutdownParams());
}
Future<void> test_isolateSend_pluginVersionCheck() async {
await assertValidForIsolateSend(
PluginVersionCheckParams('byteStorePath', 'sdkPath', '0.1.0'));
}
Future<void> test_isolateSend_setContextRoots() async {
await assertValidForIsolateSend(
AnalysisSetContextRootsParams([contextRoot1]));
}
void test_onDone() {
channel.sendDone();
}