mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:19:47 +00:00
Sort files in analysis_server_client and analyzer_plugin and add tests to keep them that way
I didn't update the generators to generate sorted output, I just whitelisted those files for now. Change-Id: Ia1d233ee978691f15bce06b2556aa3371c54183f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/141209 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
b59217721b
commit
050c7e1ac7
|
@ -5,6 +5,6 @@
|
|||
export 'package:analysis_server_client/src/protocol/protocol_base.dart';
|
||||
export 'package:analysis_server_client/src/protocol/protocol_common.dart';
|
||||
export 'package:analysis_server_client/src/protocol/protocol_constants.dart';
|
||||
export 'package:analysis_server_client/src/protocol/protocol_generated.dart';
|
||||
export 'package:analysis_server_client/src/protocol/protocol_internal.dart'
|
||||
show ResponseDecoder;
|
||||
export 'package:analysis_server_client/src/protocol/protocol_generated.dart';
|
||||
|
|
|
@ -6,10 +6,11 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:analysis_server_client/src/server_base.dart';
|
||||
import 'package:analysis_server_client/listener/server_listener.dart';
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
import 'package:analysis_server_client/src/server_base.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
export 'package:analysis_server_client/src/server_base.dart'
|
||||
show NotificationProcessor;
|
||||
|
||||
|
|
|
@ -17,6 +17,17 @@
|
|||
/// same operations as the performance critical variant, but allocates an extra
|
||||
/// object.
|
||||
class JenkinsSmiHash {
|
||||
int _hash = 0;
|
||||
|
||||
/// Finalizes the hash and return the resulting hashcode.
|
||||
@override
|
||||
int get hashCode => finish(_hash);
|
||||
|
||||
/// Accumulates the object [o] into the hash.
|
||||
void add(Object o) {
|
||||
_hash = combine(_hash, o.hashCode);
|
||||
}
|
||||
|
||||
/// Accumulates the hash code [value] into the running hash [hash].
|
||||
static int combine(int hash, int value) {
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
|
@ -41,15 +52,4 @@ class JenkinsSmiHash {
|
|||
/// Combines together four hash codes.
|
||||
static int hash4(int a, int b, int c, int d) =>
|
||||
finish(combine(combine(combine(combine(0, a), b), c), d));
|
||||
|
||||
int _hash = 0;
|
||||
|
||||
/// Accumulates the object [o] into the hash.
|
||||
void add(Object o) {
|
||||
_hash = combine(_hash, o.hashCode);
|
||||
}
|
||||
|
||||
/// Finalizes the hash and return the resulting hashcode.
|
||||
@override
|
||||
int get hashCode => finish(_hash);
|
||||
}
|
||||
|
|
|
@ -9,12 +9,6 @@ import 'dart:io';
|
|||
import 'package:analysis_server_client/listener/server_listener.dart';
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
|
||||
/// Type of callbacks used to process notifications.
|
||||
typedef NotificationProcessor = void Function(Notification notification);
|
||||
|
||||
/// A function via which data can be sent to a started server.
|
||||
typedef CommandSender = void Function(List<int> utf8bytes);
|
||||
|
||||
///
|
||||
/// Add server arguments.
|
||||
///
|
||||
|
@ -58,6 +52,12 @@ List<String> getServerArguments({
|
|||
return arguments;
|
||||
}
|
||||
|
||||
/// A function via which data can be sent to a started server.
|
||||
typedef CommandSender = void Function(List<int> utf8bytes);
|
||||
|
||||
/// Type of callbacks used to process notifications.
|
||||
typedef NotificationProcessor = void Function(Notification notification);
|
||||
|
||||
/// Implementations of the class [ServerBase] manage an analysis server,
|
||||
/// and facilitate communication to and from the server.
|
||||
///
|
||||
|
@ -74,53 +74,16 @@ abstract class ServerBase {
|
|||
/// about interactions with the server.
|
||||
final ServerListener _listener;
|
||||
|
||||
ServerListener get listener => _listener;
|
||||
|
||||
ServerBase({ServerListener listener, bool stdioPassthrough = false})
|
||||
: _listener = listener,
|
||||
_stdioPassthrough = stdioPassthrough;
|
||||
|
||||
/// Commands that have been sent to the server but not yet acknowledged,
|
||||
/// and the [Completer] objects which should be completed
|
||||
/// when acknowledgement is received.
|
||||
final _pendingCommands = <String, Completer<Map<String, dynamic>>>{};
|
||||
|
||||
/// Force kill the server. Returns a future that completes when the server
|
||||
/// stops.
|
||||
Future kill({String reason = 'none'});
|
||||
ServerBase({ServerListener listener, bool stdioPassthrough = false})
|
||||
: _listener = listener,
|
||||
_stdioPassthrough = stdioPassthrough;
|
||||
|
||||
/// Start listening to output from the server,
|
||||
/// and deliver notifications to [notificationProcessor].
|
||||
void listenToOutput({NotificationProcessor notificationProcessor});
|
||||
|
||||
/// Send a command to the server. An 'id' will be automatically assigned.
|
||||
/// The returned [Future] will be completed when the server acknowledges
|
||||
/// the command with a response.
|
||||
/// If the server acknowledges the command with a normal (non-error) response,
|
||||
/// the future will be completed with the 'result' field from the response.
|
||||
/// If the server acknowledges the command with an error response,
|
||||
/// the future will be completed with an error.
|
||||
Future<Map<String, dynamic>> send(String method, Map<String, dynamic> params);
|
||||
|
||||
/// Encodes a request for transmission and sends it as a utf8 encoded byte
|
||||
/// string with [sendWith].
|
||||
Future<Map<String, dynamic>> sendCommandWith(
|
||||
String method, Map<String, dynamic> params, CommandSender sendWith) {
|
||||
String id = '${_nextId++}';
|
||||
Map<String, dynamic> command = <String, dynamic>{
|
||||
Request.ID: id,
|
||||
Request.METHOD: method
|
||||
};
|
||||
if (params != null) {
|
||||
command[Request.PARAMS] = params;
|
||||
}
|
||||
final completer = Completer<Map<String, dynamic>>();
|
||||
_pendingCommands[id] = completer;
|
||||
String line = json.encode(command);
|
||||
listener?.requestSent(line);
|
||||
sendWith(utf8.encoder.convert('$line\n'));
|
||||
return completer.future;
|
||||
}
|
||||
ServerListener get listener => _listener;
|
||||
|
||||
/// If the implementation of [ServerBase] captures an error stream,
|
||||
/// it can use this to forward the errors to [listener] and [stderr] if
|
||||
|
@ -132,6 +95,14 @@ abstract class ServerBase {
|
|||
listener?.errorMessage(trimmedLine);
|
||||
}
|
||||
|
||||
/// Force kill the server. Returns a future that completes when the server
|
||||
/// stops.
|
||||
Future kill({String reason = 'none'});
|
||||
|
||||
/// Start listening to output from the server,
|
||||
/// and deliver notifications to [notificationProcessor].
|
||||
void listenToOutput({NotificationProcessor notificationProcessor});
|
||||
|
||||
/// Handle a (possibly) json encoded object, completing the [Completer] in
|
||||
/// [_pendingCommands] corresponding to the response. Reports problems in
|
||||
/// decoding or message synchronization using [listener], and replicates
|
||||
|
@ -189,6 +160,35 @@ abstract class ServerBase {
|
|||
}
|
||||
}
|
||||
|
||||
/// Send a command to the server. An 'id' will be automatically assigned.
|
||||
/// The returned [Future] will be completed when the server acknowledges
|
||||
/// the command with a response.
|
||||
/// If the server acknowledges the command with a normal (non-error) response,
|
||||
/// the future will be completed with the 'result' field from the response.
|
||||
/// If the server acknowledges the command with an error response,
|
||||
/// the future will be completed with an error.
|
||||
Future<Map<String, dynamic>> send(String method, Map<String, dynamic> params);
|
||||
|
||||
/// Encodes a request for transmission and sends it as a utf8 encoded byte
|
||||
/// string with [sendWith].
|
||||
Future<Map<String, dynamic>> sendCommandWith(
|
||||
String method, Map<String, dynamic> params, CommandSender sendWith) {
|
||||
String id = '${_nextId++}';
|
||||
Map<String, dynamic> command = <String, dynamic>{
|
||||
Request.ID: id,
|
||||
Request.METHOD: method
|
||||
};
|
||||
if (params != null) {
|
||||
command[Request.PARAMS] = params;
|
||||
}
|
||||
final completer = Completer<Map<String, dynamic>>();
|
||||
_pendingCommands[id] = completer;
|
||||
String line = json.encode(command);
|
||||
listener?.requestSent(line);
|
||||
sendWith(utf8.encoder.convert('$line\n'));
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/// Start the server. The returned future completes when the server
|
||||
/// is started and it is valid to call [listenToOutput].
|
||||
Future start({
|
||||
|
|
|
@ -2,10 +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.
|
||||
|
||||
import 'live_test.dart' as live_test;
|
||||
import 'server_test.dart' as server_test;
|
||||
import 'live_test.dart' as live;
|
||||
import 'server_test.dart' as server;
|
||||
import 'verify_sorted_test.dart' as verify_sorted;
|
||||
|
||||
void main() {
|
||||
server_test.main();
|
||||
live_test.main();
|
||||
live.main();
|
||||
server.main();
|
||||
verify_sorted.main();
|
||||
}
|
||||
|
|
29
pkg/analysis_server_client/test/utils/package_root.dart
Normal file
29
pkg/analysis_server_client/test/utils/package_root.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2017, 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:io';
|
||||
|
||||
import 'package:path/path.dart' as pathos;
|
||||
|
||||
/// Returns a path to the directory containing source code for packages such as
|
||||
/// kernel, front_end, and analyzer.
|
||||
String get packageRoot {
|
||||
// If the package root directory is specified on the command line using
|
||||
// -DpkgRoot=..., use it.
|
||||
const String pkgRootVar =
|
||||
bool.hasEnvironment('pkgRoot') ? String.fromEnvironment('pkgRoot') : null;
|
||||
if (pkgRootVar != null) {
|
||||
String path = pathos.join(Directory.current.path, pkgRootVar);
|
||||
if (!path.endsWith(pathos.separator)) path += pathos.separator;
|
||||
return path;
|
||||
}
|
||||
// Otherwise try to guess based on the script path.
|
||||
String scriptPath = pathos.fromUri(Platform.script);
|
||||
List<String> parts = pathos.split(scriptPath);
|
||||
int pkgIndex = parts.indexOf('pkg');
|
||||
if (pkgIndex != -1) {
|
||||
return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
|
||||
}
|
||||
throw StateError('Unable to find sdk/pkg/ in $scriptPath');
|
||||
}
|
79
pkg/analysis_server_client/test/verify_sorted_test.dart
Normal file
79
pkg/analysis_server_client/test/verify_sorted_test.dart
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2019, 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:io';
|
||||
|
||||
import 'package:analysis_server/src/services/correction/sort_members.dart';
|
||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'utils/package_root.dart';
|
||||
|
||||
void main() {
|
||||
var provider = PhysicalResourceProvider.INSTANCE;
|
||||
var normalizedRoot = provider.pathContext.normalize(packageRoot);
|
||||
var packagePath =
|
||||
provider.pathContext.join(normalizedRoot, 'analysis_server_client');
|
||||
// TODO(brianwilkerson) Fix the generator to sort the generated files and
|
||||
// remove these exclusions.
|
||||
var generatedFilePaths = [
|
||||
provider.pathContext
|
||||
.join(packagePath, 'lib', 'src', 'protocol', 'protocol_common.dart'),
|
||||
provider.pathContext
|
||||
.join(packagePath, 'lib', 'src', 'protocol', 'protocol_constants.dart'),
|
||||
provider.pathContext
|
||||
.join(packagePath, 'lib', 'src', 'protocol', 'protocol_generated.dart'),
|
||||
];
|
||||
|
||||
var collection = AnalysisContextCollection(
|
||||
includedPaths: <String>[packagePath],
|
||||
excludedPaths: generatedFilePaths,
|
||||
resourceProvider: provider);
|
||||
var contexts = collection.contexts;
|
||||
if (contexts.length != 1) {
|
||||
fail('The directory $packagePath contains multiple analysis contexts.');
|
||||
}
|
||||
|
||||
buildTestsIn(contexts[0].currentSession, packagePath, generatedFilePaths,
|
||||
provider.getFolder(packagePath));
|
||||
}
|
||||
|
||||
void buildTestsIn(AnalysisSession session, String testDirPath,
|
||||
List<String> generatedFilePaths, Folder directory) {
|
||||
var pathContext = session.resourceProvider.pathContext;
|
||||
var children = directory.getChildren();
|
||||
children.sort((first, second) => first.shortName.compareTo(second.shortName));
|
||||
for (var child in children) {
|
||||
if (child is Folder) {
|
||||
buildTestsIn(session, testDirPath, generatedFilePaths, child);
|
||||
} else if (child is File && child.shortName.endsWith('.dart')) {
|
||||
var path = child.path;
|
||||
if (generatedFilePaths.contains(path)) {
|
||||
continue;
|
||||
}
|
||||
var relativePath = pathContext.relative(path, from: testDirPath);
|
||||
test(relativePath, () {
|
||||
var result = session.getParsedUnit(path);
|
||||
if (result.state != ResultState.VALID) {
|
||||
fail('Could not parse $path');
|
||||
}
|
||||
var code = result.content;
|
||||
var unit = result.unit;
|
||||
var errors = result.errors;
|
||||
if (errors.isNotEmpty) {
|
||||
fail('Errors found when parsing $path');
|
||||
}
|
||||
var sorter = MemberSorter(code, unit);
|
||||
var edits = sorter.sort();
|
||||
if (edits.isNotEmpty) {
|
||||
fail('Unsorted file $path');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import '../tool/spec/check_all_test.dart' as check_spec;
|
|||
import 'plugin/test_all.dart' as plugin;
|
||||
import 'src/test_all.dart' as src;
|
||||
import 'utilities/test_all.dart' as utilities;
|
||||
import 'verify_sorted_test.dart' as verify_sorted;
|
||||
import 'verify_tests_test.dart' as verify_tests;
|
||||
|
||||
void main() {
|
||||
|
@ -16,6 +17,7 @@ void main() {
|
|||
src.main();
|
||||
utilities.main();
|
||||
verify_tests.main();
|
||||
verify_sorted.main();
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(SpecTest);
|
||||
}, name: 'spec');
|
||||
|
|
81
pkg/analyzer_plugin/test/verify_sorted_test.dart
Normal file
81
pkg/analyzer_plugin/test/verify_sorted_test.dart
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) 2019, 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:io';
|
||||
|
||||
import 'package:analysis_server/src/services/correction/sort_members.dart';
|
||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'utils/package_root.dart';
|
||||
|
||||
void main() {
|
||||
var provider = PhysicalResourceProvider.INSTANCE;
|
||||
var normalizedRoot = provider.pathContext.normalize(packageRoot);
|
||||
var packagePath =
|
||||
provider.pathContext.join(normalizedRoot, 'analyzer_plugin');
|
||||
// TODO(brianwilkerson) Fix the generator to sort the generated files and
|
||||
// remove these exclusions.
|
||||
var generatedFilePaths = [
|
||||
provider.pathContext
|
||||
.join(packagePath, 'lib', 'protocol', 'protocol_common.dart'),
|
||||
provider.pathContext
|
||||
.join(packagePath, 'lib', 'protocol', 'protocol_generated.dart'),
|
||||
provider.pathContext.join(packagePath, 'test', 'integration', 'support',
|
||||
'integration_test_methods.dart'),
|
||||
provider.pathContext.join(packagePath, 'test', 'integration', 'support',
|
||||
'protocol_matchers.dart'),
|
||||
];
|
||||
|
||||
var collection = AnalysisContextCollection(
|
||||
includedPaths: <String>[packagePath],
|
||||
excludedPaths: generatedFilePaths,
|
||||
resourceProvider: provider);
|
||||
var contexts = collection.contexts;
|
||||
if (contexts.length != 1) {
|
||||
fail('The directory $packagePath contains multiple analysis contexts.');
|
||||
}
|
||||
|
||||
buildTestsIn(contexts[0].currentSession, packagePath, generatedFilePaths,
|
||||
provider.getFolder(packagePath));
|
||||
}
|
||||
|
||||
void buildTestsIn(AnalysisSession session, String testDirPath,
|
||||
List<String> generatedFilePaths, Folder directory) {
|
||||
var pathContext = session.resourceProvider.pathContext;
|
||||
var children = directory.getChildren();
|
||||
children.sort((first, second) => first.shortName.compareTo(second.shortName));
|
||||
for (var child in children) {
|
||||
if (child is Folder) {
|
||||
buildTestsIn(session, testDirPath, generatedFilePaths, child);
|
||||
} else if (child is File && child.shortName.endsWith('.dart')) {
|
||||
var path = child.path;
|
||||
if (generatedFilePaths.contains(path)) {
|
||||
continue;
|
||||
}
|
||||
var relativePath = pathContext.relative(path, from: testDirPath);
|
||||
test(relativePath, () {
|
||||
var result = session.getParsedUnit(path);
|
||||
if (result.state != ResultState.VALID) {
|
||||
fail('Could not parse $path');
|
||||
}
|
||||
var code = result.content;
|
||||
var unit = result.unit;
|
||||
var errors = result.errors;
|
||||
if (errors.isNotEmpty) {
|
||||
fail('Errors found when parsing $path');
|
||||
}
|
||||
var sorter = MemberSorter(code, unit);
|
||||
var edits = sorter.sort();
|
||||
if (edits.isNotEmpty) {
|
||||
fail('Unsorted file $path');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue