Version 2.10.0-147.0.dev
Merge commit '51840c501aafa8cea4e4de5fabedf85dc9a4d664' into 'dev'
diff --git a/DEPS b/DEPS
index d96c4d0..8e76008 100644
--- a/DEPS
+++ b/DEPS
@@ -114,7 +114,7 @@
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_rev": "8f189db8f0c299187a0e8fa959dba7e9b0254be5",
"linter_tag": "0.1.119",
- "logging_rev": "9561ba016ae607747ae69b846c0e10958ca58ed4",
+ "logging_rev": "1590ba0b648a51e7eb3895c612e4b72f72623b6f",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_rev": "dbeafd47759e7dd0a167602153bb9c49fb5e5fe7",
"matcher_rev": "9cae8faa7868bf3a88a7ba45eb0bd128e66ac515",
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 71b8251..9e50585 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -534,6 +534,9 @@
/// Return `true` if this element has an annotation of the form `@factory`.
bool get hasFactory;
+ /// Return `true` if this element has an annotation of the form `@internal`.
+ bool get hasInternal;
+
/// Return `true` if this element has an annotation of the form `@isTest`.
bool get hasIsTest;
@@ -717,6 +720,10 @@
/// subclasses as being immutable.
bool get isImmutable;
+ /// Return `true` if this annotation marks the associated element as being
+ /// internal to its package.
+ bool get isInternal;
+
/// Return `true` if this annotation marks the associated member as running
/// a single test.
bool get isIsTest;
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 4f13b90..9312ea8 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -492,10 +492,12 @@
HintCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
HintCode.INVALID_ANNOTATION_TARGET,
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
HintCode.INVALID_FACTORY_ANNOTATION,
HintCode.INVALID_FACTORY_METHOD_DECL,
HintCode.INVALID_FACTORY_METHOD_IMPL,
HintCode.INVALID_IMMUTABLE_ANNOTATION,
+ HintCode.INVALID_INTERNAL_ANNOTATION,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index ecf68fe..63df85d 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2313,6 +2313,10 @@
/// as being immutable.
static const String _IMMUTABLE_VARIABLE_NAME = "immutable";
+ /// The name of the top-level variable used to mark an element as being
+ /// internal to its package.
+ static const String _INTERNAL_VARIABLE_NAME = "internal";
+
/// The name of the top-level variable used to mark a constructor as being
/// literal.
static const String _LITERAL_VARIABLE_NAME = "literal";
@@ -2460,6 +2464,12 @@
element.library?.name == _META_LIB_NAME;
@override
+ bool get isInternal =>
+ element is PropertyAccessorElement &&
+ element.name == _INTERNAL_VARIABLE_NAME &&
+ element.library?.name == _META_LIB_NAME;
+
+ @override
bool get isIsTest =>
element is PropertyAccessorElement &&
element.name == _IS_TEST_VARIABLE_NAME &&
@@ -2748,6 +2758,18 @@
}
@override
+ bool get hasInternal {
+ var metadata = this.metadata;
+ for (var i = 0; i < metadata.length; i++) {
+ var annotation = metadata[i];
+ if (annotation.isInternal) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
bool get hasIsTest {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
@@ -5996,6 +6018,9 @@
bool get hasFactory => false;
@override
+ bool get hasInternal => false;
+
+ @override
bool get hasIsTest => false;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index 641f80f..d6dd68a 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -14,7 +14,6 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart';
-import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/error/codes.dart'
@@ -477,7 +476,7 @@
void _nonNullifyTypes(List<DartType> types) {
if (_typeSystem.isNonNullableByDefault) {
for (var i = 0; i < types.length; i++) {
- types[i] = nonNullifyType(_typeSystem, types[i]);
+ types[i] = _typeSystem.nonNullifyLegacy(types[i]);
}
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index a37c9d4..5c08ec5 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -460,6 +460,9 @@
bool get hasFactory => _declaration.hasFactory;
@override
+ bool get hasInternal => _declaration.hasInternal;
+
+ @override
bool get hasIsTest => _declaration.hasIsTest;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/type_demotion.dart b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
index 581f22b..37757e7 100644
--- a/pkg/analyzer/lib/src/dart/element/type_demotion.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
@@ -8,17 +8,16 @@
import 'package:analyzer/dart/element/type_visitor.dart';
import 'package:analyzer/src/dart/element/replacement_visitor.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_system.dart';
/// Returns [type] in which all promoted type variables have been replace with
/// their unpromoted equivalents, and, if [library] is non-nullable by default,
/// replaces all legacy types with their non-nullable equivalents.
DartType demoteType(LibraryElement library, DartType type) {
if (library.isNonNullableByDefault) {
- var visitor = const _DemotionNonNullification();
+ var visitor = const DemotionNonNullificationVisitor();
return type.accept(visitor) ?? type;
} else {
- var visitor = const _DemotionNonNullification(nonNullifyTypes: false);
+ var visitor = const DemotionNonNullificationVisitor(nonNullifyTypes: false);
return type.accept(visitor) ?? type;
}
}
@@ -30,25 +29,15 @@
);
}
-/// Returns [type] in which all legacy types have been replaced with
-/// non-nullable types.
-DartType nonNullifyType(TypeSystemImpl typeSystem, DartType type) {
- if (typeSystem.isNonNullableByDefault && type != null) {
- var visitor = const _DemotionNonNullification(demoteTypeVariables: false);
- return type.accept(visitor) ?? type;
- }
- return type;
-}
-
/// Visitor that replaces all promoted type variables the type variable itself
/// and/or replaces all legacy types with non-nullable types.
///
/// The visitor returns `null` if the type wasn't changed.
-class _DemotionNonNullification extends ReplacementVisitor {
+class DemotionNonNullificationVisitor extends ReplacementVisitor {
final bool demoteTypeVariables;
final bool nonNullifyTypes;
- const _DemotionNonNullification({
+ const DemotionNonNullificationVisitor({
this.demoteTypeVariables = true,
this.nonNullifyTypes = true,
}) : assert(demoteTypeVariables || nonNullifyTypes);
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index e4c683a..bb8f69f 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -25,6 +25,7 @@
import 'package:analyzer/src/dart/element/top_merge.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_schema_elimination.dart';
@@ -1181,6 +1182,17 @@
return inferredTypes;
}
+ /// Replace legacy types in [type] with non-nullable types.
+ DartType nonNullifyLegacy(DartType type) {
+ if (isNonNullableByDefault && type != null) {
+ var visitor = const DemotionNonNullificationVisitor(
+ demoteTypeVariables: false,
+ );
+ return type.accept(visitor) ?? type;
+ }
+ return type;
+ }
+
/// Compute the canonical representation of [T].
///
/// https://github.com/dart-lang/language
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 9d9c4eb..9be0aa2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -577,6 +577,19 @@
"The annotation '{0}' can only be used on {1}");
/**
+ * This hint is generated anywhere where an element annotated with `@internal`
+ * is exported as a part of a package's public API.
+ *
+ * Parameters:
+ * 0: the name of the element
+ */
+ static const HintCode INVALID_EXPORT_OF_INTERNAL_ELEMENT = HintCode(
+ 'INVALID_EXPORT_OF_INTERNAL_ELEMENT',
+ "The member '{0}' can't be exported as a part of a package's public "
+ "API.",
+ correction: "Try using a hide clause to hide '{0}'.");
+
+ /**
* This hint is generated anywhere a @factory annotation is associated with
* anything other than a method.
*/
@@ -612,6 +625,15 @@
'INVALID_IMMUTABLE_ANNOTATION',
"Only classes can be annotated as being immutable.");
+ /**
+ * This hint is generated anywhere a @internal annotation is associated with
+ * an element found in a package's public API.
+ */
+ static const HintCode INVALID_INTERNAL_ANNOTATION = HintCode(
+ 'INVALID_INTERNAL_ANNOTATION',
+ "Only public elements in a package's private API can be annotated as "
+ "being internal.");
+
/// Invalid Dart language version comments don't follow the specification [1].
/// If a comment begins with "@dart" or "dart" (letters in any case),
/// followed by optional whitespace, followed by optional non-alphanumeric,
@@ -922,7 +944,7 @@
/**
* This hint is generated anywhere where a member annotated with `@protected`
- * is used outside an instance member of a subclass.
+ * is used outside of an instance member of a subclass.
*
* Parameters:
* 0: the name of the member
diff --git a/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart b/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
index 6b5aaf4..b470871 100644
--- a/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/body_inference_context.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:meta/meta.dart';
@@ -137,7 +136,7 @@
}
// Otherwise, let `S` be `R`.
- return nonNullifyType(_typeSystem, R);
+ return _typeSystem.nonNullifyLegacy(R);
}
DartType _computeActualReturnedType({
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
index f496a13..0f3a2b1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
@@ -112,7 +111,7 @@
inferredType = _migrationResolutionHooks.modifyInferredParameterType(
p, inferredType);
} else {
- inferredType = nonNullifyType(_typeSystem, inferredType);
+ inferredType = _typeSystem.nonNullifyLegacy(inferredType);
}
if (!inferredType.isDynamic) {
p.type = inferredType;
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 24c9c85..5d65e55 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -21,6 +21,7 @@
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -113,6 +114,11 @@
);
}
+ bool get _inPublicPackageApi {
+ return _workspacePackage != null &&
+ _workspacePackage.sourceIsInPublicApi(_currentLibrary.source);
+ }
+
@override
void visitAnnotation(Annotation node) {
ElementAnnotation element = node.elementAnnotation;
@@ -132,6 +138,35 @@
_errorReporter.reportErrorForNode(
HintCode.INVALID_IMMUTABLE_ANNOTATION, node, []);
}
+ } else if (element.isInternal) {
+ var parentElement = parent is Declaration ? parent.declaredElement : null;
+ if (parent is TopLevelVariableDeclaration) {
+ for (VariableDeclaration variable in parent.variables.variables) {
+ if (Identifier.isPrivateName(variable.declaredElement.name)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, variable, []);
+ }
+ }
+ } else if (parent is FieldDeclaration) {
+ for (VariableDeclaration variable in parent.fields.variables) {
+ if (Identifier.isPrivateName(variable.declaredElement.name)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, variable, []);
+ }
+ }
+ } else if (parent is ConstructorDeclaration) {
+ var class_ = parent.declaredElement.enclosingElement;
+ if (class_.isPrivate || (parentElement?.isPrivate ?? false)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ }
+ } else if (parentElement?.isPrivate ?? false) {
+ _errorReporter
+ .reportErrorForNode(HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ } else if (_inPublicPackageApi) {
+ _errorReporter
+ .reportErrorForNode(HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ }
} else if (element.isLiteral == true) {
if (parent is! ConstructorDeclaration ||
(parent as ConstructorDeclaration).constKeyword == null) {
@@ -319,6 +354,7 @@
@override
void visitExportDirective(ExportDirective node) {
_checkForDeprecatedMemberUse(node.uriElement, node);
+ _checkForInternalExport(node);
super.visitExportDirective(node);
}
@@ -994,6 +1030,31 @@
}
}
+ /// Check that the namespace exported by [node] does not include any elements
+ /// annotated with `@internal`.
+ void _checkForInternalExport(ExportDirective node) {
+ if (!_inPublicPackageApi) return;
+
+ var libraryElement = node.uriElement;
+ if (libraryElement == null) return;
+ if (libraryElement.hasInternal) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+ node,
+ [libraryElement.displayName]);
+ }
+ var exportNamespace =
+ NamespaceBuilder().createExportNamespaceForDirective(node.element);
+ exportNamespace.definedNames.forEach((String name, Element element) {
+ if (element.hasInternal) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+ node,
+ [element.displayName]);
+ }
+ });
+ }
+
void _checkForInvalidFactory(MethodDeclaration decl) {
// Check declaration.
// Note that null return types are expected to be flagged by other analyses.
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 0918c70..6639055 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/summary/format.dart';
@@ -450,7 +449,7 @@
}
if (_typeSystem.isNonNullableByDefault) {
- return nonNullifyType(_typeSystem, type);
+ return _typeSystem.nonNullifyLegacy(type);
} else {
if (type.isBottom) {
return DynamicTypeImpl.instance;
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index fe58576..2f72a64 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -10,7 +10,6 @@
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
@@ -141,7 +140,7 @@
);
if (combinedGetter != null) {
var returnType = combinedGetter.returnType;
- return nonNullifyType(typeSystem, returnType);
+ return typeSystem.nonNullifyLegacy(returnType);
}
return DynamicTypeImpl.instance;
}
@@ -155,7 +154,7 @@
);
if (combinedSetter != null) {
var type = combinedSetter.parameters[0].type;
- return nonNullifyType(typeSystem, type);
+ return typeSystem.nonNullifyLegacy(type);
}
return DynamicTypeImpl.instance;
}
@@ -282,7 +281,7 @@
if (getterType == setterType) {
var type = getterType;
- type = nonNullifyType(typeSystem, type);
+ type = typeSystem.nonNullifyLegacy(type);
field.type = type;
} else {
LazyAst.setTypeInferenceError(
@@ -443,7 +442,7 @@
if (element.hasImplicitReturnType && element.displayName != '[]=') {
if (combinedSignatureType != null) {
var returnType = combinedSignatureType.returnType;
- returnType = nonNullifyType(typeSystem, returnType);
+ returnType = typeSystem.nonNullifyLegacy(returnType);
element.returnType = returnType;
} else {
element.returnType = DynamicTypeImpl.instance;
@@ -490,7 +489,7 @@
);
if (matchingParameter != null) {
var type = matchingParameter.type;
- type = nonNullifyType(typeSystem, type);
+ type = typeSystem.nonNullifyLegacy(type);
parameter.type = type;
} else {
parameter.type = DynamicTypeImpl.instance;
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index 2f054b5..9482e66 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -28,6 +28,7 @@
const _DoNotStore doNotStore = _DoNotStore();
const _Factory factory = const _Factory();
const Immutable immutable = const Immutable();
+const _Internal internal = const Internal();
const _Literal literal = const _Literal();
const _MustCallSuper mustCallSuper = const _MustCallSuper();
const _NonVirtual nonVirtual = const _NonVirtual();
@@ -50,6 +51,9 @@
final String reason;
const Immutable([this.reason]);
}
+class _Internal {
+ const Internal();
+}
class _Literal {
const _Literal();
}
diff --git a/pkg/analyzer/lib/src/workspace/basic.dart b/pkg/analyzer/lib/src/workspace/basic.dart
index fb02a62..5f3be2a 100644
--- a/pkg/analyzer/lib/src/workspace/basic.dart
+++ b/pkg/analyzer/lib/src/workspace/basic.dart
@@ -80,4 +80,12 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace.packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ // Since every source file in a BasicPackage is in the same directory, they
+ // are all in the public API of the package. A file in a subdirectory
+ // is in a separate package.
+ return true;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index 0320187..2c474e6 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -260,6 +260,19 @@
WorkspacePackage findPackageFor(String filePath) {
path.Context context = provider.pathContext;
Folder folder = provider.getFolder(context.dirname(filePath));
+ if (!context.isWithin(root, folder.path)) {
+ return null;
+ }
+
+ // Handle files which are given with their location in "bazel-bin", etc.
+ // This does not typically happen during usual analysis, but it still could,
+ // and it can come up in tests.
+ if ([genfiles, ...binPaths]
+ .any((binPath) => context.isWithin(binPath, folder.path))) {
+ var relative = context.relative(filePath, from: root);
+ return findPackageFor(
+ context.joinAll([root, ...context.split(relative).skip(1)]));
+ }
while (true) {
Folder parent = folder.parent;
@@ -300,7 +313,8 @@
// [folder]'s path, relative to [root]. For example, "foo/bar".
String relative = context.relative(folder.path, from: root);
for (String bin in binPaths) {
- Folder binChild = provider.getFolder(context.join(bin, relative));
+ Folder binChild =
+ provider.getFolder(context.normalize(context.join(bin, relative)));
if (binChild.exists &&
binChild.getChildren().any((c) => c.path.endsWith('.packages'))) {
// [folder]'s sister folder within [bin] contains a ".packages" file.
@@ -548,4 +562,41 @@
// lists.
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
<String, List<Folder>>{};
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$root/lib" is public iff it is not in "$root/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ var relativeRoot =
+ workspace.provider.pathContext.relative(root, from: workspace.root);
+ for (var binPath in workspace.binPaths) {
+ libFolder =
+ workspace.provider.pathContext.join(binPath, relativeRoot, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$bin/lib" is public iff it is not in "$bin/lib/src".
+ var libSrcFolder =
+ workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ }
+
+ libFolder = workspace.provider.pathContext
+ .join(workspace.genfiles, relativeRoot, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$genfiles/lib" is public iff it is not in
+ // "$genfiles/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/gn.dart b/pkg/analyzer/lib/src/workspace/gn.dart
index cca441f..fe78cc0 100644
--- a/pkg/analyzer/lib/src/workspace/gn.dart
+++ b/pkg/analyzer/lib/src/workspace/gn.dart
@@ -237,4 +237,17 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace.packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ var libSrcFolder =
+ workspace.provider.pathContext.join(root, 'lib', 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/package_build.dart b/pkg/analyzer/lib/src/workspace/package_build.dart
index 60eb742..7240390 100644
--- a/pkg/analyzer/lib/src/workspace/package_build.dart
+++ b/pkg/analyzer/lib/src/workspace/package_build.dart
@@ -137,6 +137,12 @@
/// package:build does it.
static const String _pubspecName = 'pubspec.yaml';
+ static const List<String> _generatedPathParts = [
+ '.dart_tool',
+ 'build',
+ 'generated'
+ ];
+
/// The resource provider used to access the file system.
final ResourceProvider provider;
@@ -286,7 +292,7 @@
final yaml = loadYaml(pubspec.readAsStringSync());
final packageName = yaml['name'] as String;
final generatedRootPath = provider.pathContext
- .join(folder.path, '.dart_tool', 'build', 'generated');
+ .joinAll([folder.path, ..._generatedPathParts]);
final generatedThisPath =
provider.pathContext.join(generatedRootPath, packageName);
return PackageBuildWorkspace._(provider, packageMap, folder.path,
@@ -334,4 +340,26 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace._packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$root/lib" is public iff it is not in "$root/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ libFolder = workspace.provider.pathContext.joinAll(
+ [root, ...PackageBuildWorkspace._generatedPathParts, 'test', 'lib']);
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$generated/lib" is public iff it is not in
+ // "$generated/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/pub.dart b/pkg/analyzer/lib/src/workspace/pub.dart
index f47327d..1fed22e 100644
--- a/pkg/analyzer/lib/src/workspace/pub.dart
+++ b/pkg/analyzer/lib/src/workspace/pub.dart
@@ -120,4 +120,20 @@
// [libraryPath] is inside the `lib` directory.
return workspace.packageMap;
}
+
+ @override
+
+ /// A Pub package's public API consists of libraries found in the top-level
+ /// "lib" directory, and any subdirectories, excluding the "src" directory
+ /// just inside the top-level "lib" directory.
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (!workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ return false;
+ }
+ var libSrcFolder = workspace.provider.pathContext.join(root, 'lib', 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/workspace.dart b/pkg/analyzer/lib/src/workspace/workspace.dart
index d9dc17a..0b83b88 100644
--- a/pkg/analyzer/lib/src/workspace/workspace.dart
+++ b/pkg/analyzer/lib/src/workspace/workspace.dart
@@ -67,6 +67,9 @@
/// path of the root of those packages for all of the packages that could
/// validly be imported by the library with the given [libraryPath].
Map<String, List<Folder>> packagesAvailableTo(String libraryPath);
+
+ /// Return whether [source] is located in this package's public API.
+ bool sourceIsInPublicApi(Source source);
}
/// An interface for a workspace that contains a default analysis options file.
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index 9fca7de..5a7be88 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -23,6 +23,8 @@
}
test_lints() async {
+ useEmptyByteStore();
+
newFile(testFilePath, content: r'''
void f() {
![0].isEmpty;
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 4e85656..4c28ad0 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -24,6 +24,7 @@
import 'package:meta/meta.dart';
import 'package:test/test.dart';
+import 'context_collection_resolution_caching.dart';
import 'resolution.dart';
class AnalysisOptionsFileConfig {
@@ -127,7 +128,7 @@
with ResourceProviderMixin, ResolutionTest {
static bool _lintRulesAreRegistered = false;
- final ByteStore _byteStore = MemoryByteStore();
+ ByteStore _byteStore = getContextResolutionTestByteStore();
Map<String, String> _declaredVariables = {};
AnalysisContextCollection _analysisContextCollection;
@@ -218,6 +219,12 @@
);
}
+ /// Call this method if the test needs to use the empty byte store, without
+ /// any information cached.
+ void useEmptyByteStore() {
+ _byteStore = MemoryByteStore();
+ }
+
void verifyCreatedCollection() {}
/// Create all analysis contexts in [collectionIncludedPaths].
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart
new file mode 100644
index 0000000..9f2dc62
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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:analyzer/src/dart/analysis/byte_store.dart';
+
+final _sharedByteStore = MemoryByteStore();
+final _useSharedByteStore = false;
+
+ByteStore getContextResolutionTestByteStore() {
+ if (_useSharedByteStore) {
+ return _sharedByteStore;
+ } else {
+ return MemoryByteStore();
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
new file mode 100644
index 0000000..40ce958
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
@@ -0,0 +1,512 @@
+// Copyright (c) 2020, 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:analyzer/dart/analysis/analysis_context.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/mock_packages.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:analyzer/src/workspace/package_build.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidExportOfInternalElement_BazelPackageTest);
+ defineReflectiveTests(
+ InvalidExportOfInternalElement_PackageBuildPackageTest);
+ defineReflectiveTests(InvalidExportOfInternalElement_PubPackageTest);
+ });
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_BazelPackageTest
+ extends BazelWorkspaceResolutionTest
+ with InvalidExportOfInternalElementTest {
+ /// A cached analysis context for resolving sources via the same [Workspace].
+ AnalysisContext analysisContext;
+
+ String get testPackageBazelBinPath => '$workspaceRootPath/bazel-bin/dart/my';
+
+ String get testPackageGenfilesPath =>
+ '$workspaceRootPath/bazel-genfiles/dart/my';
+
+ @override
+ String get testPackageLibPath => myPackageLibPath;
+
+ @override
+ Future<ResolvedUnitResult> resolveFile(String path) {
+ analysisContext ??= contextFor(path);
+ assert(analysisContext.workspace is BazelWorkspace);
+ return analysisContext.currentSession.getResolvedUnit(path);
+ }
+
+ @override
+ void setUp() async {
+ super.setUp();
+ var metaPath = '$workspaceThirdPartyDartPath/meta';
+ MockPackages.addMetaPackageFiles(
+ getFolder(metaPath),
+ );
+ newFile('$testPackageBazelBinPath/my.packages');
+ newFolder('$workspaceRootPath/bazel-out');
+ }
+
+ void test_exporterIsInBazelBinLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageBazelBinPath/lib/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageBazelBinPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInBazelBinLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageBazelBinPath/lib/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageBazelBinPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInGenfilesLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageGenfilesPath/lib/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageGenfilesPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInGenfilesLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageGenfilesPath/lib/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageGenfilesPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInTest() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$myPackageRootPath/test/foo_test.dart', content: r'''
+export 'package:dart.my/src/foo.dart';
+''');
+ await resolveFile2('$myPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsInBazelBin() async {
+ newFile('$testPackageBazelBinPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+
+ void test_internalIsInGenfiles() async {
+ newFile('$testPackageGenfilesPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+
+ void test_internalIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_PackageBuildPackageTest
+ extends InvalidExportOfInternalElement_PubPackageTest {
+ /// A cached analysis context for resolving sources via the same [Workspace].
+ AnalysisContext analysisContext;
+
+ String get testPackageDartToolPath =>
+ '$testPackageRootPath/.dart_tool/build/generated/test';
+
+ @override
+ Future<ResolvedUnitResult> resolveFile(String path) {
+ analysisContext ??= contextFor(path);
+ assert(analysisContext.workspace is PackageBuildWorkspace);
+ return analysisContext.currentSession.getResolvedUnit(path);
+ }
+
+ @override
+ void setUp() async {
+ analysisContext = null;
+ super.setUp();
+ newFolder(testPackageDartToolPath);
+ }
+
+ void test_exporterInGeneratedLib() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageDartToolPath/lib/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageDartToolPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_exporterInGeneratedLibSrc() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageDartToolPath/lib/src/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageDartToolPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterInLib() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageRootPath/lib/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_exporterInLibSrc() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageRootPath/lib/src/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsInGeneratedLibSrc() async {
+ newFile('$testPackageDartToolPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_internalIsLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_PubPackageTest
+ extends PubPackageResolutionTest with InvalidExportOfInternalElementTest {
+ @override
+ void setUp() async {
+ super.setUp();
+ writeTestPackageConfigWithMeta();
+ newFile('$testPackageRootPath/pubspec.yaml', content: r'''
+name: test
+version: 0.0.1
+''');
+ }
+
+ void test_exporterIsInLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInTest() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageRootPath/test/foo_test.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+}
+
+mixin InvalidExportOfInternalElementTest on ContextResolutionTest {
+ String get testPackageImplementationFilePath =>
+ '$testPackageLibPath/src/foo.dart';
+
+ String get testPackageLibPath;
+
+ void test_hideCombinator_internalHidden() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart' hide One;
+''');
+ }
+
+ void test_hideCombinator_internalNotHidden() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart' hide Two;
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 31),
+ ]);
+ }
+
+ void test_noCombinators() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_indirectExport() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+export 'bar.dart';
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_library() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+@internal
+library foo;
+
+import 'package:meta/meta.dart';
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_library_notInternal() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+library foo;
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart';
+''');
+ }
+
+ void test_noCombinators_noInternal() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+class One {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart';
+''');
+ }
+
+ void test_showCombinator_internalNotShown() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart' show Two;
+''');
+ }
+
+ void test_showCombinator_internalShown() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart' show One;
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 31),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart
new file mode 100644
index 0000000..2dee934
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart
@@ -0,0 +1,361 @@
+// Copyright (c) 2020, 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:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidInternalAnnotationTest);
+ });
+}
+
+@reflectiveTest
+class InvalidInternalAnnotationTest extends PubPackageResolutionTest {
+ String get testPackageImplementationFilePath =>
+ '$testPackageLibPath/src/foo.dart';
+
+ @override
+ void setUp() async {
+ super.setUp();
+ writeTestPackageConfigWithMeta();
+ await newFile('$testPackageRootPath/pubspec.yaml', content: r'''
+name: test
+version: 0.0.1
+''');
+ }
+
+ void test_annotationInLib() async {
+ await newFile('$testPackageLibPath/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_annotationInLib_onLibrary() async {
+ await newFile('$testPackageLibPath/foo.dart', content: r'''
+@internal
+library foo;
+import 'package:meta/meta.dart';
+''');
+ await resolveFile2('$testPackageLibPath/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 0, 9),
+ ]);
+ }
+
+ void test_annotationInLibSrc() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_annotationInLibSrcSubdirectory() async {
+ await newFile('$testPackageLibPath/src/foo/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo/foo.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_annotationInLibSubdirectory() async {
+ await newFile('$testPackageLibPath/foo/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/foo/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_annotationInTest() async {
+ await newFile('$testPackageRootPath/test/foo_test.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_privateClass() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class _One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 49, 4),
+ ]);
+ }
+
+ void test_privateClassConstructor_named() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal _C.named();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 46, 9),
+ ]);
+ }
+
+ void test_privateClassConstructor_unnamed() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal _C();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 46, 9),
+ ]);
+ }
+
+ void test_privateConstructor() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal C._f();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ ]);
+ }
+
+ void test_privateEnum() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal enum _E {one}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 48, 2),
+ error(HintCode.UNUSED_FIELD, 52, 3),
+ ]);
+ }
+
+ void test_privateEnumValue() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+enum E {@internal _one}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 41, 9),
+ error(HintCode.UNUSED_FIELD, 51, 4),
+ ]);
+ }
+
+ void test_privateExtension() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal extension _One on String {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_privateExtension_unnamed() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal extension on String {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_privateField_instance() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal int _i = 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_FIELD, 59, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 59, 6),
+ ]);
+ }
+
+ void test_privateField_static() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal static int _i = 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_FIELD, 66, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 66, 6),
+ ]);
+ }
+
+ void test_privateGetter() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal int get _i => 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 63, 2),
+ ]);
+ }
+
+ void test_privateMethod_instance() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal void _f() {}
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 60, 2),
+ ]);
+ }
+
+ void test_privateMethod_static() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal static void _f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 67, 2),
+ ]);
+ }
+
+ void test_privateMixin() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal mixin _One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 49, 4),
+ ]);
+ }
+
+ void test_privateTopLevelFunction() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal void _f() {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 48, 2),
+ ]);
+ }
+
+ void test_privateTopLevelVariable() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal int _i = 1;
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 47, 6),
+ error(HintCode.UNUSED_ELEMENT, 47, 2),
+ ]);
+ }
+
+ void test_privateTypedef() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal typedef _T = void Function();
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 51, 2),
+ ]);
+ }
+
+ void test_publicMethod_privateClass() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal void f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ ]);
+ }
+
+ void test_publicMethod_privateClass_static() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal static void f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.UNUSED_ELEMENT, 68, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 55f08d2..08a65a1 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -279,6 +279,8 @@
import 'invalid_constant_test.dart' as invalid_constant;
import 'invalid_constructor_name_test.dart' as invalid_constructor_name;
import 'invalid_exception_value_test.dart' as invalid_exception_value;
+import 'invalid_export_of_internal_element_test.dart'
+ as invalid_export_of_internal_element;
import 'invalid_extension_argument_count_test.dart'
as invalid_extension_argument_count;
import 'invalid_factory_annotation_test.dart' as invalid_factory_annotation;
@@ -287,6 +289,7 @@
as invalid_factory_name_not_a_class;
import 'invalid_field_type_in_struct_test.dart' as invalid_field_type_in_struct;
import 'invalid_immutable_annotation_test.dart' as invalid_immutable_annotation;
+import 'invalid_internal_annotation_test.dart' as invalid_internal_annotation;
import 'invalid_language_override_greater_test.dart'
as invalid_language_override_greater;
import 'invalid_language_override_test.dart' as invalid_language_override;
@@ -828,12 +831,14 @@
invalid_constant.main();
invalid_constructor_name.main();
invalid_exception_value.main();
+ invalid_export_of_internal_element.main();
invalid_extension_argument_count.main();
invalid_factory_annotation.main();
invalid_factory_method_impl.main();
invalid_factory_name_not_a_class.main();
invalid_field_type_in_struct.main();
invalid_immutable_annotation.main();
+ invalid_internal_annotation.main();
invalid_language_override_greater.main();
invalid_language_override.main();
invalid_literal_annotation.main();
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 0f23cdf..ced7369 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1308,40 +1308,61 @@
@override
HInstruction visitGetLength(HGetLength node) {
HInstruction receiver = node.receiver;
- if (_graph.allocatedFixedLists.contains(receiver)) {
- // TODO(sra): How do we keep this working if we lower/inline the receiver
- // in an optimization?
- // TODO(ngeoffray): checking if the second input is an integer
- // should not be necessary but it currently makes it easier for
- // other optimizations to reason about a fixed length constructor
- // that we know takes an int.
- if (receiver.inputs[0].isInteger(_abstractValueDomain).isDefinitelyTrue) {
- return receiver.inputs[0];
- }
- } else if (receiver.isConstantList()) {
+ if (receiver.isConstantList()) {
HConstant constantReceiver = receiver;
ListConstantValue constant = constantReceiver.constant;
return _graph.addConstantInt(constant.length, _closedWorld);
- } else if (receiver.isConstantString()) {
+ }
+
+ if (receiver.isConstantString()) {
HConstant constantReceiver = receiver;
StringConstantValue constant = constantReceiver.constant;
return _graph.addConstantInt(constant.length, _closedWorld);
- } else {
- AbstractValue type = receiver.instructionType;
- if (_abstractValueDomain.isContainer(type) &&
- _abstractValueDomain.getContainerLength(type) != null) {
- HInstruction constant = _graph.addConstantInt(
- _abstractValueDomain.getContainerLength(type), _closedWorld);
- if (_abstractValueDomain.isNull(type).isPotentiallyTrue) {
+ }
+
+ AbstractValue receiverType = receiver.instructionType;
+ if (_abstractValueDomain.isContainer(receiverType)) {
+ int /*?*/ length = _abstractValueDomain.getContainerLength(receiverType);
+ if (length != null) {
+ HInstruction constant = _graph.addConstantInt(length, _closedWorld);
+ if (_abstractValueDomain.isNull(receiverType).isPotentiallyTrue) {
// If the container can be null, we update all uses of the length
// access to use the constant instead, but keep the length access in
// the graph, to ensure we still have a null check.
node.block.rewrite(node, constant);
return node;
- } else {
- return constant;
}
+ return constant;
+ }
+ }
+
+ // Can we find the length as an input to an allocation?
+ HInstruction potentialAllocation = receiver;
+ if (receiver is HInvokeStatic &&
+ receiver.element == commonElements.setRuntimeTypeInfo) {
+ // Look through `setRuntimeTypeInfo(new Array(), ...)`
+ potentialAllocation = receiver.inputs.first;
+ }
+ if (_graph.allocatedFixedLists.contains(potentialAllocation)) {
+ // TODO(sra): How do we keep this working if we lower/inline the receiver
+ // in an optimization?
+
+ HInstruction lengthInput = potentialAllocation.inputs.first;
+
+ // We don't expect a non-integer first input to the fixed-size allocation,
+ // but checking the input is an integer ensures we do not replace a
+ // HGetlength with a reference to something with a type that will confuse
+ // bounds check eliminiation.
+ if (lengthInput.isInteger(_abstractValueDomain).isDefinitelyTrue) {
+ // TODO(sra). HGetLength may have a better type than [lengthInput] as
+ // the allocation may throw on an out-of-range input. Typically the
+ // input is an unconstrained `int` and the length is non-negative. We
+ // may have done some optimizations with the better type that we won't
+ // be able to do with the broader type of [lengthInput]. We should
+ // insert a HTypeKnown witnessed by the allocation to narrow the
+ // lengthInput.
+ return lengthInput;
}
}
diff --git a/pkg/compiler/test/analyses/api_allowed.json b/pkg/compiler/test/analyses/api_allowed.json
index e303a89..241f168 100644
--- a/pkg/compiler/test/analyses/api_allowed.json
+++ b/pkg/compiler/test/analyses/api_allowed.json
@@ -109,16 +109,7 @@
"Dynamic access of 'dart.io::_path'.": 1,
"Dynamic access of 'pid'.": 1,
"Dynamic access of 'dart.io::_arguments'.": 1,
- "Dynamic access of 'dart.io::_workingDirectory'.": 2,
- "Dynamic access of 'isListening'.": 3,
- "Dynamic access of 'address'.": 4,
- "Dynamic access of 'host'.": 5,
- "Dynamic access of 'port'.": 3,
- "Dynamic access of 'remoteAddress'.": 2,
- "Dynamic access of 'remotePort'.": 2,
- "Dynamic access of 'isTcp'.": 1,
- "Dynamic access of 'type'.": 1,
- "Dynamic access of 'name'.": 1
+ "Dynamic access of 'dart.io::_workingDirectory'.": 2
},
"org-dartlang-sdk:///lib/io/link.dart": {
"Dynamic invocation of '[]'.": 3
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 049e01d1..0d06590 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 5.1.0
+- Added support for `dart:io` extensions version 1.2.
+- Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs.
+- Added `OpenFileList`, `OpenFileRef`, `OpenFile`, `SpawnedProcessList`, `SpawnedProcessRef`, and `SpawnedProcess` objects.
+
## 5.0.0
- **breaking**: Update to version `3.39.0` of the spec.
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index 4297e45..ddecfc5 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -4,6 +4,8 @@
// TODO(bkonyi): autogenerate from service_extensions.md
+import 'dart:collection';
+
import 'package:meta/meta.dart';
import 'vm_service.dart';
@@ -54,6 +56,42 @@
'enable': enable,
});
+ /// The `getOpenFiles` RPC is used to retrieve the list of files currently
+ /// opened files by `dart:io` from a given isolate.
+ Future<OpenFileList> getOpenFiles(String isolateId) => _callHelper(
+ 'ext.dart.io.getOpenFiles',
+ isolateId,
+ );
+
+ /// The `getOpenFileById` RPC is used to retrieve information about files
+ /// currently opened by `dart:io` from a given isolate.
+ Future<OpenFile> getOpenFileById(String isolateId, int id) => _callHelper(
+ 'ext.dart.io.getOpenFileById',
+ isolateId,
+ args: {
+ 'id': id,
+ },
+ );
+
+ /// The `getSpawnedProcesses` RPC is used to retrieve the list of processed opened
+ /// by `dart:io` from a given isolate
+ Future<SpawnedProcessList> getSpawnedProcesses(String isolateId) =>
+ _callHelper(
+ 'ext.dart.io.getSpawnedProcesses',
+ isolateId,
+ );
+
+ /// The `getSpawnedProcessById` RPC is used to retrieve information about a process
+ /// spawned by `dart:io` from a given isolate.
+ Future<SpawnedProcess> getSpawnedProcessById(String isolateId, int id) =>
+ _callHelper(
+ 'ext.dart.io.getSpawnedProcessById',
+ isolateId,
+ args: {
+ 'id': id,
+ },
+ );
+
Future<T> _callHelper<T>(String method, String isolateId,
{Map args = const {}}) {
if (!_factoriesRegistered) {
@@ -70,9 +108,15 @@
}
static void _registerFactories() {
- addTypeFactory('SocketStatistic', SocketStatistic.parse);
- addTypeFactory('SocketProfile', SocketProfile.parse);
+ addTypeFactory('OpenFile', OpenFile.parse);
+ addTypeFactory('OpenFileList', OpenFileList.parse);
+ addTypeFactory('@OpenFile', OpenFileRef.parse);
addTypeFactory('HttpTimelineLoggingState', HttpTimelineLoggingState.parse);
+ addTypeFactory('SpawnedProcess', SpawnedProcess.parse);
+ addTypeFactory('SpawnedProcessList', SpawnedProcessList.parse);
+ addTypeFactory('@SpawnedProcess', SpawnedProcessRef.parse);
+ addTypeFactory('SocketProfile', SocketProfile.parse);
+ addTypeFactory('SocketStatistic', SocketStatistic.parse);
_factoriesRegistered = true;
}
}
@@ -162,3 +206,206 @@
/// Whether or not HttpClient.enableTimelineLogging is set to true for a given isolate.
final bool enabled;
}
+
+/// A [SpawnedProcessRef] contains identifying information about a spawned process.
+class SpawnedProcessRef {
+ static SpawnedProcessRef parse(Map json) =>
+ json == null ? null : SpawnedProcessRef._fromJson(json);
+
+ SpawnedProcessRef({
+ @required this.id,
+ @required this.name,
+ });
+
+ SpawnedProcessRef._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ id = json['id'],
+ name = json['name'];
+
+ static const String type = 'SpawnedProcessRef';
+
+ /// The unique ID associated with this process.
+ final int id;
+
+ /// The name of the executable.
+ final String name;
+}
+
+/// A [SpawnedProcess] contains startup information of a spawned process.
+class SpawnedProcess extends Response implements SpawnedProcessRef {
+ static SpawnedProcess parse(Map json) =>
+ json == null ? null : SpawnedProcess._fromJson(json);
+
+ SpawnedProcess({
+ @required this.id,
+ @required this.name,
+ @required this.pid,
+ @required this.startedAt,
+ @required List<String> arguments,
+ @required this.workingDirectory,
+ }) : _arguments = arguments;
+
+ SpawnedProcess._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ id = json['id'],
+ name = json['name'],
+ pid = json['pid'],
+ startedAt = json['startedAt'],
+ _arguments = List<String>.from(
+ createServiceObject(json['arguments'], const ['String']) as List ??
+ []),
+ workingDirectory = json['workingDirectory'] {
+ type = json['type'];
+ }
+
+ /// The unique ID associated with this process.
+ final int id;
+
+ /// The name of the executable.
+ final String name;
+
+ /// The process ID associated with the process.
+ final int pid;
+
+ /// The time the process was started in milliseconds since epoch.
+ final int startedAt;
+
+ /// The list of arguments provided to the process at launch.
+ List<String> get arguments => UnmodifiableListView(_arguments);
+ final List<String> _arguments;
+
+ /// The working directory of the process at launch.
+ final String workingDirectory;
+}
+
+class SpawnedProcessList extends Response {
+ static SpawnedProcessList parse(Map json) =>
+ json == null ? null : SpawnedProcessList._fromJson(json);
+
+ SpawnedProcessList({@required List<SpawnedProcessRef> processes})
+ : _processes = processes;
+
+ SpawnedProcessList._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ _processes = List<SpawnedProcessRef>.from(
+ createServiceObject(json['processes'], const ['SpawnedProcessRef'])
+ as List ??
+ []) {
+ type = json['type'];
+ }
+
+ /// A list of processes spawned through dart:io on a given isolate.
+ List<SpawnedProcessRef> get processes => UnmodifiableListView(_processes);
+ final List<SpawnedProcessRef> _processes;
+}
+
+/// A [OpenFileRef] contains identifying information about a currently opened file.
+class OpenFileRef {
+ static OpenFileRef parse(Map json) =>
+ json == null ? null : OpenFileRef._fromJson(json);
+
+ OpenFileRef({
+ @required this.id,
+ @required this.name,
+ });
+
+ OpenFileRef._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ id = json['id'],
+ name = json['name'];
+
+ static const String type = 'OpenFileRef';
+
+ /// The unique ID associated with this file.
+ final int id;
+
+ /// The path of the file.
+ final String name;
+}
+
+/// A [File] contains information about reads and writes to a currently opened file.
+class OpenFile extends Response implements OpenFileRef {
+ static OpenFile parse(Map json) =>
+ json == null ? null : OpenFile._fromJson(json);
+
+ OpenFile({
+ @required this.id,
+ @required this.name,
+ @required this.readBytes,
+ @required this.writeBytes,
+ @required this.readCount,
+ @required this.writeCount,
+ @required this.lastReadTime,
+ @required this.lastWriteTime,
+ });
+
+ OpenFile._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ id = json['id'],
+ name = json['name'],
+ readBytes = json['readBytes'],
+ writeBytes = json['writeBytes'],
+ readCount = json['readCount'],
+ writeCount = json['writeCount'],
+ lastReadTime =
+ DateTime.fromMillisecondsSinceEpoch(json['lastReadTime']),
+ lastWriteTime =
+ DateTime.fromMillisecondsSinceEpoch(json['lastWriteTime']) {
+ type = json['type'];
+ }
+
+ /// The unique ID associated with this file.
+ final int id;
+
+ /// The path of the file.
+ final String name;
+
+ /// The total number of bytes read from this file.
+ final int readBytes;
+
+ /// The total number of bytes written to this file.
+ final int writeBytes;
+
+ /// The number of reads made from this file.
+ final int readCount;
+
+ /// The number of writes made to this file.
+ final int writeCount;
+
+ /// The time at which this file was last read by this process.
+ final DateTime lastReadTime;
+
+ /// The time at which this file was last written to by this process.
+ final DateTime lastWriteTime;
+}
+
+class OpenFileList extends Response {
+ static OpenFileList parse(Map json) =>
+ json == null ? null : OpenFileList._fromJson(json);
+
+ OpenFileList({@required List<OpenFileRef> files}) : _files = files;
+
+ OpenFileList._fromJson(Map<String, dynamic> json)
+ :
+ // TODO(bkonyi): make this part of the vm_service.dart library so we can
+ // call super._fromJson.
+ _files = List<OpenFileRef>.from(
+ createServiceObject(json['files'], const ['OpenFileRef']) as List ??
+ []) {
+ type = json['type'];
+ }
+
+ /// A list of all files opened through dart:io on a given isolate.
+ List<OpenFileRef> get files => UnmodifiableListView(_files);
+ final List<OpenFileRef> _files;
+}
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 66b2910..dd8502a 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 5.0.0+1
+version: 5.1.0+1
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 1b19ba1..836e323 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:io';
+import 'dart:io' as io;
import 'package:vm_service/vm_service_io.dart';
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
@@ -30,21 +30,22 @@
const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
const Map<String, String> _TESTEE_SPAWN_ENV = {_TESTEE_ENV_KEY: 'true'};
bool _isTestee() {
- return Platform.environment.containsKey(_TESTEE_ENV_KEY);
+ return io.Platform.environment.containsKey(_TESTEE_ENV_KEY);
}
Uri _getTestUri() {
- if (Platform.script.scheme == 'data') {
+ if (io.Platform.script.scheme == 'data') {
// If we're using pub to run these tests this value isn't a file URI.
// We'll need to parse the actual URI out...
final fileRegExp = RegExp(r'file:\/\/\/.*\.dart');
- final path = fileRegExp.stringMatch(Platform.script.data.contentAsString());
+ final path =
+ fileRegExp.stringMatch(io.Platform.script.data.contentAsString());
if (path == null) {
throw 'Unable to determine file path for script!';
}
return Uri.parse(path);
} else {
- return Platform.script;
+ return io.Platform.script;
}
}
@@ -72,7 +73,7 @@
if (!pause_on_exit) {
// Wait around for the process to be killed.
// ignore: unawaited_futures
- stdin.first.then((_) => exit(0));
+ io.stdin.first.then((_) => io.exit(0));
}
}
@@ -92,20 +93,20 @@
}
if (!pause_on_exit) {
// Wait around for the process to be killed.
- stdin.first.then((_) => exit(0));
+ io.stdin.first.then((_) => io.exit(0));
}
}
}
class _ServiceTesteeLauncher {
- Process process;
+ io.Process process;
List<String> args;
bool killedByTester = false;
_ServiceTesteeLauncher() : args = [_getTestUri().toFilePath()];
// Spawn the testee process.
- Future<Process> _spawnProcess(
+ Future<io.Process> _spawnProcess(
bool pause_on_start,
bool pause_on_exit,
bool pause_on_unhandled_exceptions,
@@ -127,14 +128,14 @@
extraArgs);
}
- Future<Process> _spawnDartProcess(
+ Future<io.Process> _spawnDartProcess(
bool pause_on_start,
bool pause_on_exit,
bool pause_on_unhandled_exceptions,
bool testeeControlsServer,
bool useAuthToken,
List<String> extraArgs) {
- String dartExecutable = Platform.executable;
+ String dartExecutable = io.Platform.executable;
var fullArgs = <String>[
'--disable-dart-dev',
@@ -143,7 +144,7 @@
fullArgs.add('--pause-isolates-on-start');
}
if (pause_on_exit) {
- fullArgs.add('--pause-isolates-on-exit');
+ fullArgs.add('--pause-isolates-on-io.exit');
}
if (!useAuthToken) {
fullArgs.add('--disable-service-auth-codes');
@@ -156,7 +157,7 @@
fullArgs.addAll(extraArgs);
}
- fullArgs.addAll(Platform.executableArguments);
+ fullArgs.addAll(io.Platform.executableArguments);
if (!testeeControlsServer) {
fullArgs.add('--enable-vm-service:0');
}
@@ -165,7 +166,7 @@
return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
}
- Future<Process> _spawnCommon(String executable, List<String> arguments,
+ Future<io.Process> _spawnCommon(String executable, List<String> arguments,
Map<String, String> dartEnvironment) {
var environment = _TESTEE_SPAWN_ENV;
var bashEnvironment = StringBuffer();
@@ -176,7 +177,7 @@
});
}
print('** Launching $bashEnvironment$executable ${arguments.join(' ')}');
- return Process.start(executable, arguments, environment: environment);
+ return io.Process.start(executable, arguments, environment: environment);
}
Future<Uri> launch(
@@ -217,17 +218,17 @@
first = false;
print('** Signaled to run test queries on $uri');
}
- stdout.write('>testee>out> ${line}\n');
+ io.stdout.write('>testee>out> ${line}\n');
});
process.stderr
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((line) {
- stdout.write('>testee>err> ${line}\n');
+ io.stdout.write('>testee>err> ${line}\n');
});
process.exitCode.then((exitCode) {
- if ((exitCode != 0) && !killedByTester) {
- throw "Testee exited with $exitCode";
+ if ((io.exitCode != 0) && !killedByTester) {
+ throw "Testee io.exited with $exitCode";
}
print("** Process exited");
});
@@ -275,7 +276,7 @@
var pid = process.process.pid;
var wait = Duration(seconds: 10);
print("Testee has pid $pid, waiting $wait before continuing");
- sleep(wait);
+ io.sleep(wait);
}
setupAddresses(serverAddress);
vm = await vmServiceConnectUri(serviceWebsocketAddress);
diff --git a/pkg/vm_service/test/file_service_test.dart b/pkg/vm_service/test/file_service_test.dart
new file mode 100644
index 0000000..c74fdae
--- /dev/null
+++ b/pkg/vm_service/test/file_service_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2020, 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:convert';
+import 'dart:developer';
+import 'dart:io' as io;
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+
+Future setupFiles() async {
+ final dir = await io.Directory.systemTemp.createTemp('file_service');
+ var writingFile;
+ var readingFile;
+
+ void closeDown() {
+ if (writingFile != null) {
+ writingFile.closeSync();
+ }
+ if (readingFile != null) {
+ readingFile.closeSync();
+ }
+ dir.deleteSync(recursive: true);
+ }
+
+ Future<ServiceExtensionResponse> cleanup(ignored_a, ignored_b) {
+ closeDown();
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
+ }
+
+ Future<ServiceExtensionResponse> setup(ignored_a, ignored_b) async {
+ try {
+ final filePath = dir.path + io.Platform.pathSeparator + "file";
+ final f = io.File(filePath);
+ writingFile = await f.open(mode: io.FileMode.write);
+ await writingFile.writeByte(42);
+ await writingFile.writeByte(42);
+ await writingFile.writeByte(42);
+
+ final file = io.File.fromUri(io.Platform.script);
+ readingFile = await file.open();
+ await readingFile.readByte();
+ await readingFile.readByte();
+ await readingFile.readByte();
+ await readingFile.readByte();
+ await readingFile.readByte();
+
+ // The utility functions should close the files after them, so we
+ // don't expect the calls below to result in open files.
+ final writeTemp = dir.path + io.Platform.pathSeparator + "other_file";
+ final utilFile = io.File(writeTemp);
+ await utilFile.writeAsString('foobar');
+ final readTemp = io.File(writeTemp);
+ await readTemp.readAsString();
+ } catch (e) {
+ closeDown();
+ rethrow;
+ }
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
+ }
+
+ registerExtension('ext.dart.io.cleanup', cleanup);
+ registerExtension('ext.dart.io.setup', setup);
+}
+
+var fileTests = <IsolateTest>[
+ (VmService service, IsolateRef isolate) async {
+ await service.callServiceExtension(
+ 'ext.dart.io.setup',
+ isolateId: isolate.id,
+ );
+ try {
+ final result = await service.getOpenFiles(isolate.id);
+ expect(result, isA<OpenFileList>());
+ expect(result.files.length, equals(2));
+ final writing = await service.getOpenFileById(
+ isolate.id,
+ result.files[0].id,
+ );
+
+ expect(writing.readBytes, 0);
+ expect(writing.readCount, 0);
+ expect(writing.writeCount, 3);
+ expect(writing.writeBytes, 3);
+ expect(writing.lastWriteTime.millisecondsSinceEpoch, greaterThan(0));
+ expect(writing.lastReadTime.millisecondsSinceEpoch, 0);
+
+ final reading = await service.getOpenFileById(
+ isolate.id,
+ result.files[1].id,
+ );
+ expect(reading.readBytes, 5);
+ expect(reading.readCount, 5);
+ expect(reading.writeCount, 0);
+ expect(reading.writeBytes, 0);
+ expect(reading.lastWriteTime.millisecondsSinceEpoch, 0);
+ expect(reading.lastReadTime.millisecondsSinceEpoch, greaterThan(0));
+ } finally {
+ await service.callServiceExtension(
+ 'ext.dart.io.cleanup',
+ isolateId: isolate.id,
+ );
+ }
+ },
+];
+
+main(args) async => runIsolateTests(args, fileTests, testeeBefore: setupFiles);
diff --git a/pkg/vm_service/test/process_service_test.dart b/pkg/vm_service/test/process_service_test.dart
new file mode 100644
index 0000000..a47359a
--- /dev/null
+++ b/pkg/vm_service/test/process_service_test.dart
@@ -0,0 +1,151 @@
+// Copyright (c) 2020, 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:convert';
+import 'dart:developer';
+import 'dart:io' as io;
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+
+final dartJITBinary = path.join(path.dirname(io.Platform.resolvedExecutable),
+ 'dart' + path.extension(io.Platform.resolvedExecutable));
+
+Future setupProcesses() async {
+ final dir = await io.Directory.systemTemp.createTemp('file_service');
+
+ final args = [
+ ...io.Platform.executableArguments,
+ '--pause_isolates_on_start',
+ io.Platform.script.toFilePath(),
+ ];
+ io.Process process1;
+ io.Process process2;
+ io.Process process3;
+
+ void closeDown() {
+ if (process1 != null) {
+ process1.kill();
+ }
+ if (process2 != null) {
+ process2.kill();
+ }
+ if (process3 != null) {
+ process3.kill();
+ }
+ dir.deleteSync(recursive: true);
+ }
+
+ Future<ServiceExtensionResponse> cleanup(ignored_a, ignored_b) {
+ closeDown();
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
+ }
+
+ Future<ServiceExtensionResponse> setup(ignored_a, ignored_b) async {
+ try {
+ process1 = await io.Process.start(io.Platform.executable, args);
+ process2 =
+ await io.Process.start(io.Platform.executable, args..add('foobar'));
+ final codeFilePath = dir.path + io.Platform.pathSeparator + "other_file";
+ final codeFile = io.File(codeFilePath);
+ await codeFile.writeAsString('''
+ import "dart:io";
+
+ void main() async {
+ await stdin.drain();
+ }
+ ''');
+ process3 = await io.Process.start(
+ dartJITBinary, [...io.Platform.executableArguments, codeFilePath]);
+ } catch (_) {
+ closeDown();
+ rethrow;
+ }
+
+ final result = jsonEncode({
+ 'type': 'foobar',
+ 'pids': [process1.pid, process2.pid, process3.pid]
+ });
+ return Future.value(ServiceExtensionResponse.result(result));
+ }
+
+ Future<ServiceExtensionResponse> closeStdin(ignored_a, ignored_b) {
+ process3.stdin.close();
+ return process3.exitCode.then<ServiceExtensionResponse>((int exit) {
+ final result = jsonEncode({'type': 'foobar'});
+ return ServiceExtensionResponse.result(result);
+ });
+ }
+
+ registerExtension('ext.dart.io.cleanup', cleanup);
+ registerExtension('ext.dart.io.setup', setup);
+ registerExtension('ext.dart.io.closeStdin', closeStdin);
+}
+
+final processTests = <IsolateTest>[
+ // Initial.
+ (VmService service, IsolateRef isolate) async {
+ final setup = await service.callServiceExtension(
+ 'ext.dart.io.setup',
+ isolateId: isolate.id,
+ );
+ try {
+ SpawnedProcessList all = await service.getSpawnedProcesses(isolate.id);
+ expect(all.processes.length, equals(3));
+
+ final first = await service.getSpawnedProcessById(
+ isolate.id,
+ all.processes[0].id,
+ );
+
+ expect(first.name, io.Platform.executable);
+ expect(first.pid, equals(setup.json['pids'][0]));
+ expect(first.arguments.contains('foobar'), isFalse);
+ expect(first.startedAt, greaterThan(0));
+
+ final second = await service.getSpawnedProcessById(
+ isolate.id,
+ all.processes[1].id,
+ );
+
+ expect(second.name, io.Platform.executable);
+ expect(second.pid, equals(setup.json['pids'][1]));
+ expect(second.arguments.contains('foobar'), isTrue);
+ expect(second.pid != first.pid, isTrue);
+ expect(second.startedAt, greaterThan(0));
+ expect(second.startedAt, greaterThanOrEqualTo(first.startedAt));
+
+ final third = await service.getSpawnedProcessById(
+ isolate.id,
+ all.processes[2].id,
+ );
+
+ expect(third.name, dartJITBinary);
+ expect(third.pid, equals(setup.json['pids'][2]));
+ expect(third.pid != first.pid, isTrue);
+ expect(third.pid != second.pid, isTrue);
+ expect(third.startedAt, greaterThanOrEqualTo(second.startedAt));
+
+ await service.callServiceExtension(
+ 'ext.dart.io.closeStdin',
+ isolateId: isolate.id,
+ );
+ all = await service.getSpawnedProcesses(isolate.id);
+ expect(all.processes.length, equals(2));
+ } finally {
+ await service.callServiceExtension(
+ 'ext.dart.io.cleanup',
+ isolateId: isolate.id,
+ );
+ }
+ },
+];
+
+main(args) async =>
+ runIsolateTests(args, processTests, testeeBefore: setupProcesses);
diff --git a/runtime/observatory/tests/service/file_service_test.dart b/runtime/observatory/tests/service/file_service_test.dart
index 08c6d71..b347920 100644
--- a/runtime/observatory/tests/service/file_service_test.dart
+++ b/runtime/observatory/tests/service/file_service_test.dart
@@ -12,7 +12,7 @@
import 'test_helper.dart';
Future setupFiles() async {
- var dir = await io.Directory.systemTemp.createTemp('file_service');
+ final dir = await io.Directory.systemTemp.createTemp('file_service');
var writingFile;
var readingFile;
@@ -28,20 +28,20 @@
Future<ServiceExtensionResponse> cleanup(ignored_a, ignored_b) {
closeDown();
- var result = jsonEncode({'type': 'foobar'});
- return new Future.value(new ServiceExtensionResponse.result(result));
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
}
Future<ServiceExtensionResponse> setup(ignored_a, ignored_b) async {
try {
- var filePath = dir.path + io.Platform.pathSeparator + "file";
- var f = new io.File(filePath);
+ final filePath = dir.path + io.Platform.pathSeparator + "file";
+ final f = io.File(filePath);
writingFile = await f.open(mode: io.FileMode.write);
await writingFile.writeByte(42);
await writingFile.writeByte(42);
await writingFile.writeByte(42);
- var file = new io.File.fromUri(io.Platform.script);
+ final file = io.File.fromUri(io.Platform.script);
readingFile = await file.open();
await readingFile.readByte();
await readingFile.readByte();
@@ -51,18 +51,18 @@
// The utility functions should close the files after them, so we
// don't expect the calls below to result in open files.
- var writeTemp = dir.path + io.Platform.pathSeparator + "other_file";
- var utilFile = new io.File(writeTemp);
+ final writeTemp = dir.path + io.Platform.pathSeparator + "other_file";
+ final utilFile = io.File(writeTemp);
await utilFile.writeAsString('foobar');
- var readTemp = new io.File(writeTemp);
- var result = await readTemp.readAsString();
+ final readTemp = io.File(writeTemp);
+ final result = await readTemp.readAsString();
Expect.equals(result, 'foobar');
} catch (e) {
closeDown();
throw e;
}
- var result = jsonEncode({'type': 'foobar'});
- return new Future.value(new ServiceExtensionResponse.result(result));
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
}
registerExtension('ext.dart.io.cleanup', cleanup);
@@ -73,30 +73,29 @@
(Isolate isolate) async {
await isolate.invokeRpcNoUpgrade('ext.dart.io.setup', {});
try {
- var result =
+ final result =
await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenFiles', {});
- expect(result['type'], equals('_openfiles'));
+ expect(result['type'], equals('OpenFileList'));
+ expect(result['files'].length, equals(2));
+ final writing = await isolate.invokeRpcNoUpgrade(
+ 'ext.dart.io.getOpenFileById', {'id': result['files'][0]['id']});
- expect(result['data'].length, equals(2));
- var writing = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getFileByID', {'id': result['data'][0]['id']});
-
- expect(writing['totalRead'], equals(0));
+ expect(writing['readBytes'], equals(0));
expect(writing['readCount'], equals(0));
expect(writing['writeCount'], equals(3));
- expect(writing['totalWritten'], equals(3));
- expect(writing['lastWrite'], greaterThan(0));
- expect(writing['lastRead'], equals(0));
+ expect(writing['writeBytes'], equals(3));
+ expect(writing['lastWriteTime'], greaterThan(0));
+ expect(writing['lastReadTime'], equals(0));
- var reading = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getFileByID', {'id': result['data'][1]['id']});
+ final reading = await isolate.invokeRpcNoUpgrade(
+ 'ext.dart.io.getOpenFileById', {'id': result['files'][1]['id']});
- expect(reading['totalRead'], equals(5));
+ expect(reading['readBytes'], equals(5));
expect(reading['readCount'], equals(5));
expect(reading['writeCount'], equals(0));
- expect(reading['totalWritten'], equals(0));
- expect(reading['lastWrite'], equals(0));
- expect(reading['lastRead'], greaterThan(0));
+ expect(reading['writeBytes'], equals(0));
+ expect(reading['lastWriteTime'], equals(0));
+ expect(reading['lastReadTime'], greaterThan(0));
} finally {
await isolate.invokeRpcNoUpgrade('ext.dart.io.cleanup', {});
}
diff --git a/runtime/observatory/tests/service/process_service_test.dart b/runtime/observatory/tests/service/process_service_test.dart
index ced9326..8840ef1 100644
--- a/runtime/observatory/tests/service/process_service_test.dart
+++ b/runtime/observatory/tests/service/process_service_test.dart
@@ -13,20 +13,20 @@
import 'test_helper.dart';
-final dartJITBinary = path.join(path.dirname(io.Platform.executable),
- 'dart' + path.extension(io.Platform.executable));
+final dartJITBinary = path.join(path.dirname(io.Platform.resolvedExecutable),
+ 'dart' + path.extension(io.Platform.resolvedExecutable));
Future setupProcesses() async {
- var dir = await io.Directory.systemTemp.createTemp('file_service');
+ final dir = await io.Directory.systemTemp.createTemp('file_service');
- var args = [
+ final args = [
...io.Platform.executableArguments,
'--pause_isolates_on_start',
io.Platform.script.toFilePath(),
];
- var process1;
- var process2;
- var process3;
+ io.Process process1;
+ io.Process process2;
+ io.Process process3;
void closeDown() {
if (process1 != null) {
@@ -43,8 +43,8 @@
Future<ServiceExtensionResponse> cleanup(ignored_a, ignored_b) {
closeDown();
- var result = jsonEncode({'type': 'foobar'});
- return new Future.value(new ServiceExtensionResponse.result(result));
+ final result = jsonEncode({'type': 'foobar'});
+ return Future.value(ServiceExtensionResponse.result(result));
}
Future<ServiceExtensionResponse> setup(ignored_a, ignored_b) async {
@@ -52,8 +52,8 @@
process1 = await io.Process.start(io.Platform.executable, args);
process2 =
await io.Process.start(io.Platform.executable, args..add('foobar'));
- var codeFilePath = dir.path + io.Platform.pathSeparator + "other_file";
- var codeFile = new io.File(codeFilePath);
+ final codeFilePath = dir.path + io.Platform.pathSeparator + "other_file";
+ final codeFile = io.File(codeFilePath);
await codeFile.writeAsString('''
import "dart:io";
@@ -63,23 +63,23 @@
''');
process3 = await io.Process.start(
dartJITBinary, [...io.Platform.executableArguments, codeFilePath]);
- } catch (e) {
+ } catch (_) {
closeDown();
- throw e;
+ rethrow;
}
- var result = jsonEncode({
+ final result = jsonEncode({
'type': 'foobar',
'pids': [process1.pid, process2.pid, process3.pid]
});
- return new Future.value(new ServiceExtensionResponse.result(result));
+ return Future.value(ServiceExtensionResponse.result(result));
}
Future<ServiceExtensionResponse> closeStdin(ignored_a, ignored_b) {
process3.stdin.close();
return process3.exitCode.then<ServiceExtensionResponse>((int exit) {
- var result = jsonEncode({'type': 'foobar'});
- return new ServiceExtensionResponse.result(result);
+ final result = jsonEncode({'type': 'foobar'});
+ return ServiceExtensionResponse.result(result);
});
}
@@ -88,26 +88,28 @@
registerExtension('ext.dart.io.closeStdin', closeStdin);
}
-var processTests = <IsolateTest>[
+final processTests = <IsolateTest>[
// Initial.
(Isolate isolate) async {
- var setup = await isolate.invokeRpcNoUpgrade('ext.dart.io.setup', {});
+ final setup = await isolate.invokeRpcNoUpgrade('ext.dart.io.setup', {});
try {
- var all =
- await isolate.invokeRpcNoUpgrade('ext.dart.io.getProcesses', {});
- expect(all['type'], equals('_startedprocesses'));
+ var all = await isolate
+ .invokeRpcNoUpgrade('ext.dart.io.getSpawnedProcesses', {});
+ expect(all['type'], equals('SpawnedProcessList'));
- expect(all['data'].length, equals(3));
+ expect(all['processes'].length, equals(3));
- var first = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getProcessById', {'id': all['data'][0]['id']});
+ final first = await isolate.invokeRpcNoUpgrade(
+ 'ext.dart.io.getSpawnedProcessById',
+ {'id': all['processes'][0]['id']});
expect(first['name'], io.Platform.executable);
expect(first['pid'], equals(setup['pids'][0]));
expect(first['arguments'].contains('foobar'), isFalse);
expect(first['startedAt'], greaterThan(0));
- var second = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getProcessById', {'id': all['data'][1]['id']});
+ final second = await isolate.invokeRpcNoUpgrade(
+ 'ext.dart.io.getSpawnedProcessById',
+ {'id': all['processes'][1]['id']});
expect(second['name'], io.Platform.executable);
expect(second['pid'], equals(setup['pids'][1]));
expect(second['arguments'].contains('foobar'), isTrue);
@@ -115,8 +117,9 @@
expect(second['startedAt'], greaterThan(0));
expect(second['startedAt'], greaterThanOrEqualTo(first['startedAt']));
- var third = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getProcessById', {'id': all['data'][2]['id']});
+ final third = await isolate.invokeRpcNoUpgrade(
+ 'ext.dart.io.getSpawnedProcessById',
+ {'id': all['processes'][2]['id']});
expect(third['name'], dartJITBinary);
expect(third['pid'], equals(setup['pids'][2]));
expect(third['pid'] != first['pid'], isTrue);
@@ -124,9 +127,10 @@
expect(third['startedAt'], greaterThanOrEqualTo(second['startedAt']));
await isolate.invokeRpcNoUpgrade('ext.dart.io.closeStdin', {});
- all = await isolate.invokeRpcNoUpgrade('ext.dart.io.getProcesses', {});
- expect(all['type'], equals('_startedprocesses'));
- expect(all['data'].length, equals(2));
+ all = await isolate
+ .invokeRpcNoUpgrade('ext.dart.io.getSpawnedProcesses', {});
+ expect(all['type'], equals('SpawnedProcessList'));
+ expect(all['processes'].length, equals(2));
} finally {
await isolate.invokeRpcNoUpgrade('ext.dart.io.cleanup', {});
}
diff --git a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart b/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
deleted file mode 100644
index 8996577..0000000
--- a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2015, 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:convert';
-import 'dart:io' as io;
-import 'package:observatory/service_io.dart';
-import 'package:test/test.dart';
-import 'test_helper.dart';
-
-/// Test that we correctly remove sockets that have been closed from the list
-/// of open sockets. We explicitly leave one socket open.
-
-Future setup() async {
- var serverSocket = await io.ServerSocket.bind('127.0.0.1', 0);
- serverSocket.listen((s) {
- s.drain();
- s.close();
- });
- var socket = await io.Socket.connect("127.0.0.1", serverSocket.port);
- socket.write("foobar");
- socket.write("foobar");
-
- await socket.flush();
- await socket.close();
- await socket.drain();
-
- var socket2 = await io.Socket.connect("127.0.0.1", serverSocket.port);
- socket2.write("foobarfoobar");
- await socket2.flush();
- await socket2.close();
- await socket2.drain();
- await serverSocket.close();
-
- var server = await io.RawDatagramSocket.bind('127.0.0.1', 0);
- server.listen((io.RawSocketEvent event) {
- if (event == io.RawSocketEvent.read) {
- io.Datagram dg = server.receive();
- dg.data.forEach((x) => true);
- server.close();
- }
- });
- var client = await io.RawDatagramSocket.bind('127.0.0.1', 0);
- client.send(utf8.encoder.convert('foobar'),
- new io.InternetAddress('127.0.0.1'), server.port);
- client.close();
-
- // The one socket to expect.
- await io.ServerSocket.bind('127.0.0.1', 0);
-}
-
-var tests = <IsolateTest>[
- // Initial.
- (Isolate isolate) async {
- var result =
- await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
- expect(result['type'], equals('_opensockets'));
- // We expect only one socket to be open, the server socket create at the
- // end of test.
- expect(result['data'].length, equals(1));
- var server = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][0]['id']});
- expect(server['listening'], isTrue);
- expect(server['lastRead'], equals(0));
- expect(server['totalRead'], equals(0));
- expect(server['lastWrite'], equals(0));
- expect(server['totalWritten'], equals(0));
- expect(server['writeCount'], equals(0));
- expect(server['readCount'], equals(0));
- },
-];
-
-main(args) async => runIsolateTests(args, tests, testeeBefore: setup);
diff --git a/runtime/observatory/tests/service/tcp_socket_service_test.dart b/runtime/observatory/tests/service/tcp_socket_service_test.dart
deleted file mode 100644
index 9e61a01..0000000
--- a/runtime/observatory/tests/service/tcp_socket_service_test.dart
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2015, 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:convert';
-import 'dart:io' as io;
-import 'package:observatory/service_io.dart';
-import 'package:test/test.dart';
-import 'test_helper.dart';
-
-Future setupTCP() async {
- // Note that we don't close after us, by design we leave the sockets opens
- // to allow us to query them from the other isolate.
- var serverSocket = await io.ServerSocket.bind('127.0.0.1', 0);
- serverSocket.listen((s) {
- utf8.decoder.bind(s).listen(print);
- s.close();
- });
- var socket = await io.Socket.connect("127.0.0.1", serverSocket.port);
- socket.write("foobar");
- socket.write("foobar");
- await socket.flush();
-
- var socket2 = await io.Socket.connect("127.0.0.1", serverSocket.port);
- socket2.write("foobarfoobar");
- await socket2.flush();
-}
-
-var tcpTests = <IsolateTest>[
- // Initial.
- (Isolate isolate) async {
- var result =
- await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
- expect(result['type'], equals('_opensockets'));
- // We expect 3 sockets to be open (in this order):
- // The server socket accepting connections, on port X
- // The accepted connection on the client, on port Y
- // The client connection, on port X
- if (result['data'].length != 5) {
- print(result['data']);
- }
- expect(result['data'].length, equals(5));
- // The first socket will have a name like listening:127.0.0.1:X
- // The second will have a name like 127.0.0.1:Y
- // The third will have a name like 127.0.0.1:X
- expect(result['data'][0]['name'].startsWith('listening:127.0.0.1'), isTrue);
- expect(result['data'][1]['name'].startsWith('127.0.0.1:'), isTrue);
- expect(result['data'][2]['name'].startsWith('127.0.0.1:'), isTrue);
-
- var listening = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][0]['id']});
- expect(listening['id'], equals(result['data'][0]['id']));
- expect(listening['listening'], isTrue);
- expect(listening['socketType'], equals('TCP'));
- expect(listening['port'], greaterThanOrEqualTo(1024));
- expect(listening['lastRead'], greaterThan(0));
-
- expect(listening['totalRead'], equals(2));
- expect(listening['lastWrite'], equals(0));
- expect(listening['totalWritten'], equals(0));
- expect(listening['writeCount'], equals(0));
- expect(listening['readCount'], equals(2));
- expect(listening['remoteHost'], equals('NA'));
- expect(listening['remotePort'], equals('NA'));
-
- var client = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][1]['id']});
- expect(client['id'], equals(result['data'][1]['id']));
-
- var server = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][2]['id']});
- expect(server['id'], equals(result['data'][2]['id']));
-
- // We expect the client to be connected on the port and
- // host of the listening socket.
- expect(client['remotePort'], equals(listening['port']));
- expect(client['remoteHost'], equals(listening['host']));
- // We expect the third socket (accepted server) to be connected to the
- // same port and host as the listening socket (the listening one).
- expect(server['port'], equals(listening['port']));
- expect(server['host'], equals(listening['host']));
-
- expect(client['listening'], isFalse);
- expect(server['listening'], isFalse);
-
- expect(client['socketType'], equals('TCP'));
- expect(server['socketType'], equals('TCP'));
-
- // We are using no reserved ports.
- expect(client['port'], greaterThanOrEqualTo(1024));
- expect(server['port'], greaterThanOrEqualTo(1024));
-
- // The client and server "mirror" each other in reads and writes, and the
- // timestamps are in correct order.
- expect(client['lastRead'], equals(0));
- expect(server['lastRead'], greaterThan(0));
- expect(client['totalRead'], equals(0));
- expect(server['totalRead'], equals(12));
- expect(client['readCount'], equals(0));
- expect(server['readCount'], greaterThanOrEqualTo(1));
-
- expect(client['lastWrite'], greaterThan(0));
- expect(server['lastWrite'], equals(0));
- expect(client['totalWritten'], equals(12));
- expect(server['totalWritten'], equals(0));
- expect(client['writeCount'], greaterThanOrEqualTo(2));
- expect(server['writeCount'], equals(0));
-
- // Order
- // Stopwatch resolution on windows can make us have the same timestamp.
- if (io.Platform.isWindows) {
- expect(server['lastRead'], greaterThanOrEqualTo(client['lastWrite']));
- } else {
- expect(server['lastRead'], greaterThan(client['lastWrite']));
- }
-
- var secondClient = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][3]['id']});
- expect(secondClient['id'], equals(result['data'][3]['id']));
- var secondServer = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][4]['id']});
- expect(secondServer['id'], equals(result['data'][4]['id']));
-
- // We expect the client to be connected on the port and
- // host of the listening socket.
- expect(secondClient['remotePort'], equals(listening['port']));
- expect(secondClient['remoteHost'], equals(listening['host']));
- // We expect the third socket (accepted server) to be connected to the
- // same port and host as the listening socket (the listening one).
- expect(secondServer['port'], equals(listening['port']));
- expect(secondServer['host'], equals(listening['host']));
-
- expect(secondClient['listening'], isFalse);
- expect(secondServer['listening'], isFalse);
-
- expect(secondClient['socketType'], equals('TCP'));
- expect(secondServer['socketType'], equals('TCP'));
-
- // We are using no reserved ports.
- expect(secondClient['port'], greaterThanOrEqualTo(1024));
- expect(secondServer['port'], greaterThanOrEqualTo(1024));
-
- // The client and server "mirror" each other in reads and writes, and the
- // timestamps are in correct order.
- expect(secondClient['lastRead'], equals(0));
- expect(secondServer['lastRead'], greaterThan(0));
- expect(secondClient['totalRead'], equals(0));
- expect(secondServer['totalRead'], equals(12));
- expect(secondClient['readCount'], equals(0));
- expect(secondServer['readCount'], greaterThanOrEqualTo(1));
-
- expect(secondClient['lastWrite'], greaterThan(0));
- expect(secondServer['lastWrite'], equals(0));
- expect(secondClient['totalWritten'], equals(12));
- expect(secondServer['totalWritten'], equals(0));
- expect(secondClient['writeCount'], greaterThanOrEqualTo(1));
- expect(secondServer['writeCount'], equals(0));
-
- // Order
- // Stopwatch resolution on windows make us sometimes report the same value.
- if (io.Platform.isWindows) {
- expect(server['lastRead'], greaterThanOrEqualTo(client['lastWrite']));
- } else {
- expect(server['lastRead'], greaterThan(client['lastWrite']));
- }
- },
-];
-
-main(args) async => runIsolateTests(args, tcpTests, testeeBefore: setupTCP);
diff --git a/runtime/observatory/tests/service/udp_socket_service_test.dart b/runtime/observatory/tests/service/udp_socket_service_test.dart
deleted file mode 100644
index e49aa97..0000000
--- a/runtime/observatory/tests/service/udp_socket_service_test.dart
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2015, 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:convert';
-import 'dart:io' as io;
-import 'package:observatory/service_io.dart';
-import 'package:test/test.dart';
-import 'test_helper.dart';
-
-Future setupUDP() async {
- // Service might attach to us after we completed the setup but
- // before we actually received a datagram - if it will start inspecting
- // IO metrics at that point then it will see that no reads happened
- // and the test will fail. That is why we don't consider setup complete
- // until after we received the datagram.
- final doneCompleter = Completer<void>();
-
- var server = await io.RawDatagramSocket.bind('127.0.0.1', 0);
- server.listen((io.RawSocketEvent event) {
- if (event == io.RawSocketEvent.read) {
- io.Datagram dg = server.receive();
- dg.data.forEach((x) => true);
- if (!doneCompleter.isCompleted) {
- doneCompleter.complete(null);
- }
- }
- });
- var client = await io.RawDatagramSocket.bind('127.0.0.1', 0);
- client.send(utf8.encoder.convert('foobar'),
- new io.InternetAddress('127.0.0.1'), server.port);
-
- // Wait for datagram to arrive.
- await doneCompleter.future;
-}
-
-var udpTests = <IsolateTest>[
- // Initial.
- (Isolate isolate) async {
- var result =
- await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
- expect(result['type'], equals('_opensockets'));
- // We expect 2 sockets to be open (in this order):
- // The server socket accepting connections, on port X
- // The client socket on port Y
- expect(result['data'].length, equals(2));
- // The first socket will have a name like listening:127.0.0.1:X
- // The second will have a name like 127.0.0.1:Y
- // The third will have a name like 127.0.0.1:X
- expect(result['data'][0]['name'].startsWith('127.0.0.1'), isTrue);
- expect(result['data'][1]['name'].startsWith('127.0.0.1:'), isTrue);
-
- var server = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][0]['id']});
- expect(server['id'], equals(result['data'][0]['id']));
- expect(server['remotePort'], equals('NA'));
- expect(server['remoteHost'], equals('NA'));
- expect(server['listening'], isFalse);
- expect(server['socketType'], equals('UDP'));
- expect(server['port'], greaterThanOrEqualTo(1024));
- final now = DateTime.now().millisecondsSinceEpoch;
- expect(
- server['lastRead'], closeTo(now, Duration(seconds: 10).inMilliseconds));
- expect(server['totalRead'], equals(6));
- expect(server['lastWrite'], equals(0));
- expect(server['totalWritten'], equals(0));
- expect(server['writeCount'], equals(0));
- expect(server['readCount'], greaterThanOrEqualTo(1));
-
- var client = await isolate.invokeRpcNoUpgrade(
- 'ext.dart.io.getSocketByID', {'id': result['data'][1]['id']});
- expect(client['id'], equals(result['data'][1]['id']));
- expect(client['remotePort'], equals('NA'));
- expect(client['remoteHost'], equals('NA'));
- expect(client['listening'], isFalse);
- expect(client['socketType'], equals('UDP'));
- expect(client['port'], greaterThanOrEqualTo(1024));
- expect(client['lastRead'], equals(0));
- expect(client['totalRead'], equals(0));
- // Stopwatch resolution on windows makes us sometimes report 0;
- if (io.Platform.isWindows) {
- expect(client['lastWrite'], greaterThanOrEqualTo(0));
- } else {
- expect(client['lastWrite'], greaterThan(0));
- }
- expect(client['totalWritten'], equals(6));
- expect(client['writeCount'], greaterThanOrEqualTo(1));
- expect(client['readCount'], equals(0));
- },
-];
-
-main(args) async => runIsolateTests(args, udpTests, testeeBefore: setupUDP);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index a2226fb..8c96d22 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3133,10 +3133,6 @@
}
TEST_CASE(DartAPI_WeakPersistentHandle) {
- // GCs due to allocations or weak handle creation can cause early promotion
- // and interfer with the scenario this test is verifying.
- NoHeapGrowthControlScope force_growth;
-
Dart_Handle local_new_ref = Dart_Null();
weak_new_ref = Dart_NewWeakPersistentHandle(local_new_ref, NULL, 0,
WeakPersistentHandleCallback);
@@ -3148,25 +3144,32 @@
{
Dart_EnterScope();
- // Create an object in new space.
- Dart_Handle new_ref = AllocateNewString("new string");
- EXPECT_VALID(new_ref);
+ Dart_Handle new_ref, old_ref;
+ {
+ // GCs due to allocations or weak handle creation can cause early
+ // promotion and interfere with the scenario this test is verifying.
+ NoHeapGrowthControlScope force_growth;
- // Create an object in old space.
- Dart_Handle old_ref = AllocateOldString("old string");
- EXPECT_VALID(old_ref);
+ // Create an object in new space.
+ new_ref = AllocateNewString("new string");
+ EXPECT_VALID(new_ref);
- // Create a weak ref to the new space object.
- weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, 0,
- WeakPersistentHandleCallback);
- EXPECT_VALID(AsHandle(weak_new_ref));
- EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
+ // Create an object in old space.
+ old_ref = AllocateOldString("old string");
+ EXPECT_VALID(old_ref);
- // Create a weak ref to the old space object.
- weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, 0,
- WeakPersistentHandleCallback);
- EXPECT_VALID(AsHandle(weak_old_ref));
- EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
+ // Create a weak ref to the new space object.
+ weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, 0,
+ WeakPersistentHandleCallback);
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
+
+ // Create a weak ref to the old space object.
+ weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, 0,
+ WeakPersistentHandleCallback);
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
+ }
{
TransitionNativeToVM transition(thread);
@@ -3264,10 +3267,6 @@
}
TEST_CASE(DartAPI_FinalizableHandle) {
- // GCs due to allocations or weak handle creation can cause early promotion
- // and interfer with the scenario this test is verifying.
- NoHeapGrowthControlScope force_growth;
-
void* peer = reinterpret_cast<void*>(0);
Dart_Handle local_new_ref = Dart_Null();
finalizable_new_ref = Dart_NewFinalizableHandle(local_new_ref, peer, 0,
@@ -3283,25 +3282,32 @@
{
Dart_EnterScope();
- // Create an object in new space.
- Dart_Handle new_ref = AllocateNewString("new string");
- EXPECT_VALID(new_ref);
+ Dart_Handle new_ref, old_ref;
+ {
+ // GCs due to allocations or weak handle creation can cause early
+ // promotion and interfere with the scenario this test is verifying.
+ NoHeapGrowthControlScope force_growth;
- // Create an object in old space.
- Dart_Handle old_ref = AllocateOldString("old string");
- EXPECT_VALID(old_ref);
+ // Create an object in new space.
+ new_ref = AllocateNewString("new string");
+ EXPECT_VALID(new_ref);
- // Create a weak ref to the new space object.
- peer = reinterpret_cast<void*>(2);
- finalizable_new_ref =
- Dart_NewFinalizableHandle(new_ref, peer, 0, FinalizableHandleCallback);
- finalizable_new_ref_peer = peer;
+ // Create an object in old space.
+ old_ref = AllocateOldString("old string");
+ EXPECT_VALID(old_ref);
- // Create a weak ref to the old space object.
- peer = reinterpret_cast<void*>(3);
- finalizable_old_ref =
- Dart_NewFinalizableHandle(old_ref, peer, 0, FinalizableHandleCallback);
- finalizable_old_ref_peer = peer;
+ // Create a weak ref to the new space object.
+ peer = reinterpret_cast<void*>(2);
+ finalizable_new_ref = Dart_NewFinalizableHandle(
+ new_ref, peer, 0, FinalizableHandleCallback);
+ finalizable_new_ref_peer = peer;
+
+ // Create a weak ref to the old space object.
+ peer = reinterpret_cast<void*>(3);
+ finalizable_old_ref = Dart_NewFinalizableHandle(
+ old_ref, peer, 0, FinalizableHandleCallback);
+ finalizable_old_ref_peer = peer;
+ }
{
TransitionNativeToVM transition(thread);
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index b2dd597..2acdfd3 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -111,15 +111,13 @@
uword Heap::AllocateOld(intptr_t size, OldPage::PageType type) {
ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
- CollectForDebugging();
- uword addr = old_space_.TryAllocate(size, type);
- if (addr != 0) {
- return addr;
- }
- // If we are in the process of running a sweep, wait for the sweeper to free
- // memory.
- Thread* thread = Thread::Current();
if (old_space_.GrowthControlState()) {
+ CollectForDebugging();
+ uword addr = old_space_.TryAllocate(size, type);
+ if (addr != 0) {
+ return addr;
+ }
+ Thread* thread = Thread::Current();
// Wait for any GC tasks that are in progress.
WaitForSweeperTasks(thread);
addr = old_space_.TryAllocate(size, type);
@@ -148,7 +146,7 @@
CollectAllGarbage(kLowMemory);
WaitForSweeperTasks(thread);
}
- addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
+ uword addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
if (addr != 0) {
return addr;
}
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index e0f10cb..3c73952 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -452,6 +452,7 @@
void PageSpace::EvaluateConcurrentMarking(GrowthPolicy growth_policy) {
if (growth_policy != kForceGrowth) {
+ ASSERT(GrowthControlState());
if (heap_ != NULL) { // Some unit tests.
Thread* thread = Thread::Current();
if (thread->CanCollectGarbage()) {
@@ -1020,6 +1021,8 @@
}
void PageSpace::CollectGarbage(bool compact, bool finalize) {
+ ASSERT(GrowthControlState());
+
if (!finalize) {
#if defined(TARGET_ARCH_IA32)
return; // Barrier not implemented.
diff --git a/runtime/vm/heap/pages_test.cc b/runtime/vm/heap/pages_test.cc
index 1db6113..fed0a88 100644
--- a/runtime/vm/heap/pages_test.cc
+++ b/runtime/vm/heap/pages_test.cc
@@ -10,6 +10,7 @@
TEST_CASE(Pages) {
PageSpace* space = new PageSpace(NULL, 4 * MBInWords);
+ space->InitGrowthControl();
EXPECT(!space->Contains(reinterpret_cast<uword>(&space)));
uword block = space->TryAllocate(8 * kWordSize);
EXPECT(block != 0);
diff --git a/runtime/vm/service/service_extension.md b/runtime/vm/service/service_extension.md
index 64de58a..7bdca7f 100644
--- a/runtime/vm/service/service_extension.md
+++ b/runtime/vm/service/service_extension.md
@@ -1,4 +1,4 @@
-# Dart VM Service Protocol Extension 1.1
+# Dart VM Service Protocol Extension 1.2
This protocol describes service extensions that are made available through
the Dart core libraries, but are not part of the core
@@ -10,7 +10,7 @@
## dart:io Extensions
-This section describes _version 1.1_ of the dart:io service protocol extensions.
+This section describes _version 1.2_ of the dart:io service protocol extensions.
### getVersion
@@ -52,6 +52,50 @@
See [Success](#success).
+### getOpenFileById
+
+```
+OpenFile getOpenFileById(string isolateId, int id);
+```
+
+The _getOpenFileById_ RPC is used to retrieve information about files currently
+opened by `dart:io` from a given isolate.
+
+See [getOpenFiles](#getopenfiles) and [File](#file).
+
+### getOpenFiles
+
+```
+FileList getOpenFiles(string isolateId);
+```
+
+The _getOpenFiles_ RPC is used to retrieve the list of files currently opened
+files by `dart:io` from a given isolate.
+
+See [FileList](#filelist) and [File](#file).
+
+### getSpawnedProcessById
+
+```
+SpawnedProcess getSpawnedProcessById(string isolateId, int id);
+```
+
+The _getSpawnedProcessById_ RPC is used to retrieve information about a process spawned
+by `dart:io` from a given isolate.
+
+See [getSpawnedProcesses](#getspawnedprocesses) and [SpawnedProcess](#spawnedprocess).
+
+### getSpawnedProcesses
+
+```
+SpawnedProcessList getSpawnedProcesses(string isolateId);
+```
+
+The _getSpawnedProcesses_ RPC is used to retrieve the list of processed opened by
+`dart:io` from a given isolate.
+
+See [SpawnedProcessList](#spawnedprocesslist) and [SpawnedProcess](#spawnedprocess).
+
### getSocketProfile
```
@@ -88,6 +132,108 @@
## Public Types
+### File
+
+```
+class @OpenFile extends Response {
+ // The unique ID associated with this file.
+ int id;
+
+ // The path of the file.
+ string name;
+}
+```
+
+_@File_ is a reference to a _File_.
+
+```
+class OpenFile extends Response {
+ // The unique ID associated with this file.
+ int id;
+
+ // The path of the file.
+ string name;
+
+ // The total number of bytes read from this file.
+ int readBytes;
+
+ // The total number of bytes written to this file.
+ int writeBytes;
+
+ // The number of reads made from this file.
+ int readCount;
+
+ // The number of writes made to this file.
+ int writeCount;
+
+ // The time at which this file was last read by this process in milliseconds
+ // since epoch.
+ int lastReadTime;
+
+ // The time at which this file was last written to by this process in
+ // milliseconds since epoch.
+ int lastWriteTime;
+}
+```
+
+A _OpenFile_ contains information about reads and writes to a currently opened file.
+
+### OpenFileList
+
+```
+class OpenFileList extends Response {
+ // A list of all files opened through dart:io.
+ @OpenFile[] files;
+}
+```
+
+### SpawnedProcess
+
+```
+class @SpawnedProcess {
+ // The unique ID associated with this process.
+ int id;
+
+ // The name of the executable.
+ string name;
+}
+```
+
+_@SpawnedProcess_ is a reference to a _SpawnedProcess_.
+
+```
+class SpawnedProcess extends Response {
+ // The unique ID associated with this process.
+ int id;
+
+ // The name of the executable.
+ string name;
+
+ // The process ID associated with the process.
+ int pid;
+
+ // The time the process was started in milliseconds since epoch.
+ int startedAt;
+
+ // The list of arguments provided to the process at launch.
+ string[] arguments;
+
+ // The working directory of the process at launch.
+ string workingDirectory;
+}
+```
+
+A _Process_ contains startup information of a spawned process.
+
+### SpawnedProcessList
+
+```
+class SpawnedProcessList extends Response {
+ // A list of processes spawned through dart:io on a given isolate.
+ @SpawnedProcess[] processes;
+}
+```
+
### Response
```
@@ -178,3 +324,4 @@
------- | --------
1.0 | Initial revision.
1.1 | Added `lastReadTime` and `lastWriteTime` properties to `SocketStatistic`.
+1.2 | Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs and added `OpenFile` and `SpawnedProcess` objects.
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index a5618c6..41e3374 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -176,8 +176,6 @@
Monitor sync[kTaskCount];
bool done[kTaskCount];
Isolate* isolate = thread->isolate();
- EXPECT(isolate->heap()->GrowthControlState());
- isolate->heap()->DisableGrowthControl();
for (int i = 0; i < kTaskCount; i++) {
done[i] = false;
Dart::thread_pool()->Run<TaskWithZoneAllocation>(isolate, &sync[i],
diff --git a/sdk/lib/_internal/vm/bin/process_patch.dart b/sdk/lib/_internal/vm/bin/process_patch.dart
index bb86a0d..97426b8 100644
--- a/sdk/lib/_internal/vm/bin/process_patch.dart
+++ b/sdk/lib/_internal/vm/bin/process_patch.dart
@@ -225,10 +225,10 @@
ArgumentError.checkNotNull(_mode, "mode");
if (!connectedResourceHandler) {
- registerExtension(
- 'ext.dart.io.getProcesses', _ProcessResourceInfo.getStartedProcesses);
- registerExtension('ext.dart.io.getProcessById',
- _ProcessResourceInfo.getProcessInfoMapById);
+ registerExtension('ext.dart.io.getSpawnedProcesses',
+ _SpawnedProcessResourceInfo.getStartedProcesses);
+ registerExtension('ext.dart.io.getSpawnedProcessById',
+ _SpawnedProcessResourceInfo.getProcessInfoMapById);
connectedResourceHandler = true;
}
@@ -413,7 +413,7 @@
}
_started = true;
- final resourceInfo = new _ProcessResourceInfo(this);
+ final resourceInfo = new _SpawnedProcessResourceInfo(this);
// Setup an exit handler to handle internal cleanup and possible
// callback when a process terminates.
@@ -474,7 +474,7 @@
_path, _arguments, status._errorMessage!, status._errorCode!);
}
- final resourceInfo = new _ProcessResourceInfo(this);
+ final resourceInfo = new _SpawnedProcessResourceInfo(this);
var result = _wait(_stdinNativeSocket, _stdoutNativeSocket,
_stderrNativeSocket, _exitHandler._nativeSocket);
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index abd886f..976b1f1 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.dart
@@ -487,9 +487,6 @@
bool writeEventIssued = false;
bool writeAvailable = false;
- static bool connectedResourceHandler = false;
- _SocketResourceInfo? resourceInfo;
-
// The owner object is the object that the Socket is being used by, e.g.
// a HttpServer, a WebSocket connection, a process pipe, etc.
Object? owner;
@@ -658,7 +655,6 @@
var duration =
address.isLoopback ? _retryDurationLoopback : _retryDuration;
var timer = new Timer(duration, connectNext);
- setupResourceInfo(socket);
connecting[socket] = timer;
// Setup handlers for receiving the first write event which
@@ -775,15 +771,10 @@
osError: result, address: address, port: port);
}
if (port != 0) socket.localPort = port;
- setupResourceInfo(socket);
socket.connectToEventHandler();
return socket;
}
- static void setupResourceInfo(_NativeSocket socket) {
- socket.resourceInfo = new _SocketResourceInfo(socket);
- }
-
static Future<_NativeSocket> bindDatagram(
host, int port, bool reuseAddress, bool reusePort, int ttl) async {
_throwOnBadPort(port);
@@ -799,7 +790,6 @@
osError: result, address: address, port: port);
}
if (port != 0) socket.localPort = port;
- setupResourceInfo(socket);
return socket;
}
@@ -868,19 +858,6 @@
list = builder.toBytes();
}
}
- final resourceInformation = resourceInfo;
- assert(resourceInformation != null ||
- isPipe ||
- isInternal ||
- isInternalSignal);
- if (list != null) {
- if (resourceInformation != null) {
- resourceInformation.totalRead += list.length;
- }
- }
- if (resourceInformation != null) {
- resourceInformation.didRead();
- }
if (!const bool.fromEnvironment("dart.vm.product")) {
_SocketProfile.collectStatistic(
nativeGetSocketId(), _SocketProfileType.readBytes, list?.length);
@@ -896,16 +873,6 @@
if (isClosing || isClosed) return null;
try {
Datagram? result = nativeRecvFrom();
- if (result != null) {
- final resourceInformation = resourceInfo;
- if (resourceInformation != null) {
- resourceInformation.totalRead += result.data.length;
- }
- }
- final resourceInformation = resourceInfo;
- if (resourceInformation != null) {
- resourceInformation.didRead();
- }
if (!const bool.fromEnvironment("dart.vm.product")) {
_SocketProfile.collectStatistic(nativeGetSocketId(),
_SocketProfileType.readBytes, result?.data.length);
@@ -955,14 +922,6 @@
}
// Negate the result, as stated above.
if (result < 0) result = -result;
- final resourceInformation = resourceInfo;
- assert(resourceInformation != null ||
- isPipe ||
- isInternal ||
- isInternalSignal);
- if (resourceInformation != null) {
- resourceInformation.addWrite(result);
- }
return result;
} catch (e) {
StackTrace st = StackTrace.current;
@@ -986,14 +945,6 @@
}
int result = nativeSendTo(bufferAndStart.buffer, bufferAndStart.start,
bytes, (address as _InternetAddress)._in_addr, port);
- final resourceInformation = resourceInfo;
- assert(resourceInformation != null ||
- isPipe ||
- isInternal ||
- isInternalSignal);
- if (resourceInformation != null) {
- resourceInformation.addWrite(result);
- }
return result;
} catch (e) {
StackTrace st = StackTrace.current;
@@ -1012,16 +963,6 @@
var socket = new _NativeSocket.normal(address);
if (nativeAccept(socket) != true) return null;
socket.localPort = localPort;
- setupResourceInfo(socket);
- final resourceInformation = resourceInfo;
- assert(resourceInformation != null ||
- isPipe ||
- isInternal ||
- isInternalSignal);
- if (resourceInformation != null) {
- // We track this as read one byte.
- resourceInformation.addRead(1);
- }
return socket;
}
@@ -1149,14 +1090,6 @@
if (i == destroyedEvent) {
assert(isClosing);
assert(!isClosed);
- final resourceInformation = resourceInfo;
- assert(resourceInformation != null ||
- isPipe ||
- isInternal ||
- isInternalSignal);
- if (resourceInformation != null) {
- _SocketResourceInfo.SocketClosed(resourceInformation);
- }
isClosed = true;
closeCompleter.complete();
disconnectFromEventHandler();
@@ -1275,14 +1208,6 @@
if (eventPort == null) {
eventPort = new RawReceivePort(multiplex);
}
- if (!connectedResourceHandler) {
- registerExtension(
- 'ext.dart.io.getOpenSockets', _SocketResourceInfo.getOpenSockets);
- registerExtension('ext.dart.io.getSocketByID',
- _SocketResourceInfo.getSocketInfoMapByID);
-
- connectedResourceHandler = true;
- }
}
void disconnectFromEventHandler() {
diff --git a/sdk/lib/_internal/vm/bin/sync_socket_patch.dart b/sdk/lib/_internal/vm/bin/sync_socket_patch.dart
index f602449..6554c11 100644
--- a/sdk/lib/_internal/vm/bin/sync_socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/sync_socket_patch.dart
@@ -60,9 +60,6 @@
// Holds the port of the socket, 0 if not known.
int localPort = 0;
- // Always set by setupResourceInfo called by connectSync.
- late _SocketResourceInfo resourceInfo;
-
static _NativeSynchronousSocket connectSync(host, int port) {
if (host == null) {
throw new ArgumentError("Parameter host cannot be null");
@@ -108,7 +105,6 @@
}
return connectNext();
}
- setupResourceInfo(socket);
}
return socket;
}
@@ -164,7 +160,6 @@
void closeSync() {
if (!isClosed) {
_nativeCloseSync();
- _SocketResourceInfo.SocketClosed(resourceInfo);
isClosed = true;
}
}
@@ -210,7 +205,6 @@
if (result is OSError) {
throw new SocketException("readIntoSync failed", osError: result);
}
- resourceInfo.addRead(result);
return result;
}
@@ -230,17 +224,9 @@
if (result is OSError) {
throw result;
}
- if (result is List<int>) {
- resourceInfo.totalRead += result.length;
- }
- resourceInfo.didRead();
return result;
}
- static void setupResourceInfo(_NativeSynchronousSocket socket) {
- socket.resourceInfo = new _SocketResourceInfo(socket);
- }
-
void shutdown(SocketDirection direction) {
if (isClosed) {
return;
@@ -303,7 +289,6 @@
if (result is OSError) {
throw new SocketException("writeFromSync failed", osError: result);
}
- resourceInfo.addWrite(result);
}
void _checkAvailable() {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index ee34b7d..75f78b1 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -679,7 +679,7 @@
void _maybePerformCleanup() {
if (closed) {
- _FileResourceInfo.FileClosed(_resourceInfo);
+ _FileResourceInfo.fileClosed(_resourceInfo);
}
}
@@ -691,8 +691,8 @@
// open.
registerExtension(
'ext.dart.io.getOpenFiles', _FileResourceInfo.getOpenFiles);
- registerExtension(
- 'ext.dart.io.getFileByID', _FileResourceInfo.getFileInfoMapByID);
+ registerExtension('ext.dart.io.getOpenFileById',
+ _FileResourceInfo.getOpenFileInfoMapByID);
_connectedResourceHandler = true;
}
}
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index b916dd8..3ba76c9 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -10,10 +10,10 @@
String get name;
static int _count = 0;
- static final Stopwatch _sw = new Stopwatch()..start();
- static final _startTime = new DateTime.now().millisecondsSinceEpoch;
+ static final Stopwatch _sw = Stopwatch()..start();
+ static final _startTime = DateTime.now().millisecondsSinceEpoch;
- static double get timestamp => _startTime + _sw.elapsedMicroseconds / 1000;
+ static int get timestamp => _startTime + _sw.elapsedMicroseconds ~/ 1000;
_IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
@@ -34,20 +34,20 @@
}
abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
- int totalRead;
- int totalWritten;
+ int readBytes;
+ int writeBytes;
int readCount;
int writeCount;
- double lastRead;
- double lastWrite;
+ int lastReadTime;
+ int lastWriteTime;
// Not all call sites use this. In some cases, e.g., a socket, a read does
// not always mean that we actually read some bytes (we may do a read to see
// if there are some bytes available).
void addRead(int bytes) {
- totalRead += bytes;
+ readBytes += bytes;
readCount++;
- lastRead = _IOResourceInfo.timestamp;
+ lastReadTime = _IOResourceInfo.timestamp;
}
// In cases where we read but did not necessarily get any bytes, use this to
@@ -58,102 +58,100 @@
}
void addWrite(int bytes) {
- totalWritten += bytes;
+ writeBytes += bytes;
writeCount++;
- lastWrite = _IOResourceInfo.timestamp;
+ lastWriteTime = _IOResourceInfo.timestamp;
}
_ReadWriteResourceInfo(String type)
- : totalRead = 0,
- totalWritten = 0,
+ : readBytes = 0,
+ writeBytes = 0,
readCount = 0,
writeCount = 0,
- lastRead = 0.0,
- lastWrite = 0.0,
+ lastReadTime = 0,
+ lastWriteTime = 0,
super(type);
Map<String, dynamic> get fullValueMap => {
'type': type,
'id': id,
'name': name,
- 'totalRead': totalRead,
- 'totalWritten': totalWritten,
+ 'readBytes': readBytes,
+ 'writeBytes': writeBytes,
'readCount': readCount,
'writeCount': writeCount,
- 'lastRead': lastRead,
- 'lastWrite': lastWrite
+ 'lastReadTime': lastReadTime,
+ 'lastWriteTime': lastWriteTime
};
}
class _FileResourceInfo extends _ReadWriteResourceInfo {
- static const String _type = '_file';
+ static const String _type = 'OpenFile';
final file;
- static Map<int, _FileResourceInfo> openFiles =
- new Map<int, _FileResourceInfo>();
+ static Map<int, _FileResourceInfo> openFiles = {};
_FileResourceInfo(this.file) : super(_type) {
- FileOpened(this);
+ fileOpened(this);
}
- static FileOpened(_FileResourceInfo info) {
+ static fileOpened(_FileResourceInfo info) {
assert(!openFiles.containsKey(info.id));
openFiles[info.id] = info;
}
- static FileClosed(_FileResourceInfo info) {
+ static fileClosed(_FileResourceInfo info) {
assert(openFiles.containsKey(info.id));
openFiles.remove(info.id);
}
static Iterable<Map<String, dynamic>> getOpenFilesList() {
- return new List.from(openFiles.values.map((e) => e.referenceValueMap));
+ return List.from(openFiles.values.map(
+ (e) => e.referenceValueMap,
+ ));
}
static Future<ServiceExtensionResponse> getOpenFiles(function, params) {
assert(function == 'ext.dart.io.getOpenFiles');
- var data = {'type': '_openfiles', 'data': getOpenFilesList()};
- var jsonValue = json.encode(data);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ final data = {
+ 'type': 'OpenFileList',
+ 'files': getOpenFilesList(),
+ };
+ final jsonValue = json.encode(data);
+ return Future.value(ServiceExtensionResponse.result(jsonValue));
}
- Map<String, dynamic> getFileInfoMap() {
- return fullValueMap;
+ Map<String, dynamic> get fileInfoMap => fullValueMap;
+
+ static Future<ServiceExtensionResponse> getOpenFileInfoMapByID(
+ function, params) {
+ final id = int.parse(params['id']!);
+ final result = openFiles.containsKey(id) ? openFiles[id]!.fileInfoMap : {};
+ final jsonValue = json.encode(result);
+ return Future.value(ServiceExtensionResponse.result(jsonValue));
}
- static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) {
- var id = int.parse(params['id']!);
- var result =
- openFiles.containsKey(id) ? openFiles[id]!.getFileInfoMap() : {};
- var jsonValue = json.encode(result);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
- }
-
- String get name {
- return '${file.path}';
- }
+ String get name => file.path;
}
-class _ProcessResourceInfo extends _IOResourceInfo {
- static const String _type = '_process';
+class _SpawnedProcessResourceInfo extends _IOResourceInfo {
+ static const String _type = 'SpawnedProcess';
final process;
- final double startedAt;
+ final int startedAt;
- static Map<int, _ProcessResourceInfo> startedProcesses =
- new Map<int, _ProcessResourceInfo>();
+ static Map<int, _SpawnedProcessResourceInfo> startedProcesses =
+ Map<int, _SpawnedProcessResourceInfo>();
- _ProcessResourceInfo(this.process)
+ _SpawnedProcessResourceInfo(this.process)
: startedAt = _IOResourceInfo.timestamp,
super(_type) {
- ProcessStarted(this);
+ processStarted(this);
}
String get name => process._path;
- void stopped() {
- ProcessStopped(this);
- }
+ void stopped() => processStopped(this);
Map<String, dynamic> get fullValueMap => {
'type': type,
@@ -166,115 +164,39 @@
process._workingDirectory == null ? '.' : process._workingDirectory,
};
- static ProcessStarted(_ProcessResourceInfo info) {
+ static processStarted(_SpawnedProcessResourceInfo info) {
assert(!startedProcesses.containsKey(info.id));
startedProcesses[info.id] = info;
}
- static ProcessStopped(_ProcessResourceInfo info) {
+ static processStopped(_SpawnedProcessResourceInfo info) {
assert(startedProcesses.containsKey(info.id));
startedProcesses.remove(info.id);
}
static Iterable<Map<String, dynamic>> getStartedProcessesList() =>
- new List.from(startedProcesses.values.map((e) => e.referenceValueMap));
+ List.from(startedProcesses.values.map(
+ (e) => e.referenceValueMap,
+ ));
static Future<ServiceExtensionResponse> getStartedProcesses(
String function, Map<String, String> params) {
- assert(function == 'ext.dart.io.getProcesses');
- var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()};
- var jsonValue = json.encode(data);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ assert(function == 'ext.dart.io.getSpawnedProcesses');
+ final data = {
+ 'type': 'SpawnedProcessList',
+ 'processes': getStartedProcessesList(),
+ };
+ final jsonValue = json.encode(data);
+ return Future.value(ServiceExtensionResponse.result(jsonValue));
}
static Future<ServiceExtensionResponse> getProcessInfoMapById(
String function, Map<String, String> params) {
- var id = int.parse(params['id']!);
- var result = startedProcesses.containsKey(id)
+ final id = int.parse(params['id']!);
+ final result = startedProcesses.containsKey(id)
? startedProcesses[id]!.fullValueMap
: {};
- var jsonValue = json.encode(result);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
- }
-}
-
-class _SocketResourceInfo extends _ReadWriteResourceInfo {
- static const String _tcpString = 'TCP';
- static const String _udpString = 'UDP';
- static const String _type = '_socket';
-
- final /*_NativeSocket|*/ socket;
-
- static Map<int, _SocketResourceInfo> openSockets =
- new Map<int, _SocketResourceInfo>();
-
- _SocketResourceInfo(this.socket) : super(_type) {
- SocketOpened(this);
- }
-
- String get name {
- if (socket.isListening) {
- return 'listening:${socket.address.host}:${socket.port}';
- }
- var remote = '';
- try {
- var remoteHost = socket.remoteAddress.host;
- var remotePort = socket.remotePort;
- remote = ' -> $remoteHost:$remotePort';
- } catch (e) {} // ignored if we can't get the information
- return '${socket.address.host}:${socket.port}$remote';
- }
-
- static Iterable<Map<String, dynamic>> getOpenSocketsList() {
- return new List.from(openSockets.values.map((e) => e.referenceValueMap));
- }
-
- Map<String, dynamic> getSocketInfoMap() {
- var result = fullValueMap;
- result['socketType'] = socket.isTcp ? _tcpString : _udpString;
- result['listening'] = socket.isListening;
- result['host'] = socket.address.host;
- result['port'] = socket.port;
- if (!socket.isListening) {
- try {
- result['remoteHost'] = socket.remoteAddress.host;
- result['remotePort'] = socket.remotePort;
- } catch (e) {
- // UDP.
- result['remotePort'] = 'NA';
- result['remoteHost'] = 'NA';
- }
- } else {
- result['remotePort'] = 'NA';
- result['remoteHost'] = 'NA';
- }
- result['addressType'] = socket.address.type.name;
- return result;
- }
-
- static Future<ServiceExtensionResponse> getSocketInfoMapByID(
- String function, Map<String, String> params) {
- var id = int.parse(params['id']!);
- var result =
- openSockets.containsKey(id) ? openSockets[id]!.getSocketInfoMap() : {};
- var jsonValue = json.encode(result);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
- }
-
- static Future<ServiceExtensionResponse> getOpenSockets(function, params) {
- assert(function == 'ext.dart.io.getOpenSockets');
- var data = {'type': '_opensockets', 'data': getOpenSocketsList()};
- var jsonValue = json.encode(data);
- return new Future.value(new ServiceExtensionResponse.result(jsonValue));
- }
-
- static SocketOpened(_SocketResourceInfo info) {
- assert(!openSockets.containsKey(info.id));
- openSockets[info.id] = info;
- }
-
- static SocketClosed(_SocketResourceInfo info) {
- assert(openSockets.containsKey(info.id));
- openSockets.remove(info.id);
+ final jsonValue = json.encode(result);
+ return Future.value(ServiceExtensionResponse.result(jsonValue));
}
}
diff --git a/sdk/lib/io/network_profiling.dart b/sdk/lib/io/network_profiling.dart
index 5032d72..7121d3c 100644
--- a/sdk/lib/io/network_profiling.dart
+++ b/sdk/lib/io/network_profiling.dart
@@ -4,8 +4,9 @@
part of dart.io;
+// TODO(bkonyi): refactor into io_resource_info.dart
const int _versionMajor = 1;
-const int _versionMinor = 1;
+const int _versionMinor = 2;
const String _tcpSocket = 'tcp';
const String _udpSocket = 'udp';
diff --git a/tools/VERSION b/tools/VERSION
index c246888..7a99022 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 146
+PRERELEASE 147
PRERELEASE_PATCH 0
\ No newline at end of file