mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:44:59 +00:00
Remove the core library stubbing infrastructure.
This hasn't been used in a long time. It's just clutter now. R=ahe@google.com Review URL: https://codereview.chromium.org//1134583005
This commit is contained in:
parent
4936eb8d5d
commit
e7a1c3c585
|
@ -11,7 +11,6 @@
|
|||
'runtime/dart-runtime.gyp:dart',
|
||||
'utils/compiler/compiler.gyp:dart2js',
|
||||
'utils/pub/pub.gyp:pub',
|
||||
'utils/pub/pub.gyp:core_stubs',
|
||||
'utils/dartfmt/dartfmt.gyp:dartfmt',
|
||||
'utils/analysis_server/analysis_server.gyp:analysis_server',
|
||||
'utils/dartanalyzer/dartanalyzer.gyp:dartanalyzer',
|
||||
|
@ -38,7 +37,6 @@
|
|||
'<(SHARED_INTERMEDIATE_DIR)/pub.dart.snapshot',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/dartanalyzer.dart.snapshot',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/dartfmt.dart.snapshot',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/core_stubs/dart_io.dart',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/analysis_server.dart.snapshot',
|
||||
'tools/VERSION'
|
||||
],
|
||||
|
|
|
@ -124,7 +124,6 @@ docgen/test/*: SkipByDesign # Uses dart:io.
|
|||
http_server/test/*: Fail, OK # Uses dart:io.
|
||||
observe/test/transformer_test: Fail, OK # Uses dart:io.
|
||||
observe/test/unique_message_test: SkipByDesign # Uses dart:io.
|
||||
stub_core_library/test/*: Fail, OK # Uses dart:io.
|
||||
|
||||
[ $runtime == vm && ($arch == simarm64 || $arch == simarm || $arch == simarmv5te || $arch == simmips || $arch == armv5te) ]
|
||||
# Timeout. These are not unit tests. They do not run efficiently on our
|
||||
|
@ -187,7 +186,6 @@ analyzer2dart/test/tree_shaker_test: Crash # unsupported element kind: _escapeRe
|
|||
fixnum/test/int_32_test: Crash # try/finally
|
||||
fixnum/test/int_64_test: Crash # try/finally
|
||||
js_ast/test/printer_callback_test: Crash # unsupported element kind: templateManager:field
|
||||
stub_core_library/test/stub_test: Crash # try/finally
|
||||
typed_data/test/typed_buffers_test/01: Crash # unsupported element kind: _escapeRegExp:field
|
||||
typed_data/test/typed_buffers_test/none: Crash # unsupported element kind: _escapeRegExp:field
|
||||
typed_mock/test/typed_mock_test: Crash # try/finally
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
This package exists to create stubs for core libraries that can't be safely
|
||||
imported on some platforms: `dart:io`, `dart:html`, and so on. These stubs are
|
||||
included in the SDK and used by pub to support cross-platform packages.
|
||||
|
||||
This is an application package and is not intended to be uploaded to
|
||||
pub.dartlang.org.
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library stub_core_library.bin;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:stub_core_library/src/utils.dart';
|
||||
import 'package:stub_core_library/stub_core_library.dart';
|
||||
|
||||
/// A map from Dart core library sources to the filenames into which they should
|
||||
/// be generated.
|
||||
///
|
||||
/// The source paths are URL-formatted and relative to the Dart SDK root.
|
||||
const CORE_LIBRARIES = const {
|
||||
'lib/io/io.dart': 'dart_io.dart',
|
||||
'lib/html/html_common/html_common.dart': 'dart_html_common.dart',
|
||||
'lib/html/html_common/metadata.dart': 'metadata.dart',
|
||||
'lib/html/dartium/html_dartium.dart': 'dart_html.dart',
|
||||
'lib/indexed_db/dartium/indexed_db_dartium.dart': 'dart_indexed_db.dart',
|
||||
'lib/js/dartium/js_dartium.dart': 'dart_js.dart',
|
||||
'lib/svg/dartium/svg_dartium.dart': 'dart_svg.dart',
|
||||
'lib/web_audio/dartium/web_audio_dartium.dart': 'dart_web_audio.dart',
|
||||
'lib/web_gl/dartium/web_gl_dartium.dart': 'dart_web_gl.dart',
|
||||
'lib/web_sql/dartium/web_sql_dartium.dart': 'dart_web_sql.dart'
|
||||
};
|
||||
|
||||
/// A map from stubbable "dart:" URLs to the names of the stub files they should
|
||||
/// be replaced with.
|
||||
const IMPORT_REPLACEMENTS = const {
|
||||
'dart:io': 'dart_io.dart',
|
||||
'dart:html_common': 'dart_html_common.dart',
|
||||
'dart:html': 'dart_html.dart',
|
||||
'dart:indexed_db': 'dart_indexed_db.dart',
|
||||
'dart:js': 'dart_js.dart',
|
||||
'dart:svg': 'dart_svg.dart',
|
||||
'dart:web_audio': 'dart_web_audio.dart',
|
||||
'dart:web_gl': 'dart_web_gl.dart',
|
||||
'dart:web_sql': 'dart_web_sql.dart'
|
||||
};
|
||||
|
||||
/// The exit code for a usage error.
|
||||
const USAGE_ERROR = 64;
|
||||
|
||||
/// The root directory of the SDK.
|
||||
String get sdkRoot => p.join(
|
||||
p.dirname(p.fromUri(Platform.script)), '..', '..', '..', 'sdk');
|
||||
|
||||
/// The argument parser.
|
||||
final argParser = new ArgParser()
|
||||
..addFlag('help', abbr: 'h', help: 'Print this usage information.');
|
||||
|
||||
/// The usage string.
|
||||
String get usage => """
|
||||
Generate Dart core library stubs.
|
||||
|
||||
Usage: stub_core_libraries.dart <directory>
|
||||
|
||||
${argParser.getUsage()}""";
|
||||
|
||||
void main(List<String> arguments) {
|
||||
var options;
|
||||
try {
|
||||
options = argParser.parse(arguments);
|
||||
} on FormatException catch (e) {
|
||||
stderr.writeln(e.message);
|
||||
stderr.writeln(usage);
|
||||
exitCode = USAGE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (options['help']) {
|
||||
print(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
var destination = options.rest.isEmpty ? p.current : options.rest.first;
|
||||
|
||||
// Don't allow extra arguments.
|
||||
if (options.rest.length > 1) {
|
||||
var unexpected = options.rest.skip(1).map((arg) => '"$arg"');
|
||||
var arguments = pluralize("argument", unexpected.length);
|
||||
stderr.writeln("Unexpected $arguments ${toSentence(unexpected)}.");
|
||||
stderr.writeln(usage);
|
||||
exitCode = USAGE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
new Directory(destination).createSync(recursive: true);
|
||||
|
||||
// TODO(nweiz): Tree-shake these libraries when issue 19896 is fixed.
|
||||
CORE_LIBRARIES.forEach((path, output) {
|
||||
path = p.join(sdkRoot, p.fromUri(path));
|
||||
new File(p.join(destination, output))
|
||||
.writeAsStringSync(stubFile(path, IMPORT_REPLACEMENTS));
|
||||
});
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library stub_core_libraries.utils;
|
||||
|
||||
/// Returns a sentence fragment listing the elements of [iter].
|
||||
///
|
||||
/// This converts each element of [iter] to a string and separates them with
|
||||
/// commas and/or "and" where appropriate.
|
||||
String toSentence(Iterable iter) {
|
||||
if (iter.length == 1) return iter.first.toString();
|
||||
return iter.take(iter.length - 1).join(", ") + " and ${iter.last}";
|
||||
}
|
||||
|
||||
/// Returns [name] if [number] is 1, or the plural of [name] otherwise.
|
||||
///
|
||||
/// By default, this just adds "s" to the end of [name] to get the plural. If
|
||||
/// [plural] is passed, that's used instead.
|
||||
String pluralize(String name, int number, {String plural}) {
|
||||
if (number == 1) return name;
|
||||
if (plural != null) return plural;
|
||||
return '${name}s';
|
||||
}
|
|
@ -1,391 +0,0 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library stub_core_library;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:analyzer/src/generated/scanner.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
/// Returns the contents of a stub version of the library at [path].
|
||||
///
|
||||
/// A stub library has the same API as the original library, but none of the
|
||||
/// implementation. Specifically, this guarantees that any code that worked with
|
||||
/// the original library will be statically valid with the stubbed library, and
|
||||
/// its only runtime errors will be [UnsupportedError]s. This means that
|
||||
/// constants and const constructors are preserved.
|
||||
///
|
||||
/// [importReplacements] is a map from import URIs to their replacements. It's
|
||||
/// used so that mutliple interrelated libraries can refer to their stubbed
|
||||
/// versions rather than the originals.
|
||||
String stubFile(String path, [Map<String, String> importReplacements]) {
|
||||
var visitor = new _StubVisitor(path, importReplacements);
|
||||
parseDartFile(path).accept(visitor);
|
||||
return visitor.toString();
|
||||
}
|
||||
|
||||
/// Returns the contents of a stub version of the library parsed from [code].
|
||||
///
|
||||
/// If [code] contains `part` directives, they will be resolved relative to
|
||||
/// [path]. The contents of the parted files will be stubbed and inlined.
|
||||
String stubCode(String code, String path,
|
||||
[Map<String, String> importReplacements]) {
|
||||
var visitor = new _StubVisitor(path, importReplacements);
|
||||
parseCompilationUnit(code, name: path).accept(visitor);
|
||||
return visitor.toString();
|
||||
}
|
||||
|
||||
/// An AST visitor that traverses the tree of the original library and writes
|
||||
/// the stubbed version.
|
||||
///
|
||||
/// In order to avoid complex tree-shaking logic, this takes a conservative
|
||||
/// approach to removing private code. Private classes may still be extended by
|
||||
/// public classes; private constants may be referenced by public constants; and
|
||||
/// private static and top-level methods may be referenced by public constants
|
||||
/// or by superclass constructor calls. All of these are preserved even though
|
||||
/// most could theoretically be eliminated.
|
||||
class _StubVisitor extends ToSourceVisitor {
|
||||
/// The directory containing the library being visited.
|
||||
final String _root;
|
||||
|
||||
/// Which imports to replace.
|
||||
final Map<String, String> _importReplacements;
|
||||
|
||||
final PrintStringWriter _writer;
|
||||
|
||||
// TODO(nweiz): Get rid of this when issue 19897 is fixed.
|
||||
/// The current class declaration being visited.
|
||||
///
|
||||
/// This is `null` if there is no current class declaration.
|
||||
ClassDeclaration _class;
|
||||
|
||||
_StubVisitor(String path, Map<String, String> importReplacements)
|
||||
: this._(path, importReplacements, new PrintStringWriter());
|
||||
|
||||
_StubVisitor._(String path, Map<String, String> importReplacements,
|
||||
PrintStringWriter writer)
|
||||
: _root = p.dirname(path),
|
||||
_importReplacements = importReplacements == null ? const {} :
|
||||
importReplacements,
|
||||
_writer = writer,
|
||||
super(writer);
|
||||
|
||||
String toString() => _writer.toString();
|
||||
|
||||
visitImportDirective(ImportDirective node) {
|
||||
node = _modifyDirective(node);
|
||||
if (node != null) super.visitImportDirective(node);
|
||||
}
|
||||
|
||||
visitExportDirective(ExportDirective node) {
|
||||
node = _modifyDirective(node);
|
||||
if (node != null) super.visitExportDirective(node);
|
||||
}
|
||||
|
||||
visitPartDirective(PartDirective node) {
|
||||
// Inline parts directly in the output file.
|
||||
var path = p.url.join(_root, p.fromUri(node.uri.stringValue));
|
||||
parseDartFile(path).accept(new _StubVisitor._(path, const {}, _writer));
|
||||
}
|
||||
|
||||
visitPartOfDirective(PartOfDirective node) {
|
||||
// Remove "part of", since parts are inlined.
|
||||
}
|
||||
|
||||
visitClassDeclaration(ClassDeclaration node) {
|
||||
_class = _clone(node);
|
||||
_class.nativeClause = null;
|
||||
super.visitClassDeclaration(_class);
|
||||
_class = null;
|
||||
}
|
||||
|
||||
visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
node = _withoutExternal(node);
|
||||
|
||||
// Remove field initializers and redirecting initializers but not superclass
|
||||
// initializers. The code is ugly because NodeList doesn't support
|
||||
// removeWhere.
|
||||
var superclassInitializers = node.initializers.where((initializer) =>
|
||||
initializer is SuperConstructorInvocation).toList();
|
||||
node.initializers.clear();
|
||||
node.initializers.addAll(superclassInitializers);
|
||||
|
||||
// Add a space because ToSourceVisitor doesn't and it makes testing easier.
|
||||
_writer.print(" ");
|
||||
super.visitConstructorDeclaration(node);
|
||||
}
|
||||
|
||||
visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
||||
// If this is a const constructor, it should actually work, so don't screw
|
||||
// with the superclass constructor.
|
||||
if ((node.parent as ConstructorDeclaration).constKeyword != null) {
|
||||
return super.visitSuperConstructorInvocation(node);
|
||||
}
|
||||
|
||||
_writer.print("super");
|
||||
_visitNodeWithPrefix(".", node.constructorName);
|
||||
_writer.print("(");
|
||||
|
||||
// If one stubbed class extends another, we don't want to run the original
|
||||
// code for the superclass constructor call, and we do want an
|
||||
// UnsupportedException that points to the subclass rather than the
|
||||
// superclass. To do this, we null out all but the first superclass
|
||||
// constructor parameter and replace the first parameter with a throw.
|
||||
var positionalArguments = node.argumentList.arguments
|
||||
.where((argument) => argument is! NamedExpression);
|
||||
if (positionalArguments.isNotEmpty) {
|
||||
_writer.print(_unsupported(_functionName(node)));
|
||||
for (var i = 0; i < positionalArguments.length - 1; i++) {
|
||||
_writer.print(", null");
|
||||
}
|
||||
}
|
||||
|
||||
_writer.print(")");
|
||||
}
|
||||
|
||||
visitMethodDeclaration(MethodDeclaration node) {
|
||||
// Private non-static methods aren't public and aren't accessible from
|
||||
// constant expressions, so can be safely removed.
|
||||
if (Identifier.isPrivateName(node.name.name) && !node.isStatic) return;
|
||||
_writer.print(" ");
|
||||
super.visitMethodDeclaration(_withoutExternal(node));
|
||||
}
|
||||
|
||||
visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
super.visitFunctionDeclaration(_withoutExternal(node));
|
||||
}
|
||||
|
||||
visitBlockFunctionBody(BlockFunctionBody node) => _emitFunctionBody(node);
|
||||
|
||||
visitExpressionFunctionBody(ExpressionFunctionBody node) =>
|
||||
_emitFunctionBody(node);
|
||||
|
||||
visitNativeFunctionBody(NativeFunctionBody node) => _emitFunctionBody(node);
|
||||
|
||||
visitEmptyFunctionBody(FunctionBody node) {
|
||||
// Preserve empty function bodies for abstract methods, since there's no
|
||||
// reason not to. Note that "empty" here means "foo();" not "foo() {}".
|
||||
var isAbstractMethod = node.parent is MethodDeclaration &&
|
||||
!(node.parent as MethodDeclaration).isStatic && _class != null &&
|
||||
_class.isAbstract;
|
||||
|
||||
// Preserve empty function bodies for const constructors because we want
|
||||
// them to continue to work.
|
||||
var isConstConstructor = node.parent is ConstructorDeclaration &&
|
||||
(node.parent as ConstructorDeclaration).constKeyword != null;
|
||||
|
||||
if (isAbstractMethod || isConstConstructor) {
|
||||
super.visitEmptyFunctionBody(node);
|
||||
_writer.print(" ");
|
||||
} else {
|
||||
_writer.print(" ");
|
||||
_emitFunctionBody(node);
|
||||
}
|
||||
}
|
||||
|
||||
visitFieldFormalParameter(FieldFormalParameter node) {
|
||||
// Remove "this." because instance variables are replaced with getters and
|
||||
// setters or just set to null.
|
||||
_emitTokenWithSuffix(node.keyword, " ");
|
||||
|
||||
// Make sure the parameter is still typed by grabbing the type from the
|
||||
// associated instance variable.
|
||||
var type = node.type;
|
||||
if (type == null) {
|
||||
var variable = _class.members
|
||||
.where((member) => member is FieldDeclaration)
|
||||
.expand((member) => member.fields.variables)
|
||||
.firstWhere((variable) => variable.name.name == node.identifier.name,
|
||||
orElse: () => null);
|
||||
if (variable != null) type = variable.parent.type;
|
||||
}
|
||||
|
||||
_visitNodeWithSuffix(type, " ");
|
||||
_visitNode(node.identifier);
|
||||
_visitNode(node.parameters);
|
||||
}
|
||||
|
||||
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
||||
node.variables.variables.forEach(_emitVariableDeclaration);
|
||||
}
|
||||
|
||||
visitFieldDeclaration(FieldDeclaration node) {
|
||||
_writer.print(" ");
|
||||
node.fields.variables.forEach(_emitVariableDeclaration);
|
||||
}
|
||||
|
||||
/// Modifies a directive to respect [importReplacements] and ignore hidden
|
||||
/// core libraries.
|
||||
///
|
||||
/// This can return `null`, indicating that the directive should not be
|
||||
/// emitted.
|
||||
UriBasedDirective _modifyDirective(UriBasedDirective node) {
|
||||
// Ignore internal "dart:" libraries.
|
||||
if (node.uri.stringValue.startsWith('dart:_')) return null;
|
||||
|
||||
// Replace libraries in [importReplacements].
|
||||
if (_importReplacements.containsKey(node.uri.stringValue)) {
|
||||
node = _clone(node);
|
||||
var token = new StringToken(TokenType.STRING,
|
||||
'"${_importReplacements[node.uri.stringValue]}"', 0);
|
||||
node.uri = new SimpleStringLiteral(token, null);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// Emits a variable declaration, either as a literal variable or as a getter
|
||||
/// and maybe a setter that throw [UnsupportedError]s.
|
||||
_emitVariableDeclaration(VariableDeclaration node) {
|
||||
VariableDeclarationList parent = node.parent;
|
||||
var isStatic = node.parent.parent is FieldDeclaration &&
|
||||
(node.parent.parent as FieldDeclaration).isStatic;
|
||||
|
||||
// Preserve constants as-is.
|
||||
if (node.isConst) {
|
||||
if (isStatic) _writer.print("static ");
|
||||
_writer.print("const ");
|
||||
_visitNode(node);
|
||||
_writer.print("; ");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore non-const private variables.
|
||||
if (Identifier.isPrivateName(node.name.name)) return;
|
||||
|
||||
// There's no need to throw errors for instance fields of classes that can't
|
||||
// be constructed.
|
||||
if (!isStatic && _class != null && !_inConstructableClass) {
|
||||
_emitTokenWithSuffix(parent.keyword, " ");
|
||||
_visitNodeWithSuffix(parent.type, " ");
|
||||
_visitNode(node.name);
|
||||
// Add an initializer to make sure that final variables are initialized.
|
||||
if (node.isFinal) _writer.print(" = null; ");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = node.name.name;
|
||||
if (_class != null) name = "${_class.name}.$name";
|
||||
|
||||
// Convert public variables into getters and setters that throw
|
||||
// UnsupportedErrors.
|
||||
if (isStatic) _writer.print("static ");
|
||||
_visitNodeWithSuffix(parent.type, " ");
|
||||
_writer.print("get ");
|
||||
_visitNode(node.name);
|
||||
_writer.print(" => ${_unsupported(name)}; ");
|
||||
if (node.isFinal) return;
|
||||
|
||||
if (isStatic) _writer.print("static ");
|
||||
_writer.print("set ");
|
||||
_visitNode(node.name);
|
||||
_writer.print("(");
|
||||
_visitNodeWithSuffix(parent.type, " ");
|
||||
_writer.print("_) { ${_unsupported("$name=")}; } ");
|
||||
}
|
||||
|
||||
/// Emits a function body.
|
||||
///
|
||||
/// This usually emits a body that throws an [UnsupportedError], but it can
|
||||
/// emit an empty body as well.
|
||||
void _emitFunctionBody(FunctionBody node) {
|
||||
// There's no need to throw errors for instance methods of classes that
|
||||
// can't be constructed.
|
||||
var parent = node.parent;
|
||||
if (parent is MethodDeclaration && !parent.isStatic &&
|
||||
!_inConstructableClass) {
|
||||
_writer.print('{} ');
|
||||
return;
|
||||
}
|
||||
|
||||
_writer.print('{ ${_unsupported(_functionName(node))}; } ');
|
||||
}
|
||||
|
||||
// Returns a human-readable name for the function containing [node].
|
||||
String _functionName(AstNode node) {
|
||||
// Come up with a nice name for the error message so users can tell exactly
|
||||
// what unsupported method they're calling.
|
||||
var function = node.getAncestor((ancestor) =>
|
||||
ancestor is FunctionDeclaration || ancestor is MethodDeclaration);
|
||||
if (function != null) {
|
||||
var name = function.name.name;
|
||||
if (function.isSetter) {
|
||||
name = "$name=";
|
||||
} else if (!function.isGetter &&
|
||||
!(function is MethodDeclaration && function.isOperator)) {
|
||||
name = "$name()";
|
||||
}
|
||||
if (_class != null) name = "${_class.name}.$name";
|
||||
return name;
|
||||
}
|
||||
|
||||
var constructor = node.getAncestor((ancestor) =>
|
||||
ancestor is ConstructorDeclaration);
|
||||
if (constructor == null) return "This function";
|
||||
|
||||
var name = "new ${constructor.returnType.name}";
|
||||
if (constructor.name != null) name = "$name.${constructor.name}";
|
||||
return "$name()";
|
||||
}
|
||||
|
||||
/// Returns a deep copy of [node].
|
||||
AstNode _clone(AstNode node) => node.accept(new AstCloner());
|
||||
|
||||
/// Returns a deep copy of [node] without the "external" keyword.
|
||||
AstNode _withoutExternal(node) {
|
||||
var clone = node.accept(new AstCloner());
|
||||
clone.externalKeyword = null;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// Visits [node] if it's non-`null`.
|
||||
void _visitNode(AstNode node) {
|
||||
if (node != null) node.accept(this);
|
||||
}
|
||||
|
||||
/// Visits [node] then emits [suffix] if [node] isn't `null`.
|
||||
void _visitNodeWithSuffix(AstNode node, String suffix) {
|
||||
if (node == null) return;
|
||||
node.accept(this);
|
||||
_writer.print(suffix);
|
||||
}
|
||||
|
||||
/// Emits [prefix] then visits [node] if [node] isn't `null`.
|
||||
void _visitNodeWithPrefix(String prefix, AstNode node) {
|
||||
if (node == null) return;
|
||||
_writer.print(prefix);
|
||||
node.accept(this);
|
||||
}
|
||||
|
||||
/// Emits [token] followed by [suffix] if [token] isn't `null`.
|
||||
void _emitTokenWithSuffix(Token token, String suffix) {
|
||||
if (token == null) return;
|
||||
_writer.print(token.lexeme);
|
||||
_writer.print(suffix);
|
||||
}
|
||||
|
||||
/// Returns an expression that throws an [UnsupportedError] explaining that
|
||||
/// [name] isn't supported.
|
||||
String _unsupported(String name) => 'throw new UnsupportedError("$name is '
|
||||
'unsupported on this platform.")';
|
||||
|
||||
/// Returns whether or not the visitor is currently visiting a class that can
|
||||
/// be constructed without error after it's stubbed.
|
||||
///
|
||||
/// There are two cases where a class will be constructable once it's been
|
||||
/// stubbed. First, a class with a const constructor will be preserved, since
|
||||
/// making the const constructor fail would statically break code. Second, a
|
||||
/// class with a default constructor is preserved since adding a constructor
|
||||
/// that throws an error could statically break uses of the class as a mixin.
|
||||
bool get _inConstructableClass {
|
||||
if (_class == null) return false;
|
||||
|
||||
var constructors = _class.members.where((member) =>
|
||||
member is ConstructorDeclaration);
|
||||
if (constructors.isEmpty) return true;
|
||||
|
||||
return constructors.any((constructor) => constructor.constKeyword != null);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
name: stub_core_library
|
||||
description: A repo-internal package for creating core library stubs.
|
||||
dependencies:
|
||||
args: ">=0.11.0 <0.14.0"
|
||||
analyzer: ">=0.22.0-dev <0.23.0"
|
||||
path: ">=1.1.0 <2.0.0"
|
|
@ -1,428 +0,0 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library stub_core_libraries.test;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:stub_core_library/stub_core_library.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
String sandbox;
|
||||
|
||||
main() {
|
||||
setUp(() {
|
||||
sandbox = Directory.systemTemp.createTempSync('stub_core_library_').path;
|
||||
});
|
||||
|
||||
tearDown(() => new Directory(sandbox).deleteSync(recursive: true));
|
||||
|
||||
group("imports", () {
|
||||
test("dart: imports are preserved by default", () {
|
||||
expectStub("""
|
||||
import "dart:core";
|
||||
import "dart:html";
|
||||
import "dart:fblthp";
|
||||
""", """
|
||||
import "dart:core";
|
||||
import "dart:html";
|
||||
import "dart:fblthp";
|
||||
""");
|
||||
});
|
||||
|
||||
test("internal dart: imports are removed", () {
|
||||
expectStub("""
|
||||
import "dart:_internal";
|
||||
import "dart:_blink" as _blink;
|
||||
import "dart:_fblthp";
|
||||
""", "");
|
||||
});
|
||||
|
||||
test("replaced imports are replaced", () {
|
||||
expectStub("""
|
||||
import "dart:html";
|
||||
import "foo.dart" as foo;
|
||||
""", """
|
||||
import "dart_html.dart";
|
||||
import "bar.dart" as foo;
|
||||
""", {
|
||||
"dart:html": "dart_html.dart",
|
||||
"foo.dart": "bar.dart"
|
||||
});
|
||||
});
|
||||
|
||||
test("exports are replaced as well", () {
|
||||
expectStub("""
|
||||
export "dart:html";
|
||||
export "foo.dart" show foo;
|
||||
""", """
|
||||
export "dart_html.dart";
|
||||
export "bar.dart" show foo;
|
||||
""", {
|
||||
"dart:html": "dart_html.dart",
|
||||
"foo.dart": "bar.dart"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("a parted file is stubbed and included inline", () {
|
||||
new File(p.join(sandbox, "part.dart")).writeAsStringSync("""
|
||||
part of lib;
|
||||
void foo() => print('foo!');
|
||||
""");
|
||||
|
||||
expectStub("""
|
||||
library lib;
|
||||
part "part.dart";
|
||||
""", """
|
||||
library lib;
|
||||
void foo() { ${unsupported("foo()")}; }
|
||||
""");
|
||||
});
|
||||
|
||||
test("a class declaration's native clause is removed", () {
|
||||
expectStub("class Foo native 'Foo' {}", "class Foo {}");
|
||||
});
|
||||
|
||||
group("constructors", () {
|
||||
test("a constructor's body is stubbed out", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
Foo() { print("Created a foo!"); }
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's empty body is stubbed out", () {
|
||||
expectStub("class Foo { Foo(); }", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's external declaration is removed", () {
|
||||
expectStub("class Foo { external Foo(); }", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's field initializers are removed", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
final _field1;
|
||||
final _field2;
|
||||
|
||||
Foo()
|
||||
: _field1 = 1,
|
||||
_field2 = 2;
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's redirecting initializers are removed", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
Foo() : this.create();
|
||||
Foo.create();
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
Foo.create() { ${unsupported("new Foo.create()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's superclass calls are preserved", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
Foo(int i, int j, {int k});
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
Bar() : super(1, 2, k: 3);
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo(int i, int j, {int k}) { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
Bar()
|
||||
: super(${unsupported("new Bar()")}, null) {
|
||||
${unsupported("new Bar()")};
|
||||
}
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a constructor's initializing formals are replaced with normal "
|
||||
"parameters", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
final int _i;
|
||||
var _j;
|
||||
final List<int> _k;
|
||||
|
||||
Foo(this._i, this._j, this._k);
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo(int _i, _j, List<int> _k) { ${unsupported("new Foo()")}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a const constructor isn't stubbed", () {
|
||||
expectStub("class Foo { const Foo(); }", "class Foo { const Foo(); }");
|
||||
});
|
||||
|
||||
test("a const constructor's superclass calls are fully preserved", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
const Foo(int i, int j, int k);
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
const Bar() : super(1, 2, 3);
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
const Foo(int i, int j, int k);
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
const Bar() : super(1, 2, 3);
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("a redirecting const constructor stops redirecting", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
const Foo.named(int i, int j, int k)
|
||||
: this(i, j, k);
|
||||
const Foo(int i, int j, int k);
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
const Foo.named(int i, int j, int k);
|
||||
const Foo(int i, int j, int k);
|
||||
}
|
||||
""");
|
||||
});
|
||||
});
|
||||
|
||||
group("functions", () {
|
||||
test("stubs a top-level function", () {
|
||||
expectStub("void foo() => print('hello!');",
|
||||
"void foo() { ${unsupported('foo()')}; }");
|
||||
});
|
||||
|
||||
test("stubs a private top-level function", () {
|
||||
expectStub("void _foo() => print('hello!');",
|
||||
"void _foo() { ${unsupported('_foo()')}; }");
|
||||
});
|
||||
|
||||
test("stubs a method", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
foo() => print("hello!");
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
foo() { ${unsupported('Foo.foo()')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("empties a method in an unconstructable class", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
Foo();
|
||||
foo() => print("hello!");
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported('new Foo()')}; }
|
||||
foo() {}
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("removes a private instance method", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
_foo() => print("hello!");
|
||||
}
|
||||
""", "class Foo {}");
|
||||
});
|
||||
|
||||
test("stubs a private static method", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
static _foo() => print("hello!");
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
static _foo() { ${unsupported('Foo._foo()')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("preserves an abstract instance method", () {
|
||||
expectStub("abstract class Foo { foo(); }",
|
||||
"abstract class Foo { foo(); }");
|
||||
});
|
||||
|
||||
test("removes a native function body", () {
|
||||
expectStub("void foo() native 'foo';",
|
||||
"void foo() { ${unsupported('foo()')}; }");
|
||||
});
|
||||
});
|
||||
|
||||
group("top-level fields", () {
|
||||
test("stubs out a top-level field", () {
|
||||
expectStub("int foo;", """
|
||||
int get foo => ${unsupported('foo')};
|
||||
set foo(int _) { ${unsupported('foo=')}; }
|
||||
""");
|
||||
});
|
||||
|
||||
test("stubs out a top-level field with a value", () {
|
||||
expectStub("int foo = 12;", """
|
||||
int get foo => ${unsupported('foo')};
|
||||
set foo(int _) { ${unsupported('foo=')}; }
|
||||
""");
|
||||
});
|
||||
|
||||
test("stubs out a final top-level field", () {
|
||||
expectStub("final int foo = 12;",
|
||||
"int get foo => ${unsupported('foo')};");
|
||||
});
|
||||
|
||||
test("preserves a const top-level field", () {
|
||||
expectStub("const foo = 12;", "const foo = 12;");
|
||||
});
|
||||
|
||||
test("removes a private top-level field", () {
|
||||
expectStub("int _foo = 12;", "");
|
||||
});
|
||||
|
||||
test("preserves a private const top-level field", () {
|
||||
expectStub("const _foo = 12;", "const _foo = 12;");
|
||||
});
|
||||
|
||||
test("splits a multiple-declaration top-level field", () {
|
||||
expectStub("int foo, bar, baz;", """
|
||||
int get foo => ${unsupported('foo')};
|
||||
set foo(int _) { ${unsupported('foo=')}; }
|
||||
int get bar => ${unsupported('bar')};
|
||||
set bar(int _) { ${unsupported('bar=')}; }
|
||||
int get baz => ${unsupported('baz')};
|
||||
set baz(int _) { ${unsupported('baz=')}; }
|
||||
""");
|
||||
});
|
||||
});
|
||||
|
||||
group("instance fields", () {
|
||||
test("stubs out an instance field", () {
|
||||
expectStub("class Foo { int foo; }", """
|
||||
class Foo {
|
||||
int get foo => ${unsupported('Foo.foo')};
|
||||
set foo(int _) { ${unsupported('Foo.foo=')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("stubs out an instance field with a value", () {
|
||||
expectStub("class Foo { int foo = 12; }", """
|
||||
class Foo {
|
||||
int get foo => ${unsupported('Foo.foo')};
|
||||
set foo(int _) { ${unsupported('Foo.foo=')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("stubs out a final instance field", () {
|
||||
expectStub("class Foo { final int foo = 12; }", """
|
||||
class Foo {
|
||||
int get foo => ${unsupported('Foo.foo')};
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("removes a private instance field", () {
|
||||
expectStub("class Foo { int _foo = 12; }", "class Foo { }");
|
||||
});
|
||||
|
||||
test("stubs out a static instance field", () {
|
||||
expectStub("class Foo { static int foo = 12; }", """
|
||||
class Foo {
|
||||
static int get foo => ${unsupported('Foo.foo')};
|
||||
static set foo(int _) { ${unsupported('Foo.foo=')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("removes a private static instance field", () {
|
||||
expectStub("class Foo { static int _foo = 12; }", "class Foo { }");
|
||||
});
|
||||
|
||||
test("preserves a static const instance field", () {
|
||||
expectStub("class Foo { static const foo = 12; }",
|
||||
"class Foo { static const foo = 12; }");
|
||||
});
|
||||
|
||||
test("nulls a field for an unconstructable class", () {
|
||||
expectStub("""
|
||||
class Foo {
|
||||
Foo();
|
||||
final foo = 12;
|
||||
}
|
||||
""", """
|
||||
class Foo {
|
||||
Foo() { ${unsupported("new Foo()")}; }
|
||||
final foo = null;
|
||||
}
|
||||
""");
|
||||
});
|
||||
|
||||
test("splits a multiple-declaration instance field", () {
|
||||
expectStub("class Foo { int foo, bar, baz; }", """
|
||||
class Foo {
|
||||
int get foo => ${unsupported('Foo.foo')};
|
||||
set foo(int _) { ${unsupported('Foo.foo=')}; }
|
||||
int get bar => ${unsupported('Foo.bar')};
|
||||
set bar(int _) { ${unsupported('Foo.bar=')}; }
|
||||
int get baz => ${unsupported('Foo.baz')};
|
||||
set baz(int _) { ${unsupported('Foo.baz=')}; }
|
||||
}
|
||||
""");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Expects that [source] will transform into [expected] when stubbed.
|
||||
void expectStub(String source, String expected,
|
||||
[Map<String, String> importReplacements]) {
|
||||
expect(stubCode(source, p.join(sandbox, 'source.dart'), importReplacements),
|
||||
equalsIgnoringWhitespace(expected));
|
||||
}
|
||||
|
||||
/// Returns code for throwing an [UnsupportedError] for the given name.
|
||||
String unsupported(String name) => 'throw new UnsupportedError("$name is '
|
||||
'unsupported on this platform.")';
|
|
@ -233,9 +233,6 @@ def Main():
|
|||
join(RESOURCE),
|
||||
ignore=ignore_patterns('.svn'))
|
||||
|
||||
copytree(join(SNAPSHOT, 'core_stubs'),
|
||||
join(RESOURCE, 'dart', 'core_stubs'))
|
||||
|
||||
# Copy in 7zip for Windows.
|
||||
if HOST_OS == 'win32':
|
||||
copytree(join(HOME, 'third_party', '7zip'),
|
||||
|
|
|
@ -37,34 +37,6 @@
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'core_stubs',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'../../runtime/dart-runtime.gyp:dart',
|
||||
'../../pkg/pkg.gyp:pkg_packages',
|
||||
'../../pkg/pkg_files.gyp:pkg_files_stamp'
|
||||
],
|
||||
'actions': [
|
||||
{
|
||||
'action_name': 'generate_core_stubs',
|
||||
'inputs': [
|
||||
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
|
||||
'../../sdk/lib/_internal/libraries.dart',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/pkg_files.stamp',
|
||||
],
|
||||
'outputs': [
|
||||
'<(SHARED_INTERMEDIATE_DIR)/core_stubs/dart_io.dart',
|
||||
],
|
||||
'action': [
|
||||
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
|
||||
'--package-root=<(PRODUCT_DIR)/packages/',
|
||||
'../../pkg/stub_core_library/bin/stub_core_library.dart',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/core_stubs',
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
# Other targets depend on pub files, but have to many inputs, which causes
|
||||
# issues on some platforms.
|
||||
# This target lists all the files in sdk/lib/_internal/pub,
|
||||
|
|
Loading…
Reference in a new issue